FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2024-03-29 01:21:52
Exec Total Coverage
Lines: 3324 5049 65.8%
Functions: 161 215 74.9%
Branches: 1951 3462 56.4%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <stdint.h>
27 #include <inttypes.h>
28
29 #include "movenc.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
33 #include "riff.h"
34 #include "avio.h"
35 #include "iamf_writer.h"
36 #include "isom.h"
37 #include "av1.h"
38 #include "avc.h"
39 #include "evc.h"
40 #include "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/bsf.h"
46 #include "libavcodec/internal.h"
47 #include "libavcodec/put_bits.h"
48 #include "libavcodec/vc1_common.h"
49 #include "libavcodec/raw.h"
50 #include "internal.h"
51 #include "libavutil/avstring.h"
52 #include "libavutil/bprint.h"
53 #include "libavutil/channel_layout.h"
54 #include "libavutil/csp.h"
55 #include "libavutil/intfloat.h"
56 #include "libavutil/mathematics.h"
57 #include "libavutil/libm.h"
58 #include "libavutil/opt.h"
59 #include "libavutil/dict.h"
60 #include "libavutil/pixdesc.h"
61 #include "libavutil/stereo3d.h"
62 #include "libavutil/timecode.h"
63 #include "libavutil/dovi_meta.h"
64 #include "libavutil/uuid.h"
65 #include "hevc.h"
66 #include "rtpenc.h"
67 #include "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 { "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},
115 { "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},
116 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
117 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
118 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
119 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
120 { "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},
121 { "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},
122 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
123 { "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"},
124 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
125 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
126 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
127 { NULL },
128 };
129
130 static const AVClass mov_isobmff_muxer_class = {
131 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
132 .item_name = av_default_item_name,
133 .option = options,
134 .version = LIBAVUTIL_VERSION_INT,
135 };
136
137 static int get_moov_size(AVFormatContext *s);
138 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
139
140 23 static int utf8len(const uint8_t *b)
141 {
142 23 int len = 0;
143 int val;
144
2/2
✓ Branch 0 taken 457 times.
✓ Branch 1 taken 23 times.
480 while (*b) {
145
3/8
✓ Branch 0 taken 457 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 457 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 457 times.
457 GET_UTF8(val, *b++, return -1;)
146 457 len++;
147 }
148 23 return len;
149 }
150
151 //FIXME support 64 bit variant with wide placeholders
152 5805 static int64_t update_size(AVIOContext *pb, int64_t pos)
153 {
154 5805 int64_t curpos = avio_tell(pb);
155 5805 avio_seek(pb, pos, SEEK_SET);
156 5805 avio_wb32(pb, curpos - pos); /* rewrite size */
157 5805 avio_seek(pb, curpos, SEEK_SET);
158
159 5805 return curpos - pos;
160 }
161
162 313 static int co64_required(const MOVTrack *track)
163 {
164
3/4
✓ Branch 0 taken 225 times.
✓ Branch 1 taken 88 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 225 times.
313 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
165 return 1;
166 313 return 0;
167 }
168
169 18414 static int is_cover_image(const AVStream *st)
170 {
171 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
172 * is encoded as sparse video track */
173
3/4
✓ Branch 0 taken 18414 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 18402 times.
18414 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
174 }
175
176 6 static int rtp_hinting_needed(const AVStream *st)
177 {
178 /* Add hint tracks for each real audio and video stream */
179
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
180 return 0;
181
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
182
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
183 }
184
185 /* Chunk offset atom */
186 313 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
187 {
188 int i;
189 313 int mode64 = co64_required(track); // use 32 bit size variant if possible
190 313 int64_t pos = avio_tell(pb);
191 313 avio_wb32(pb, 0); /* size */
192
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 if (mode64)
193 ffio_wfourcc(pb, "co64");
194 else
195 313 ffio_wfourcc(pb, "stco");
196 313 avio_wb32(pb, 0); /* version & flags */
197 313 avio_wb32(pb, track->chunkCount); /* entry count */
198
2/2
✓ Branch 0 taken 13057 times.
✓ Branch 1 taken 313 times.
13370 for (i = 0; i < track->entry; i++) {
199
2/2
✓ Branch 0 taken 10119 times.
✓ Branch 1 taken 2938 times.
13057 if (!track->cluster[i].chunkNum)
200 10119 continue;
201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2938 times.
2938 if (mode64 == 1)
202 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
203 else
204 2938 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
205 }
206 313 return update_size(pb, pos);
207 }
208
209 /* Sample size atom */
210 313 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
211 {
212 313 int equalChunks = 1;
213 313 int i, j, entries = 0, tst = -1, oldtst = -1;
214
215 313 int64_t pos = avio_tell(pb);
216 313 avio_wb32(pb, 0); /* size */
217 313 ffio_wfourcc(pb, "stsz");
218 313 avio_wb32(pb, 0); /* version & flags */
219
220
2/2
✓ Branch 0 taken 13057 times.
✓ Branch 1 taken 313 times.
13370 for (i = 0; i < track->entry; i++) {
221 13057 tst = track->cluster[i].size / track->cluster[i].entries;
222
4/4
✓ Branch 0 taken 12832 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 8464 times.
✓ Branch 3 taken 4368 times.
13057 if (oldtst != -1 && tst != oldtst)
223 8464 equalChunks = 0;
224 13057 oldtst = tst;
225 13057 entries += track->cluster[i].entries;
226 }
227
4/4
✓ Branch 0 taken 189 times.
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 88 times.
414 if (equalChunks && track->entry) {
228
1/2
✓ Branch 0 taken 101 times.
✗ Branch 1 not taken.
101 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
229 101 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
230 101 avio_wb32(pb, sSize); // sample size
231 101 avio_wb32(pb, entries); // sample count
232 } else {
233 212 avio_wb32(pb, 0); // sample size
234 212 avio_wb32(pb, entries); // sample count
235
2/2
✓ Branch 0 taken 9616 times.
✓ Branch 1 taken 212 times.
9828 for (i = 0; i < track->entry; i++) {
236
2/2
✓ Branch 0 taken 9616 times.
✓ Branch 1 taken 9616 times.
19232 for (j = 0; j < track->cluster[i].entries; j++) {
237 9616 avio_wb32(pb, track->cluster[i].size /
238 9616 track->cluster[i].entries);
239 }
240 }
241 }
242 313 return update_size(pb, pos);
243 }
244
245 /* Sample to chunk atom */
246 313 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
247 {
248 313 int index = 0, oldval = -1, i;
249 int64_t entryPos, curpos;
250
251 313 int64_t pos = avio_tell(pb);
252 313 avio_wb32(pb, 0); /* size */
253 313 ffio_wfourcc(pb, "stsc");
254 313 avio_wb32(pb, 0); // version & flags
255 313 entryPos = avio_tell(pb);
256 313 avio_wb32(pb, track->chunkCount); // entry count
257
2/2
✓ Branch 0 taken 13057 times.
✓ Branch 1 taken 313 times.
13370 for (i = 0; i < track->entry; i++) {
258
4/4
✓ Branch 0 taken 10889 times.
✓ Branch 1 taken 2168 times.
✓ Branch 2 taken 770 times.
✓ Branch 3 taken 10119 times.
13057 if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) {
259 770 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
260 770 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
261 770 avio_wb32(pb, 0x1); // sample description index
262 770 oldval = track->cluster[i].samples_in_chunk;
263 770 index++;
264 }
265 }
266 313 curpos = avio_tell(pb);
267 313 avio_seek(pb, entryPos, SEEK_SET);
268 313 avio_wb32(pb, index); // rewrite size
269 313 avio_seek(pb, curpos, SEEK_SET);
270
271 313 return update_size(pb, pos);
272 }
273
274 /* Sync sample atom */
275 49 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
276 {
277 int64_t curpos, entryPos;
278 49 int i, index = 0;
279 49 int64_t pos = avio_tell(pb);
280 49 avio_wb32(pb, 0); // size
281
1/2
✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
49 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
282 49 avio_wb32(pb, 0); // version & flags
283 49 entryPos = avio_tell(pb);
284 49 avio_wb32(pb, track->entry); // entry count
285
2/2
✓ Branch 0 taken 2943 times.
✓ Branch 1 taken 49 times.
2992 for (i = 0; i < track->entry; i++) {
286
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 2751 times.
2943 if (track->cluster[i].flags & flag) {
287 192 avio_wb32(pb, i + 1);
288 192 index++;
289 }
290 }
291 49 curpos = avio_tell(pb);
292 49 avio_seek(pb, entryPos, SEEK_SET);
293 49 avio_wb32(pb, index); // rewrite size
294 49 avio_seek(pb, curpos, SEEK_SET);
295 49 return update_size(pb, pos);
296 }
297
298 /* Sample dependency atom */
299 2 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
300 {
301 int i;
302 uint8_t leading, dependent, reference, redundancy;
303 2 int64_t pos = avio_tell(pb);
304 2 avio_wb32(pb, 0); // size
305 2 ffio_wfourcc(pb, "sdtp");
306 2 avio_wb32(pb, 0); // version & flags
307
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 for (i = 0; i < track->entry; i++) {
308 2 dependent = MOV_SAMPLE_DEPENDENCY_YES;
309 2 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
310
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
311 2 reference = MOV_SAMPLE_DEPENDENCY_NO;
312 }
313
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
314 2 dependent = MOV_SAMPLE_DEPENDENCY_NO;
315 }
316 2 avio_w8(pb, (leading << 6) | (dependent << 4) |
317 2 (reference << 2) | redundancy);
318 }
319 2 return update_size(pb, pos);
320 }
321
322 4 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
323 {
324 AVIOContext *dyn_bc;
325 4 int64_t pos = avio_tell(pb);
326 4 uint8_t *dyn_buf = NULL;
327 int dyn_size;
328 4 int ret = avio_open_dyn_buf(&dyn_bc);
329
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
330 return ret;
331
332 4 avio_wb32(pb, 0);
333 4 ffio_wfourcc(pb, "iacb");
334 4 avio_w8(pb, 1); // configurationVersion
335
336 4 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
338 return ret;
339
340 4 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
341 4 ffio_write_leb(pb, dyn_size);
342 4 avio_write(pb, dyn_buf, dyn_size);
343 4 av_free(dyn_buf);
344
345 4 return update_size(pb, pos);
346 }
347
348 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
349 {
350 avio_wb32(pb, 0x11); /* size */
351 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
352 else ffio_wfourcc(pb, "damr");
353 ffio_wfourcc(pb, "FFMP");
354 avio_w8(pb, 0); /* decoder version */
355
356 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
357 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
358 avio_w8(pb, 0x01); /* Frames per sample */
359 return 0x11;
360 }
361
362 struct eac3_info {
363 AVPacket *pkt;
364 uint8_t ec3_done;
365 uint8_t num_blocks;
366
367 /* Layout of the EC3SpecificBox */
368 /* maximum bitrate */
369 uint16_t data_rate;
370 int8_t ac3_bit_rate_code;
371 /* number of independent substreams */
372 uint8_t num_ind_sub;
373 struct {
374 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
375 uint8_t fscod;
376 /* bit stream identification 5 bits */
377 uint8_t bsid;
378 /* one bit reserved */
379 /* audio service mixing (not supported yet) 1 bit */
380 /* bit stream mode 3 bits */
381 uint8_t bsmod;
382 /* audio coding mode 3 bits */
383 uint8_t acmod;
384 /* sub woofer on 1 bit */
385 uint8_t lfeon;
386 /* 3 bits reserved */
387 /* number of dependent substreams associated with this substream 4 bits */
388 uint8_t num_dep_sub;
389 /* channel locations of the dependent substream(s), if any, 9 bits */
390 uint16_t chan_loc;
391 /* if there is no dependent substream, then one bit reserved instead */
392 } substream[1]; /* TODO: support 8 independent substreams */
393 };
394
395 5 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
396 {
397 5 struct eac3_info *info = track->eac3_priv;
398 PutBitContext pbc;
399 uint8_t buf[3];
400
401
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) {
402 av_log(s, AV_LOG_ERROR,
403 "Cannot write moov atom before AC3 packets."
404 " Set the delay_moov flag to fix this.\n");
405 return AVERROR(EINVAL);
406 }
407
408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->substream[0].bsid > 8) {
409 av_log(s, AV_LOG_ERROR,
410 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
411 "ISOBMFF specification in ETSI TS 102 366!\n",
412 info->substream[0].bsid);
413 return AVERROR(EINVAL);
414 }
415
416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->ac3_bit_rate_code < 0) {
417 av_log(s, AV_LOG_ERROR,
418 "No valid AC3 bit rate code for data rate of %d!\n",
419 info->data_rate);
420 return AVERROR(EINVAL);
421 }
422
423 5 avio_wb32(pb, 11);
424 5 ffio_wfourcc(pb, "dac3");
425
426 5 init_put_bits(&pbc, buf, sizeof(buf));
427 5 put_bits(&pbc, 2, info->substream[0].fscod);
428 5 put_bits(&pbc, 5, info->substream[0].bsid);
429 5 put_bits(&pbc, 3, info->substream[0].bsmod);
430 5 put_bits(&pbc, 3, info->substream[0].acmod);
431 5 put_bits(&pbc, 1, info->substream[0].lfeon);
432 5 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
433 5 put_bits(&pbc, 5, 0); // reserved
434
435 5 flush_put_bits(&pbc);
436 5 avio_write(pb, buf, sizeof(buf));
437
438 5 return 11;
439 }
440
441 1039 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
442 {
443 1039 AC3HeaderInfo *hdr = NULL;
444 struct eac3_info *info;
445 int num_blocks, ret;
446
447
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
1039 if (!track->eac3_priv) {
448
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
449 return AVERROR(ENOMEM);
450
451 5 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
452 }
453 1039 info = track->eac3_priv;
454
455
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()))
456 return AVERROR(ENOMEM);
457
458
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) {
459
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
460 goto end;
461
462 /* drop the packets until we see a good one */
463
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
464 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
465 1 ret = 0;
466 } else
467 ret = AVERROR_INVALIDDATA;
468 1 goto end;
469 }
470
471 1038 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
472 1038 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
473 hdr->ac3_bit_rate_code);
474 1038 num_blocks = hdr->num_blocks;
475
476
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6 times.
1038 if (!info->ec3_done) {
477 /* AC-3 substream must be the first one */
478
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) {
479 ret = AVERROR(EINVAL);
480 goto end;
481 }
482
483 /* this should always be the case, given that our AC-3 parser
484 * concatenates dependent frames to their independent parent */
485
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
486
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
487 /* substream ids must be incremental */
488
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid > info->num_ind_sub + 1) {
489 ret = AVERROR(EINVAL);
490 goto end;
491 }
492
493
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid == info->num_ind_sub + 1) {
494 //info->num_ind_sub++;
495 avpriv_request_sample(mov->fc, "Multiple independent substreams");
496 ret = AVERROR_PATCHWELCOME;
497 goto end;
498
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (hdr->substreamid < info->num_ind_sub ||
499
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) {
500 1 info->ec3_done = 1;
501 1 goto concatenate;
502 }
503 } else {
504 if (hdr->substreamid != 0) {
505 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
506 ret = AVERROR_PATCHWELCOME;
507 goto end;
508 }
509 }
510
511 /* fill the info needed for the "dec3" atom */
512 5 info->substream[hdr->substreamid].fscod = hdr->sr_code;
513 5 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
514 5 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
515 5 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
516 5 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
517
518
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_AC3) {
519 // with AC-3 we only require the information of a single packet,
520 // so we can finish as soon as the basic values of the bit stream
521 // have been set to the track's informational structure.
522 4 info->ec3_done = 1;
523 4 goto concatenate;
524 }
525
526 /* Parse dependent substream(s), if any */
527
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pkt->size != hdr->frame_size) {
528 int cumul_size = hdr->frame_size;
529 int parent = hdr->substreamid;
530
531 while (cumul_size != pkt->size) {
532 GetBitContext gbc;
533 int i;
534 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
535 if (ret < 0)
536 goto end;
537 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
538 ret = AVERROR(EINVAL);
539 goto end;
540 }
541 info->substream[parent].num_dep_sub++;
542 ret /= 8;
543
544 /* header is parsed up to lfeon, but custom channel map may be needed */
545 init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret);
546 /* skip bsid */
547 skip_bits(&gbc, 5);
548 /* skip volume control params */
549 for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
550 skip_bits(&gbc, 5); // skip dialog normalization
551 if (get_bits1(&gbc)) {
552 skip_bits(&gbc, 8); // skip compression gain word
553 }
554 }
555 /* get the dependent stream channel map, if exists */
556 if (get_bits1(&gbc))
557 info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f;
558 else
559 info->substream[parent].chan_loc |= hdr->channel_mode;
560 cumul_size += hdr->frame_size;
561 }
562 }
563 }
564
565 1033 concatenate:
566
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) {
567 1038 ret = pkt->size;
568 1038 goto end;
569 }
570 else if (info->num_blocks + num_blocks > 6) {
571 ret = AVERROR_INVALIDDATA;
572 goto end;
573 }
574
575 if (!info->num_blocks) {
576 ret = av_packet_ref(info->pkt, pkt);
577 if (!ret)
578 info->num_blocks = num_blocks;
579 goto end;
580 } else {
581 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
582 goto end;
583 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
584 info->num_blocks += num_blocks;
585 info->pkt->duration += pkt->duration;
586 if (info->num_blocks != 6)
587 goto end;
588 av_packet_unref(pkt);
589 av_packet_move_ref(pkt, info->pkt);
590 info->num_blocks = 0;
591 }
592 ret = pkt->size;
593
594 1039 end:
595 1039 av_free(hdr);
596
597 1039 return ret;
598 }
599
600 1 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
601 {
602 PutBitContext pbc;
603 uint8_t *buf;
604 struct eac3_info *info;
605 int size, i;
606
607
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->eac3_priv) {
608 av_log(s, AV_LOG_ERROR,
609 "Cannot write moov atom before EAC3 packets parsed.\n");
610 return AVERROR(EINVAL);
611 }
612
613 1 info = track->eac3_priv;
614 1 size = 2 + ((34 * (info->num_ind_sub + 1) + 7) >> 3);
615 1 buf = av_malloc(size);
616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buf) {
617 return AVERROR(ENOMEM);
618 }
619
620 1 init_put_bits(&pbc, buf, size);
621 1 put_bits(&pbc, 13, info->data_rate);
622 1 put_bits(&pbc, 3, info->num_ind_sub);
623
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i <= info->num_ind_sub; i++) {
624 1 put_bits(&pbc, 2, info->substream[i].fscod);
625 1 put_bits(&pbc, 5, info->substream[i].bsid);
626 1 put_bits(&pbc, 1, 0); /* reserved */
627 1 put_bits(&pbc, 1, 0); /* asvc */
628 1 put_bits(&pbc, 3, info->substream[i].bsmod);
629 1 put_bits(&pbc, 3, info->substream[i].acmod);
630 1 put_bits(&pbc, 1, info->substream[i].lfeon);
631 1 put_bits(&pbc, 5, 0); /* reserved */
632 1 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
633
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!info->substream[i].num_dep_sub) {
634 1 put_bits(&pbc, 1, 0); /* reserved */
635 } else {
636 put_bits(&pbc, 9, info->substream[i].chan_loc);
637 }
638 }
639 1 flush_put_bits(&pbc);
640 1 size = put_bytes_output(&pbc);
641
642 1 avio_wb32(pb, size + 8);
643 1 ffio_wfourcc(pb, "dec3");
644 1 avio_write(pb, buf, size);
645
646 1 av_free(buf);
647
648 1 return size;
649 }
650
651 /**
652 * This function writes extradata "as is".
653 * Extradata must be formatted like a valid atom (with size and tag).
654 */
655 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
656 {
657 12 avio_write(pb, track->par->extradata, track->par->extradata_size);
658 12 return track->par->extradata_size;
659 }
660
661 static int mov_write_enda_tag(AVIOContext *pb)
662 {
663 avio_wb32(pb, 10);
664 ffio_wfourcc(pb, "enda");
665 avio_wb16(pb, 1); /* little endian */
666 return 10;
667 }
668
669 2 static int mov_write_enda_tag_be(AVIOContext *pb)
670 {
671 2 avio_wb32(pb, 10);
672 2 ffio_wfourcc(pb, "enda");
673 2 avio_wb16(pb, 0); /* big endian */
674 2 return 10;
675 }
676
677 292 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
678 {
679 292 int i = 3;
680 292 avio_w8(pb, tag);
681
2/2
✓ Branch 0 taken 876 times.
✓ Branch 1 taken 292 times.
1168 for (; i > 0; i--)
682 876 avio_w8(pb, (size >> (7 * i)) | 0x80);
683 292 avio_w8(pb, size & 0x7F);
684 292 }
685
686 197 static unsigned compute_avg_bitrate(MOVTrack *track)
687 {
688 197 uint64_t size = 0;
689 int i;
690
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 163 times.
197 if (!track->track_duration)
691 34 return 0;
692
2/2
✓ Branch 0 taken 8709 times.
✓ Branch 1 taken 163 times.
8872 for (i = 0; i < track->entry; i++)
693 8709 size += track->cluster[i].size;
694 163 return size * 8 * track->timescale / track->track_duration;
695 }
696
697 struct mpeg4_bit_rate_values {
698 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
699 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
700 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
701 };
702
703 197 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
704 {
705 394 const AVPacketSideData *sd = track->st ?
706 196 av_packet_side_data_get(track->st->codecpar->coded_side_data,
707 196 track->st->codecpar->nb_coded_side_data,
708
2/2
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 1 times.
197 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
709
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 170 times.
197 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
710 197 struct mpeg4_bit_rate_values bit_rates = { 0 };
711
712 197 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
713
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 73 times.
197 if (!bit_rates.avg_bit_rate) {
714 // if the average bit rate cannot be calculated at this point, such as
715 // in the case of fragmented MP4, utilize the following values as
716 // fall-back in priority order:
717 //
718 // 1. average bit rate property
719 // 2. bit rate (usually average over the whole clip)
720 // 3. maximum bit rate property
721
722
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 121 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
124 if (props && props->avg_bitrate) {
723 3 bit_rates.avg_bit_rate = props->avg_bitrate;
724
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 119 times.
121 } else if (track->par->bit_rate) {
725 2 bit_rates.avg_bit_rate = track->par->bit_rate;
726
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 119 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
119 } else if (props && props->max_bitrate) {
727 bit_rates.avg_bit_rate = props->max_bitrate;
728 }
729 }
730
731 // (FIXME should be max rate in any 1 sec window)
732 197 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
733 bit_rates.avg_bit_rate);
734
735 // utilize values from properties if we have them available
736
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 170 times.
197 if (props) {
737 27 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
738 props->max_bitrate);
739 27 bit_rates.buffer_size = props->buffer_size / 8;
740 }
741
742 197 return bit_rates;
743 }
744
745 73 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
746 {
747 73 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
748 73 int64_t pos = avio_tell(pb);
749
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 int decoder_specific_info_len = track->vos_len ? 5 + track->vos_len : 0;
750
751 73 avio_wb32(pb, 0); // size
752 73 ffio_wfourcc(pb, "esds");
753 73 avio_wb32(pb, 0); // Version
754
755 // ES descriptor
756 73 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
757 73 avio_wb16(pb, track->track_id);
758 73 avio_w8(pb, 0x00); // flags (= no flags)
759
760 // DecoderConfig descriptor
761 73 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
762
763 // Object type indication
764
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
765
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 track->par->codec_id == AV_CODEC_ID_MP3) &&
766 track->par->sample_rate > 24000)
767 avio_w8(pb, 0x6B); // 11172-3
768 else
769 73 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
770
771 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
772 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
774 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
775
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 20 times.
73 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
776 53 avio_w8(pb, 0x15); // flags (= Audiostream)
777 else
778 20 avio_w8(pb, 0x11); // flags (= Visualstream)
779
780 73 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
781 73 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
782 73 avio_wb32(pb, bit_rates.avg_bit_rate);
783
784
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if (track->vos_len) {
785 // DecoderSpecific info descriptor
786 73 put_descr(pb, 0x05, track->vos_len);
787 73 avio_write(pb, track->vos_data, track->vos_len);
788 }
789
790 // SL descriptor
791 73 put_descr(pb, 0x06, 1);
792 73 avio_w8(pb, 0x02);
793 73 return update_size(pb, pos);
794 }
795
796 71 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
797 {
798
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 return codec_id == AV_CODEC_ID_PCM_S24LE ||
799
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 codec_id == AV_CODEC_ID_PCM_S32LE ||
800
2/4
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 71 times.
142 codec_id == AV_CODEC_ID_PCM_F32LE ||
801 codec_id == AV_CODEC_ID_PCM_F64LE;
802 }
803
804 71 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
805 {
806
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 4 times.
67 return codec_id == AV_CODEC_ID_PCM_S24BE ||
807
1/2
✓ Branch 0 taken 63 times.
✗ Branch 1 not taken.
63 codec_id == AV_CODEC_ID_PCM_S32BE ||
808
3/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63 times.
138 codec_id == AV_CODEC_ID_PCM_F32BE ||
809 codec_id == AV_CODEC_ID_PCM_F64BE;
810 }
811
812 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
813 {
814 int ret;
815 int64_t pos = avio_tell(pb);
816 avio_wb32(pb, 0);
817 avio_wl32(pb, track->tag); // store it byteswapped
818 track->par->codec_tag = av_bswap16(track->tag >> 16);
819 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
820 return ret;
821 return update_size(pb, pos);
822 }
823
824 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
825 {
826 int ret;
827 int64_t pos = avio_tell(pb);
828 avio_wb32(pb, 0);
829 ffio_wfourcc(pb, "wfex");
830 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
831 return ret;
832 return update_size(pb, pos);
833 }
834
835 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
836 {
837 int64_t pos = avio_tell(pb);
838 avio_wb32(pb, 0);
839 ffio_wfourcc(pb, "dfLa");
840 avio_w8(pb, 0); /* version */
841 avio_wb24(pb, 0); /* flags */
842
843 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
844 if (track->par->extradata_size != FLAC_STREAMINFO_SIZE)
845 return AVERROR_INVALIDDATA;
846
847 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
848 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
849 avio_wb24(pb, track->par->extradata_size); /* Length */
850 avio_write(pb, track->par->extradata, track->par->extradata_size); /* BlockData[Length] */
851
852 return update_size(pb, pos);
853 }
854
855 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
856 {
857 int64_t pos = avio_tell(pb);
858 int channels, channel_map;
859 avio_wb32(pb, 0);
860 ffio_wfourcc(pb, "dOps");
861 avio_w8(pb, 0); /* Version */
862 if (track->par->extradata_size < 19) {
863 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
864 return AVERROR_INVALIDDATA;
865 }
866 /* extradata contains an Ogg OpusHead, other than byte-ordering and
867 OpusHead's preceeding magic/version, OpusSpecificBox is currently
868 identical. */
869 channels = AV_RB8(track->par->extradata + 9);
870 channel_map = AV_RB8(track->par->extradata + 18);
871
872 avio_w8(pb, channels); /* OuputChannelCount */
873 avio_wb16(pb, AV_RL16(track->par->extradata + 10)); /* PreSkip */
874 avio_wb32(pb, AV_RL32(track->par->extradata + 12)); /* InputSampleRate */
875 avio_wb16(pb, AV_RL16(track->par->extradata + 16)); /* OutputGain */
876 avio_w8(pb, channel_map); /* ChannelMappingFamily */
877 /* Write the rest of the header out without byte-swapping. */
878 if (channel_map) {
879 if (track->par->extradata_size < 21 + channels) {
880 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
881 return AVERROR_INVALIDDATA;
882 }
883 avio_write(pb, track->par->extradata + 19, 2 + channels); /* ChannelMappingTable */
884 }
885
886 return update_size(pb, pos);
887 }
888
889 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
890 {
891 int64_t pos = avio_tell(pb);
892 int length;
893 avio_wb32(pb, 0);
894 ffio_wfourcc(pb, "dmlp");
895
896 if (track->vos_len < 20) {
897 av_log(s, AV_LOG_ERROR,
898 "Cannot write moov atom before TrueHD packets."
899 " Set the delay_moov flag to fix this.\n");
900 return AVERROR(EINVAL);
901 }
902
903 length = (AV_RB16(track->vos_data) & 0xFFF) * 2;
904 if (length < 20 || length > track->vos_len)
905 return AVERROR_INVALIDDATA;
906
907 // Only TrueHD is supported
908 if (AV_RB32(track->vos_data + 4) != 0xF8726FBA)
909 return AVERROR_INVALIDDATA;
910
911 avio_wb32(pb, AV_RB32(track->vos_data + 8)); /* format_info */
912 avio_wb16(pb, AV_RB16(track->vos_data + 18) << 1); /* peak_data_rate */
913 avio_wb32(pb, 0); /* reserved */
914
915 return update_size(pb, pos);
916 }
917
918 37 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
919 {
920 uint32_t layout_tag, bitmap, *channel_desc;
921 37 int64_t pos = avio_tell(pb);
922 int num_desc, ret;
923
924
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (track->multichannel_as_mono)
925 return 0;
926
927 37 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
928 &bitmap, &channel_desc);
929
930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 if (ret < 0) {
931 if (ret == AVERROR(ENOSYS)) {
932 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
933 "lack of channel information\n");
934 ret = 0;
935 }
936
937 return ret;
938 }
939
940
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
37 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
942 1 channel_desc = av_malloc(sizeof(*channel_desc));
943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
944 return AVERROR(ENOMEM);
945
946 1 layout_tag = 0;
947 1 bitmap = 0;
948 1 *channel_desc = 3; // channel label "Center"
949 }
950
951
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 34 times.
37 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
952
953 37 avio_wb32(pb, 0); // Size
954 37 ffio_wfourcc(pb, "chan"); // Type
955 37 avio_w8(pb, 0); // Version
956 37 avio_wb24(pb, 0); // Flags
957 37 avio_wb32(pb, layout_tag); // mChannelLayoutTag
958 37 avio_wb32(pb, bitmap); // mChannelBitmap
959 37 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
960
961
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 for (int i = 0; i < num_desc; i++) {
962 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
963 3 avio_wb32(pb, 0); // mChannelFlags
964 3 avio_wl32(pb, 0); // mCoordinates[0]
965 3 avio_wl32(pb, 0); // mCoordinates[1]
966 3 avio_wl32(pb, 0); // mCoordinates[2]
967 }
968
969 37 av_free(channel_desc);
970
971 37 return update_size(pb, pos);
972 }
973
974 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
975 {
976 15 int64_t pos = avio_tell(pb);
977
978 15 avio_wb32(pb, 0); /* size */
979 15 ffio_wfourcc(pb, "wave");
980
981
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
982 15 avio_wb32(pb, 12); /* size */
983 15 ffio_wfourcc(pb, "frma");
984 15 avio_wl32(pb, track->tag);
985 }
986
987
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
988 /* useless atom needed by mplayer, ipod, not needed by quicktime */
989 3 avio_wb32(pb, 12); /* size */
990 3 ffio_wfourcc(pb, "mp4a");
991 3 avio_wb32(pb, 0);
992 3 mov_write_esds_tag(pb, track);
993
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
994 mov_write_enda_tag(pb);
995
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
996 2 mov_write_enda_tag_be(pb);
997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
998 mov_write_amr_tag(pb, track);
999
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1000 1 mov_write_ac3_tag(s, pb, track);
1001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1002 mov_write_eac3_tag(s, pb, track);
1003
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1004 track->par->codec_id == AV_CODEC_ID_QDM2) {
1005 9 mov_write_extradata_tag(pb, track);
1006 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1007 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1008 mov_write_ms_tag(s, pb, track);
1009 }
1010
1011 15 avio_wb32(pb, 8); /* size */
1012 15 avio_wb32(pb, 0); /* null tag */
1013
1014 15 return update_size(pb, pos);
1015 }
1016
1017 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1018 {
1019 uint8_t *unescaped;
1020 const uint8_t *start, *next, *end = track->vos_data + track->vos_len;
1021 int unescaped_size, seq_found = 0;
1022 int level = 0, interlace = 0;
1023 int packet_seq = track->vc1_info.packet_seq;
1024 int packet_entry = track->vc1_info.packet_entry;
1025 int slices = track->vc1_info.slices;
1026 PutBitContext pbc;
1027
1028 if (track->start_dts == AV_NOPTS_VALUE) {
1029 /* No packets written yet, vc1_info isn't authoritative yet. */
1030 /* Assume inline sequence and entry headers. */
1031 packet_seq = packet_entry = 1;
1032 av_log(NULL, AV_LOG_WARNING,
1033 "moov atom written before any packets, unable to write correct "
1034 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1035 }
1036
1037 unescaped = av_mallocz(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
1038 if (!unescaped)
1039 return AVERROR(ENOMEM);
1040 start = find_next_marker(track->vos_data, end);
1041 for (next = start; next < end; start = next) {
1042 GetBitContext gb;
1043 int size;
1044 next = find_next_marker(start + 4, end);
1045 size = next - start - 4;
1046 if (size <= 0)
1047 continue;
1048 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1049 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1050 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1051 int profile = get_bits(&gb, 2);
1052 if (profile != PROFILE_ADVANCED) {
1053 av_free(unescaped);
1054 return AVERROR(ENOSYS);
1055 }
1056 seq_found = 1;
1057 level = get_bits(&gb, 3);
1058 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1059 * width, height */
1060 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1061 skip_bits(&gb, 1); /* broadcast */
1062 interlace = get_bits1(&gb);
1063 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1064 }
1065 }
1066 if (!seq_found) {
1067 av_free(unescaped);
1068 return AVERROR(ENOSYS);
1069 }
1070
1071 init_put_bits(&pbc, buf, 7);
1072 /* VC1DecSpecStruc */
1073 put_bits(&pbc, 4, 12); /* profile - advanced */
1074 put_bits(&pbc, 3, level);
1075 put_bits(&pbc, 1, 0); /* reserved */
1076 /* VC1AdvDecSpecStruc */
1077 put_bits(&pbc, 3, level);
1078 put_bits(&pbc, 1, 0); /* cbr */
1079 put_bits(&pbc, 6, 0); /* reserved */
1080 put_bits(&pbc, 1, !interlace); /* no interlace */
1081 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1082 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1083 put_bits(&pbc, 1, !slices); /* no slice code */
1084 put_bits(&pbc, 1, 0); /* no bframe */
1085 put_bits(&pbc, 1, 0); /* reserved */
1086
1087 /* framerate */
1088 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1089 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1090 else
1091 put_bits32(&pbc, 0xffffffff);
1092
1093 flush_put_bits(&pbc);
1094
1095 av_free(unescaped);
1096
1097 return 0;
1098 }
1099
1100 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1101 {
1102 uint8_t buf[7] = { 0 };
1103 int ret;
1104
1105 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1106 return ret;
1107
1108 avio_wb32(pb, track->vos_len + 8 + sizeof(buf));
1109 ffio_wfourcc(pb, "dvc1");
1110 avio_write(pb, buf, sizeof(buf));
1111 avio_write(pb, track->vos_data, track->vos_len);
1112
1113 return 0;
1114 }
1115
1116 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1117 {
1118 4 avio_wb32(pb, track->vos_len + 8);
1119 4 ffio_wfourcc(pb, "glbl");
1120 4 avio_write(pb, track->vos_data, track->vos_len);
1121 4 return 8 + track->vos_len;
1122 }
1123
1124 /**
1125 * Compute flags for 'lpcm' tag.
1126 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1127 */
1128 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1129 {
1130
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) {
1131 case AV_CODEC_ID_PCM_F32BE:
1132 case AV_CODEC_ID_PCM_F64BE:
1133 return 11;
1134 case AV_CODEC_ID_PCM_F32LE:
1135 case AV_CODEC_ID_PCM_F64LE:
1136 return 9;
1137 case AV_CODEC_ID_PCM_U8:
1138 return 10;
1139 case AV_CODEC_ID_PCM_S16BE:
1140 case AV_CODEC_ID_PCM_S24BE:
1141 case AV_CODEC_ID_PCM_S32BE:
1142 return 14;
1143 case AV_CODEC_ID_PCM_S8:
1144 case AV_CODEC_ID_PCM_S16LE:
1145 case AV_CODEC_ID_PCM_S24LE:
1146 case AV_CODEC_ID_PCM_S32LE:
1147 return 12;
1148 8 default:
1149 8 return 0;
1150 }
1151 }
1152
1153 24062 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1154 {
1155 int64_t next_dts;
1156
1157
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24062 times.
24062 if (cluster_idx >= track->entry)
1158 return 0;
1159
1160
2/2
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 23460 times.
24062 if (cluster_idx + 1 == track->entry)
1161 602 next_dts = track->track_duration + track->start_dts;
1162 else
1163 23460 next_dts = track->cluster[cluster_idx + 1].dts;
1164
1165 24062 next_dts -= track->cluster[cluster_idx].dts;
1166
1167
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24062 times.
24062 av_assert0(next_dts >= 0);
1168
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24062 times.
24062 av_assert0(next_dts <= INT_MAX);
1169
1170 24062 return next_dts;
1171 }
1172
1173 4 static int get_samples_per_packet(MOVTrack *track)
1174 {
1175 int i, first_duration;
1176
1177 // return track->par->frame_size;
1178
1179 /* use 1 for raw PCM */
1180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1181 return 1;
1182
1183 /* check to see if duration is constant for all clusters */
1184
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1185 return 0;
1186 4 first_duration = get_cluster_duration(track, 0);
1187
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1188
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1189 4 return 0;
1190 }
1191 return first_duration;
1192 }
1193
1194 124 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1195 {
1196 124 int64_t pos = avio_tell(pb);
1197 124 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1198
3/4
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
124 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1199
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 !bit_rates.buffer_size)
1200 // no useful data to be written, skip
1201 79 return 0;
1202
1203 45 avio_wb32(pb, 0); /* size */
1204 45 ffio_wfourcc(pb, "btrt");
1205
1206 45 avio_wb32(pb, bit_rates.buffer_size);
1207 45 avio_wb32(pb, bit_rates.max_bit_rate);
1208 45 avio_wb32(pb, bit_rates.avg_bit_rate);
1209
1210 45 return update_size(pb, pos);
1211 }
1212
1213 5 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1214 {
1215 5 int64_t pos = avio_tell(pb);
1216 5 int config = 0;
1217 int ret;
1218 5 uint8_t *speaker_pos = NULL;
1219 5 const AVChannelLayout *layout = &track->par->ch_layout;
1220
1221 5 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1222
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
5 if (ret || !config) {
1223 3 config = 0;
1224 3 speaker_pos = av_malloc(layout->nb_channels);
1225 3 ret = ff_mov_get_channel_positions_from_layout(layout,
1226 3 speaker_pos, layout->nb_channels);
1227
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (ret) {
1228 char buf[128] = {0};
1229
1230 av_freep(&speaker_pos);
1231 av_channel_layout_describe(layout, buf, sizeof(buf));
1232 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1233 return ret;
1234 }
1235 }
1236
1237 5 avio_wb32(pb, 0); /* size */
1238 5 ffio_wfourcc(pb, "chnl");
1239 5 avio_wb32(pb, 0); /* version & flags */
1240
1241 5 avio_w8(pb, 1); /* stream_structure */
1242 5 avio_w8(pb, config);
1243
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
5 if (config) {
1244 2 avio_wb64(pb, 0);
1245 } else {
1246
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 3 times.
15 for (int i = 0; i < layout->nb_channels; i++)
1247 12 avio_w8(pb, speaker_pos[i]);
1248 3 av_freep(&speaker_pos);
1249 }
1250
1251 5 return update_size(pb, pos);
1252 }
1253
1254 7 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1255 {
1256 7 int64_t pos = avio_tell(pb);
1257 int format_flags;
1258 int sample_size;
1259
1260 7 avio_wb32(pb, 0); /* size */
1261 7 ffio_wfourcc(pb, "pcmC");
1262 7 avio_wb32(pb, 0); /* version & flags */
1263
1264 /* 0x01: indicates little-endian format */
1265 20 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1266
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1268
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 ||
1269 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1270 7 avio_w8(pb, format_flags);
1271 7 sample_size = track->par->bits_per_raw_sample;
1272
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (!sample_size)
1273 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1274
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 av_assert0(sample_size);
1275 7 avio_w8(pb, sample_size);
1276
1277 7 return update_size(pb, pos);
1278 }
1279
1280 103 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1281 {
1282 103 int64_t pos = avio_tell(pb);
1283 103 int version = 0;
1284 103 uint32_t tag = track->tag;
1285 103 int ret = 0;
1286
1287
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 66 times.
103 if (track->mode == MODE_MOV) {
1288
3/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 33 times.
37 if (track->timescale > UINT16_MAX || !track->par->ch_layout.nb_channels) {
1289
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1290 tag = AV_RL32("lpcm");
1291 4 version = 2;
1292
5/6
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 23 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 21 times.
✓ Branch 6 taken 2 times.
56 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1293 23 mov_pcm_be_gt16(track->par->codec_id) ||
1294
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1295
1/2
✓ Branch 0 taken 21 times.
✗ Branch 1 not taken.
21 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
21 track->par->codec_id == AV_CODEC_ID_QDM2) {
1297 12 version = 1;
1298 }
1299 }
1300
1301 103 avio_wb32(pb, 0); /* size */
1302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 if (mov->encryption_scheme != MOV_ENC_NONE) {
1303 ffio_wfourcc(pb, "enca");
1304 } else {
1305 103 avio_wl32(pb, tag); // store it byteswapped
1306 }
1307 103 avio_wb32(pb, 0); /* Reserved */
1308 103 avio_wb16(pb, 0); /* Reserved */
1309 103 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1310
1311 /* SoundDescription */
1312 103 avio_wb16(pb, version); /* Version */
1313 103 avio_wb16(pb, 0); /* Revision level */
1314 103 avio_wb32(pb, 0); /* Reserved */
1315
1316
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 99 times.
103 if (version == 2) {
1317 4 avio_wb16(pb, 3);
1318 4 avio_wb16(pb, 16);
1319 4 avio_wb16(pb, 0xfffe);
1320 4 avio_wb16(pb, 0);
1321 4 avio_wb32(pb, 0x00010000);
1322 4 avio_wb32(pb, 72);
1323 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1324 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1325 4 avio_wb32(pb, 0x7F000000);
1326 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1327 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1328 4 avio_wb32(pb, track->sample_size);
1329 4 avio_wb32(pb, get_samples_per_packet(track));
1330 } else {
1331
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 66 times.
99 if (track->mode == MODE_MOV) {
1332 33 avio_wb16(pb, track->par->ch_layout.nb_channels);
1333
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1334
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 32 times.
33 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1335 1 avio_wb16(pb, 8); /* bits per sample */
1336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1337 avio_wb16(pb, track->par->bits_per_coded_sample);
1338 else
1339 32 avio_wb16(pb, 16);
1340
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 23 times.
33 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1341 } else { /* reserved for mp4/3gp */
1342 66 avio_wb16(pb, track->par->ch_layout.nb_channels);
1343
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 4 times.
66 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1344
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 track->par->codec_id == AV_CODEC_ID_ALAC) {
1345 4 avio_wb16(pb, track->par->bits_per_raw_sample);
1346 } else {
1347 62 avio_wb16(pb, 16);
1348 }
1349 66 avio_wb16(pb, 0);
1350 }
1351
1352 99 avio_wb16(pb, 0); /* packet size (= 0) */
1353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 if (track->par->codec_id == AV_CODEC_ID_OPUS)
1354 avio_wb16(pb, 48000);
1355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1356 avio_wb32(pb, track->par->sample_rate);
1357 else
1358
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
198 avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ?
1359 99 track->par->sample_rate : 0);
1360
1361
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
99 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1362 99 avio_wb16(pb, 0); /* Reserved */
1363 }
1364
1365
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 91 times.
103 if (version == 1) { /* SoundDescription V1 extended info */
1366
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) ||
1367 12 mov_pcm_be_gt16(track->par->codec_id))
1368 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1369 else
1370 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1371 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1372 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1373 12 avio_wb32(pb, 2); /* Bytes per sample */
1374 }
1375
1376
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 66 times.
103 if (track->mode == MODE_MOV &&
1377
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 3 times.
37 (track->par->codec_id == AV_CODEC_ID_AAC ||
1378
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 1 times.
34 track->par->codec_id == AV_CODEC_ID_AC3 ||
1379
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1380
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1381
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 9 times.
33 track->par->codec_id == AV_CODEC_ID_ALAC ||
1382
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1383
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1384
2/4
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 24 times.
48 track->par->codec_id == AV_CODEC_ID_QDM2 ||
1385
2/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 22 times.
48 (mov_pcm_le_gt16(track->par->codec_id) && version==1) ||
1386
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
26 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1387 15 ret = mov_write_wave_tag(s, pb, track);
1388
2/2
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 38 times.
88 else if (track->tag == MKTAG('m','p','4','a'))
1389 50 ret = mov_write_esds_tag(pb, track);
1390
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 34 times.
38 else if (track->tag == MKTAG('i','a','m','f'))
1391 4 ret = mov_write_iacb_tag(mov->fc, pb, track);
1392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1393 ret = mov_write_amr_tag(pb, track);
1394
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 30 times.
34 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1395 4 ret = mov_write_ac3_tag(s, pb, track);
1396
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 29 times.
30 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1397 1 ret = mov_write_eac3_tag(s, pb, track);
1398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1399 ret = mov_write_extradata_tag(pb, track);
1400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1401 ret = mov_write_wfex_tag(s, pb, track);
1402
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1403 ret = mov_write_dfla_tag(pb, track);
1404
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1405 ret = mov_write_dops_tag(s, pb, track);
1406
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 29 times.
29 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1407 ret = mov_write_dmlp_tag(s, pb, track);
1408
4/4
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 22 times.
29 else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) {
1409
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (track->par->ch_layout.nb_channels > 1)
1410 5 ret = mov_write_chnl_tag(s, pb, track);
1411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ret < 0)
1412 return ret;
1413 7 ret = mov_write_pcmc_tag(s, pb, track);
1414
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 22 times.
22 } else if (track->vos_len > 0)
1415 ret = mov_write_glbl_tag(pb, track);
1416
1417
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 if (ret < 0)
1418 return ret;
1419
1420
3/4
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 37 times.
✗ Branch 3 not taken.
103 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1421
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 37 times.
37 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1422 return ret;
1423 }
1424
1425
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
103 if (mov->encryption_scheme != MOV_ENC_NONE
1426 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1427 return ret;
1428 }
1429
1430
3/4
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 40 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 63 times.
166 if (mov->write_btrt &&
1431 63 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1432 return ret;
1433
1434 103 ret = update_size(pb, pos);
1435 103 return ret;
1436 }
1437
1438 static int mov_write_d263_tag(AVIOContext *pb)
1439 {
1440 avio_wb32(pb, 0xf); /* size */
1441 ffio_wfourcc(pb, "d263");
1442 ffio_wfourcc(pb, "FFMP");
1443 avio_w8(pb, 0); /* decoder version */
1444 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1445 avio_w8(pb, 0xa); /* level */
1446 avio_w8(pb, 0); /* profile */
1447 return 0xf;
1448 }
1449
1450 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1451 {
1452 1 int64_t pos = avio_tell(pb);
1453
1454 1 avio_wb32(pb, 0);
1455 1 ffio_wfourcc(pb, "av1C");
1456 1 ff_isom_write_av1c(pb, track->vos_data, track->vos_len, track->mode != MODE_AVIF);
1457 1 return update_size(pb, pos);
1458 }
1459
1460 51 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1461 {
1462 51 int64_t pos = avio_tell(pb);
1463
1464 51 avio_wb32(pb, 0);
1465 51 ffio_wfourcc(pb, "avcC");
1466 51 ff_isom_write_avcc(pb, track->vos_data, track->vos_len);
1467 51 return update_size(pb, pos);
1468 }
1469
1470 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1471 {
1472 int64_t pos = avio_tell(pb);
1473
1474 avio_wb32(pb, 0);
1475 ffio_wfourcc(pb, "vpcC");
1476 ff_isom_write_vpcc(s, pb, track->vos_data, track->vos_len, track->par);
1477 return update_size(pb, pos);
1478 }
1479
1480 1 static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track)
1481 {
1482 1 int64_t pos = avio_tell(pb);
1483
1484 1 avio_wb32(pb, 0);
1485 1 ffio_wfourcc(pb, "hvcC");
1486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->tag == MKTAG('h','v','c','1'))
1487 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 1);
1488 else
1489 1 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0);
1490 1 return update_size(pb, pos);
1491 }
1492
1493 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1494 {
1495 1 int64_t pos = avio_tell(pb);
1496
1497 1 avio_wb32(pb, 0);
1498 1 ffio_wfourcc(pb, "evcC");
1499
1500
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1501 1 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 1);
1502 else
1503 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 0);
1504
1505 1 return update_size(pb, pos);
1506 }
1507
1508 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1509 {
1510 int64_t pos = avio_tell(pb);
1511
1512 avio_wb32(pb, 0);
1513 ffio_wfourcc(pb, "vvcC");
1514
1515 avio_w8 (pb, 0); /* version */
1516 avio_wb24(pb, 0); /* flags */
1517
1518 if (track->tag == MKTAG('v','v','c','1'))
1519 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 1);
1520 else
1521 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 0);
1522 return update_size(pb, pos);
1523 }
1524
1525 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1526 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1527 {
1528 int interlaced;
1529 int cid;
1530 23 int display_width = track->par->width;
1531
1532
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) {
1533
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->vos_data) != 0) {
1534 /* looks like a DNxHD bit stream */
1535 23 interlaced = (track->vos_data[5] & 2);
1536 23 cid = AV_RB32(track->vos_data + 0x28);
1537 } else {
1538 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1539 return 0;
1540 }
1541 } else {
1542 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1543 return 0;
1544 }
1545
1546 23 avio_wb32(pb, 24); /* size */
1547 23 ffio_wfourcc(pb, "ACLR");
1548 23 ffio_wfourcc(pb, "ACLR");
1549 23 ffio_wfourcc(pb, "0001");
1550
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1551
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1552 23 avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */
1553 } else { /* Full range (0-255) */
1554 avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */
1555 }
1556 23 avio_wb32(pb, 0); /* unknown */
1557
1558
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1559 12 avio_wb32(pb, 32);
1560 12 ffio_wfourcc(pb, "ADHR");
1561 12 ffio_wfourcc(pb, "0001");
1562 12 avio_wb32(pb, cid);
1563 12 avio_wb32(pb, 0); /* unknown */
1564 12 avio_wb32(pb, 1); /* unknown */
1565 12 avio_wb32(pb, 0); /* unknown */
1566 12 avio_wb32(pb, 0); /* unknown */
1567 12 return 0;
1568 }
1569
1570 11 avio_wb32(pb, 24); /* size */
1571 11 ffio_wfourcc(pb, "APRG");
1572 11 ffio_wfourcc(pb, "APRG");
1573 11 ffio_wfourcc(pb, "0001");
1574 11 avio_wb32(pb, 1); /* unknown */
1575 11 avio_wb32(pb, 0); /* unknown */
1576
1577 11 avio_wb32(pb, 120); /* size */
1578 11 ffio_wfourcc(pb, "ARES");
1579 11 ffio_wfourcc(pb, "ARES");
1580 11 ffio_wfourcc(pb, "0001");
1581 11 avio_wb32(pb, cid); /* dnxhd cid, some id ? */
1582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1583 && track->par->sample_aspect_ratio.den > 0)
1584 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1585 11 avio_wb32(pb, display_width);
1586 /* values below are based on samples created with quicktime and avid codecs */
1587
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1588 11 avio_wb32(pb, track->par->height / 2);
1589 11 avio_wb32(pb, 2); /* unknown */
1590 11 avio_wb32(pb, 0); /* unknown */
1591 11 avio_wb32(pb, 4); /* unknown */
1592 } else {
1593 avio_wb32(pb, track->par->height);
1594 avio_wb32(pb, 1); /* unknown */
1595 avio_wb32(pb, 0); /* unknown */
1596 if (track->par->height == 1080)
1597 avio_wb32(pb, 5); /* unknown */
1598 else
1599 avio_wb32(pb, 6); /* unknown */
1600 }
1601 /* padding */
1602 11 ffio_fill(pb, 0, 10 * 8);
1603
1604 11 return 0;
1605 }
1606
1607 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1608 {
1609 avio_wb32(pb, 12);
1610 ffio_wfourcc(pb, "DpxE");
1611 if (track->par->extradata_size >= 12 &&
1612 !memcmp(&track->par->extradata[4], "DpxE", 4)) {
1613 avio_wb32(pb, track->par->extradata[11]);
1614 } else {
1615 avio_wb32(pb, 1);
1616 }
1617 return 0;
1618 }
1619
1620 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1621 {
1622 int tag;
1623
1624
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1625
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1626
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');
1627 1 else tag = MKTAG('d','v','c',' ');
1628 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1629 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1630 else tag = MKTAG('d','v','p','p');
1631 } else if (track->par->height == 720) { /* HD 720 line */
1632 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1633 else tag = MKTAG('d','v','h','p');
1634 } else if (track->par->height == 1080) { /* HD 1080 line */
1635 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1636 else tag = MKTAG('d','v','h','6');
1637 } else {
1638 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1639 return 0;
1640 }
1641
1642 1 return tag;
1643 }
1644
1645 2 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1646 {
1647 2 AVRational rational_framerate = st->avg_frame_rate;
1648 2 int rate = 0;
1649
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (rational_framerate.den != 0)
1650 2 rate = av_q2d(rational_framerate);
1651 2 return rate;
1652 }
1653
1654 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1655 {
1656 1 int tag = track->par->codec_tag;
1657 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1658 1 AVStream *st = track->st;
1659 1 int rate = defined_frame_rate(s, st);
1660
1661
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1662 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1663
1664
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1665
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) {
1666 if (!interlaced) {
1667 if (rate == 24) tag = MKTAG('x','d','v','4');
1668 else if (rate == 25) tag = MKTAG('x','d','v','5');
1669 else if (rate == 30) tag = MKTAG('x','d','v','1');
1670 else if (rate == 50) tag = MKTAG('x','d','v','a');
1671 else if (rate == 60) tag = MKTAG('x','d','v','9');
1672 }
1673
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) {
1674 if (!interlaced) {
1675 if (rate == 24) tag = MKTAG('x','d','v','6');
1676 else if (rate == 25) tag = MKTAG('x','d','v','7');
1677 else if (rate == 30) tag = MKTAG('x','d','v','8');
1678 } else {
1679 if (rate == 25) tag = MKTAG('x','d','v','3');
1680 else if (rate == 30) tag = MKTAG('x','d','v','2');
1681 }
1682
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) {
1683 if (!interlaced) {
1684 if (rate == 24) tag = MKTAG('x','d','v','d');
1685 else if (rate == 25) tag = MKTAG('x','d','v','e');
1686 else if (rate == 30) tag = MKTAG('x','d','v','f');
1687 } else {
1688 if (rate == 25) tag = MKTAG('x','d','v','c');
1689 else if (rate == 30) tag = MKTAG('x','d','v','b');
1690 }
1691 }
1692 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1693 if (track->par->width == 1280 && track->par->height == 720) {
1694 if (!interlaced) {
1695 if (rate == 24) tag = MKTAG('x','d','5','4');
1696 else if (rate == 25) tag = MKTAG('x','d','5','5');
1697 else if (rate == 30) tag = MKTAG('x','d','5','1');
1698 else if (rate == 50) tag = MKTAG('x','d','5','a');
1699 else if (rate == 60) tag = MKTAG('x','d','5','9');
1700 }
1701 } else if (track->par->width == 1920 && track->par->height == 1080) {
1702 if (!interlaced) {
1703 if (rate == 24) tag = MKTAG('x','d','5','d');
1704 else if (rate == 25) tag = MKTAG('x','d','5','e');
1705 else if (rate == 30) tag = MKTAG('x','d','5','f');
1706 } else {
1707 if (rate == 25) tag = MKTAG('x','d','5','c');
1708 else if (rate == 30) tag = MKTAG('x','d','5','b');
1709 }
1710 }
1711 }
1712
1713 1 return tag;
1714 }
1715
1716 1 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1717 {
1718 1 int tag = track->par->codec_tag;
1719 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1720 1 AVStream *st = track->st;
1721 1 int rate = defined_frame_rate(s, st);
1722
1723
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1724 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1725
1726
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1727 if (track->par->width == 960 && track->par->height == 720) {
1728 if (!interlaced) {
1729 if (rate == 24) tag = MKTAG('a','i','5','p');
1730 else if (rate == 25) tag = MKTAG('a','i','5','q');
1731 else if (rate == 30) tag = MKTAG('a','i','5','p');
1732 else if (rate == 50) tag = MKTAG('a','i','5','q');
1733 else if (rate == 60) tag = MKTAG('a','i','5','p');
1734 }
1735 } else if (track->par->width == 1440 && track->par->height == 1080) {
1736 if (!interlaced) {
1737 if (rate == 24) tag = MKTAG('a','i','5','3');
1738 else if (rate == 25) tag = MKTAG('a','i','5','2');
1739 else if (rate == 30) tag = MKTAG('a','i','5','3');
1740 } else {
1741 if (rate == 50) tag = MKTAG('a','i','5','5');
1742 else if (rate == 60) tag = MKTAG('a','i','5','6');
1743 }
1744 }
1745
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1746 if (track->par->width == 1280 && track->par->height == 720) {
1747 if (!interlaced) {
1748 if (rate == 24) tag = MKTAG('a','i','1','p');
1749 else if (rate == 25) tag = MKTAG('a','i','1','q');
1750 else if (rate == 30) tag = MKTAG('a','i','1','p');
1751 else if (rate == 50) tag = MKTAG('a','i','1','q');
1752 else if (rate == 60) tag = MKTAG('a','i','1','p');
1753 }
1754 } else if (track->par->width == 1920 && track->par->height == 1080) {
1755 if (!interlaced) {
1756 if (rate == 24) tag = MKTAG('a','i','1','3');
1757 else if (rate == 25) tag = MKTAG('a','i','1','2');
1758 else if (rate == 30) tag = MKTAG('a','i','1','3');
1759 } else {
1760 if (rate == 25) tag = MKTAG('a','i','1','5');
1761 else if (rate == 50) tag = MKTAG('a','i','1','5');
1762 else if (rate == 60) tag = MKTAG('a','i','1','6');
1763 }
1764 } else if ( track->par->width == 4096 && track->par->height == 2160
1765 || track->par->width == 3840 && track->par->height == 2160
1766 || track->par->width == 2048 && track->par->height == 1080) {
1767 tag = MKTAG('a','i','v','x');
1768 }
1769 }
1770
1771 1 return tag;
1772 }
1773
1774 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
1775 {
1776 int tag = track->par->codec_tag;
1777
1778 if (!tag)
1779 tag = MKTAG('e', 'v', 'c', '1');
1780
1781 return tag;
1782 }
1783
1784 static const struct {
1785 enum AVPixelFormat pix_fmt;
1786 uint32_t tag;
1787 unsigned bps;
1788 } mov_pix_fmt_tags[] = {
1789 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
1790 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
1791 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
1792 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
1793 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
1794 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
1795 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
1796 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
1797 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
1798 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
1799 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
1800 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
1801 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
1802 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
1803 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
1804 };
1805
1806 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
1807 {
1808 23 int tag = MKTAG('A','V','d','n');
1809
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
1810
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
1811 12 tag = MKTAG('A','V','d','h');
1812 23 return tag;
1813 }
1814
1815 12 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
1816 {
1817 12 int tag = track->par->codec_tag;
1818 int i;
1819 enum AVPixelFormat pix_fmt;
1820
1821
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 12 times.
192 for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
1822
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 168 times.
180 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
1823 12 tag = mov_pix_fmt_tags[i].tag;
1824 12 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
1825
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
1826 break;
1827 }
1828 }
1829
1830 12 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
1831 12 track->par->bits_per_coded_sample);
1832
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (tag == MKTAG('r','a','w',' ') &&
1833 track->par->format != pix_fmt &&
1834 track->par->format != AV_PIX_FMT_GRAY8 &&
1835 track->par->format != AV_PIX_FMT_NONE)
1836 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
1837 av_get_pix_fmt_name(track->par->format));
1838 12 return tag;
1839 }
1840
1841 156 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
1842 {
1843 156 unsigned int tag = track->par->codec_tag;
1844
1845 // "rtp " is used to distinguish internally created RTP-hint tracks
1846 // (with rtp_ctx) from other tracks.
1847
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 156 times.
156 if (tag == MKTAG('r','t','p',' '))
1848 tag = 0;
1849
3/4
✓ Branch 0 taken 156 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 120 times.
✓ Branch 3 taken 36 times.
156 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
1850
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 1 times.
120 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
1851
2/2
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 12 times.
119 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
1852
1/2
✓ Branch 0 taken 107 times.
✗ Branch 1 not taken.
107 track->par->codec_id == AV_CODEC_ID_H263 ||
1853
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 1 times.
107 track->par->codec_id == AV_CODEC_ID_H264 ||
1854
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 23 times.
106 track->par->codec_id == AV_CODEC_ID_DNXHD ||
1855
4/4
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 65 times.
165 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
1856 82 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
1857
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 54 times.
55 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
1858 1 tag = mov_get_dv_codec_tag(s, track);
1859
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 42 times.
54 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
1860 12 tag = mov_get_rawvideo_codec_tag(s, track);
1861
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 41 times.
42 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
1862 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
1863
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 40 times.
41 else if (track->par->codec_id == AV_CODEC_ID_H264)
1864 1 tag = mov_get_h264_codec_tag(s, track);
1865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 else if (track->par->codec_id == AV_CODEC_ID_EVC)
1866 tag = mov_get_evc_codec_tag(s, track);
1867
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 17 times.
40 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
1868 23 tag = mov_get_dnxhd_codec_tag(s, track);
1869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
1870 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
1871 if (!tag) { // if no mac fcc found, try with Microsoft tags
1872 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
1873 if (tag)
1874 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
1875 "the file may be unplayable!\n");
1876 }
1877
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
1878 17 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
1879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (!tag) { // if no mac fcc found, try with Microsoft tags
1880 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
1881 if (ms_tag) {
1882 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
1883 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
1884 "the file may be unplayable!\n");
1885 }
1886 }
1887 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
1888 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
1889 }
1890
1891 156 return tag;
1892 }
1893
1894 static const AVCodecTag codec_cover_image_tags[] = {
1895 { AV_CODEC_ID_MJPEG, 0xD },
1896 { AV_CODEC_ID_PNG, 0xE },
1897 { AV_CODEC_ID_BMP, 0x1B },
1898 { AV_CODEC_ID_NONE, 0 },
1899 };
1900
1901 89 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
1902 unsigned int tag, int codec_id)
1903 {
1904 int i;
1905
1906 /**
1907 * Check that tag + id is in the table
1908 */
1909
2/4
✓ Branch 0 taken 89 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 89 times.
✗ Branch 3 not taken.
89 for (i = 0; tags && tags[i]; i++) {
1910 89 const AVCodecTag *codec_tags = tags[i];
1911
1/2
✓ Branch 0 taken 1256 times.
✗ Branch 1 not taken.
1256 while (codec_tags->id != AV_CODEC_ID_NONE) {
1912
2/2
✓ Branch 2 taken 101 times.
✓ Branch 3 taken 1155 times.
1256 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
1913
2/2
✓ Branch 0 taken 89 times.
✓ Branch 1 taken 12 times.
101 codec_tags->id == codec_id)
1914 89 return codec_tags->tag;
1915 1167 codec_tags++;
1916 }
1917 }
1918 return 0;
1919 }
1920
1921 247 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
1922 {
1923
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 245 times.
247 if (is_cover_image(track->st))
1924 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
1925
1926
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 244 times.
245 if (track->mode == MODE_IPOD)
1927
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") &&
1928
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
1929 1 !av_match_ext(s->url, "m4b"))
1930 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
1931 "Quicktime/Ipod might not play the file\n");
1932
1933
2/2
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 89 times.
245 if (track->mode == MODE_MOV) {
1934 156 return mov_get_codec_tag(s, track);
1935 } else
1936 89 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
1937 89 track->par->codec_id);
1938 }
1939
1940 /** Write uuid atom.
1941 * Needed to make file play in iPods running newest firmware
1942 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
1943 */
1944 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
1945 {
1946 avio_wb32(pb, 28);
1947 ffio_wfourcc(pb, "uuid");
1948 avio_wb32(pb, 0x6b6840f2);
1949 avio_wb32(pb, 0x5f244fc5);
1950 avio_wb32(pb, 0xba39a51b);
1951 avio_wb32(pb, 0xcf0323f3);
1952 avio_wb32(pb, 0x0);
1953 return 28;
1954 }
1955
1956 static const uint16_t fiel_data[] = {
1957 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
1958 };
1959
1960 90 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
1961 {
1962 90 unsigned mov_field_order = 0;
1963
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 if (field_order < FF_ARRAY_ELEMS(fiel_data))
1964 90 mov_field_order = fiel_data[field_order];
1965 else
1966 return 0;
1967 90 avio_wb32(pb, 10);
1968 90 ffio_wfourcc(pb, "fiel");
1969 90 avio_wb16(pb, mov_field_order);
1970 90 return 10;
1971 }
1972
1973 4 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1974 {
1975 4 MOVMuxContext *mov = s->priv_data;
1976 4 int ret = AVERROR_BUG;
1977 4 int64_t pos = avio_tell(pb);
1978 4 avio_wb32(pb, 0); /* size */
1979 4 avio_wl32(pb, track->tag); // store it byteswapped
1980 4 avio_wb32(pb, 0); /* Reserved */
1981 4 avio_wb16(pb, 0); /* Reserved */
1982 4 avio_wb16(pb, 1); /* Data-reference index */
1983
1984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
1985 mov_write_esds_tag(pb, track);
1986
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
1987
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (track->par->codec_tag) {
1988 1 case MOV_ISMV_TTML_TAG:
1989 // ISMV dfxp requires no extradata.
1990 2 break;
1991 1 case MOV_MP4_TTML_TAG:
1992 // As specified in 14496-30, XMLSubtitleSampleEntry
1993 // Namespace
1994 1 avio_put_str(pb, "http://www.w3.org/ns/ttml");
1995 // Empty schema_location
1996 1 avio_w8(pb, 0);
1997 // Empty auxiliary_mime_types
1998 1 avio_w8(pb, 0);
1999 1 break;
2000 default:
2001 av_log(NULL, AV_LOG_ERROR,
2002 "Unknown codec tag '%s' utilized for TTML stream with "
2003 "index %d (track id %d)!\n",
2004 av_fourcc2str(track->par->codec_tag), track->st->index,
2005 track->track_id);
2006 return AVERROR(EINVAL);
2007 }
2008
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->par->extradata_size)
2009 2 avio_write(pb, track->par->extradata, track->par->extradata_size);
2010
2011
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 &&
2012 4 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2013 return ret;
2014
2015 4 return update_size(pb, pos);
2016 }
2017
2018 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2019 {
2020 int8_t stereo_mode;
2021
2022 if (stereo_3d->flags != 0) {
2023 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2024 return 0;
2025 }
2026
2027 switch (stereo_3d->type) {
2028 case AV_STEREO3D_2D:
2029 stereo_mode = 0;
2030 break;
2031 case AV_STEREO3D_TOPBOTTOM:
2032 stereo_mode = 1;
2033 break;
2034 case AV_STEREO3D_SIDEBYSIDE:
2035 stereo_mode = 2;
2036 break;
2037 default:
2038 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2039 return 0;
2040 }
2041 avio_wb32(pb, 13); /* size */
2042 ffio_wfourcc(pb, "st3d");
2043 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2044 avio_w8(pb, stereo_mode);
2045 return 13;
2046 }
2047
2048 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2049 {
2050 int64_t sv3d_pos, svhd_pos, proj_pos;
2051 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2052
2053 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2054 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2055 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2056 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2057 return 0;
2058 }
2059
2060 sv3d_pos = avio_tell(pb);
2061 avio_wb32(pb, 0); /* size */
2062 ffio_wfourcc(pb, "sv3d");
2063
2064 svhd_pos = avio_tell(pb);
2065 avio_wb32(pb, 0); /* size */
2066 ffio_wfourcc(pb, "svhd");
2067 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2068 avio_put_str(pb, metadata_source);
2069 update_size(pb, svhd_pos);
2070
2071 proj_pos = avio_tell(pb);
2072 avio_wb32(pb, 0); /* size */
2073 ffio_wfourcc(pb, "proj");
2074
2075 avio_wb32(pb, 24); /* size */
2076 ffio_wfourcc(pb, "prhd");
2077 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2078 avio_wb32(pb, spherical_mapping->yaw);
2079 avio_wb32(pb, spherical_mapping->pitch);
2080 avio_wb32(pb, spherical_mapping->roll);
2081
2082 switch (spherical_mapping->projection) {
2083 case AV_SPHERICAL_EQUIRECTANGULAR:
2084 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2085 avio_wb32(pb, 28); /* size */
2086 ffio_wfourcc(pb, "equi");
2087 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2088 avio_wb32(pb, spherical_mapping->bound_top);
2089 avio_wb32(pb, spherical_mapping->bound_bottom);
2090 avio_wb32(pb, spherical_mapping->bound_left);
2091 avio_wb32(pb, spherical_mapping->bound_right);
2092 break;
2093 case AV_SPHERICAL_CUBEMAP:
2094 avio_wb32(pb, 20); /* size */
2095 ffio_wfourcc(pb, "cbmp");
2096 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2097 avio_wb32(pb, 0); /* layout */
2098 avio_wb32(pb, spherical_mapping->padding); /* padding */
2099 break;
2100 }
2101 update_size(pb, proj_pos);
2102
2103 return update_size(pb, sv3d_pos);
2104 }
2105
2106 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2107 {
2108 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2109
2110 avio_wb32(pb, 32); /* size = 8 + 24 */
2111 if (dovi->dv_profile > 10)
2112 ffio_wfourcc(pb, "dvwC");
2113 else if (dovi->dv_profile > 7)
2114 ffio_wfourcc(pb, "dvvC");
2115 else
2116 ffio_wfourcc(pb, "dvcC");
2117
2118 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2119 avio_write(pb, buf, sizeof(buf));
2120
2121 return 32; /* 8 + 24 */
2122 }
2123
2124 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track)
2125 {
2126 avio_wb32(pb, 40);
2127 ffio_wfourcc(pb, "clap");
2128 avio_wb32(pb, track->par->width); /* apertureWidth_N */
2129 avio_wb32(pb, 1); /* apertureWidth_D (= 1) */
2130 avio_wb32(pb, track->height); /* apertureHeight_N */
2131 avio_wb32(pb, 1); /* apertureHeight_D (= 1) */
2132 avio_wb32(pb, 0); /* horizOff_N (= 0) */
2133 avio_wb32(pb, 1); /* horizOff_D (= 1) */
2134 avio_wb32(pb, 0); /* vertOff_N (= 0) */
2135 avio_wb32(pb, 1); /* vertOff_D (= 1) */
2136 return 40;
2137 }
2138
2139 5 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2140 {
2141 AVRational sar;
2142 5 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2143 5 track->par->sample_aspect_ratio.den, INT_MAX);
2144
2145 5 avio_wb32(pb, 16);
2146 5 ffio_wfourcc(pb, "pasp");
2147 5 avio_wb32(pb, sar.num);
2148 5 avio_wb32(pb, sar.den);
2149 5 return 16;
2150 }
2151
2152 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2153 {
2154 uint32_t gama = 0;
2155 if (gamma <= 0.0)
2156 gamma = av_csp_approximate_trc_gamma(track->par->color_trc);
2157 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2158
2159 if (gamma > 1e-6) {
2160 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2161 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2162
2163 av_assert0(track->mode == MODE_MOV);
2164 avio_wb32(pb, 12);
2165 ffio_wfourcc(pb, "gama");
2166 avio_wb32(pb, gama);
2167 return 12;
2168 } else {
2169 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2170 }
2171 return 0;
2172 }
2173
2174 8 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2175 {
2176 8 int64_t pos = avio_tell(pb);
2177
2178 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2179 // Ref (MP4): ISO/IEC 14496-12:2012
2180
2181
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (prefer_icc) {
2182 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2183 4 track->st->codecpar->nb_coded_side_data,
2184 AV_PKT_DATA_ICC_PROFILE);
2185
2186
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2187 avio_wb32(pb, 12 + sd->size);
2188 ffio_wfourcc(pb, "colr");
2189 ffio_wfourcc(pb, "prof");
2190 avio_write(pb, sd->data, sd->size);
2191 return 12 + sd->size;
2192 }
2193 else {
2194 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2195 }
2196 }
2197
2198 /* We should only ever be called for MOV, MP4 and AVIF. */
2199
3/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
8 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2200 track->mode == MODE_AVIF);
2201
2202 8 avio_wb32(pb, 0); /* size */
2203 8 ffio_wfourcc(pb, "colr");
2204
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
8 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2205 1 ffio_wfourcc(pb, "nclx");
2206 else
2207 7 ffio_wfourcc(pb, "nclc");
2208 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2209 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2210 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2211 8 avio_wb16(pb, track->par->color_primaries);
2212 8 avio_wb16(pb, track->par->color_trc);
2213 8 avio_wb16(pb, track->par->color_space);
2214
3/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 7 times.
8 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2215 1 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2216 1 avio_w8(pb, full_range << 7);
2217 }
2218
2219 8 return update_size(pb, pos);
2220 }
2221
2222 185 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2223 {
2224 const AVPacketSideData *side_data;
2225 const AVContentLightMetadata *content_light_metadata;
2226
2227 185 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2228 185 track->st->codecpar->nb_coded_side_data,
2229 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2230
1/2
✓ Branch 0 taken 185 times.
✗ Branch 1 not taken.
185 if (!side_data) {
2231 185 return 0;
2232 }
2233 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2234
2235 avio_wb32(pb, 12); // size
2236 ffio_wfourcc(pb, "clli");
2237 avio_wb16(pb, content_light_metadata->MaxCLL);
2238 avio_wb16(pb, content_light_metadata->MaxFALL);
2239 return 12;
2240 }
2241
2242 3 static inline int64_t rescale_rational(AVRational q, int b)
2243 {
2244 3 return av_rescale(q.num, b, q.den);
2245 }
2246
2247 185 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2248 {
2249 185 const int chroma_den = 50000;
2250 185 const int luma_den = 10000;
2251 const AVPacketSideData *side_data;
2252 185 const AVMasteringDisplayMetadata *metadata = NULL;
2253
2254 185 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2255 185 track->st->codecpar->nb_coded_side_data,
2256 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
185 if (side_data)
2258 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2259
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 185 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
185 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2260 185 return 0;
2261 }
2262
2263 avio_wb32(pb, 32); // size
2264 ffio_wfourcc(pb, "mdcv");
2265 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2266 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2267 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2268 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2269 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2270 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2271 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2272 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2273 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2274 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2275 return 32;
2276 }
2277
2278 185 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2279 {
2280 185 const int illuminance_den = 10000;
2281 185 const int ambient_den = 50000;
2282 const AVPacketSideData *side_data;
2283 const AVAmbientViewingEnvironment *ambient;
2284
2285
2286 185 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2287 185 track->st->codecpar->nb_coded_side_data,
2288 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2289
2290
2/2
✓ Branch 0 taken 184 times.
✓ Branch 1 taken 1 times.
185 if (!side_data)
2291 184 return 0;
2292
2293 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2294
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)
2295 return 0;
2296
2297 1 avio_wb32(pb, 16); // size
2298 1 ffio_wfourcc(pb, "amve");
2299 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2300 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2301 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2302 1 return 16;
2303 }
2304
2305 190 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2306 {
2307 AVDictionaryEntry *encoder;
2308
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2309
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 189 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
189 || (track->par->width == 1440 && track->par->height == 1080)
2310
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 189 times.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 177 times.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
380 || (track->par->width == 1920 && track->par->height == 1080);
2311
2312
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
190 if ((track->mode == MODE_AVIF ||
2313
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 128 times.
190 track->mode == MODE_MOV ||
2314
4/4
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 134 times.
✓ Branch 3 taken 51 times.
247 track->mode == MODE_MP4) &&
2315 185 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2316 134 av_strlcpy(compressor_name, encoder->value, 32);
2317
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
56 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2318 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2319 AVStream *st = track->st;
2320 int rate = defined_frame_rate(NULL, st);
2321 av_strlcatf(compressor_name, len, "XDCAM");
2322 if (track->par->format == AV_PIX_FMT_YUV422P) {
2323 av_strlcatf(compressor_name, len, " HD422");
2324 } else if(track->par->width == 1440) {
2325 av_strlcatf(compressor_name, len, " HD");
2326 } else
2327 av_strlcatf(compressor_name, len, " EX");
2328
2329 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2330
2331 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2332 }
2333 190 }
2334
2335 static int mov_write_ccst_tag(AVIOContext *pb)
2336 {
2337 int64_t pos = avio_tell(pb);
2338 // Write sane defaults:
2339 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2340 // intra_pred_used = 1 : intra prediction may or may not be used.
2341 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2342 // reference images can be used.
2343 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2344 (1 << 6) | /* intra_pred_used */
2345 (15 << 2); /* max_ref_per_pic */
2346 avio_wb32(pb, 0); /* size */
2347 ffio_wfourcc(pb, "ccst");
2348 avio_wb32(pb, 0); /* Version & flags */
2349 avio_w8(pb, ccstValue);
2350 avio_wb24(pb, 0); /* reserved */
2351 return update_size(pb, pos);
2352 }
2353
2354 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2355 {
2356 int64_t pos = avio_tell(pb);
2357 avio_wb32(pb, 0); /* size */
2358 ffio_wfourcc(pb, aux_type);
2359 avio_wb32(pb, 0); /* Version & flags */
2360 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2361 return update_size(pb, pos);
2362 }
2363
2364 190 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2365 {
2366 190 int ret = AVERROR_BUG;
2367 190 int64_t pos = avio_tell(pb);
2368 190 char compressor_name[32] = { 0 };
2369 190 int avid = 0;
2370
2371
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 int uncompressed_ycbcr = ((track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVY422)
2372
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 178 times.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
190 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2373
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
190 || track->par->codec_id == AV_CODEC_ID_V308
2374
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
190 || track->par->codec_id == AV_CODEC_ID_V408
2375
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
190 || track->par->codec_id == AV_CODEC_ID_V410
2376
3/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 178 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 190 times.
380 || track->par->codec_id == AV_CODEC_ID_V210);
2377
2378 190 avio_wb32(pb, 0); /* size */
2379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (mov->encryption_scheme != MOV_ENC_NONE) {
2380 ffio_wfourcc(pb, "encv");
2381 } else {
2382 190 avio_wl32(pb, track->tag); // store it byteswapped
2383 }
2384 190 avio_wb32(pb, 0); /* Reserved */
2385 190 avio_wb16(pb, 0); /* Reserved */
2386 190 avio_wb16(pb, 1); /* Data-reference index */
2387
2388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (uncompressed_ycbcr) {
2389 avio_wb16(pb, 2); /* Codec stream version */
2390 } else {
2391 190 avio_wb16(pb, 0); /* Codec stream version */
2392 }
2393 190 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2394
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 62 times.
190 if (track->mode == MODE_MOV) {
2395 128 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2396
3/4
✓ Branch 0 taken 116 times.
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 116 times.
128 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2397 12 avio_wb32(pb, 0); /* Temporal Quality */
2398 12 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2399 } else {
2400 116 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2401 116 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2402 }
2403 } else {
2404 62 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2405 }
2406 190 avio_wb16(pb, track->par->width); /* Video width */
2407 190 avio_wb16(pb, track->height); /* Video height */
2408 190 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2409 190 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2410 190 avio_wb32(pb, 0); /* Data size (= 0) */
2411 190 avio_wb16(pb, 1); /* Frame count (= 1) */
2412
2413 190 find_compressor(compressor_name, 32, track);
2414 190 avio_w8(pb, strlen(compressor_name));
2415 190 avio_write(pb, compressor_name, 31);
2416
2417
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 62 times.
190 if (track->mode == MODE_MOV &&
2418
2/4
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 128 times.
128 (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210))
2419 avio_wb16(pb, 0x18);
2420
4/4
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 99 times.
190 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2421 29 avio_wb16(pb, track->par->bits_per_coded_sample |
2422
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 26 times.
29 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2423 else
2424 161 avio_wb16(pb, 0x18); /* Reserved */
2425
2426
4/4
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 62 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 123 times.
195 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2427 int pal_size, i;
2428 5 avio_wb16(pb, 0); /* Color table ID */
2429 5 avio_wb32(pb, 0); /* Color table seed */
2430 5 avio_wb16(pb, 0x8000); /* Color table flags */
2431
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)
2432 return AVERROR(EINVAL);
2433 5 pal_size = 1 << track->par->bits_per_coded_sample;
2434 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2435
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2436 1040 uint32_t rgb = track->palette[i];
2437 1040 uint16_t r = (rgb >> 16) & 0xff;
2438 1040 uint16_t g = (rgb >> 8) & 0xff;
2439 1040 uint16_t b = rgb & 0xff;
2440 1040 avio_wb16(pb, 0);
2441 1040 avio_wb16(pb, (r << 8) | r);
2442 1040 avio_wb16(pb, (g << 8) | g);
2443 1040 avio_wb16(pb, (b << 8) | b);
2444 }
2445 } else
2446 185 avio_wb16(pb, 0xffff); /* Reserved */
2447
2448
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 170 times.
190 if (track->tag == MKTAG('m','p','4','v'))
2449 20 mov_write_esds_tag(pb, track);
2450
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 170 times.
170 else if (track->par->codec_id == AV_CODEC_ID_H263)
2451 mov_write_d263_tag(pb);
2452
2/2
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 3 times.
170 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2454 3 mov_write_extradata_tag(pb, track);
2455 3 avio_wb32(pb, 0);
2456
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 144 times.
167 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2457 23 mov_write_avid_tag(pb, track);
2458 23 avid = 1;
2459
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 143 times.
144 } else if (track->par->codec_id == AV_CODEC_ID_HEVC)
2460 1 mov_write_hvcc_tag(pb, track);
2461
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 143 times.
143 else if (track->par->codec_id == AV_CODEC_ID_VVC)
2462 mov_write_vvcc_tag(pb, track);
2463
16/30
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 92 times.
✓ Branch 2 taken 51 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 51 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 51 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 51 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 51 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 51 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 51 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 51 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 51 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 51 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 51 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 51 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 51 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 51 times.
✗ Branch 29 not taken.
143 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2464 51 mov_write_avcc_tag(pb, track);
2465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51 times.
51 if (track->mode == MODE_IPOD)
2466 mov_write_uuid_tag_ipod(pb);
2467 }
2468
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 91 times.
92 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2469 1 mov_write_evcc_tag(pb, track);
2470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2471 mov_write_vpcc_tag(mov->fc, pb, track);
2472
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 90 times.
91 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2473 1 mov_write_av1c_tag(pb, track);
2474
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
90 } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
2475 mov_write_dvc1_tag(pb, track);
2476
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2477
1/2
✓ Branch 0 taken 90 times.
✗ Branch 1 not taken.
90 track->par->codec_id == AV_CODEC_ID_VP6A) {
2478 /* Don't write any potential extradata here - the cropping
2479 * is signalled via the normal width/height fields. */
2480
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 90 times.
90 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2481 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2482 mov_write_dpxe_tag(pb, track);
2483
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 86 times.
90 } else if (track->vos_len > 0)
2484 4 mov_write_glbl_tag(pb, track);
2485
2486
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 51 times.
190 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2487
2/2
✓ Branch 0 taken 119 times.
✓ Branch 1 taken 20 times.
139 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2488
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 23 times.
119 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2489 96 int field_order = track->par->field_order;
2490
2491
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 6 times.
96 if (field_order != AV_FIELD_UNKNOWN)
2492 90 mov_write_fiel_tag(pb, track, field_order);
2493 }
2494
2495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2496 if (track->mode == MODE_MOV)
2497 mov_write_gama_tag(s, pb, track, mov->gamma);
2498 else
2499 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2500 }
2501
5/6
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 57 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
375 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2502 374 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2503
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 181 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
189 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2504
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2505
5/6
✓ Branch 0 taken 181 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 177 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 177 times.
362 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2506 177 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2507 AV_PKT_DATA_ICC_PROFILE)) {
2508
3/4
✓ Branch 0 taken 8 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
8 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
2509 8 mov_write_colr_tag(pb, track, prefer_icc);
2510 }
2511
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2512 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2513 }
2514
2515
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 57 times.
✓ Branch 3 taken 5 times.
190 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2516 185 mov_write_clli_tag(pb, track);
2517 185 mov_write_mdcv_tag(pb, track);
2518 185 mov_write_amve_tag(pb, track);
2519 }
2520
2521
3/4
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 133 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 57 times.
190 if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2522 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2523 track->st->codecpar->nb_coded_side_data,
2524 AV_PKT_DATA_STEREO3D);
2525 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2526 track->st->codecpar->nb_coded_side_data,
2527 AV_PKT_DATA_SPHERICAL);
2528 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2529 track->st->codecpar->nb_coded_side_data,
2530 AV_PKT_DATA_DOVI_CONF);
2531
2532 if (stereo_3d)
2533 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2534 if (spherical_mapping)
2535 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2536 if (dovi)
2537 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2538 }
2539
2540
3/4
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 185 times.
190 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
2541 5 mov_write_pasp_tag(pb, track);
2542 }
2543
2544
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (uncompressed_ycbcr){
2545 mov_write_clap_tag(pb, track);
2546 }
2547
2548
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (mov->encryption_scheme != MOV_ENC_NONE) {
2549 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
2550 }
2551
2552
3/4
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 133 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 57 times.
247 if (mov->write_btrt &&
2553 57 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2554 return ret;
2555
2556 /* extra padding for avid stsd */
2557 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
2558
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 167 times.
190 if (avid)
2559 23 avio_wb32(pb, 0);
2560
2561
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (track->mode == MODE_AVIF) {
2562 mov_write_ccst_tag(pb);
2563 if (mov->nb_streams > 0 && track == &mov->tracks[1])
2564 mov_write_aux_tag(pb, "auxi");
2565 }
2566
2567 190 return update_size(pb, pos);
2568 }
2569
2570 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
2571 {
2572 2 int64_t pos = avio_tell(pb);
2573 2 avio_wb32(pb, 0); /* size */
2574 2 ffio_wfourcc(pb, "rtp ");
2575 2 avio_wb32(pb, 0); /* Reserved */
2576 2 avio_wb16(pb, 0); /* Reserved */
2577 2 avio_wb16(pb, 1); /* Data-reference index */
2578
2579 2 avio_wb16(pb, 1); /* Hint track version */
2580 2 avio_wb16(pb, 1); /* Highest compatible version */
2581 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
2582
2583 2 avio_wb32(pb, 12); /* size */
2584 2 ffio_wfourcc(pb, "tims");
2585 2 avio_wb32(pb, track->timescale);
2586
2587 2 return update_size(pb, pos);
2588 }
2589
2590 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
2591 {
2592 2 uint64_t str_size =strlen(reel_name);
2593 2 int64_t pos = avio_tell(pb);
2594
2595
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
2596 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
2597 avio_wb16(pb, 0);
2598 return AVERROR(EINVAL);
2599 }
2600
2601 2 avio_wb32(pb, 0); /* size */
2602 2 ffio_wfourcc(pb, "name"); /* Data format */
2603 2 avio_wb16(pb, str_size); /* string size */
2604 2 avio_wb16(pb, track->language); /* langcode */
2605 2 avio_write(pb, reel_name, str_size); /* reel name */
2606 2 return update_size(pb,pos);
2607 }
2608
2609 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
2610 {
2611 13 int64_t pos = avio_tell(pb);
2612 #if 1
2613 int frame_duration;
2614 int nb_frames;
2615 13 AVDictionaryEntry *t = NULL;
2616
2617
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) {
2618 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
2619 return AVERROR(EINVAL);
2620 } else {
2621 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
2622
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);
2623 }
2624
2625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
2626 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
2627 return AVERROR(EINVAL);
2628 }
2629
2630 13 avio_wb32(pb, 0); /* size */
2631 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
2632 13 avio_wb32(pb, 0); /* Reserved */
2633 13 avio_wb32(pb, 1); /* Data reference index */
2634 13 avio_wb32(pb, 0); /* Flags */
2635 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
2636 13 avio_wb32(pb, track->timescale); /* Timescale */
2637 13 avio_wb32(pb, frame_duration); /* Frame duration */
2638 13 avio_w8(pb, nb_frames); /* Number of frames */
2639 13 avio_w8(pb, 0); /* Reserved */
2640
2641 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
2642
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)
2643 2 mov_write_source_reference_tag(pb, track, t->value);
2644 else
2645 11 avio_wb16(pb, 0); /* zero size */
2646 #else
2647
2648 avio_wb32(pb, 0); /* size */
2649 ffio_wfourcc(pb, "tmcd"); /* Data format */
2650 avio_wb32(pb, 0); /* Reserved */
2651 avio_wb32(pb, 1); /* Data reference index */
2652 if (track->par->extradata_size)
2653 avio_write(pb, track->par->extradata, track->par->extradata_size);
2654 #endif
2655 13 return update_size(pb, pos);
2656 }
2657
2658 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
2659 {
2660 1 int64_t pos = avio_tell(pb);
2661 1 avio_wb32(pb, 0); /* size */
2662 1 ffio_wfourcc(pb, "gpmd");
2663 1 avio_wb32(pb, 0); /* Reserved */
2664 1 avio_wb16(pb, 0); /* Reserved */
2665 1 avio_wb16(pb, 1); /* Data-reference index */
2666 1 avio_wb32(pb, 0); /* Reserved */
2667 1 return update_size(pb, pos);
2668 }
2669
2670 313 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2671 {
2672 313 int64_t pos = avio_tell(pb);
2673 313 int ret = 0;
2674 313 avio_wb32(pb, 0); /* size */
2675 313 ffio_wfourcc(pb, "stsd");
2676 313 avio_wb32(pb, 0); /* version & flags */
2677 313 avio_wb32(pb, 1); /* entry count */
2678
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 123 times.
313 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
2679 190 ret = mov_write_video_tag(s, pb, mov, track);
2680
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 20 times.
123 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
2681 103 ret = mov_write_audio_tag(s, pb, mov, track);
2682
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2683 4 ret = mov_write_subtitle_tag(s, pb, track);
2684
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
2685 2 ret = mov_write_rtp_tag(pb, track);
2686
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
2687 13 ret = mov_write_tmcd_tag(pb, track);
2688
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
2689 1 ret = mov_write_gpmd_tag(pb, track);
2690
2691
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 if (ret < 0)
2692 return ret;
2693
2694 313 return update_size(pb, pos);
2695 }
2696
2697 7 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2698 {
2699 7 MOVMuxContext *mov = s->priv_data;
2700 MOVCtts *ctts_entries;
2701 7 uint32_t entries = 0;
2702 uint32_t atom_size;
2703 int i;
2704
2705 7 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
2706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!ctts_entries)
2707 return AVERROR(ENOMEM);
2708 7 ctts_entries[0].count = 1;
2709 7 ctts_entries[0].duration = track->cluster[0].cts;
2710
2/2
✓ Branch 0 taken 492 times.
✓ Branch 1 taken 7 times.
499 for (i = 1; i < track->entry; i++) {
2711
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 388 times.
492 if (track->cluster[i].cts == ctts_entries[entries].duration) {
2712 104 ctts_entries[entries].count++; /* compress */
2713 } else {
2714 388 entries++;
2715 388 ctts_entries[entries].duration = track->cluster[i].cts;
2716 388 ctts_entries[entries].count = 1;
2717 }
2718 }
2719 7 entries++; /* last one */
2720 7 atom_size = 16 + (entries * 8);
2721 7 avio_wb32(pb, atom_size); /* size */
2722 7 ffio_wfourcc(pb, "ctts");
2723
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
2724 avio_w8(pb, 1); /* version */
2725 else
2726 7 avio_w8(pb, 0); /* version */
2727 7 avio_wb24(pb, 0); /* flags */
2728 7 avio_wb32(pb, entries); /* entry count */
2729
2/2
✓ Branch 0 taken 395 times.
✓ Branch 1 taken 7 times.
402 for (i = 0; i < entries; i++) {
2730 395 avio_wb32(pb, ctts_entries[i].count);
2731 395 avio_wb32(pb, ctts_entries[i].duration);
2732 }
2733 7 av_free(ctts_entries);
2734 7 return atom_size;
2735 }
2736
2737 /* Time to sample atom */
2738 313 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
2739 {
2740 313 MOVStts *stts_entries = NULL;
2741 313 uint32_t entries = -1;
2742 uint32_t atom_size;
2743 int i;
2744
2745
4/4
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 30 times.
✓ Branch 3 taken 73 times.
313 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
2746 30 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
2747
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (!stts_entries)
2748 return AVERROR(ENOMEM);
2749 30 stts_entries[0].count = track->sample_count;
2750 30 stts_entries[0].duration = 1;
2751 30 entries = 1;
2752 } else {
2753
2/2
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 88 times.
283 if (track->entry) {
2754 195 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
2755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 195 times.
195 if (!stts_entries)
2756 return AVERROR(ENOMEM);
2757 }
2758
2/2
✓ Branch 0 taken 11705 times.
✓ Branch 1 taken 283 times.
11988 for (i = 0; i < track->entry; i++) {
2759 11705 int duration = get_cluster_duration(track, i);
2760
4/4
✓ Branch 0 taken 11510 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 11130 times.
✓ Branch 3 taken 380 times.
11705 if (i && duration == stts_entries[entries].duration) {
2761 11130 stts_entries[entries].count++; /* compress */
2762 } else {
2763 575 entries++;
2764 575 stts_entries[entries].duration = duration;
2765 575 stts_entries[entries].count = 1;
2766 }
2767 }
2768 283 entries++; /* last one */
2769 }
2770 313 atom_size = 16 + (entries * 8);
2771 313 avio_wb32(pb, atom_size); /* size */
2772 313 ffio_wfourcc(pb, "stts");
2773 313 avio_wb32(pb, 0); /* version & flags */
2774 313 avio_wb32(pb, entries); /* entry count */
2775
2/2
✓ Branch 0 taken 605 times.
✓ Branch 1 taken 313 times.
918 for (i = 0; i < entries; i++) {
2776 605 avio_wb32(pb, stts_entries[i].count);
2777 605 avio_wb32(pb, stts_entries[i].duration);
2778 }
2779 313 av_free(stts_entries);
2780 313 return atom_size;
2781 }
2782
2783 313 static int mov_write_dref_tag(AVIOContext *pb)
2784 {
2785 313 avio_wb32(pb, 28); /* size */
2786 313 ffio_wfourcc(pb, "dref");
2787 313 avio_wb32(pb, 0); /* version & flags */
2788 313 avio_wb32(pb, 1); /* entry count */
2789
2790 313 avio_wb32(pb, 0xc); /* size */
2791 //FIXME add the alis and rsrc atom
2792 313 ffio_wfourcc(pb, "url ");
2793 313 avio_wb32(pb, 1); /* version & flags */
2794
2795 313 return 28;
2796 }
2797
2798 52 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
2799 {
2800 struct sgpd_entry {
2801 int count;
2802 int16_t roll_distance;
2803 int group_description_index;
2804 };
2805
2806 52 struct sgpd_entry *sgpd_entries = NULL;
2807 52 int entries = -1;
2808 52 int group = 0;
2809 int i, j;
2810
2811 52 const int OPUS_SEEK_PREROLL_MS = 80;
2812 52 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
2813 52 (AVRational){1, 1000},
2814 52 (AVRational){1, 48000});
2815
2816
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 12 times.
52 if (!track->entry)
2817 40 return 0;
2818
2819 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
2820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
2821 return AVERROR(ENOMEM);
2822
2823
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);
2824
2825
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
2826 for (i = 0; i < track->entry; i++) {
2827 int roll_samples_remaining = roll_samples;
2828 int distance = 0;
2829 for (j = i - 1; j >= 0; j--) {
2830 roll_samples_remaining -= get_cluster_duration(track, j);
2831 distance++;
2832 if (roll_samples_remaining <= 0)
2833 break;
2834 }
2835 /* We don't have enough preceeding samples to compute a valid
2836 roll_distance here, so this sample can't be independently
2837 decoded. */
2838 if (roll_samples_remaining > 0)
2839 distance = 0;
2840 /* Verify distance is a maximum of 32 (2.5ms) packets. */
2841 if (distance > 32)
2842 return AVERROR_INVALIDDATA;
2843 if (i && distance == sgpd_entries[entries].roll_distance) {
2844 sgpd_entries[entries].count++;
2845 } else {
2846 entries++;
2847 sgpd_entries[entries].count = 1;
2848 sgpd_entries[entries].roll_distance = distance;
2849 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
2850 }
2851 }
2852 } else {
2853 12 entries++;
2854 12 sgpd_entries[entries].count = track->sample_count;
2855 12 sgpd_entries[entries].roll_distance = 1;
2856 12 sgpd_entries[entries].group_description_index = ++group;
2857 }
2858 12 entries++;
2859
2860
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
2861 av_free(sgpd_entries);
2862 return 0;
2863 }
2864
2865 /* Write sgpd tag */
2866 12 avio_wb32(pb, 24 + (group * 2)); /* size */
2867 12 ffio_wfourcc(pb, "sgpd");
2868 12 avio_wb32(pb, 1 << 24); /* fullbox */
2869 12 ffio_wfourcc(pb, "roll");
2870 12 avio_wb32(pb, 2); /* default_length */
2871 12 avio_wb32(pb, group); /* entry_count */
2872
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
2873
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
2874 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
2875 }
2876 }
2877
2878 /* Write sbgp tag */
2879 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
2880 12 ffio_wfourcc(pb, "sbgp");
2881 12 avio_wb32(pb, 0); /* fullbox */
2882 12 ffio_wfourcc(pb, "roll");
2883 12 avio_wb32(pb, entries); /* entry_count */
2884
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
2885 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
2886 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
2887 }
2888
2889 12 av_free(sgpd_entries);
2890 12 return 0;
2891 }
2892
2893 313 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2894 {
2895 313 int64_t pos = avio_tell(pb);
2896 313 int ret = 0;
2897
2898 313 avio_wb32(pb, 0); /* size */
2899 313 ffio_wfourcc(pb, "stbl");
2900
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 313 times.
313 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
2901 return ret;
2902 313 mov_write_stts_tag(pb, track);
2903
2/2
✓ Branch 0 taken 123 times.
✓ Branch 1 taken 190 times.
313 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
2904
1/2
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
123 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
2905
1/2
✓ Branch 0 taken 123 times.
✗ Branch 1 not taken.
123 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
2906
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 121 times.
123 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
2907
4/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 49 times.
✓ Branch 3 taken 95 times.
192 track->has_keyframes && track->has_keyframes < track->entry)
2908 49 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
2909
4/4
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 123 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 188 times.
313 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable)
2910 2 mov_write_sdtp_tag(pb, track);
2911
3/4
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 139 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 174 times.
313 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
2912 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
2913
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 123 times.
313 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
2914
4/4
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 161 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 22 times.
190 track->flags & MOV_TRACK_CTTS && track->entry) {
2915
2916
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
7 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
2917 return ret;
2918 }
2919 313 mov_write_stsc_tag(pb, track);
2920 313 mov_write_stsz_tag(pb, track);
2921 313 mov_write_stco_tag(pb, track);
2922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 if (track->cenc.aes_ctr) {
2923 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb);
2924 }
2925
3/4
✓ Branch 0 taken 313 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
✓ Branch 3 taken 261 times.
313 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
2926 52 mov_preroll_write_stbl_atoms(pb, track);
2927 }
2928 313 return update_size(pb, pos);
2929 }
2930
2931 313 static int mov_write_dinf_tag(AVIOContext *pb)
2932 {
2933 313 int64_t pos = avio_tell(pb);
2934 313 avio_wb32(pb, 0); /* size */
2935 313 ffio_wfourcc(pb, "dinf");
2936 313 mov_write_dref_tag(pb);
2937 313 return update_size(pb, pos);
2938 }
2939
2940 6 static int mov_write_nmhd_tag(AVIOContext *pb)
2941 {
2942 6 avio_wb32(pb, 12);
2943 6 ffio_wfourcc(pb, "nmhd");
2944 6 avio_wb32(pb, 0);
2945 6 return 12;
2946 }
2947
2948 1 static int mov_write_sthd_tag(AVIOContext *pb)
2949 {
2950 1 avio_wb32(pb, 12);
2951 1 ffio_wfourcc(pb, "sthd");
2952 1 avio_wb32(pb, 0);
2953 1 return 12;
2954 }
2955
2956 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
2957 {
2958 9 int64_t pos = avio_tell(pb);
2959 9 const char *font = "Lucida Grande";
2960 9 avio_wb32(pb, 0); /* size */
2961 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
2962 9 avio_wb32(pb, 0); /* version & flags */
2963 9 avio_wb16(pb, 0); /* text font */
2964 9 avio_wb16(pb, 0); /* text face */
2965 9 avio_wb16(pb, 12); /* text size */
2966 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
2967 9 avio_wb16(pb, 0x0000); /* text color (red) */
2968 9 avio_wb16(pb, 0x0000); /* text color (green) */
2969 9 avio_wb16(pb, 0x0000); /* text color (blue) */
2970 9 avio_wb16(pb, 0xffff); /* background color (red) */
2971 9 avio_wb16(pb, 0xffff); /* background color (green) */
2972 9 avio_wb16(pb, 0xffff); /* background color (blue) */
2973 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
2974 9 avio_write(pb, font, strlen(font)); /* font name */
2975 9 return update_size(pb, pos);
2976 }
2977
2978 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
2979 {
2980 11 int64_t pos = avio_tell(pb);
2981 11 avio_wb32(pb, 0); /* size */
2982 11 ffio_wfourcc(pb, "gmhd");
2983 11 avio_wb32(pb, 0x18); /* gmin size */
2984 11 ffio_wfourcc(pb, "gmin");/* generic media info */
2985 11 avio_wb32(pb, 0); /* version & flags */
2986 11 avio_wb16(pb, 0x40); /* graphics mode = */
2987 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
2988 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
2989 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
2990 11 avio_wb16(pb, 0); /* balance */
2991 11 avio_wb16(pb, 0); /* reserved */
2992
2993 /*
2994 * This special text atom is required for
2995 * Apple Quicktime chapters. The contents
2996 * don't appear to be documented, so the
2997 * bytes are copied verbatim.
2998 */
2999
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3000 11 avio_wb32(pb, 0x2C); /* size */
3001 11 ffio_wfourcc(pb, "text");
3002 11 avio_wb16(pb, 0x01);
3003 11 avio_wb32(pb, 0x00);
3004 11 avio_wb32(pb, 0x00);
3005 11 avio_wb32(pb, 0x00);
3006 11 avio_wb32(pb, 0x01);
3007 11 avio_wb32(pb, 0x00);
3008 11 avio_wb32(pb, 0x00);
3009 11 avio_wb32(pb, 0x00);
3010 11 avio_wb32(pb, 0x00004000);
3011 11 avio_wb16(pb, 0x0000);
3012 }
3013
3014
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3015 9 int64_t tmcd_pos = avio_tell(pb);
3016 9 avio_wb32(pb, 0); /* size */
3017 9 ffio_wfourcc(pb, "tmcd");
3018 9 mov_write_tcmi_tag(pb, track);
3019 9 update_size(pb, tmcd_pos);
3020
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3021 1 int64_t gpmd_pos = avio_tell(pb);
3022 1 avio_wb32(pb, 0); /* size */
3023 1 ffio_wfourcc(pb, "gpmd");
3024 1 avio_wb32(pb, 0); /* version */
3025 1 update_size(pb, gpmd_pos);
3026 }
3027 11 return update_size(pb, pos);
3028 }
3029
3030 103 static int mov_write_smhd_tag(AVIOContext *pb)
3031 {
3032 103 avio_wb32(pb, 16); /* size */
3033 103 ffio_wfourcc(pb, "smhd");
3034 103 avio_wb32(pb, 0); /* version & flags */
3035 103 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3036 103 avio_wb16(pb, 0); /* reserved */
3037 103 return 16;
3038 }
3039
3040 190 static int mov_write_vmhd_tag(AVIOContext *pb)
3041 {
3042 190 avio_wb32(pb, 0x14); /* size (always 0x14) */
3043 190 ffio_wfourcc(pb, "vmhd");
3044 190 avio_wb32(pb, 0x01); /* version & flags */
3045 190 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3046 190 return 0x14;
3047 }
3048
3049 199 static int is_clcp_track(MOVTrack *track)
3050 {
3051
1/2
✓ Branch 0 taken 199 times.
✗ Branch 1 not taken.
398 return track->tag == MKTAG('c','7','0','8') ||
3052
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 199 times.
199 track->tag == MKTAG('c','6','0','8');
3053 }
3054
3055 487 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3056 {
3057 487 MOVMuxContext *mov = s->priv_data;
3058 487 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3059 487 int64_t pos = avio_tell(pb);
3060 size_t descr_len;
3061
3062 487 hdlr = "dhlr";
3063 487 hdlr_type = "url ";
3064 487 descr = "DataHandler";
3065
3066
2/2
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 174 times.
487 if (track) {
3067
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 139 times.
313 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3068
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 123 times.
313 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3069
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (track->mode == MODE_AVIF) {
3070 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3071 descr = "PictureHandler";
3072 } else {
3073 190 hdlr_type = "vide";
3074 190 descr = "VideoHandler";
3075 }
3076
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 20 times.
123 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3077 103 hdlr_type = "soun";
3078 103 descr = "SoundHandler";
3079
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3080
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (is_clcp_track(track)) {
3081 hdlr_type = "clcp";
3082 descr = "ClosedCaptionHandler";
3083 } else {
3084
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (track->tag == MKTAG('t','x','3','g')) {
3085 1 hdlr_type = "sbtl";
3086
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (track->tag == MKTAG('m','p','4','s')) {
3087 hdlr_type = "subp";
3088
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3089 1 hdlr_type = "subt";
3090 } else {
3091 2 hdlr_type = "text";
3092 }
3093 4 descr = "SubtitleHandler";
3094 }
3095
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3096 2 hdlr_type = "hint";
3097 2 descr = "HintHandler";
3098
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3099 13 hdlr_type = "tmcd";
3100 13 descr = "TimeCodeHandler";
3101
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3102 1 hdlr_type = "meta";
3103 1 descr = "GoPro MET"; // GoPro Metadata
3104 } else {
3105 av_log(s, AV_LOG_WARNING,
3106 "Unknown hdlr_type for %s, writing dummy values\n",
3107 av_fourcc2str(track->par->codec_tag));
3108 }
3109
2/2
✓ Branch 0 taken 310 times.
✓ Branch 1 taken 3 times.
313 if (track->st) {
3110 // hdlr.name is used by some players to identify the content title
3111 // of the track. So if an alternate handler description is
3112 // specified, use it.
3113 AVDictionaryEntry *t;
3114 310 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3115
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 290 times.
✓ Branch 3 taken 20 times.
✗ Branch 4 not taken.
310 if (t && utf8len(t->value))
3116 20 descr = t->value;
3117 }
3118 }
3119
3120
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 487 times.
487 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3121 descr = "";
3122
3123 487 avio_wb32(pb, 0); /* size */
3124 487 ffio_wfourcc(pb, "hdlr");
3125 487 avio_wb32(pb, 0); /* Version & flags */
3126 487 avio_write(pb, hdlr, 4); /* handler */
3127 487 ffio_wfourcc(pb, hdlr_type); /* handler type */
3128 487 avio_wb32(pb, 0); /* reserved */
3129 487 avio_wb32(pb, 0); /* reserved */
3130 487 avio_wb32(pb, 0); /* reserved */
3131 487 descr_len = strlen(descr);
3132
4/4
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 139 times.
487 if (!track || track->mode == MODE_MOV)
3133 348 avio_w8(pb, descr_len); /* pascal string */
3134 487 avio_write(pb, descr, descr_len); /* handler description */
3135
4/4
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 139 times.
✓ Branch 3 taken 174 times.
487 if (track && track->mode != MODE_MOV)
3136 139 avio_w8(pb, 0); /* c string */
3137 487 return update_size(pb, pos);
3138 }
3139
3140 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3141 {
3142 int64_t pos = avio_tell(pb);
3143 avio_wb32(pb, 0); /* size */
3144 ffio_wfourcc(pb, "pitm");
3145 avio_wb32(pb, 0); /* Version & flags */
3146 avio_wb16(pb, item_id); /* item_id */
3147 return update_size(pb, pos);
3148 }
3149
3150 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3151 {
3152 int64_t pos = avio_tell(pb);
3153 avio_wb32(pb, 0); /* size */
3154 ffio_wfourcc(pb, "iloc");
3155 avio_wb32(pb, 0); /* Version & flags */
3156 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3157 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3158 avio_wb16(pb, mov->nb_streams); /* item_count */
3159
3160 for (int i = 0; i < mov->nb_streams; i++) {
3161 avio_wb16(pb, i + 1); /* item_id */
3162 avio_wb16(pb, 0); /* data_reference_index */
3163 avio_wb16(pb, 1); /* extent_count */
3164 mov->avif_extent_pos[i] = avio_tell(pb);
3165 avio_wb32(pb, 0); /* extent_offset (written later) */
3166 // For animated AVIF, we simply write the first packet's size.
3167 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3168 }
3169
3170 return update_size(pb, pos);
3171 }
3172
3173 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3174 {
3175 int64_t iinf_pos = avio_tell(pb);
3176 avio_wb32(pb, 0); /* size */
3177 ffio_wfourcc(pb, "iinf");
3178 avio_wb32(pb, 0); /* Version & flags */
3179 avio_wb16(pb, mov->nb_streams); /* entry_count */
3180
3181 for (int i = 0; i < mov->nb_streams; i++) {
3182 int64_t infe_pos = avio_tell(pb);
3183 avio_wb32(pb, 0); /* size */
3184 ffio_wfourcc(pb, "infe");
3185 avio_w8(pb, 0x2); /* Version */
3186 avio_wb24(pb, 0); /* flags */
3187 avio_wb16(pb, i + 1); /* item_id */
3188 avio_wb16(pb, 0); /* item_protection_index */
3189 avio_write(pb, "av01", 4); /* item_type */
3190 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3191 update_size(pb, infe_pos);
3192 }
3193
3194 return update_size(pb, iinf_pos);
3195 }
3196
3197
3198 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3199 {
3200 int64_t auxl_pos;
3201 int64_t iref_pos = avio_tell(pb);
3202 avio_wb32(pb, 0); /* size */
3203 ffio_wfourcc(pb, "iref");
3204 avio_wb32(pb, 0); /* Version & flags */
3205
3206 auxl_pos = avio_tell(pb);
3207 avio_wb32(pb, 0); /* size */
3208 ffio_wfourcc(pb, "auxl");
3209 avio_wb16(pb, 2); /* from_item_ID */
3210 avio_wb16(pb, 1); /* reference_count */
3211 avio_wb16(pb, 1); /* to_item_ID */
3212 update_size(pb, auxl_pos);
3213
3214 return update_size(pb, iref_pos);
3215 }
3216
3217 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3218 int stream_index)
3219 {
3220 int64_t pos = avio_tell(pb);
3221 avio_wb32(pb, 0); /* size */
3222 ffio_wfourcc(pb, "ispe");
3223 avio_wb32(pb, 0); /* Version & flags */
3224 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3225 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3226 return update_size(pb, pos);
3227 }
3228
3229 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3230 int stream_index)
3231 {
3232 int64_t pos = avio_tell(pb);
3233 const AVPixFmtDescriptor *pixdesc =
3234 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3235 avio_wb32(pb, 0); /* size */
3236 ffio_wfourcc(pb, "pixi");
3237 avio_wb32(pb, 0); /* Version & flags */
3238 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3239 for (int i = 0; i < pixdesc->nb_components; ++i) {
3240 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3241 }
3242 return update_size(pb, pos);
3243 }
3244
3245 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3246 {
3247 int64_t pos = avio_tell(pb);
3248 avio_wb32(pb, 0); /* size */
3249 ffio_wfourcc(pb, "ipco");
3250 for (int i = 0; i < mov->nb_streams; i++) {
3251 mov_write_ispe_tag(pb, mov, s, i);
3252 mov_write_pixi_tag(pb, mov, s, i);
3253 mov_write_av1c_tag(pb, &mov->tracks[i]);
3254 if (!i)
3255 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3256 else
3257 mov_write_aux_tag(pb, "auxC");
3258 }
3259 return update_size(pb, pos);
3260 }
3261
3262 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3263 {
3264 int64_t pos = avio_tell(pb);
3265 avio_wb32(pb, 0); /* size */
3266 ffio_wfourcc(pb, "ipma");
3267 avio_wb32(pb, 0); /* Version & flags */
3268 avio_wb32(pb, mov->nb_streams); /* entry_count */
3269
3270 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3271 avio_wb16(pb, i + 1); /* item_ID */
3272 avio_w8(pb, 4); /* association_count */
3273
3274 // ispe association.
3275 avio_w8(pb, index++); /* essential and property_index */
3276 // pixi association.
3277 avio_w8(pb, index++); /* essential and property_index */
3278 // av1C association.
3279 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3280 // colr/auxC association.
3281 avio_w8(pb, index++); /* essential and property_index */
3282 }
3283 return update_size(pb, pos);
3284 }
3285
3286 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3287 {
3288 int64_t pos = avio_tell(pb);
3289 avio_wb32(pb, 0); /* size */
3290 ffio_wfourcc(pb, "iprp");
3291 mov_write_ipco_tag(pb, mov, s);
3292 mov_write_ipma_tag(pb, mov, s);
3293 return update_size(pb, pos);
3294 }
3295
3296 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3297 {
3298 /* This atom must be present, but leaving the values at zero
3299 * seems harmless. */
3300 2 avio_wb32(pb, 28); /* size */
3301 2 ffio_wfourcc(pb, "hmhd");
3302 2 avio_wb32(pb, 0); /* version, flags */
3303 2 avio_wb16(pb, 0); /* maxPDUsize */
3304 2 avio_wb16(pb, 0); /* avgPDUsize */
3305 2 avio_wb32(pb, 0); /* maxbitrate */
3306 2 avio_wb32(pb, 0); /* avgbitrate */
3307 2 avio_wb32(pb, 0); /* reserved */
3308 2 return 28;
3309 }
3310
3311 313 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3312 {
3313 313 int64_t pos = avio_tell(pb);
3314 int ret;
3315
3316 313 avio_wb32(pb, 0); /* size */
3317 313 ffio_wfourcc(pb, "minf");
3318
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 123 times.
313 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3319 190 mov_write_vmhd_tag(pb);
3320
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 20 times.
123 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3321 103 mov_write_smhd_tag(pb);
3322
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3323
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)) {
3324 1 mov_write_gmhd_tag(pb, track);
3325
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3326 1 mov_write_sthd_tag(pb);
3327 } else {
3328 2 mov_write_nmhd_tag(pb);
3329 }
3330
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3331 2 mov_write_hmhd_tag(pb);
3332
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3333
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3334 4 mov_write_nmhd_tag(pb);
3335 else
3336 9 mov_write_gmhd_tag(pb, track);
3337
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3338 1 mov_write_gmhd_tag(pb, track);
3339 }
3340
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 139 times.
313 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3341 174 mov_write_hdlr_tag(s, pb, NULL);
3342 313 mov_write_dinf_tag(pb);
3343
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 313 times.
313 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3344 return ret;
3345 313 return update_size(pb, pos);
3346 }
3347
3348 1224 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3349 int64_t *start, int64_t *end)
3350 {
3351
4/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1174 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
1224 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) {
3352 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3353 // another track's duration, while the end_pts may be left at zero.
3354 // Calculate the pts duration for that track instead.
3355 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end);
3356 38 *start = av_rescale(*start, track->timescale,
3357 38 mov->tracks[track->src_track].timescale);
3358 38 *end = av_rescale(*end, track->timescale,
3359 38 mov->tracks[track->src_track].timescale);
3360 38 return;
3361 }
3362
2/2
✓ Branch 0 taken 1132 times.
✓ Branch 1 taken 54 times.
1186 if (track->end_pts != AV_NOPTS_VALUE &&
3363
1/2
✓ Branch 0 taken 1132 times.
✗ Branch 1 not taken.
1132 track->start_dts != AV_NOPTS_VALUE &&
3364
1/2
✓ Branch 0 taken 1132 times.
✗ Branch 1 not taken.
1132 track->start_cts != AV_NOPTS_VALUE) {
3365 1132 *start = track->start_dts + track->start_cts;
3366 1132 *end = track->end_pts;
3367 1132 return;
3368 }
3369 54 *start = 0;
3370 54 *end = track->track_duration;
3371 }
3372
3373 584 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3374 {
3375 int64_t start, end;
3376 584 get_pts_range(mov, track, &start, &end);
3377 584 return end - start;
3378 }
3379
3380 // Calculate the actual duration of the track, after edits.
3381 // If it starts with a pts < 0, that is removed by the edit list.
3382 // If it starts with a pts > 0, the edit list adds a delay before that.
3383 // Thus, with edit lists enabled, the post-edit output of the file is
3384 // starting with pts=0.
3385 602 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3386 {
3387 int64_t start, end;
3388 602 get_pts_range(mov, track, &start, &end);
3389
2/2
✓ Branch 0 taken 548 times.
✓ Branch 1 taken 54 times.
602 if (mov->use_editlist != 0)
3390 548 start = 0;
3391 602 return end - start;
3392 }
3393
3394 849 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3395 {
3396
4/4
✓ Branch 0 taken 626 times.
✓ Branch 1 taken 223 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 612 times.
849 if (track && track->mode == MODE_ISM)
3397 14 return 1;
3398
2/2
✓ Branch 0 taken 831 times.
✓ Branch 1 taken 4 times.
835 if (duration < INT32_MAX)
3399 831 return 0;
3400 4 return 1;
3401 }
3402
3403 313 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3404 MOVTrack *track)
3405 {
3406 313 int64_t duration = calc_samples_pts_duration(mov, track);
3407 313 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3408
3409
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 302 times.
313 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3410 313 ffio_wfourcc(pb, "mdhd");
3411 313 avio_w8(pb, version);
3412 313 avio_wb24(pb, 0); /* flags */
3413
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 302 times.
313 if (version == 1) {
3414 11 avio_wb64(pb, track->time);
3415 11 avio_wb64(pb, track->time);
3416 } else {
3417 302 avio_wb32(pb, track->time); /* creation time */
3418 302 avio_wb32(pb, track->time); /* modification time */
3419 }
3420 313 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3421
4/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 81 times.
313 if (!track->entry && mov->mode == MODE_ISM)
3422
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3423
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 225 times.
306 else if (!track->entry)
3424
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 77 times.
81 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3425 else
3426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 225 times.
225 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3427 313 avio_wb16(pb, track->language); /* language */
3428 313 avio_wb16(pb, 0); /* reserved (quality) */
3429
3430
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
313 if (version != 0 && track->mode == MODE_MOV) {
3431 av_log(NULL, AV_LOG_ERROR,
3432 "FATAL error, file duration too long for timebase, this file will not be\n"
3433 "playable with QuickTime. Choose a different timebase with "
3434 "-video_track_timescale or a different container format\n");
3435 }
3436
3437 313 return 32;
3438 }
3439
3440 313 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3441 MOVMuxContext *mov, MOVTrack *track)
3442 {
3443 313 int64_t pos = avio_tell(pb);
3444 int ret;
3445
3446 313 avio_wb32(pb, 0); /* size */
3447 313 ffio_wfourcc(pb, "mdia");
3448 313 mov_write_mdhd_tag(pb, mov, track);
3449 313 mov_write_hdlr_tag(s, pb, track);
3450
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 313 times.
313 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3451 return ret;
3452 313 return update_size(pb, pos);
3453 }
3454
3455 /* transformation matrix
3456 |a b u|
3457 |c d v|
3458 |tx ty w| */
3459 535 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3460 int16_t d, int16_t tx, int16_t ty)
3461 {
3462 535 avio_wb32(pb, a << 16); /* 16.16 format */
3463 535 avio_wb32(pb, b << 16); /* 16.16 format */
3464 535 avio_wb32(pb, 0); /* u in 2.30 format */
3465 535 avio_wb32(pb, c << 16); /* 16.16 format */
3466 535 avio_wb32(pb, d << 16); /* 16.16 format */
3467 535 avio_wb32(pb, 0); /* v in 2.30 format */
3468 535 avio_wb32(pb, tx << 16); /* 16.16 format */
3469 535 avio_wb32(pb, ty << 16); /* 16.16 format */
3470 535 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3471 535 }
3472
3473 313 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3474 MOVTrack *track, AVStream *st)
3475 {
3476 626 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3477 313 mov->movie_timescale, track->timescale,
3478 AV_ROUND_UP);
3479 int version;
3480 313 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3481 313 int group = 0;
3482
3483 313 uint32_t *display_matrix = NULL;
3484 int i;
3485
3486
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 if (mov->mode == MODE_AVIF)
3487 if (!mov->avif_loop_count)
3488 duration = INT64_MAX;
3489 else
3490 duration *= mov->avif_loop_count;
3491
3492
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 13 times.
313 if (st) {
3493 const AVPacketSideData *sd;
3494
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
300 if (mov->per_stream_grouping)
3495 group = st->index;
3496 else
3497 300 group = st->codecpar->codec_type;
3498
3499 300 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3500 300 st->codecpar->nb_coded_side_data,
3501 AV_PKT_DATA_DISPLAYMATRIX);
3502
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 299 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
300 if (sd && sd->size == 9 * sizeof(*display_matrix))
3503 1 display_matrix = (uint32_t *)sd->data;
3504 }
3505
3506
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 25 times.
313 if (track->flags & MOV_TRACK_ENABLED)
3507 288 flags |= MOV_TKHD_FLAG_ENABLED;
3508
3509 313 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3510
3511
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 306 times.
313 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
3512 313 ffio_wfourcc(pb, "tkhd");
3513 313 avio_w8(pb, version);
3514 313 avio_wb24(pb, flags);
3515
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 306 times.
313 if (version == 1) {
3516 7 avio_wb64(pb, track->time);
3517 7 avio_wb64(pb, track->time);
3518 } else {
3519 306 avio_wb32(pb, track->time); /* creation time */
3520 306 avio_wb32(pb, track->time); /* modification time */
3521 }
3522 313 avio_wb32(pb, track->track_id); /* track-id */
3523 313 avio_wb32(pb, 0); /* reserved */
3524
4/4
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 81 times.
313 if (!track->entry && mov->mode == MODE_ISM)
3525
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3526
2/2
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 225 times.
306 else if (!track->entry)
3527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 81 times.
81 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3528 else
3529
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 225 times.
225 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
3530
3531 313 avio_wb32(pb, 0); /* reserved */
3532 313 avio_wb32(pb, 0); /* reserved */
3533 313 avio_wb16(pb, 0); /* layer */
3534 313 avio_wb16(pb, group); /* alternate group) */
3535 /* Volume, only for audio */
3536
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 210 times.
313 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3537 103 avio_wb16(pb, 0x0100);
3538 else
3539 210 avio_wb16(pb, 0);
3540 313 avio_wb16(pb, 0); /* reserved */
3541
3542 /* Matrix structure */
3543
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 312 times.
313 if (display_matrix) {
3544
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
3545 9 avio_wb32(pb, display_matrix[i]);
3546 } else {
3547 312 write_matrix(pb, 1, 0, 0, 1, 0, 0);
3548 }
3549 /* Track width and height, for visual only */
3550
4/4
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 110 times.
✓ Branch 3 taken 190 times.
313 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3551
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 107 times.
303 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
3552 int64_t track_width_1616;
3553
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 128 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
193 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
3554 128 track_width_1616 = track->par->width * 0x10000ULL;
3555 } else {
3556 65 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
3557 65 track->par->width * 0x10000LL,
3558 65 st->sample_aspect_ratio.den);
3559
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 63 times.
65 if (!track_width_1616 ||
3560
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 ||
3561 track_width_1616 > UINT32_MAX)
3562 63 track_width_1616 = track->par->width * 0x10000ULL;
3563 }
3564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 193 times.
193 if (track_width_1616 > UINT32_MAX) {
3565 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
3566 track_width_1616 = 0;
3567 }
3568 193 avio_wb32(pb, track_width_1616);
3569
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 193 times.
193 if (track->height > 0xFFFF) {
3570 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
3571 avio_wb32(pb, 0);
3572 } else
3573 193 avio_wb32(pb, track->height * 0x10000U);
3574 } else {
3575 120 avio_wb32(pb, 0);
3576 120 avio_wb32(pb, 0);
3577 }
3578 313 return 0x5c;
3579 }
3580
3581 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
3582 {
3583 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
3584 1 track->par->sample_aspect_ratio.den);
3585
3586 1 int64_t pos = avio_tell(pb);
3587
3588 1 avio_wb32(pb, 0); /* size */
3589 1 ffio_wfourcc(pb, "tapt");
3590
3591 1 avio_wb32(pb, 20);
3592 1 ffio_wfourcc(pb, "clef");
3593 1 avio_wb32(pb, 0);
3594 1 avio_wb32(pb, width << 16);
3595 1 avio_wb32(pb, track->par->height << 16);
3596
3597 1 avio_wb32(pb, 20);
3598 1 ffio_wfourcc(pb, "prof");
3599 1 avio_wb32(pb, 0);
3600 1 avio_wb32(pb, width << 16);
3601 1 avio_wb32(pb, track->par->height << 16);
3602
3603 1 avio_wb32(pb, 20);
3604 1 ffio_wfourcc(pb, "enof");
3605 1 avio_wb32(pb, 0);
3606 1 avio_wb32(pb, track->par->width << 16);
3607 1 avio_wb32(pb, track->par->height << 16);
3608
3609 1 return update_size(pb, pos);
3610 }
3611
3612 // This box is written in the following cases:
3613 // * Seems important for the psp playback. Without it the movie seems to hang.
3614 // * Used for specifying the looping behavior of animated AVIF (as specified
3615 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
3616 271 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
3617 MOVTrack *track)
3618 {
3619 542 int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track),
3620 271 mov->movie_timescale, track->timescale,
3621 AV_ROUND_UP);
3622 271 int version = duration < INT32_MAX ? 0 : 1;
3623 int entry_size, entry_count, size;
3624 271 int64_t delay, start_ct = track->start_cts;
3625 271 int64_t start_dts = track->start_dts;
3626 271 int flags = 0;
3627
3628
2/2
✓ Branch 0 taken 217 times.
✓ Branch 1 taken 54 times.
271 if (track->entry) {
3629
2/4
✓ Branch 0 taken 217 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 217 times.
217 if (start_dts != track->cluster[0].dts || start_ct != track->cluster[0].cts) {
3630
3631 av_log(mov->fc, AV_LOG_DEBUG,
3632 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
3633 track->cluster[0].dts, track->cluster[0].cts,
3634 start_dts, start_ct, track->track_id);
3635 start_dts = track->cluster[0].dts;
3636 start_ct = track->cluster[0].cts;
3637 }
3638 }
3639
3640 271 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
3641 271 track->timescale, AV_ROUND_DOWN);
3642
3643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 271 times.
271 if (mov->mode == MODE_AVIF) {
3644 delay = 0;
3645 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
3646 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
3647 // list is not repeated, while (flags & 1) equal to 1 specifies that the
3648 // edit list is repeated.
3649 flags = mov->avif_loop_count != 1;
3650 start_ct = 0;
3651 }
3652
3653 271 version |= delay < INT32_MAX ? 0 : 1;
3654
3655
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 271 times.
271 entry_size = (version == 1) ? 20 : 12;
3656
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 269 times.
271 entry_count = 1 + (delay > 0);
3657 271 size = 24 + entry_count * entry_size;
3658
3659 /* write the atom data */
3660 271 avio_wb32(pb, size);
3661 271 ffio_wfourcc(pb, "edts");
3662 271 avio_wb32(pb, size - 8);
3663 271 ffio_wfourcc(pb, "elst");
3664 271 avio_w8(pb, version);
3665 271 avio_wb24(pb, flags); /* flags */
3666
3667 271 avio_wb32(pb, entry_count);
3668
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 269 times.
271 if (delay > 0) { /* add an empty edit to delay presentation */
3669 /* In the positive delay case, the delay includes the cts
3670 * offset, and the second edit list entry below trims out
3671 * the same amount from the actual content. This makes sure
3672 * that the offset last sample is included in the edit
3673 * list duration as well. */
3674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
3675 avio_wb64(pb, delay);
3676 avio_wb64(pb, -1);
3677 } else {
3678 2 avio_wb32(pb, delay);
3679 2 avio_wb32(pb, -1);
3680 }
3681 2 avio_wb32(pb, 0x00010000);
3682
1/2
✓ Branch 0 taken 269 times.
✗ Branch 1 not taken.
269 } else if (mov->mode != MODE_AVIF) {
3683 /* Avoid accidentally ending up with start_ct = -1 which has got a
3684 * special meaning. Normally start_ct should end up positive or zero
3685 * here, but use FFMIN in case dts is a small positive integer
3686 * rounded to 0 when represented in movie timescale units. */
3687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 269 times.
269 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
3688 269 start_ct = -FFMIN(start_dts, 0);
3689 /* Note, this delay is calculated from the pts of the first sample,
3690 * ensuring that we don't reduce the duration for cases with
3691 * dts<0 pts=0. */
3692 269 duration += delay;
3693 }
3694
3695 /* For fragmented files, we don't know the full length yet. Setting
3696 * duration to 0 allows us to only specify the offset, including
3697 * the rest of the content (from all future fragments) without specifying
3698 * an explicit duration. */
3699
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 213 times.
271 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
3700 58 duration = 0;
3701
3702 /* duration */
3703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 271 times.
271 if (version == 1) {
3704 avio_wb64(pb, duration);
3705 avio_wb64(pb, start_ct);
3706 } else {
3707 271 avio_wb32(pb, duration);
3708 271 avio_wb32(pb, start_ct);
3709 }
3710 271 avio_wb32(pb, 0x00010000);
3711 271 return size;
3712 }
3713
3714 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
3715 {
3716 14 avio_wb32(pb, 20); // size
3717 14 ffio_wfourcc(pb, "tref");
3718 14 avio_wb32(pb, 12); // size (subatom)
3719 14 avio_wl32(pb, track->tref_tag);
3720 14 avio_wb32(pb, track->tref_id);
3721 14 return 20;
3722 }
3723
3724 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
3725 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
3726 {
3727 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
3728 2 ffio_wfourcc(pb, "uuid");
3729 2 ffio_wfourcc(pb, "USMT");
3730 2 avio_wb32(pb, 0x21d24fce);
3731 2 avio_wb32(pb, 0xbb88695c);
3732 2 avio_wb32(pb, 0xfac9c740);
3733 2 avio_wb32(pb, 0x1c); // another size here!
3734 2 ffio_wfourcc(pb, "MTDT");
3735 2 avio_wb32(pb, 0x00010012);
3736 2 avio_wb32(pb, 0x0a);
3737 2 avio_wb32(pb, 0x55c40000);
3738 2 avio_wb32(pb, 0x1);
3739 2 avio_wb32(pb, 0x0);
3740 2 return 0x34;
3741 }
3742
3743 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
3744 {
3745 2 AVFormatContext *ctx = track->rtp_ctx;
3746 2 char buf[1000] = "";
3747 int len;
3748
3749 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
3750 NULL, NULL, 0, 0, ctx);
3751 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
3752 2 len = strlen(buf);
3753
3754 2 avio_wb32(pb, len + 24);
3755 2 ffio_wfourcc(pb, "udta");
3756 2 avio_wb32(pb, len + 16);
3757 2 ffio_wfourcc(pb, "hnti");
3758 2 avio_wb32(pb, len + 8);
3759 2 ffio_wfourcc(pb, "sdp ");
3760 2 avio_write(pb, buf, len);
3761 2 return len + 24;
3762 }
3763
3764 292 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
3765 const char *tag, const char *str)
3766 {
3767 292 int64_t pos = avio_tell(pb);
3768 292 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
3769
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 291 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
292 if (!t || !utf8len(t->value))
3770 291 return 0;
3771
3772 1 avio_wb32(pb, 0); /* size */
3773 1 ffio_wfourcc(pb, tag); /* type */
3774 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
3775 1 return update_size(pb, pos);
3776 }
3777
3778 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
3779 const char *value)
3780 {
3781 2 int64_t pos = avio_tell(pb);
3782
3783 /* Box|FullBox basics */
3784 2 avio_wb32(pb, 0); /* size placeholder */
3785 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
3786 2 avio_w8(pb, 0); /* version = 0 */
3787 2 avio_wb24(pb, 0); /* flags = 0 */
3788
3789 /* Required null-terminated scheme URI */
3790 2 avio_write(pb, (const unsigned char *)scheme_uri,
3791 2 strlen(scheme_uri));
3792 2 avio_w8(pb, 0);
3793
3794 /* Optional value string */
3795
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])
3796 2 avio_write(pb, (const unsigned char *)value,
3797 2 strlen(value));
3798
3799 2 avio_w8(pb, 0);
3800
3801 2 return update_size(pb, pos);
3802 }
3803
3804 124 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
3805 {
3806 124 int ret = AVERROR_BUG;
3807
3808
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 124 times.
248 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
3809 124 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
3810
3811
2/2
✓ Branch 0 taken 620 times.
✓ Branch 1 taken 124 times.
744 for (int j = 0; map.value_maps[j].disposition; j++) {
3812 620 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
3813
2/2
✓ Branch 0 taken 618 times.
✓ Branch 1 taken 2 times.
620 if (!(st->disposition & value_map.disposition))
3814 618 continue;
3815
3816
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)
3817 return ret;
3818 }
3819 }
3820
3821 124 return 0;
3822 }
3823
3824 313 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
3825 AVStream *st)
3826 {
3827 AVIOContext *pb_buf;
3828 int ret, size;
3829 uint8_t *buf;
3830
3831
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 300 times.
313 if (!st)
3832 13 return 0;
3833
3834 300 ret = avio_open_dyn_buf(&pb_buf);
3835
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 300 times.
300 if (ret < 0)
3836 return ret;
3837
3838
2/2
✓ Branch 0 taken 292 times.
✓ Branch 1 taken 8 times.
300 if (mov->mode & (MODE_MP4|MODE_MOV))
3839 292 mov_write_track_metadata(pb_buf, st, "name", "title");
3840
3841
2/2
✓ Branch 0 taken 124 times.
✓ Branch 1 taken 176 times.
300 if (mov->mode & MODE_MP4) {
3842
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 124 times.
124 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
3843 return ret;
3844 }
3845
3846
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 297 times.
300 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
3847 3 avio_wb32(pb, size + 8);
3848 3 ffio_wfourcc(pb, "udta");
3849 3 avio_write(pb, buf, size);
3850 }
3851 300 ffio_free_dyn_buf(&pb_buf);
3852
3853 300 return 0;
3854 }
3855
3856 313 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
3857 MOVTrack *track, AVStream *st)
3858 {
3859 313 int64_t pos = avio_tell(pb);
3860 313 int entry_backup = track->entry;
3861 313 int chunk_backup = track->chunkCount;
3862 int ret;
3863
3864 /* If we want to have an empty moov, but some samples already have been
3865 * buffered (delay_moov), pretend that no samples have been written yet. */
3866
2/2
✓ Branch 0 taken 88 times.
✓ Branch 1 taken 225 times.
313 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
3867 88 track->chunkCount = track->entry = 0;
3868
3869 313 avio_wb32(pb, 0); /* size */
3870 313 ffio_wfourcc(pb, "trak");
3871 313 mov_write_tkhd_tag(pb, mov, track, st);
3872
3873 av_assert2(mov->use_editlist >= 0);
3874
3875
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 24 times.
313 if (track->start_dts != AV_NOPTS_VALUE) {
3876
2/2
✓ Branch 0 taken 271 times.
✓ Branch 1 taken 18 times.
289 if (mov->use_editlist)
3877 271 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
3878
5/8
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 18 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 18 times.
18 else if ((track->entry && track->cluster[0].dts) || track->mode == MODE_PSP || is_clcp_track(track))
3879 av_log(mov->fc, AV_LOG_WARNING,
3880 "Not writing any edit list even though one would have been required\n");
3881 }
3882
3883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 if (mov->is_animated_avif)
3884 mov_write_edts_tag(pb, mov, track);
3885
3886
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 299 times.
313 if (track->tref_tag)
3887 14 mov_write_tref_tag(pb, track);
3888
3889
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 313 times.
313 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
3890 return ret;
3891
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 311 times.
313 if (track->mode == MODE_PSP)
3892 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
3893
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 311 times.
313 if (track->tag == MKTAG('r','t','p',' '))
3894 2 mov_write_udta_sdp(pb, track);
3895
2/2
✓ Branch 0 taken 174 times.
✓ Branch 1 taken 139 times.
313 if (track->mode == MODE_MOV) {
3896
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 46 times.
174 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3897 128 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
3898
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 125 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 2 times.
128 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
3899 1 mov_write_tapt_tag(pb, track);
3900 }
3901 }
3902
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 174 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
174 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
3903 mov_write_tapt_tag(pb, track);
3904 }
3905 }
3906 313 mov_write_track_udta_tag(pb, mov, st);
3907 313 track->entry = entry_backup;
3908 313 track->chunkCount = chunk_backup;
3909 313 return update_size(pb, pos);
3910 }
3911
3912 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
3913 {
3914 int i, has_audio = 0, has_video = 0;
3915 int64_t pos = avio_tell(pb);
3916 int audio_profile = mov->iods_audio_profile;
3917 int video_profile = mov->iods_video_profile;
3918 for (i = 0; i < mov->nb_tracks; i++) {
3919 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
3920 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
3921 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
3922 }
3923 }
3924 if (audio_profile < 0)
3925 audio_profile = 0xFF - has_audio;
3926 if (video_profile < 0)
3927 video_profile = 0xFF - has_video;
3928 avio_wb32(pb, 0x0); /* size */
3929 ffio_wfourcc(pb, "iods");
3930 avio_wb32(pb, 0); /* version & flags */
3931 put_descr(pb, 0x10, 7);
3932 avio_wb16(pb, 0x004f);
3933 avio_w8(pb, 0xff);
3934 avio_w8(pb, 0xff);
3935 avio_w8(pb, audio_profile);
3936 avio_w8(pb, video_profile);
3937 avio_w8(pb, 0xff);
3938 return update_size(pb, pos);
3939 }
3940
3941 100 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
3942 {
3943 100 avio_wb32(pb, 0x20); /* size */
3944 100 ffio_wfourcc(pb, "trex");
3945 100 avio_wb32(pb, 0); /* version & flags */
3946 100 avio_wb32(pb, track->track_id); /* track ID */
3947 100 avio_wb32(pb, 1); /* default sample description index */
3948 100 avio_wb32(pb, 0); /* default sample duration */
3949 100 avio_wb32(pb, 0); /* default sample size */
3950 100 avio_wb32(pb, 0); /* default sample flags */
3951 100 return 0;
3952 }
3953
3954 52 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
3955 {
3956 52 int64_t pos = avio_tell(pb);
3957 int i;
3958 52 avio_wb32(pb, 0x0); /* size */
3959 52 ffio_wfourcc(pb, "mvex");
3960
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 52 times.
152 for (i = 0; i < mov->nb_tracks; i++)
3961 100 mov_write_trex_tag(pb, &mov->tracks[i]);
3962 52 return update_size(pb, pos);
3963 }
3964
3965 223 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
3966 {
3967 223 int max_track_id = 1, i;
3968 223 int64_t max_track_len = 0;
3969 int version;
3970 int timescale;
3971
3972
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 223 times.
538 for (i = 0; i < mov->nb_tracks; i++) {
3973
3/4
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 289 times.
✗ Branch 3 not taken.
315 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
3974 578 int64_t max_track_len_temp = av_rescale_rnd(
3975 289 calc_pts_duration(mov, &mov->tracks[i]),
3976 289 mov->movie_timescale,
3977 289 mov->tracks[i].timescale,
3978 AV_ROUND_UP);
3979
2/2
✓ Branch 0 taken 222 times.
✓ Branch 1 taken 67 times.
289 if (max_track_len < max_track_len_temp)
3980 222 max_track_len = max_track_len_temp;
3981
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 211 times.
289 if (max_track_id < mov->tracks[i].track_id)
3982 78 max_track_id = mov->tracks[i].track_id;
3983 }
3984 }
3985 /* If using delay_moov, make sure the output is the same as if no
3986 * samples had been written yet. */
3987
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 177 times.
223 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
3988 46 max_track_len = 0;
3989 46 max_track_id = 1;
3990 }
3991
3992 223 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
3993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
223 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
3994
3995 223 ffio_wfourcc(pb, "mvhd");
3996 223 avio_w8(pb, version);
3997 223 avio_wb24(pb, 0); /* flags */
3998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
223 if (version == 1) {
3999 avio_wb64(pb, mov->time);
4000 avio_wb64(pb, mov->time);
4001 } else {
4002 223 avio_wb32(pb, mov->time); /* creation time */
4003 223 avio_wb32(pb, mov->time); /* modification time */
4004 }
4005
4006 223 timescale = mov->movie_timescale;
4007
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
223 if (mov->mode == MODE_AVIF && !timescale)
4008 timescale = mov->tracks[0].timescale;
4009
4010 223 avio_wb32(pb, timescale);
4011
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
223 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4012
4013 223 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4014 223 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4015 223 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4016
4017 /* Matrix structure */
4018 223 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4019
4020 223 avio_wb32(pb, 0); /* reserved (preview time) */
4021 223 avio_wb32(pb, 0); /* reserved (preview duration) */
4022 223 avio_wb32(pb, 0); /* reserved (poster time) */
4023 223 avio_wb32(pb, 0); /* reserved (selection time) */
4024 223 avio_wb32(pb, 0); /* reserved (selection duration) */
4025 223 avio_wb32(pb, 0); /* reserved (current time) */
4026 223 avio_wb32(pb, max_track_id + 1); /* Next track id */
4027 223 return 0x6c;
4028 }
4029
4030 78 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4031 AVFormatContext *s)
4032 {
4033 78 avio_wb32(pb, 33); /* size */
4034 78 ffio_wfourcc(pb, "hdlr");
4035 78 avio_wb32(pb, 0);
4036 78 avio_wb32(pb, 0);
4037 78 ffio_wfourcc(pb, "mdir");
4038 78 ffio_wfourcc(pb, "appl");
4039 78 avio_wb32(pb, 0);
4040 78 avio_wb32(pb, 0);
4041 78 avio_w8(pb, 0);
4042 78 return 33;
4043 }
4044
4045 /* helper function to write a data tag with the specified string as data */
4046 48 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4047 {
4048 48 size_t data_len = strlen(data);
4049
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 30 times.
48 if (long_style) {
4050 18 int size = 16 + data_len;
4051 18 avio_wb32(pb, size); /* size */
4052 18 ffio_wfourcc(pb, "data");
4053 18 avio_wb32(pb, 1);
4054 18 avio_wb32(pb, 0);
4055 18 avio_write(pb, data, data_len);
4056 18 return size;
4057 } else {
4058 30 avio_wb16(pb, data_len); /* string length */
4059
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 8 times.
30 if (!lang)
4060 22 lang = ff_mov_iso639_to_lang("und", 1);
4061 30 avio_wb16(pb, lang);
4062 30 avio_write(pb, data, data_len);
4063 30 return data_len + 4;
4064 }
4065 }
4066
4067 48 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4068 const char *value, int lang, int long_style)
4069 {
4070 48 int size = 0;
4071
2/4
✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
48 if (value && value[0]) {
4072 48 int64_t pos = avio_tell(pb);
4073 48 avio_wb32(pb, 0); /* size */
4074 48 ffio_wfourcc(pb, name);
4075 48 mov_write_string_data_tag(pb, value, lang, long_style);
4076 48 size = update_size(pb, pos);
4077 }
4078 48 return size;
4079 }
4080
4081 3498 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4082 const char *tag, int *lang)
4083 {
4084 int l, len, len2;
4085 3498 AVDictionaryEntry *t, *t2 = NULL;
4086 char tag2[16];
4087
4088 3498 *lang = 0;
4089
4090
2/2
✓ Branch 1 taken 3452 times.
✓ Branch 2 taken 46 times.
3498 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4091 3452 return NULL;
4092
4093 46 len = strlen(t->key);
4094 46 snprintf(tag2, sizeof(tag2), "%s-", tag);
4095
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 38 times.
46 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4096 8 len2 = strlen(t2->key);
4097
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)
4098
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4099 8 *lang = l;
4100 8 return t;
4101 }
4102 }
4103 38 return t;
4104 }
4105
4106 3420 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4107 const char *name, const char *tag,
4108 int long_style)
4109 {
4110 int lang;
4111 3420 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4112
2/2
✓ Branch 0 taken 3374 times.
✓ Branch 1 taken 46 times.
3420 if (!t)
4113 3374 return 0;
4114 46 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4115 }
4116
4117 /* iTunes bpm number */
4118 78 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4119 {
4120 78 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 int size = 0, tmpo = t ? atoi(t->value) : 0;
4122
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (tmpo) {
4123 size = 26;
4124 avio_wb32(pb, size);
4125 ffio_wfourcc(pb, "tmpo");
4126 avio_wb32(pb, size-8); /* size */
4127 ffio_wfourcc(pb, "data");
4128 avio_wb32(pb, 0x15); //type specifier
4129 avio_wb32(pb, 0);
4130 avio_wb16(pb, tmpo); // data
4131 }
4132 78 return size;
4133 }
4134
4135 /* 3GPP TS 26.244 */
4136 78 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4137 {
4138 int lang;
4139 78 int64_t pos = avio_tell(pb);
4140 double latitude, longitude, altitude;
4141 int32_t latitude_fix, longitude_fix, altitude_fix;
4142 78 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4143 78 const char *ptr, *place = "";
4144 char *end;
4145 static const char *astronomical_body = "earth";
4146
1/2
✓ Branch 0 taken 78 times.
✗ Branch 1 not taken.
78 if (!t)
4147 78 return 0;
4148
4149 ptr = t->value;
4150 latitude = strtod(ptr, &end);
4151 if (end == ptr) {
4152 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4153 return 0;
4154 }
4155 ptr = end;
4156 longitude = strtod(ptr, &end);
4157 if (end == ptr) {
4158 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4159 return 0;
4160 }
4161 ptr = end;
4162 altitude = strtod(ptr, &end);
4163 /* If no altitude was present, the default 0 should be fine */
4164 if (*end == '/')
4165 place = end + 1;
4166
4167 latitude_fix = (int32_t) ((1 << 16) * latitude);
4168 longitude_fix = (int32_t) ((1 << 16) * longitude);
4169 altitude_fix = (int32_t) ((1 << 16) * altitude);
4170
4171 avio_wb32(pb, 0); /* size */
4172 ffio_wfourcc(pb, "loci"); /* type */
4173 avio_wb32(pb, 0); /* version + flags */
4174 avio_wb16(pb, lang);
4175 avio_write(pb, place, strlen(place) + 1);
4176 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4177 avio_wb32(pb, longitude_fix);
4178 avio_wb32(pb, latitude_fix);
4179 avio_wb32(pb, altitude_fix);
4180 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4181 avio_w8(pb, 0); /* additional notes, null terminated string */
4182
4183 return update_size(pb, pos);
4184 }
4185
4186 /* iTunes track or disc number */
4187 156 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4188 AVFormatContext *s, int disc)
4189 {
4190
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 78 times.
156 AVDictionaryEntry *t = av_dict_get(s->metadata,
4191 disc ? "disc" : "track",
4192 NULL, 0);
4193
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 154 times.
156 int size = 0, track = t ? atoi(t->value) : 0;
4194
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 154 times.
156 if (track) {
4195 2 int tracks = 0;
4196 2 char *slash = strchr(t->value, '/');
4197
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4198 2 tracks = atoi(slash + 1);
4199 2 avio_wb32(pb, 32); /* size */
4200
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4201 2 avio_wb32(pb, 24); /* size */
4202 2 ffio_wfourcc(pb, "data");
4203 2 avio_wb32(pb, 0); // 8 bytes empty
4204 2 avio_wb32(pb, 0);
4205 2 avio_wb16(pb, 0); // empty
4206 2 avio_wb16(pb, track); // track / disc number
4207 2 avio_wb16(pb, tracks); // total track / disc number
4208 2 avio_wb16(pb, 0); // empty
4209 2 size = 32;
4210 }
4211 156 return size;
4212 }
4213
4214 468 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4215 const char *name, const char *tag,
4216 int len)
4217 {
4218 468 AVDictionaryEntry *t = NULL;
4219 uint8_t num;
4220 468 int size = 24 + len;
4221
4222
3/4
✓ Branch 0 taken 156 times.
✓ Branch 1 taken 312 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 156 times.
468 if (len != 1 && len != 4)
4223 return -1;
4224
4225
2/2
✓ Branch 1 taken 466 times.
✓ Branch 2 taken 2 times.
468 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4226 466 return 0;
4227 2 num = atoi(t->value);
4228
4229 2 avio_wb32(pb, size);
4230 2 ffio_wfourcc(pb, name);
4231 2 avio_wb32(pb, size - 8);
4232 2 ffio_wfourcc(pb, "data");
4233 2 avio_wb32(pb, 0x15);
4234 2 avio_wb32(pb, 0);
4235
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4236 2 else avio_w8 (pb, num);
4237
4238 2 return size;
4239 }
4240
4241 78 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4242 {
4243 78 MOVMuxContext *mov = s->priv_data;
4244 78 int64_t pos = 0;
4245
4246
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 78 times.
210 for (int i = 0; i < mov->nb_streams; i++) {
4247 132 MOVTrack *trk = &mov->tracks[i];
4248
4249
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 130 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
132 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4250 130 continue;
4251
4252
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4253 1 pos = avio_tell(pb);
4254 1 avio_wb32(pb, 0);
4255 1 ffio_wfourcc(pb, "covr");
4256 }
4257 2 avio_wb32(pb, 16 + trk->cover_image->size);
4258 2 ffio_wfourcc(pb, "data");
4259 2 avio_wb32(pb, trk->tag);
4260 2 avio_wb32(pb , 0);
4261 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4262 }
4263
4264
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 77 times.
78 return pos ? update_size(pb, pos) : 0;
4265 }
4266
4267 /* iTunes meta data list */
4268 78 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4269 AVFormatContext *s)
4270 {
4271 78 int64_t pos = avio_tell(pb);
4272 78 avio_wb32(pb, 0); /* size */
4273 78 ffio_wfourcc(pb, "ilst");
4274 78 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4275 78 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4276 78 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4277 78 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4278 78 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4279 78 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4280
1/2
✓ Branch 1 taken 78 times.
✗ Branch 2 not taken.
78 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4281
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 76 times.
78 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4282 2 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4283 }
4284 78 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4285 78 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4286 78 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4287 78 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4288 78 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4289 78 mov_write_string_metadata(s, pb, "desc", "description",1);
4290 78 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4291 78 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4292 78 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4293 78 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4294 78 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4295 78 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4296 78 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4297 78 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4298 78 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4299 78 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4300 78 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4301 78 mov_write_covr(pb, s);
4302 78 mov_write_trkn_tag(pb, mov, s, 0); // track number
4303 78 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4304 78 mov_write_tmpo_tag(pb, s);
4305 78 return update_size(pb, pos);
4306 }
4307
4308 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4309 AVFormatContext *s)
4310 {
4311 avio_wb32(pb, 33); /* size */
4312 ffio_wfourcc(pb, "hdlr");
4313 avio_wb32(pb, 0);
4314 avio_wb32(pb, 0);
4315 ffio_wfourcc(pb, "mdta");
4316 avio_wb32(pb, 0);
4317 avio_wb32(pb, 0);
4318 avio_wb32(pb, 0);
4319 avio_w8(pb, 0);
4320 return 33;
4321 }
4322
4323 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4324 AVFormatContext *s)
4325 {
4326 const AVDictionaryEntry *t = NULL;
4327 int64_t pos = avio_tell(pb);
4328 int64_t curpos, entry_pos;
4329 int count = 0;
4330
4331 avio_wb32(pb, 0); /* size */
4332 ffio_wfourcc(pb, "keys");
4333 avio_wb32(pb, 0);
4334 entry_pos = avio_tell(pb);
4335 avio_wb32(pb, 0); /* entry count */
4336
4337 while (t = av_dict_iterate(s->metadata, t)) {
4338 size_t key_len = strlen(t->key);
4339 avio_wb32(pb, key_len + 8);
4340 ffio_wfourcc(pb, "mdta");
4341 avio_write(pb, t->key, key_len);
4342 count += 1;
4343 }
4344 curpos = avio_tell(pb);
4345 avio_seek(pb, entry_pos, SEEK_SET);
4346 avio_wb32(pb, count); // rewrite entry count
4347 avio_seek(pb, curpos, SEEK_SET);
4348
4349 return update_size(pb, pos);
4350 }
4351
4352 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4353 AVFormatContext *s)
4354 {
4355 const AVDictionaryEntry *t = NULL;
4356 int64_t pos = avio_tell(pb);
4357 int count = 1; /* keys are 1-index based */
4358
4359 avio_wb32(pb, 0); /* size */
4360 ffio_wfourcc(pb, "ilst");
4361
4362 while (t = av_dict_iterate(s->metadata, t)) {
4363 int64_t entry_pos = avio_tell(pb);
4364 avio_wb32(pb, 0); /* size */
4365 avio_wb32(pb, count); /* key */
4366 mov_write_string_data_tag(pb, t->value, 0, 1);
4367 update_size(pb, entry_pos);
4368 count += 1;
4369 }
4370 return update_size(pb, pos);
4371 }
4372
4373 /* meta data tags */
4374 78 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4375 AVFormatContext *s)
4376 {
4377 78 int size = 0;
4378 78 int64_t pos = avio_tell(pb);
4379 78 avio_wb32(pb, 0); /* size */
4380 78 ffio_wfourcc(pb, "meta");
4381 78 avio_wb32(pb, 0);
4382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4383 mov_write_mdta_hdlr_tag(pb, mov, s);
4384 mov_write_mdta_keys_tag(pb, mov, s);
4385 mov_write_mdta_ilst_tag(pb, mov, s);
4386
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
78 } else if (mov->mode == MODE_AVIF) {
4387 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4388 // We always write the primary item id as 1 since only one track is
4389 // supported for AVIF.
4390 mov_write_pitm_tag(pb, 1);
4391 mov_write_iloc_tag(pb, mov, s);
4392 mov_write_iinf_tag(pb, mov, s);
4393 if (mov->nb_streams > 1)
4394 mov_write_iref_tag(pb, mov, s);
4395 mov_write_iprp_tag(pb, mov, s);
4396 } else {
4397 /* iTunes metadata tag */
4398 78 mov_write_itunes_hdlr_tag(pb, mov, s);
4399 78 mov_write_ilst_tag(pb, mov, s);
4400 }
4401 78 size = update_size(pb, pos);
4402 78 return size;
4403 }
4404
4405 144 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4406 const char *name, const char *key)
4407 {
4408 int len;
4409 AVDictionaryEntry *t;
4410
4411
1/2
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
144 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4412 144 return 0;
4413
4414 len = strlen(t->value);
4415 if (len > 0) {
4416 int size = len + 8;
4417 avio_wb32(pb, size);
4418 ffio_wfourcc(pb, name);
4419 avio_write(pb, t->value, len);
4420 return size;
4421 }
4422 return 0;
4423 }
4424
4425 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4426 {
4427 int val;
4428 while (*b) {
4429 GET_UTF8(val, *b++, return -1;)
4430 avio_wb16(pb, val);
4431 }
4432 avio_wb16(pb, 0x00);
4433 return 0;
4434 }
4435
4436 static uint16_t language_code(const char *str)
4437 {
4438 return (((str[0] - 0x60) & 0x1F) << 10) +
4439 (((str[1] - 0x60) & 0x1F) << 5) +
4440 (( str[2] - 0x60) & 0x1F);
4441 }
4442
4443 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4444 const char *tag, const char *str)
4445 {
4446 int64_t pos = avio_tell(pb);
4447 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4448 if (!t || !utf8len(t->value))
4449 return 0;
4450 avio_wb32(pb, 0); /* size */
4451 ffio_wfourcc(pb, tag); /* type */
4452 avio_wb32(pb, 0); /* version + flags */
4453 if (!strcmp(tag, "yrrc"))
4454 avio_wb16(pb, atoi(t->value));
4455 else {
4456 avio_wb16(pb, language_code("eng")); /* language */
4457 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4458 if (!strcmp(tag, "albm") &&
4459 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4460 avio_w8(pb, atoi(t->value));
4461 }
4462 return update_size(pb, pos);
4463 }
4464
4465 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4466 {
4467 1 int64_t pos = avio_tell(pb);
4468 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4469
4470 1 avio_wb32(pb, 0); // size
4471 1 ffio_wfourcc(pb, "chpl");
4472 1 avio_wb32(pb, 0x01000000); // version + flags
4473 1 avio_wb32(pb, 0); // unknown
4474 1 avio_w8(pb, nb_chapters);
4475
4476
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4477 4 AVChapter *c = s->chapters[i];
4478 AVDictionaryEntry *t;
4479 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4480
4481
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4482
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4483 4 avio_w8(pb, len);
4484 4 avio_write(pb, t->value, len);
4485 } else
4486 avio_w8(pb, 0);
4487 }
4488 1 return update_size(pb, pos);
4489 }
4490
4491 222 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4492 AVFormatContext *s)
4493 {
4494 AVIOContext *pb_buf;
4495 int ret, size;
4496 uint8_t *buf;
4497
4498 222 ret = avio_open_dyn_buf(&pb_buf);
4499
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 222 times.
222 if (ret < 0)
4500 return ret;
4501
4502
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 222 times.
222 if (mov->mode & MODE_3GP) {
4503 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
4504 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
4505 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
4506 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
4507 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
4508 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
4509 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
4510 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
4511 mov_write_loci_tag(s, pb_buf);
4512
3/4
✓ Branch 0 taken 144 times.
✓ Branch 1 taken 78 times.
✓ Branch 2 taken 144 times.
✗ Branch 3 not taken.
222 } 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
4513 144 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
4514 144 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
4515 144 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
4516 144 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
4517 144 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
4518 144 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
4519 // currently ignored by mov.c
4520 144 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
4521 // add support for libquicktime, this atom is also actually read by mov.c
4522 144 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
4523 144 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
4524 144 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
4525 144 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
4526 144 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
4527 144 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
4528 144 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
4529 144 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
4530 } else {
4531 /* iTunes meta data */
4532 78 mov_write_meta_tag(pb_buf, mov, s);
4533 78 mov_write_loci_tag(s, pb_buf);
4534 }
4535
4536
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 221 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
222 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
4537 1 mov_write_chpl_tag(pb_buf, s);
4538
4539
2/2
✓ Branch 1 taken 102 times.
✓ Branch 2 taken 120 times.
222 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4540 102 avio_wb32(pb, size + 8);
4541 102 ffio_wfourcc(pb, "udta");
4542 102 avio_write(pb, buf, size);
4543 }
4544 222 ffio_free_dyn_buf(&pb_buf);
4545
4546 222 return 0;
4547 }
4548
4549 static void mov_write_psp_udta_tag(AVIOContext *pb,
4550 const char *str, const char *lang, int type)
4551 {
4552 int len = utf8len(str) + 1;
4553 if (len <= 0)
4554 return;
4555 avio_wb16(pb, len * 2 + 10); /* size */
4556 avio_wb32(pb, type); /* type */
4557 avio_wb16(pb, language_code(lang)); /* language */
4558 avio_wb16(pb, 0x01); /* ? */
4559 ascii_to_wc(pb, str);
4560 }
4561
4562 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
4563 {
4564 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
4565 int64_t pos, pos2;
4566
4567
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
4568 pos = avio_tell(pb);
4569 avio_wb32(pb, 0); /* size placeholder*/
4570 ffio_wfourcc(pb, "uuid");
4571 ffio_wfourcc(pb, "USMT");
4572 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
4573 avio_wb32(pb, 0xbb88695c);
4574 avio_wb32(pb, 0xfac9c740);
4575
4576 pos2 = avio_tell(pb);
4577 avio_wb32(pb, 0); /* size placeholder*/
4578 ffio_wfourcc(pb, "MTDT");
4579 avio_wb16(pb, 4);
4580
4581 // ?
4582 avio_wb16(pb, 0x0C); /* size */
4583 avio_wb32(pb, 0x0B); /* type */
4584 avio_wb16(pb, language_code("und")); /* language */
4585 avio_wb16(pb, 0x0); /* ? */
4586 avio_wb16(pb, 0x021C); /* data */
4587
4588 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4589 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
4590 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
4591 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
4592
4593 update_size(pb, pos2);
4594 return update_size(pb, pos);
4595 }
4596
4597 1 return 0;
4598 }
4599
4600 289 static void build_chunks(MOVTrack *trk)
4601 {
4602 int i;
4603 289 MOVIentry *chunk = &trk->cluster[0];
4604 289 uint64_t chunkSize = chunk->size;
4605 289 chunk->chunkNum = 1;
4606
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 236 times.
289 if (trk->chunkCount)
4607 53 return;
4608 236 trk->chunkCount = 1;
4609
2/2
✓ Branch 0 taken 14263 times.
✓ Branch 1 taken 236 times.
14499 for (i = 1; i<trk->entry; i++){
4610
2/2
✓ Branch 0 taken 12422 times.
✓ Branch 1 taken 1841 times.
14263 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
4611
2/2
✓ Branch 0 taken 11849 times.
✓ Branch 1 taken 573 times.
12422 chunkSize + trk->cluster[i].size < (1<<20)){
4612 11849 chunkSize += trk->cluster[i].size;
4613 11849 chunk->samples_in_chunk += trk->cluster[i].entries;
4614 } else {
4615 2414 trk->cluster[i].chunkNum = chunk->chunkNum+1;
4616 2414 chunk=&trk->cluster[i];
4617 2414 chunkSize = chunk->size;
4618 2414 trk->chunkCount++;
4619 }
4620 }
4621 }
4622
4623 /**
4624 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
4625 * the stream ids are used as track ids.
4626 *
4627 * This assumes mov->tracks and s->streams are in the same order and
4628 * there are no gaps in either of them (so mov->tracks[n] refers to
4629 * s->streams[n]).
4630 *
4631 * As an exception, there can be more entries in
4632 * s->streams than in mov->tracks, in which case new track ids are
4633 * generated (starting after the largest found stream id).
4634 */
4635 223 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
4636 {
4637 int i;
4638
4639
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 197 times.
223 if (mov->track_ids_ok)
4640 26 return 0;
4641
4642
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (mov->use_stream_ids_as_track_ids) {
4643 int next_generated_track_id = 0;
4644 for (i = 0; i < mov->nb_streams; i++) {
4645 AVStream *st = mov->tracks[i].st;
4646 if (st->id > next_generated_track_id)
4647 next_generated_track_id = st->id;
4648 }
4649
4650 for (i = 0; i < mov->nb_tracks; i++) {
4651 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
4652 continue;
4653
4654 mov->tracks[i].track_id = i >= mov->nb_streams ? ++next_generated_track_id : mov->tracks[i].st->id;
4655 }
4656 } else {
4657
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 197 times.
457 for (i = 0; i < mov->nb_tracks; i++) {
4658
4/4
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 236 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 22 times.
260 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
4659 2 continue;
4660
4661 258 mov->tracks[i].track_id = i + 1;
4662 }
4663 }
4664
4665 197 mov->track_ids_ok = 1;
4666
4667 197 return 0;
4668 }
4669
4670 223 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
4671 AVFormatContext *s)
4672 {
4673 int i;
4674 223 int64_t pos = avio_tell(pb);
4675 223 avio_wb32(pb, 0); /* size placeholder*/
4676 223 ffio_wfourcc(pb, "moov");
4677
4678 223 mov_setup_track_ids(mov, s);
4679
4680
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 223 times.
538 for (i = 0; i < mov->nb_tracks; i++) {
4681
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 289 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24 times.
315 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
4682 2 continue;
4683
4684 313 mov->tracks[i].time = mov->time;
4685
4686
2/2
✓ Branch 0 taken 289 times.
✓ Branch 1 taken 24 times.
313 if (mov->tracks[i].entry)
4687 289 build_chunks(&mov->tracks[i]);
4688 }
4689
4690
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 222 times.
223 if (mov->chapter_track)
4691
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
4692 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
4693 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
4694 }
4695
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 223 times.
538 for (i = 0; i < mov->nb_tracks; i++) {
4696 315 MOVTrack *track = &mov->tracks[i];
4697
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 313 times.
315 if (track->tag == MKTAG('r','t','p',' ')) {
4698 2 track->tref_tag = MKTAG('h','i','n','t');
4699 2 track->tref_id = mov->tracks[track->src_track].track_id;
4700
2/2
✓ Branch 0 taken 103 times.
✓ Branch 1 taken 210 times.
313 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
4701 103 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
4702 103 track->st->codecpar->nb_coded_side_data,
4703 AV_PKT_DATA_FALLBACK_TRACK );
4704
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 103 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
103 if (sd && sd->size == sizeof(int)) {
4705 int *fallback = (int *)sd->data;
4706 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
4707 track->tref_tag = MKTAG('f','a','l','l');
4708 track->tref_id = mov->tracks[*fallback].track_id;
4709 }
4710 }
4711 }
4712 }
4713
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 223 times.
538 for (i = 0; i < mov->nb_tracks; i++) {
4714
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 302 times.
315 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
4715 13 int src_trk = mov->tracks[i].src_track;
4716 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
4717 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
4718 //src_trk may have a different timescale than the tmcd track
4719 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
4720 13 mov->tracks[i].timescale,
4721 13 mov->tracks[src_trk].timescale);
4722 }
4723 }
4724
4725 223 mov_write_mvhd_tag(pb, mov);
4726
4/6
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 144 times.
✓ Branch 2 taken 79 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 79 times.
223 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
4727 mov_write_iods_tag(pb, mov);
4728
2/2
✓ Branch 0 taken 315 times.
✓ Branch 1 taken 223 times.
538 for (i = 0; i < mov->nb_tracks; i++) {
4729
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 289 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24 times.
315 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
4730
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
4731
2/2
✓ Branch 0 taken 300 times.
✓ Branch 1 taken 13 times.
313 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
4732
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 313 times.
313 if (ret < 0)
4733 return ret;
4734 }
4735 }
4736
2/2
✓ Branch 0 taken 52 times.
✓ Branch 1 taken 171 times.
223 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
4737 52 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
4738
4739
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 222 times.
223 if (mov->mode == MODE_PSP)
4740 1 mov_write_uuidusmt_tag(pb, s);
4741
1/2
✓ Branch 0 taken 222 times.
✗ Branch 1 not taken.
222 else if (mov->mode != MODE_AVIF)
4742 222 mov_write_udta_tag(pb, mov, s);
4743
4744 223 return update_size(pb, pos);
4745 }
4746
4747 static void param_write_int(AVIOContext *pb, const char *name, int value)
4748 {
4749 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
4750 }
4751
4752 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
4753 {
4754 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
4755 }
4756
4757 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
4758 {
4759 char buf[150];
4760 len = FFMIN(sizeof(buf) / 2 - 1, len);
4761 ff_data_to_hex(buf, value, len, 0);
4762 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
4763 }
4764
4765 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
4766 {
4767 int64_t pos = avio_tell(pb);
4768 int i;
4769
4770 static const AVUUID uuid = {
4771 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
4772 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
4773 };
4774
4775 avio_wb32(pb, 0);
4776 ffio_wfourcc(pb, "uuid");
4777 avio_write(pb, uuid, AV_UUID_LEN);
4778 avio_wb32(pb, 0);
4779
4780 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
4781 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
4782 avio_printf(pb, "<head>\n");
4783 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
4784 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
4785 LIBAVFORMAT_IDENT);
4786 avio_printf(pb, "</head>\n");
4787 avio_printf(pb, "<body>\n");
4788 avio_printf(pb, "<switch>\n");
4789
4790 mov_setup_track_ids(mov, s);
4791
4792 for (i = 0; i < mov->nb_tracks; i++) {
4793 MOVTrack *track = &mov->tracks[i];
4794 struct mpeg4_bit_rate_values bit_rates =
4795 calculate_mpeg4_bit_rates(track);
4796 const char *type;
4797 int track_id = track->track_id;
4798 char track_name_buf[32] = { 0 };
4799
4800 AVStream *st = track->st;
4801 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
4802
4803 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
4804 type = "video";
4805 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
4806 type = "audio";
4807 } else {
4808 continue;
4809 }
4810
4811 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
4812 bit_rates.avg_bit_rate);
4813 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
4814 param_write_int(pb, "trackID", track_id);
4815 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
4816
4817 /* Build track name piece by piece: */
4818 /* 1. track type */
4819 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
4820 /* 2. track language, if available */
4821 if (lang)
4822 av_strlcatf(track_name_buf, sizeof(track_name_buf),
4823 "_%s", lang->value);
4824 /* 3. special type suffix */
4825 /* "_cc" = closed captions, "_ad" = audio_description */
4826 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
4827 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
4828 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
4829 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
4830
4831 param_write_string(pb, "trackName", track_name_buf);
4832
4833 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4834 if (track->par->codec_id == AV_CODEC_ID_H264) {
4835 uint8_t *ptr;
4836 int size = track->par->extradata_size;
4837 if (!ff_avc_write_annexb_extradata(track->par->extradata, &ptr,
4838 &size)) {
4839 param_write_hex(pb, "CodecPrivateData",
4840 ptr ? ptr : track->par->extradata,
4841 size);
4842 av_free(ptr);
4843 }
4844 param_write_string(pb, "FourCC", "H264");
4845 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
4846 param_write_string(pb, "FourCC", "WVC1");
4847 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
4848 track->par->extradata_size);
4849 }
4850 param_write_int(pb, "MaxWidth", track->par->width);
4851 param_write_int(pb, "MaxHeight", track->par->height);
4852 param_write_int(pb, "DisplayWidth", track->par->width);
4853 param_write_int(pb, "DisplayHeight", track->par->height);
4854 } else {
4855 if (track->par->codec_id == AV_CODEC_ID_AAC) {
4856 switch (track->par->profile) {
4857 case AV_PROFILE_AAC_HE_V2:
4858 param_write_string(pb, "FourCC", "AACP");
4859 break;
4860 case AV_PROFILE_AAC_HE:
4861 param_write_string(pb, "FourCC", "AACH");
4862 break;
4863 default:
4864 param_write_string(pb, "FourCC", "AACL");
4865 }
4866 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
4867 param_write_string(pb, "FourCC", "WMAP");
4868 }
4869 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
4870 track->par->extradata_size);
4871 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
4872 track->par->codec_id));
4873 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
4874 param_write_int(pb, "SamplingRate", track->par->sample_rate);
4875 param_write_int(pb, "BitsPerSample", 16);
4876 param_write_int(pb, "PacketSize", track->par->block_align ?
4877 track->par->block_align : 4);
4878 }
4879 avio_printf(pb, "</%s>\n", type);
4880 }
4881 avio_printf(pb, "</switch>\n");
4882 avio_printf(pb, "</body>\n");
4883 avio_printf(pb, "</smil>\n");
4884
4885 return update_size(pb, pos);
4886 }
4887
4888 134 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4889 {
4890 134 avio_wb32(pb, 16);
4891 134 ffio_wfourcc(pb, "mfhd");
4892 134 avio_wb32(pb, 0);
4893 134 avio_wb32(pb, mov->fragments);
4894 134 return 0;
4895 }
4896
4897 9872 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
4898 {
4899
2/2
✓ Branch 0 taken 6822 times.
✓ Branch 1 taken 3050 times.
9872 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
4900 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
4901 }
4902
4903 220 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
4904 MOVTrack *track, int64_t moof_offset)
4905 {
4906 220 int64_t pos = avio_tell(pb);
4907 220 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
4908 MOV_TFHD_BASE_DATA_OFFSET;
4909
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
220 if (!track->entry) {
4910 flags |= MOV_TFHD_DURATION_IS_EMPTY;
4911 } else {
4912 220 flags |= MOV_TFHD_DEFAULT_FLAGS;
4913 }
4914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
220 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
4915 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
4916
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 150 times.
220 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
4917 70 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
4918 70 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
4919 }
4920 /* CMAF requires all values to be explicit in tfhd atoms */
4921
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
220 if (mov->flags & FF_MOV_FLAG_CMAF)
4922 flags |= MOV_TFHD_STSD_ID;
4923
4924 /* Don't set a default sample size, the silverlight player refuses
4925 * to play files with that set. Don't set a default sample duration,
4926 * WMP freaks out if it is set. Don't set a base data offset, PIFF
4927 * file format says it MUST NOT be set. */
4928
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 190 times.
220 if (track->mode == MODE_ISM)
4929 30 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
4930 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
4931
4932 220 avio_wb32(pb, 0); /* size placeholder */
4933 220 ffio_wfourcc(pb, "tfhd");
4934 220 avio_w8(pb, 0); /* version */
4935 220 avio_wb24(pb, flags);
4936
4937 220 avio_wb32(pb, track->track_id); /* track-id */
4938
2/2
✓ Branch 0 taken 120 times.
✓ Branch 1 taken 100 times.
220 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
4939 120 avio_wb64(pb, moof_offset);
4940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
220 if (flags & MOV_TFHD_STSD_ID) {
4941 avio_wb32(pb, 1);
4942 }
4943
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 30 times.
220 if (flags & MOV_TFHD_DEFAULT_DURATION) {
4944 190 track->default_duration = get_cluster_duration(track, 0);
4945 190 avio_wb32(pb, track->default_duration);
4946 }
4947
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 30 times.
220 if (flags & MOV_TFHD_DEFAULT_SIZE) {
4948
1/2
✓ Branch 0 taken 190 times.
✗ Branch 1 not taken.
190 track->default_size = track->entry ? track->cluster[0].size : 1;
4949 190 avio_wb32(pb, track->default_size);
4950 } else
4951 30 track->default_size = -1;
4952
4953
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
4954 /* Set the default flags based on the second sample, if available.
4955 * If the first sample is different, that can be signaled via a separate field. */
4956
2/2
✓ Branch 0 taken 212 times.
✓ Branch 1 taken 8 times.
220 if (track->entry > 1)
4957 212 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
4958 else
4959 8 track->default_sample_flags =
4960 8 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
4961
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
4962 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
4963 220 avio_wb32(pb, track->default_sample_flags);
4964 }
4965
4966 220 return update_size(pb, pos);
4967 }
4968
4969 220 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
4970 MOVTrack *track, int moof_size,
4971 int first, int end)
4972 {
4973 220 int64_t pos = avio_tell(pb);
4974 220 uint32_t flags = MOV_TRUN_DATA_OFFSET;
4975 int i;
4976
4977
2/2
✓ Branch 0 taken 9426 times.
✓ Branch 1 taken 220 times.
9646 for (i = first; i < end; i++) {
4978
2/2
✓ Branch 1 taken 616 times.
✓ Branch 2 taken 8810 times.
9426 if (get_cluster_duration(track, i) != track->default_duration)
4979 616 flags |= MOV_TRUN_SAMPLE_DURATION;
4980
2/2
✓ Branch 0 taken 476 times.
✓ Branch 1 taken 8950 times.
9426 if (track->cluster[i].size != track->default_size)
4981 476 flags |= MOV_TRUN_SAMPLE_SIZE;
4982
4/4
✓ Branch 0 taken 9206 times.
✓ Branch 1 taken 220 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 9200 times.
9426 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
4983 6 flags |= MOV_TRUN_SAMPLE_FLAGS;
4984 }
4985
3/4
✓ Branch 0 taken 216 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 216 times.
✗ Branch 3 not taken.
220 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
4986
2/2
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 110 times.
216 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
4987 106 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
4988
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 156 times.
220 if (track->flags & MOV_TRACK_CTTS)
4989 64 flags |= MOV_TRUN_SAMPLE_CTS;
4990
4991 220 avio_wb32(pb, 0); /* size placeholder */
4992 220 ffio_wfourcc(pb, "trun");
4993
2/2
✓ Branch 0 taken 46 times.
✓ Branch 1 taken 174 times.
220 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
4994 46 avio_w8(pb, 1); /* version */
4995 else
4996 174 avio_w8(pb, 0); /* version */
4997 220 avio_wb24(pb, flags);
4998
4999 220 avio_wb32(pb, end - first); /* sample count */
5000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
220 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5001 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5002 !mov->first_trun)
5003 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5004 else
5005 220 avio_wb32(pb, moof_size + 8 + track->data_offset +
5006 220 track->cluster[first].pos); /* data offset */
5007
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 114 times.
220 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5008 106 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5009
5010
2/2
✓ Branch 0 taken 9426 times.
✓ Branch 1 taken 220 times.
9646 for (i = first; i < end; i++) {
5011
2/2
✓ Branch 0 taken 712 times.
✓ Branch 1 taken 8714 times.
9426 if (flags & MOV_TRUN_SAMPLE_DURATION)
5012 712 avio_wb32(pb, get_cluster_duration(track, i));
5013
2/2
✓ Branch 0 taken 1030 times.
✓ Branch 1 taken 8396 times.
9426 if (flags & MOV_TRUN_SAMPLE_SIZE)
5014 1030 avio_wb32(pb, track->cluster[i].size);
5015
2/2
✓ Branch 0 taken 132 times.
✓ Branch 1 taken 9294 times.
9426 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5016 132 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5017
2/2
✓ Branch 0 taken 1740 times.
✓ Branch 1 taken 7686 times.
9426 if (flags & MOV_TRUN_SAMPLE_CTS)
5018 1740 avio_wb32(pb, track->cluster[i].cts);
5019 }
5020
5021 220 mov->first_trun = 0;
5022 220 return update_size(pb, pos);
5023 }
5024
5025 30 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5026 {
5027 30 int64_t pos = avio_tell(pb);
5028 static const uint8_t uuid[] = {
5029 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5030 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5031 };
5032
5033 30 avio_wb32(pb, 0); /* size placeholder */
5034 30 ffio_wfourcc(pb, "uuid");
5035 30 avio_write(pb, uuid, AV_UUID_LEN);
5036 30 avio_w8(pb, 1);
5037 30 avio_wb24(pb, 0);
5038 30 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5039 30 avio_wb64(pb, track->end_pts -
5040 30 (track->cluster[0].dts + track->cluster[0].cts));
5041
5042 30 return update_size(pb, pos);
5043 }
5044
5045 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5046 MOVTrack *track, int entry)
5047 {
5048 int n = track->nb_frag_info - 1 - entry, i;
5049 int size = 8 + 16 + 4 + 1 + 16*n;
5050 static const uint8_t uuid[] = {
5051 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5052 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5053 };
5054
5055 if (entry < 0)
5056 return 0;
5057
5058 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5059 avio_wb32(pb, size);
5060 ffio_wfourcc(pb, "uuid");
5061 avio_write(pb, uuid, AV_UUID_LEN);
5062 avio_w8(pb, 1);
5063 avio_wb24(pb, 0);
5064 avio_w8(pb, n);
5065 for (i = 0; i < n; i++) {
5066 int index = entry + 1 + i;
5067 avio_wb64(pb, track->frag_info[index].time);
5068 avio_wb64(pb, track->frag_info[index].duration);
5069 }
5070 if (n < mov->ism_lookahead) {
5071 int free_size = 16 * (mov->ism_lookahead - n);
5072 avio_wb32(pb, free_size);
5073 ffio_wfourcc(pb, "free");
5074 ffio_fill(pb, 0, free_size - 8);
5075 }
5076
5077 return 0;
5078 }
5079
5080 110 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5081 MOVTrack *track)
5082 {
5083 110 int64_t pos = avio_tell(pb);
5084 int i;
5085
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 110 times.
110 for (i = 0; i < mov->ism_lookahead; i++) {
5086 /* Update the tfrf tag for the last ism_lookahead fragments,
5087 * nb_frag_info - 1 is the next fragment to be written. */
5088 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5089 }
5090 110 avio_seek(pb, pos, SEEK_SET);
5091 110 return 0;
5092 }
5093
5094 67 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5095 int size)
5096 {
5097 int i;
5098
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 67 times.
192 for (i = 0; i < mov->nb_tracks; i++) {
5099 125 MOVTrack *track = &mov->tracks[i];
5100 MOVFragmentInfo *info;
5101
6/6
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 98 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 110 times.
125 if ((tracks >= 0 && i != tracks) || !track->entry)
5102 15 continue;
5103 110 track->nb_frag_info++;
5104
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 51 times.
110 if (track->nb_frag_info >= track->frag_info_capacity) {
5105 59 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5106
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 59 times.
59 if (av_reallocp_array(&track->frag_info,
5107 new_capacity,
5108 sizeof(*track->frag_info)))
5109 return AVERROR(ENOMEM);
5110 59 track->frag_info_capacity = new_capacity;
5111 }
5112 110 info = &track->frag_info[track->nb_frag_info - 1];
5113 110 info->offset = avio_tell(pb);
5114 110 info->size = size;
5115 // Try to recreate the original pts for the first packet
5116 // from the fields we have stored
5117 110 info->time = track->cluster[0].dts + track->cluster[0].cts;
5118 110 info->duration = track->end_pts -
5119 110 (track->cluster[0].dts + track->cluster[0].cts);
5120 // If the pts is less than zero, we will have trimmed
5121 // away parts of the media track using an edit list,
5122 // and the corresponding start presentation time is zero.
5123
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 102 times.
110 if (info->time < 0) {
5124 8 info->duration += info->time;
5125 8 info->time = 0;
5126 }
5127 110 info->tfrf_offset = 0;
5128 110 mov_write_tfrf_tags(pb, mov, track);
5129 }
5130 67 return 0;
5131 }
5132
5133 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5134 {
5135 int i;
5136 for (i = 0; i < mov->nb_tracks; i++) {
5137 MOVTrack *track = &mov->tracks[i];
5138 if ((tracks >= 0 && i != tracks) || !track->entry)
5139 continue;
5140 if (track->nb_frag_info > max) {
5141 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5142 track->nb_frag_info = max;
5143 }
5144 }
5145 }
5146
5147 190 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5148 {
5149 190 int64_t pos = avio_tell(pb);
5150
5151 190 avio_wb32(pb, 0); /* size */
5152 190 ffio_wfourcc(pb, "tfdt");
5153 190 avio_w8(pb, 1); /* version */
5154 190 avio_wb24(pb, 0);
5155 190 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5156 190 return update_size(pb, pos);
5157 }
5158
5159 220 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5160 MOVTrack *track, int64_t moof_offset,
5161 int moof_size)
5162 {
5163 220 int64_t pos = avio_tell(pb);
5164 220 int i, start = 0;
5165 220 avio_wb32(pb, 0); /* size placeholder */
5166 220 ffio_wfourcc(pb, "traf");
5167
5168 220 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5169
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 30 times.
220 if (mov->mode != MODE_ISM)
5170 190 mov_write_tfdt_tag(pb, track);
5171
2/2
✓ Branch 0 taken 9206 times.
✓ Branch 1 taken 220 times.
9426 for (i = 1; i < track->entry; i++) {
5172
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9206 times.
9206 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5173 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5174 start = i;
5175 }
5176 }
5177 220 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5178
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 190 times.
220 if (mov->mode == MODE_ISM) {
5179 30 mov_write_tfxd_tag(pb, track);
5180
5181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (mov->ism_lookahead) {
5182 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5183
5184 if (track->nb_frag_info > 0) {
5185 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5186 if (!info->tfrf_offset)
5187 info->tfrf_offset = avio_tell(pb);
5188 }
5189 avio_wb32(pb, 8 + size);
5190 ffio_wfourcc(pb, "free");
5191 ffio_fill(pb, 0, size);
5192 }
5193 }
5194
5195 220 return update_size(pb, pos);
5196 }
5197
5198 134 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5199 int tracks, int moof_size)
5200 {
5201 134 int64_t pos = avio_tell(pb);
5202 int i;
5203
5204 134 avio_wb32(pb, 0); /* size placeholder */
5205 134 ffio_wfourcc(pb, "moof");
5206 134 mov->first_trun = 1;
5207
5208 134 mov_write_mfhd_tag(pb, mov);
5209
2/2
✓ Branch 0 taken 250 times.
✓ Branch 1 taken 134 times.
384 for (i = 0; i < mov->nb_tracks; i++) {
5210 250 MOVTrack *track = &mov->tracks[i];
5211
4/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 196 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 30 times.
250 if (tracks >= 0 && i != tracks)
5212 24 continue;
5213
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 220 times.
226 if (!track->entry)
5214 6 continue;
5215 220 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5216 }
5217
5218 134 return update_size(pb, pos);
5219 }
5220
5221 70 static int mov_write_sidx_tag(AVIOContext *pb,
5222 MOVTrack *track, int ref_size, int total_sidx_size)
5223 {
5224 70 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5225 int64_t presentation_time, duration, offset;
5226 unsigned starts_with_SAP;
5227 int i, entries;
5228
5229
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 if (track->entry) {
5230 70 entries = 1;
5231 70 presentation_time = track->cluster[0].dts + track->cluster[0].cts -
5232 70 track->start_dts - track->start_cts;
5233 70 duration = track->end_pts -
5234 70 (track->cluster[0].dts + track->cluster[0].cts);
5235 70 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5236
5237 // pts<0 should be cut away using edts
5238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (presentation_time < 0) {
5239 duration += presentation_time;
5240 presentation_time = 0;
5241 }
5242 } else {
5243 entries = track->nb_frag_info;
5244 if (entries <= 0)
5245 return 0;
5246 presentation_time = track->frag_info[0].time;
5247 /* presentation_time <= 0 is handled by mov_add_tfra_entries() */
5248 if (presentation_time > 0)
5249 presentation_time -= track->start_dts + track->start_cts;
5250 }
5251
5252 70 avio_wb32(pb, 0); /* size */
5253 70 ffio_wfourcc(pb, "sidx");
5254 70 avio_w8(pb, 1); /* version */
5255 70 avio_wb24(pb, 0);
5256 70 avio_wb32(pb, track->track_id); /* reference_ID */
5257 70 avio_wb32(pb, track->timescale); /* timescale */
5258 70 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5259 70 offset_pos = avio_tell(pb);
5260 70 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5261 70 avio_wb16(pb, 0); /* reserved */
5262
5263 70 avio_wb16(pb, entries); /* reference_count */
5264
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 70 times.
140 for (i = 0; i < entries; i++) {
5265
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (!track->entry) {
5266 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5267 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5268 }
5269 duration = track->frag_info[i].duration;
5270 ref_size = track->frag_info[i].size;
5271 starts_with_SAP = 1;
5272 }
5273 70 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5274 70 avio_wb32(pb, duration); /* subsegment_duration */
5275 70 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5276 }
5277
5278 70 end_pos = avio_tell(pb);
5279 70 offset = pos + total_sidx_size - end_pos;
5280 70 avio_seek(pb, offset_pos, SEEK_SET);
5281 70 avio_wb64(pb, offset);
5282 70 avio_seek(pb, end_pos, SEEK_SET);
5283 70 return update_size(pb, pos);
5284 }
5285
5286 20 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5287 int tracks, int ref_size)
5288 {
5289 int i, round, ret;
5290 AVIOContext *avio_buf;
5291 20 int total_size = 0;
5292
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (round = 0; round < 2; round++) {
5293 // First run one round to calculate the total size of all
5294 // sidx atoms.
5295 // This would be much simpler if we'd only write one sidx
5296 // atom, for the first track in the moof.
5297
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0) {
5298
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5299 return ret;
5300 } else {
5301 20 avio_buf = pb;
5302 }
5303
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 40 times.
110 for (i = 0; i < mov->nb_tracks; i++) {
5304 70 MOVTrack *track = &mov->tracks[i];
5305
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)
5306 continue;
5307 // When writing a sidx for the full file, entry is 0, but
5308 // we want to include all tracks. ref_size is 0 in this case,
5309 // since we read it from frag_info instead.
5310
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)
5311 continue;
5312 70 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5313 total_size);
5314 }
5315
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0)
5316 20 total_size = ffio_close_null_buf(avio_buf);
5317 }
5318 20 return 0;
5319 }
5320
5321 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5322 {
5323 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5324 MOVTrack *first_track;
5325 int flags = 24;
5326
5327 /* PRFT should be associated with at most one track. So, choosing only the
5328 * first track. */
5329 if (tracks > 0)
5330 return 0;
5331 first_track = &(mov->tracks[0]);
5332
5333 if (!first_track->entry) {
5334 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5335 return 0;
5336 }
5337
5338 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5339 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5340 return 0;
5341 }
5342
5343 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5344 if (first_track->cluster[0].prft.wallclock) {
5345 /* Round the NTP time to whole milliseconds. */
5346 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5347 NTP_OFFSET_US);
5348 flags = first_track->cluster[0].prft.flags;
5349 } else
5350 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5351 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5352 pts_us = av_rescale_q(first_track->cluster[0].pts,
5353 first_track->st->time_base, AV_TIME_BASE_Q);
5354 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5355 } else {
5356 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5357 mov->write_prft);
5358 return 0;
5359 }
5360
5361 avio_wb32(pb, 0); // Size place holder
5362 ffio_wfourcc(pb, "prft"); // Type
5363 avio_w8(pb, 1); // Version
5364 avio_wb24(pb, flags); // Flags
5365 avio_wb32(pb, first_track->track_id); // reference track ID
5366 avio_wb64(pb, ntp_ts); // NTP time stamp
5367 avio_wb64(pb, first_track->cluster[0].pts); //media time
5368 return update_size(pb, pos);
5369 }
5370
5371 67 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5372 int64_t mdat_size)
5373 {
5374 AVIOContext *avio_buf;
5375 int ret, moof_size;
5376
5377
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
67 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5378 return ret;
5379 67 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5380 67 moof_size = ffio_close_null_buf(avio_buf);
5381
5382
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 47 times.
67 if (mov->flags & FF_MOV_FLAG_DASH &&
5383
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5384 20 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5385
5386
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
67 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
5387 mov_write_prft_tag(pb, mov, tracks);
5388
5389
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5390
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5391 mov->ism_lookahead) {
5392
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 67 times.
67 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
5393 return ret;
5394
1/2
✓ Branch 0 taken 67 times.
✗ Branch 1 not taken.
67 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
67 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5396 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5397 }
5398 }
5399
5400 67 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5401 }
5402
5403 59 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5404 {
5405 59 int64_t pos = avio_tell(pb);
5406 int i;
5407
5408 59 avio_wb32(pb, 0); /* size placeholder */
5409 59 ffio_wfourcc(pb, "tfra");
5410 59 avio_w8(pb, 1); /* version */
5411 59 avio_wb24(pb, 0);
5412
5413 59 avio_wb32(pb, track->track_id);
5414 59 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5415 59 avio_wb32(pb, track->nb_frag_info);
5416
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 59 times.
169 for (i = 0; i < track->nb_frag_info; i++) {
5417 110 avio_wb64(pb, track->frag_info[i].time);
5418 110 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5419 110 avio_w8(pb, 1); /* traf number */
5420 110 avio_w8(pb, 1); /* trun number */
5421 110 avio_w8(pb, 1); /* sample number */
5422 }
5423
5424 59 return update_size(pb, pos);
5425 }
5426
5427 32 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5428 {
5429 AVIOContext *mfra_pb;
5430 int i, ret, sz;
5431 uint8_t *buf;
5432
5433 32 ret = avio_open_dyn_buf(&mfra_pb);
5434
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (ret < 0)
5435 return ret;
5436
5437 32 avio_wb32(mfra_pb, 0); /* size placeholder */
5438 32 ffio_wfourcc(mfra_pb, "mfra");
5439 /* An empty mfra atom is enough to indicate to the publishing point that
5440 * the stream has ended. */
5441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (mov->flags & FF_MOV_FLAG_ISML)
5442 goto done_mfra;
5443
5444
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 32 times.
93 for (i = 0; i < mov->nb_tracks; i++) {
5445 61 MOVTrack *track = &mov->tracks[i];
5446
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 2 times.
61 if (track->nb_frag_info)
5447 59 mov_write_tfra_tag(mfra_pb, track);
5448 }
5449
5450 32 avio_wb32(mfra_pb, 16);
5451 32 ffio_wfourcc(mfra_pb, "mfro");
5452 32 avio_wb32(mfra_pb, 0); /* version + flags */
5453 32 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
5454
5455 32 done_mfra:
5456
5457 32 sz = update_size(mfra_pb, 0);
5458 32 ret = avio_get_dyn_buf(mfra_pb, &buf);
5459 32 avio_write(pb, buf, ret);
5460 32 ffio_free_dyn_buf(&mfra_pb);
5461
5462 32 return sz;
5463 }
5464
5465 165 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
5466 {
5467 165 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
5468
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 27 times.
165 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
5469
5470 165 mov->mdat_pos = avio_tell(pb);
5471 165 avio_wb32(pb, 0); /* size placeholder*/
5472 165 ffio_wfourcc(pb, "mdat");
5473 165 return 0;
5474 }
5475
5476 394 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
5477 int has_h264, int has_video, int write_minor)
5478 {
5479 394 MOVMuxContext *mov = s->priv_data;
5480 394 int minor = 0x200;
5481
5482
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 394 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
394 if (mov->major_brand && strlen(mov->major_brand) >= 4)
5483 ffio_wfourcc(pb, mov->major_brand);
5484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 394 times.
394 else if (mov->mode == MODE_3GP) {
5485 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
5486 minor = has_h264 ? 0x100 : 0x200;
5487
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 394 times.
394 } else if (mov->mode == MODE_AVIF) {
5488 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
5489 minor = 0;
5490
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 394 times.
394 } else if (mov->mode & MODE_3G2) {
5491 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
5492 minor = has_h264 ? 0x20000 : 0x10000;
5493
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 392 times.
394 } else if (mov->mode == MODE_PSP)
5494 2 ffio_wfourcc(pb, "MSNV");
5495
4/4
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 286 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 50 times.
392 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
5496
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 52 times.
56 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5497 4 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
5498
4/4
✓ Branch 0 taken 102 times.
✓ Branch 1 taken 286 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 80 times.
388 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5499 22 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
5500
3/4
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 286 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 80 times.
366 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5501 ffio_wfourcc(pb, "iso4");
5502
2/2
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 286 times.
366 else if (mov->mode == MODE_MP4)
5503 80 ffio_wfourcc(pb, "isom");
5504
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 284 times.
286 else if (mov->mode == MODE_IPOD)
5505
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
5506
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 276 times.
284 else if (mov->mode == MODE_ISM)
5507 8 ffio_wfourcc(pb, "isml");
5508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 276 times.
276 else if (mov->mode == MODE_F4V)
5509 ffio_wfourcc(pb, "f4v ");
5510 else
5511 276 ffio_wfourcc(pb, "qt ");
5512
5513
2/2
✓ Branch 0 taken 197 times.
✓ Branch 1 taken 197 times.
394 if (write_minor)
5514 197 avio_wb32(pb, minor);
5515 394 }
5516
5517 197 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
5518 {
5519 197 MOVMuxContext *mov = s->priv_data;
5520 197 int64_t pos = avio_tell(pb);
5521 197 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0;
5522 197 int has_iamf = 0;
5523
5524
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 193 times.
197 for (int i = 0; i < s->nb_stream_groups; i++) {
5525 4 const AVStreamGroup *stg = s->stream_groups[i];
5526
5527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
5528 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
5529 4 has_iamf = 1;
5530 4 break;
5531 }
5532 }
5533
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 197 times.
448 for (int i = 0; i < mov->nb_streams; i++) {
5534 251 AVStream *st = mov->tracks[i].st;
5535
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 249 times.
251 if (is_cover_image(st))
5536 2 continue;
5537
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 84 times.
249 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5538 165 has_video = 1;
5539
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 217 times.
249 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
5540 32 has_h264 = 1;
5541
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 248 times.
249 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
5542 1 has_av1 = 1;
5543
2/2
✓ Branch 0 taken 245 times.
✓ Branch 1 taken 4 times.
249 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
5544
2/2
✓ Branch 0 taken 244 times.
✓ Branch 1 taken 1 times.
245 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
5545
2/4
✓ Branch 0 taken 244 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 244 times.
488 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
5546 244 av_packet_side_data_get(st->codecpar->coded_side_data,
5547 244 st->codecpar->nb_coded_side_data,
5548 AV_PKT_DATA_DOVI_CONF))
5549 5 has_dolby = 1;
5550 }
5551
5552 197 avio_wb32(pb, 0); /* size */
5553 197 ffio_wfourcc(pb, "ftyp");
5554
5555 // Write major brand
5556 197 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
5557 // Write the major brand as the first compatible brand as well
5558 197 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
5559
5560 // Write compatible brands, ensuring that we don't write the major brand as a
5561 // compatible brand a second time.
5562
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 193 times.
197 if (mov->mode == MODE_ISM) {
5563 4 ffio_wfourcc(pb, "piff");
5564
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 193 times.
193 } else if (mov->mode == MODE_AVIF) {
5565 const AVPixFmtDescriptor *pix_fmt_desc =
5566 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
5567 const int depth = pix_fmt_desc->comp[0].depth;
5568 if (mov->is_animated_avif) {
5569 // For animated AVIF, major brand is "avis". Add "avif" as a
5570 // compatible brand.
5571 ffio_wfourcc(pb, "avif");
5572 ffio_wfourcc(pb, "msf1");
5573 ffio_wfourcc(pb, "iso8");
5574 }
5575 ffio_wfourcc(pb, "mif1");
5576 ffio_wfourcc(pb, "miaf");
5577 if (depth == 8 || depth == 10) {
5578 // MA1B and MA1A brands are based on AV1 profile. Short hand for
5579 // computing that is based on chroma subsampling type. 420 chroma
5580 // subsampling is MA1B. 444 chroma subsampling is MA1A.
5581 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
5582 // 444 chroma subsampling.
5583 ffio_wfourcc(pb, "MA1A");
5584 } else {
5585 // 420 chroma subsampling.
5586 ffio_wfourcc(pb, "MA1B");
5587 }
5588 }
5589
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 138 times.
193 } else if (mov->mode != MODE_MOV) {
5590 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
5591 // brand, if not already the major brand. This is compatible with users that
5592 // don't understand tfdt.
5593
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 2 times.
55 if (mov->mode == MODE_MP4) {
5594
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (mov->flags & FF_MOV_FLAG_CMAF)
5595 ffio_wfourcc(pb, "cmfc");
5596
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 2 times.
53 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
5597 26 ffio_wfourcc(pb, "iso6");
5598
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 52 times.
53 if (has_av1)
5599 1 ffio_wfourcc(pb, "av01");
5600
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 50 times.
53 if (has_dolby)
5601 3 ffio_wfourcc(pb, "dby1");
5602
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 49 times.
53 if (has_iamf)
5603 4 ffio_wfourcc(pb, "iamf");
5604 } else {
5605
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5606 ffio_wfourcc(pb, "iso6");
5607
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5608 ffio_wfourcc(pb, "iso5");
5609
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5610 ffio_wfourcc(pb, "iso4");
5611 }
5612 // Brands prior to iso5 can't be signaled when using default-base-is-moof
5613
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 11 times.
55 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
5614 // write isom for mp4 only if it it's not the major brand already.
5615
4/4
✓ Branch 0 taken 42 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 40 times.
44 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5616 4 ffio_wfourcc(pb, "isom");
5617 44 ffio_wfourcc(pb, "iso2");
5618
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 24 times.
44 if (has_h264)
5619 20 ffio_wfourcc(pb, "avc1");
5620 }
5621 }
5622
5623
2/2
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 144 times.
197 if (mov->mode == MODE_MP4)
5624 53 ffio_wfourcc(pb, "mp41");
5625
5626
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 186 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
197 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
5627 ffio_wfourcc(pb, "dash");
5628
5629 197 return update_size(pb, pos);
5630 }
5631
5632 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
5633 {
5634 1 AVStream *video_st = s->streams[0];
5635 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
5636 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
5637 1 int audio_rate = audio_par->sample_rate;
5638 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
5639
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 :
5640 0;
5641 1 int audio_kbitrate = audio_par->bit_rate / 1000;
5642 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
5643
5644
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) {
5645 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
5646 return AVERROR(EINVAL);
5647 }
5648
5649 1 avio_wb32(pb, 0x94); /* size */
5650 1 ffio_wfourcc(pb, "uuid");
5651 1 ffio_wfourcc(pb, "PROF");
5652
5653 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5654 1 avio_wb32(pb, 0xbb88695c);
5655 1 avio_wb32(pb, 0xfac9c740);
5656
5657 1 avio_wb32(pb, 0x0); /* ? */
5658 1 avio_wb32(pb, 0x3); /* 3 sections ? */
5659
5660 1 avio_wb32(pb, 0x14); /* size */
5661 1 ffio_wfourcc(pb, "FPRF");
5662 1 avio_wb32(pb, 0x0); /* ? */
5663 1 avio_wb32(pb, 0x0); /* ? */
5664 1 avio_wb32(pb, 0x0); /* ? */
5665
5666 1 avio_wb32(pb, 0x2c); /* size */
5667 1 ffio_wfourcc(pb, "APRF"); /* audio */
5668 1 avio_wb32(pb, 0x0);
5669 1 avio_wb32(pb, 0x2); /* TrackID */
5670 1 ffio_wfourcc(pb, "mp4a");
5671 1 avio_wb32(pb, 0x20f);
5672 1 avio_wb32(pb, 0x0);
5673 1 avio_wb32(pb, audio_kbitrate);
5674 1 avio_wb32(pb, audio_kbitrate);
5675 1 avio_wb32(pb, audio_rate);
5676 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
5677
5678 1 avio_wb32(pb, 0x34); /* size */
5679 1 ffio_wfourcc(pb, "VPRF"); /* video */
5680 1 avio_wb32(pb, 0x0);
5681 1 avio_wb32(pb, 0x1); /* TrackID */
5682
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
5683 1 ffio_wfourcc(pb, "avc1");
5684 1 avio_wb16(pb, 0x014D);
5685 1 avio_wb16(pb, 0x0015);
5686 } else {
5687 ffio_wfourcc(pb, "mp4v");
5688 avio_wb16(pb, 0x0000);
5689 avio_wb16(pb, 0x0103);
5690 }
5691 1 avio_wb32(pb, 0x0);
5692 1 avio_wb32(pb, video_kbitrate);
5693 1 avio_wb32(pb, video_kbitrate);
5694 1 avio_wb32(pb, frame_rate);
5695 1 avio_wb32(pb, frame_rate);
5696 1 avio_wb16(pb, video_par->width);
5697 1 avio_wb16(pb, video_par->height);
5698 1 avio_wb32(pb, 0x010001); /* ? */
5699
5700 1 return 0;
5701 }
5702
5703 197 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
5704 {
5705 197 MOVMuxContext *mov = s->priv_data;
5706 int i;
5707
5708 197 mov_write_ftyp_tag(pb,s);
5709
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 196 times.
197 if (mov->mode == MODE_PSP) {
5710 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
5711
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5712 2 AVStream *st = mov->tracks[i].st;
5713
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
5714 continue;
5715
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5716 1 video_streams_nb++;
5717
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
5718 1 audio_streams_nb++;
5719 else
5720 other_streams_nb++;
5721 }
5722
5723
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) {
5724 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
5725 return AVERROR(EINVAL);
5726 }
5727 1 return mov_write_uuidprof_tag(pb, s);
5728 }
5729 196 return 0;
5730 }
5731
5732 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
5733 {
5734 8 uint32_t c = -1;
5735 8 int i, closed_gop = 0;
5736
5737
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
5738 368 c = (c << 8) + pkt->data[i];
5739
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
5740 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
5741
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
5742 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
5743
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
5744 8 *flags = MOV_SYNC_SAMPLE;
5745 else
5746 *flags = MOV_PARTIAL_SYNC_SAMPLE;
5747 8 break;
5748 }
5749 }
5750 8 return 0;
5751 }
5752
5753 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
5754 {
5755 const uint8_t *start, *next, *end = pkt->data + pkt->size;
5756 int seq = 0, entry = 0;
5757 int key = pkt->flags & AV_PKT_FLAG_KEY;
5758 start = find_next_marker(pkt->data, end);
5759 for (next = start; next < end; start = next) {
5760 next = find_next_marker(start + 4, end);
5761 switch (AV_RB32(start)) {
5762 case VC1_CODE_SEQHDR:
5763 seq = 1;
5764 break;
5765 case VC1_CODE_ENTRYPOINT:
5766 entry = 1;
5767 break;
5768 case VC1_CODE_SLICE:
5769 trk->vc1_info.slices = 1;
5770 break;
5771 }
5772 }
5773 if (!trk->entry && trk->vc1_info.first_packet_seen)
5774 trk->vc1_info.first_frag_written = 1;
5775 if (!trk->entry && !trk->vc1_info.first_frag_written) {
5776 /* First packet in first fragment */
5777 trk->vc1_info.first_packet_seq = seq;
5778 trk->vc1_info.first_packet_entry = entry;
5779 trk->vc1_info.first_packet_seen = 1;
5780 } else if ((seq && !trk->vc1_info.packet_seq) ||
5781 (entry && !trk->vc1_info.packet_entry)) {
5782 int i;
5783 for (i = 0; i < trk->entry; i++)
5784 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
5785 trk->has_keyframes = 0;
5786 if (seq)
5787 trk->vc1_info.packet_seq = 1;
5788 if (entry)
5789 trk->vc1_info.packet_entry = 1;
5790 if (!trk->vc1_info.first_frag_written) {
5791 /* First fragment */
5792 if ((!seq || trk->vc1_info.first_packet_seq) &&
5793 (!entry || trk->vc1_info.first_packet_entry)) {
5794 /* First packet had the same headers as this one, readd the
5795 * sync sample flag. */
5796 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
5797 trk->has_keyframes = 1;
5798 }
5799 }
5800 }
5801 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
5802 key = seq && entry;
5803 else if (trk->vc1_info.packet_seq)
5804 key = seq;
5805 else if (trk->vc1_info.packet_entry)
5806 key = entry;
5807 if (key) {
5808 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
5809 trk->has_keyframes++;
5810 }
5811 }
5812
5813 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
5814 {
5815 int length;
5816
5817 if (pkt->size < 8)
5818 return;
5819
5820 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
5821 if (length < 8 || length > pkt->size)
5822 return;
5823
5824 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
5825 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
5826 trk->has_keyframes++;
5827 }
5828
5829 return;
5830 }
5831
5832 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
5833 {
5834 MOVMuxContext *mov = s->priv_data;
5835 int ret, buf_size;
5836 uint8_t *buf;
5837 int i, offset;
5838
5839 if (!track->mdat_buf)
5840 return 0;
5841 if (!mov->mdat_buf) {
5842 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
5843 return ret;
5844 }
5845 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
5846
5847 offset = avio_tell(mov->mdat_buf);
5848 avio_write(mov->mdat_buf, buf, buf_size);
5849 ffio_free_dyn_buf(&track->mdat_buf);
5850
5851 for (i = track->entries_flushed; i < track->entry; i++)
5852 track->cluster[i].pos += offset;
5853 track->entries_flushed = track->entry;
5854 return 0;
5855 }
5856
5857 2 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
5858 {
5859 2 MOVMuxContext *mov = s->priv_data;
5860 2 AVPacket *squashed_packet = mov->pkt;
5861 2 int ret = AVERROR_BUG;
5862
5863
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 switch (track->st->codecpar->codec_id) {
5864 2 case AV_CODEC_ID_TTML: {
5865 2 int had_packets = !!track->squashed_packet_queue.head;
5866
5867
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) {
5868 goto finish_squash;
5869 }
5870
5871 // We have generated a padding packet (no actual input packets in
5872 // queue) and its duration is zero. Skipping writing it.
5873
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) {
5874 goto finish_squash;
5875 }
5876
5877 2 track->end_reliable = 1;
5878 2 break;
5879 }
5880 default:
5881 ret = AVERROR(EINVAL);
5882 goto finish_squash;
5883 }
5884
5885 2 squashed_packet->stream_index = track->st->index;
5886
5887 2 ret = mov_write_single_packet(s, squashed_packet);
5888
5889 2 finish_squash:
5890 2 av_packet_unref(squashed_packet);
5891
5892 2 return ret;
5893 }
5894
5895 298 static int mov_write_squashed_packets(AVFormatContext *s)
5896 {
5897 298 MOVMuxContext *mov = s->priv_data;
5898
5899
2/2
✓ Branch 0 taken 433 times.
✓ Branch 1 taken 298 times.
731 for (int i = 0; i < mov->nb_streams; i++) {
5900 433 MOVTrack *track = &mov->tracks[i];
5901 433 int ret = AVERROR_BUG;
5902
5903
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 431 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
433 if (track->squash_fragment_samples_to_one && !track->entry) {
5904
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
5905 av_log(s, AV_LOG_ERROR,
5906 "Failed to write squashed packet for %s stream with "
5907 "index %d and track id %d. Error: %s\n",
5908 avcodec_get_name(track->st->codecpar->codec_id),
5909 track->st->index, track->track_id,
5910 av_err2str(ret));
5911 return ret;
5912 }
5913 }
5914 }
5915
5916 298 return 0;
5917 }
5918
5919 101 static int mov_flush_fragment(AVFormatContext *s, int force)
5920 {
5921 101 MOVMuxContext *mov = s->priv_data;
5922 101 int i, first_track = -1;
5923 101 int64_t mdat_size = 0;
5924 int ret;
5925 101 int has_video = 0, starts_with_key = 0, first_video_track = 1;
5926
5927
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 101 times.
101 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
5928 return 0;
5929
5930 // Check if we have any tracks that require squashing.
5931 // In that case, we'll have to write the packet here.
5932
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 101 times.
101 if ((ret = mov_write_squashed_packets(s)) < 0)
5933 return ret;
5934
5935 // Try to fill in the duration of the last packet in each stream
5936 // from queued packets in the interleave queues. If the flushing
5937 // of fragments was triggered automatically by an AVPacket, we
5938 // already have reliable info for the end of that track, but other
5939 // tracks may need to be filled in.
5940
2/2
✓ Branch 0 taken 182 times.
✓ Branch 1 taken 101 times.
283 for (i = 0; i < mov->nb_streams; i++) {
5941 182 MOVTrack *track = &mov->tracks[i];
5942
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 36 times.
182 if (!track->end_reliable) {
5943 146 const AVPacket *pkt = ff_interleaved_peek(s, i);
5944
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 141 times.
146 if (pkt) {
5945 int64_t offset, dts, pts;
5946 5 ff_get_muxer_ts_offset(s, i, &offset);
5947 5 pts = pkt->pts + offset;
5948 5 dts = pkt->dts + offset;
5949
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (track->dts_shift != AV_NOPTS_VALUE)
5950 dts += track->dts_shift;
5951 5 track->track_duration = dts - track->start_dts;
5952
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (pts != AV_NOPTS_VALUE)
5953 5 track->end_pts = pts;
5954 else
5955 track->end_pts = dts;
5956 }
5957 }
5958 }
5959
5960
2/2
✓ Branch 0 taken 188 times.
✓ Branch 1 taken 101 times.
289 for (i = 0; i < mov->nb_tracks; i++) {
5961 188 MOVTrack *track = &mov->tracks[i];
5962
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 145 times.
188 if (track->entry <= 1)
5963 43 continue;
5964 // Sample durations are calculated as the diff of dts values,
5965 // but for the last sample in a fragment, we don't know the dts
5966 // of the first sample in the next fragment, so we have to rely
5967 // on what was set as duration in the AVPacket. Not all callers
5968 // set this though, so we might want to replace it with an
5969 // estimate if it currently is zero.
5970
2/2
✓ Branch 1 taken 141 times.
✓ Branch 2 taken 4 times.
145 if (get_cluster_duration(track, track->entry - 1) != 0)
5971 141 continue;
5972 // Use the duration (i.e. dts diff) of the second last sample for
5973 // the last one. This is a wild guess (and fatal if it turns out
5974 // to be too long), but probably the best we can do - having a zero
5975 // duration is bad as well.
5976 4 track->track_duration += get_cluster_duration(track, track->entry - 2);
5977 4 track->end_pts += get_cluster_duration(track, track->entry - 2);
5978
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 if (!mov->missing_duration_warned) {
5979 2 av_log(s, AV_LOG_WARNING,
5980 "Estimating the duration of the last packet in a "
5981 "fragment, consider setting the duration field in "
5982 "AVPacket instead.\n");
5983 2 mov->missing_duration_warned = 1;
5984 }
5985 }
5986
5987
2/2
✓ Branch 0 taken 22 times.
✓ Branch 1 taken 79 times.
101 if (!mov->moov_written) {
5988 22 int64_t pos = avio_tell(s->pb);
5989 uint8_t *buf;
5990 int buf_size, moov_size;
5991
5992
2/2
✓ Branch 0 taken 43 times.
✓ Branch 1 taken 18 times.
61 for (i = 0; i < mov->nb_tracks; i++)
5993
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 39 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
43 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
5994 4 break;
5995 /* Don't write the initial moov unless all tracks have data */
5996
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 18 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
22 if (i < mov->nb_tracks && !force)
5997 2 return 0;
5998
5999 20 moov_size = get_moov_size(s);
6000
2/2
✓ Branch 0 taken 39 times.
✓ Branch 1 taken 20 times.
59 for (i = 0; i < mov->nb_tracks; i++)
6001 39 mov->tracks[i].data_offset = pos + moov_size + 8;
6002
6003 20 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6004
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 3 times.
20 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6005 17 mov_write_identification(s->pb, s);
6006
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6007 return ret;
6008
6009
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 3 times.
20 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6011 mov->reserved_header_pos = avio_tell(s->pb);
6012 17 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6013 17 mov->moov_written = 1;
6014 17 return 0;
6015 }
6016
6017 3 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6018 3 avio_wb32(s->pb, buf_size + 8);
6019 3 ffio_wfourcc(s->pb, "mdat");
6020 3 avio_write(s->pb, buf, buf_size);
6021 3 ffio_free_dyn_buf(&mov->mdat_buf);
6022
6023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6024 mov->reserved_header_pos = avio_tell(s->pb);
6025
6026 3 mov->moov_written = 1;
6027 3 mov->mdat_size = 0;
6028
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 3 times.
9 for (i = 0; i < mov->nb_tracks; i++) {
6029 6 mov->tracks[i].entry = 0;
6030 6 mov->tracks[i].end_reliable = 0;
6031 }
6032 3 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6033 3 return 0;
6034 }
6035
6036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 if (mov->frag_interleave) {
6037 for (i = 0; i < mov->nb_tracks; i++) {
6038 MOVTrack *track = &mov->tracks[i];
6039 int ret;
6040 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6041 return ret;
6042 }
6043
6044 if (!mov->mdat_buf)
6045 return 0;
6046 mdat_size = avio_tell(mov->mdat_buf);
6047 }
6048
6049
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 79 times.
224 for (i = 0; i < mov->nb_tracks; i++) {
6050 145 MOVTrack *track = &mov->tracks[i];
6051
3/4
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 126 times.
145 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6052 19 track->data_offset = 0;
6053 else
6054 126 track->data_offset = mdat_size;
6055
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 76 times.
145 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6056 69 has_video = 1;
6057
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 if (first_video_track) {
6058
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 12 times.
69 if (track->entry)
6059 57 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6060 69 first_video_track = 0;
6061 }
6062 }
6063
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 110 times.
145 if (!track->entry)
6064 35 continue;
6065
1/2
✓ Branch 0 taken 110 times.
✗ Branch 1 not taken.
110 if (track->mdat_buf)
6066 110 mdat_size += avio_tell(track->mdat_buf);
6067
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 47 times.
110 if (first_track < 0)
6068 63 first_track = i;
6069 }
6070
6071
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 63 times.
79 if (!mdat_size)
6072 16 return 0;
6073
6074
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 3 times.
63 avio_write_marker(s->pb,
6075 63 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6076
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 6 times.
63 (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);
6077
6078
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 63 times.
180 for (i = 0; i < mov->nb_tracks; i++) {
6079 117 MOVTrack *track = &mov->tracks[i];
6080 117 int buf_size, write_moof = 1, moof_tracks = -1;
6081 uint8_t *buf;
6082
6083
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 98 times.
117 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6084
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
19 if (!track->entry)
6085 7 continue;
6086 15 mdat_size = avio_tell(track->mdat_buf);
6087 15 moof_tracks = i;
6088 } else {
6089 98 write_moof = i == first_track;
6090 }
6091
6092
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 46 times.
113 if (write_moof) {
6093 67 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6094
6095 67 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6096 67 mov->fragments++;
6097
6098 67 avio_wb32(s->pb, mdat_size + 8);
6099 67 ffio_wfourcc(s->pb, "mdat");
6100 }
6101
6102 113 track->entry = 0;
6103 113 track->entries_flushed = 0;
6104 113 track->end_reliable = 0;
6105
1/2
✓ Branch 0 taken 113 times.
✗ Branch 1 not taken.
113 if (!mov->frag_interleave) {
6106
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 110 times.
113 if (!track->mdat_buf)
6107 3 continue;
6108 110 buf_size = avio_close_dyn_buf(track->mdat_buf, &buf);
6109 110 track->mdat_buf = NULL;
6110 } else {
6111 if (!mov->mdat_buf)
6112 continue;
6113 buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf);
6114 mov->mdat_buf = NULL;
6115 }
6116
6117 110 avio_write(s->pb, buf, buf_size);
6118 110 av_free(buf);
6119 }
6120
6121 63 mov->mdat_size = 0;
6122
6123 63 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6124 63 return 0;
6125 }
6126
6127 58 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6128 {
6129 58 MOVMuxContext *mov = s->priv_data;
6130 58 int had_moov = mov->moov_written;
6131 58 int ret = mov_flush_fragment(s, force);
6132
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 if (ret < 0)
6133 return ret;
6134 // If using delay_moov, the first flush only wrote the moov,
6135 // not the actual moof+mdat pair, thus flush once again.
6136
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 3 times.
58 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6137 9 ret = mov_flush_fragment(s, force);
6138 58 return ret;
6139 }
6140
6141 34604 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6142 {
6143 int64_t ref;
6144 uint64_t duration;
6145
6146
2/2
✓ Branch 0 taken 34006 times.
✓ Branch 1 taken 598 times.
34604 if (trk->entry) {
6147 34006 ref = trk->cluster[trk->entry - 1].dts;
6148
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 492 times.
598 } else if ( trk->start_dts != AV_NOPTS_VALUE
6149
2/2
✓ Branch 0 taken 98 times.
✓ Branch 1 taken 8 times.
106 && !trk->frag_discont) {
6150 98 ref = trk->start_dts + trk->track_duration;
6151 } else
6152 500 ref = pkt->dts; // Skip tests for the first packet
6153
6154
2/2
✓ Branch 0 taken 1075 times.
✓ Branch 1 taken 33529 times.
34604 if (trk->dts_shift != AV_NOPTS_VALUE) {
6155 /* With negative CTS offsets we have set an offset to the DTS,
6156 * reverse this for the check. */
6157 1075 ref -= trk->dts_shift;
6158 }
6159
6160 34604 duration = pkt->dts - ref;
6161
2/4
✓ Branch 0 taken 34604 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 34604 times.
34604 if (pkt->dts < ref || duration >= INT_MAX) {
6162 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" is out of range\n",
6163 duration, pkt->dts);
6164
6165 pkt->dts = ref + 1;
6166 pkt->pts = AV_NOPTS_VALUE;
6167 }
6168
6169
2/4
✓ Branch 0 taken 34604 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 34604 times.
34604 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6170 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" is invalid\n", pkt->duration);
6171 return AVERROR(EINVAL);
6172 }
6173 34604 return 0;
6174 }
6175
6176 17321 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6177 {
6178 17321 MOVMuxContext *mov = s->priv_data;
6179 17321 AVIOContext *pb = s->pb;
6180 MOVTrack *trk;
6181 AVCodecParameters *par;
6182 AVProducerReferenceTime *prft;
6183 17321 unsigned int samples_in_chunk = 0;
6184 17321 int size = pkt->size, ret = 0, offset = 0;
6185 size_t prft_size;
6186 17321 uint8_t *reformatted_data = NULL;
6187
6188
2/2
✓ Branch 0 taken 17275 times.
✓ Branch 1 taken 46 times.
17321 if (pkt->stream_index < s->nb_streams)
6189 17275 trk = s->streams[pkt->stream_index]->priv_data;
6190 else // Timecode or chapter
6191 46 trk = &mov->tracks[pkt->stream_index];
6192 17321 par = trk->par;
6193
6194 17321 ret = check_pkt(s, trk, pkt);
6195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17321 times.
17321 if (ret < 0)
6196 return ret;
6197
6198
3/4
✓ Branch 0 taken 12388 times.
✓ Branch 1 taken 4933 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12388 times.
17321 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
6199 int ret;
6200
4/4
✓ Branch 0 taken 2112 times.
✓ Branch 1 taken 2821 times.
✓ Branch 2 taken 1892 times.
✓ Branch 3 taken 220 times.
4933 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
6201
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 4713 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
4713 if (mov->frag_interleave && mov->fragments > 0) {
6202 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6203 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6204 return ret;
6205 }
6206 }
6207
6208
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 4603 times.
4713 if (!trk->mdat_buf) {
6209
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 110 times.
110 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6210 return ret;
6211 }
6212 4713 pb = trk->mdat_buf;
6213 } else {
6214
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 217 times.
220 if (!mov->mdat_buf) {
6215
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6216 return ret;
6217 }
6218 220 pb = mov->mdat_buf;
6219 }
6220 }
6221
6222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17321 times.
17321 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6223 /* We must find out how many AMR blocks there are in one packet */
6224 static const uint16_t packed_size[16] =
6225 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6226 int len = 0;
6227
6228 while (len < size && samples_in_chunk < 100) {
6229 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6230 samples_in_chunk++;
6231 }
6232 if (samples_in_chunk > 1) {
6233 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6234 return -1;
6235 }
6236
1/2
✓ Branch 0 taken 17321 times.
✗ Branch 1 not taken.
17321 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6237
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17321 times.
17321 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6238 samples_in_chunk = trk->par->frame_size;
6239
2/2
✓ Branch 0 taken 1286 times.
✓ Branch 1 taken 16035 times.
17321 } else if (trk->sample_size)
6240 1286 samples_in_chunk = size / trk->sample_size;
6241 else
6242 16035 samples_in_chunk = 1;
6243
6244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17321 times.
17321 if (samples_in_chunk < 1) {
6245 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6246 return AVERROR_PATCHWELCOME;
6247 }
6248
6249 /* copy extradata if it exists */
6250
4/4
✓ Branch 0 taken 5139 times.
✓ Branch 1 taken 12182 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5137 times.
17321 if (trk->vos_len == 0 && par->extradata_size > 0 &&
6251
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) &&
6252
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6253 2 trk->vos_len = par->extradata_size;
6254 2 trk->vos_data = av_malloc(trk->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
6255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->vos_data) {
6256 ret = AVERROR(ENOMEM);
6257 goto err;
6258 }
6259 2 memcpy(trk->vos_data, par->extradata, trk->vos_len);
6260 2 memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6261 }
6262
6263
2/2
✓ Branch 0 taken 17206 times.
✓ Branch 1 taken 115 times.
17321 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6264
2/2
✓ Branch 0 taken 14788 times.
✓ Branch 1 taken 2418 times.
17206 par->codec_id == AV_CODEC_ID_H264 ||
6265
2/2
✓ Branch 0 taken 14740 times.
✓ Branch 1 taken 48 times.
14788 par->codec_id == AV_CODEC_ID_HEVC ||
6266
1/2
✓ Branch 0 taken 14740 times.
✗ Branch 1 not taken.
14740 par->codec_id == AV_CODEC_ID_VVC ||
6267
1/2
✓ Branch 0 taken 14740 times.
✗ Branch 1 not taken.
14740 par->codec_id == AV_CODEC_ID_VP9 ||
6268
2/2
✓ Branch 0 taken 14440 times.
✓ Branch 1 taken 300 times.
14740 par->codec_id == AV_CODEC_ID_EVC ||
6269
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14440 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 2857 times.
17321 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->vos_len &&
6270
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)) {
6271 /* copy frame to create needed atoms */
6272 24 trk->vos_len = size;
6273 24 trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6274
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->vos_data) {
6275 ret = AVERROR(ENOMEM);
6276 goto err;
6277 }
6278 24 memcpy(trk->vos_data, pkt->data, size);
6279 24 memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6280 }
6281
6282
3/4
✓ Branch 0 taken 5369 times.
✓ Branch 1 taken 11952 times.
✓ Branch 2 taken 5369 times.
✗ Branch 3 not taken.
17321 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
6283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5369 times.
5369 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6284 if (!trk->st->nb_frames) {
6285 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6286 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6287 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6288 return -1;
6289 }
6290 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6291 }
6292
19/34
✓ Branch 0 taken 2418 times.
✓ Branch 1 taken 14903 times.
✓ Branch 2 taken 2418 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 448 times.
✓ Branch 5 taken 1970 times.
✓ Branch 6 taken 448 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 448 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 448 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 448 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 448 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 448 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 448 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 448 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 448 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 448 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 448 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 448 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 448 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 448 times.
✗ Branch 33 not taken.
17321 if (par->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1 && !TAG_IS_AVCI(trk->tag)) {
6293 /* from x264 or from bytestream H.264 */
6294 /* NAL reformatting needed */
6295
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 448 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
448 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6296 ret = ff_avc_parse_nal_units_buf(pkt->data, &reformatted_data,
6297 &size);
6298 if (ret < 0)
6299 return ret;
6300 avio_write(pb, reformatted_data, size);
6301 } else {
6302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 448 times.
448 if (trk->cenc.aes_ctr) {
6303 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6304 if (size < 0) {
6305 ret = size;
6306 goto err;
6307 }
6308 } else {
6309 448 size = ff_avc_parse_nal_units(pb, pkt->data, pkt->size);
6310 }
6311 }
6312
3/4
✓ Branch 0 taken 48 times.
✓ Branch 1 taken 16825 times.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
16873 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 &&
6313
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
48 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6314 /* extradata is Annex B, assume the bitstream is too and convert it */
6315
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
48 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6316 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6317 &size, 0, NULL);
6318 if (ret < 0)
6319 return ret;
6320 avio_write(pb, reformatted_data, size);
6321 } else {
6322
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
48 if (trk->cenc.aes_ctr) {
6323 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6324 if (size < 0) {
6325 ret = size;
6326 goto err;
6327 }
6328 } else {
6329 48 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6330 }
6331 }
6332
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 16825 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
16825 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->vos_len > 6 &&
6333 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6334 /* extradata is Annex B, assume the bitstream is too and convert it */
6335 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6336 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6337 &size, 0, NULL);
6338 if (ret < 0)
6339 return ret;
6340 avio_write(pb, reformatted_data, size);
6341 } else {
6342 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6343 }
6344
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16821 times.
16825 } else if (par->codec_id == AV_CODEC_ID_AV1) {
6345
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) {
6346 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
6347 &size, &offset);
6348 if (ret < 0)
6349 return ret;
6350 avio_write(pb, reformatted_data, size);
6351 } else {
6352 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
6353
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]) {
6354 mov->avif_extent_length[pkt->stream_index] = size;
6355 }
6356 }
6357
6358
2/2
✓ Branch 0 taken 16434 times.
✓ Branch 1 taken 387 times.
16821 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
6359
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 15782 times.
16434 par->codec_id == AV_CODEC_ID_EAC3) {
6360 1039 size = handle_eac3(mov, pkt, trk);
6361
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
6362 return size;
6363
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
6364 1 goto end;
6365 1038 avio_write(pb, pkt->data, size);
6366
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15782 times.
15782 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
6367 size = 8;
6368
6369 for (int i = 0; i < pkt->size; i += 3) {
6370 if (pkt->data[i] == 0xFC) {
6371 size += 2;
6372 }
6373 }
6374 avio_wb32(pb, size);
6375 ffio_wfourcc(pb, "cdat");
6376 for (int i = 0; i < pkt->size; i += 3) {
6377 if (pkt->data[i] == 0xFC) {
6378 avio_w8(pb, pkt->data[i + 1]);
6379 avio_w8(pb, pkt->data[i + 2]);
6380 }
6381 }
6382 } else {
6383
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15782 times.
15782 if (trk->cenc.aes_ctr) {
6384 if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 4) {
6385 int nal_size_length = (par->extradata[4] & 0x3) + 1;
6386 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6387 } else if(par->codec_id == AV_CODEC_ID_HEVC && par->extradata_size > 21) {
6388 int nal_size_length = (par->extradata[21] & 0x3) + 1;
6389 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6390 } else if(par->codec_id == AV_CODEC_ID_VVC) {
6391 ret = AVERROR_PATCHWELCOME;
6392 } else {
6393 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
6394 }
6395
6396 if (ret) {
6397 goto err;
6398 }
6399 } else {
6400 15782 avio_write(pb, pkt->data, size);
6401 }
6402 }
6403
6404
2/2
✓ Branch 0 taken 257 times.
✓ Branch 1 taken 17063 times.
17320 if (trk->entry >= trk->cluster_capacity) {
6405 257 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
6406 257 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
6407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 257 times.
257 if (!cluster) {
6408 ret = AVERROR(ENOMEM);
6409 goto err;
6410 }
6411 257 trk->cluster = cluster;
6412 257 trk->cluster_capacity = new_capacity;
6413 }
6414
6415 17320 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6416 17320 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
6417 17320 trk->cluster[trk->entry].chunkNum = 0;
6418 17320 trk->cluster[trk->entry].size = size;
6419 17320 trk->cluster[trk->entry].entries = samples_in_chunk;
6420 17320 trk->cluster[trk->entry].dts = pkt->dts;
6421 17320 trk->cluster[trk->entry].pts = pkt->pts;
6422
2/2
✓ Branch 0 taken 17318 times.
✓ Branch 1 taken 2 times.
17320 if (!trk->squash_fragment_samples_to_one &&
6423
4/4
✓ Branch 0 taken 311 times.
✓ Branch 1 taken 17007 times.
✓ Branch 2 taken 70 times.
✓ Branch 3 taken 241 times.
17318 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
6424
2/2
✓ Branch 0 taken 66 times.
✓ Branch 1 taken 4 times.
70 if (!trk->frag_discont) {
6425 /* First packet of a new fragment. We already wrote the duration
6426 * of the last packet of the previous fragment based on track_duration,
6427 * which might not exactly match our dts. Therefore adjust the dts
6428 * of this packet to be what the previous packets duration implies. */
6429 66 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
6430 /* We also may have written the pts and the corresponding duration
6431 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
6432 * the next fragment. This means the cts of the first sample must
6433 * be the same in all fragments, unless end_pts was updated by
6434 * the packet causing the fragment to be written. */
6435
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 52 times.
66 if ((mov->flags & FF_MOV_FLAG_DASH &&
6436
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
6437
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 42 times.
52 mov->mode == MODE_ISM)
6438 24 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
6439 } else {
6440 /* New fragment, but discontinuous from previous fragments.
6441 * Pretend the duration sum of the earlier fragments is
6442 * pkt->dts - trk->start_dts. */
6443 4 trk->end_pts = AV_NOPTS_VALUE;
6444 4 trk->frag_discont = 0;
6445 }
6446 }
6447
6448
6/6
✓ Branch 0 taken 313 times.
✓ Branch 1 taken 17007 times.
✓ Branch 2 taken 243 times.
✓ Branch 3 taken 70 times.
✓ Branch 4 taken 26 times.
✓ Branch 5 taken 217 times.
17320 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
6449
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 9 times.
26 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
6450 /* Not using edit lists and shifting the first track to start from zero.
6451 * If the other streams start from a later timestamp, we won't be able
6452 * to signal the difference in starting time without an edit list.
6453 * Thus move the timestamp for this first sample to 0, increasing
6454 * its duration instead. */
6455 17 trk->cluster[trk->entry].dts = trk->start_dts = 0;
6456 }
6457
2/2
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 17094 times.
17320 if (trk->start_dts == AV_NOPTS_VALUE) {
6458 226 trk->start_dts = pkt->dts;
6459
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 220 times.
226 if (trk->frag_discont) {
6460
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
6461 /* Pretend the whole stream started at pts=0, with earlier fragments
6462 * already written. If the stream started at pts=0, the duration sum
6463 * of earlier fragments would have been pkt->pts. */
6464 4 trk->start_dts = pkt->dts - pkt->pts;
6465 } else {
6466 /* Pretend the whole stream started at dts=0, with earlier fragments
6467 * already written, with a duration summing up to pkt->dts. */
6468 2 trk->start_dts = 0;
6469 }
6470 6 trk->frag_discont = 0;
6471
4/4
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 191 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 27 times.
220 } else if (pkt->dts && mov->moov_written)
6472 2 av_log(s, AV_LOG_WARNING,
6473 "Track %d starts with a nonzero dts %"PRId64", while the moov "
6474 "already has been written. Set the delay_moov flag to handle "
6475 "this case.\n",
6476 pkt->stream_index, pkt->dts);
6477 }
6478 17320 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
6479 17320 trk->last_sample_is_subtitle_end = 0;
6480
6481
2/2
✓ Branch 0 taken 496 times.
✓ Branch 1 taken 16824 times.
17320 if (pkt->pts == AV_NOPTS_VALUE) {
6482 496 av_log(s, AV_LOG_WARNING, "pts has no value\n");
6483 496 pkt->pts = pkt->dts;
6484 }
6485
2/2
✓ Branch 0 taken 880 times.
✓ Branch 1 taken 16440 times.
17320 if (pkt->dts != pkt->pts)
6486 880 trk->flags |= MOV_TRACK_CTTS;
6487 17320 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
6488 17320 trk->cluster[trk->entry].flags = 0;
6489
2/2
✓ Branch 0 taken 243 times.
✓ Branch 1 taken 17077 times.
17320 if (trk->start_cts == AV_NOPTS_VALUE)
6490 243 trk->start_cts = pkt->pts - pkt->dts;
6491
2/2
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 17073 times.
17320 if (trk->end_pts == AV_NOPTS_VALUE)
6492 247 trk->end_pts = trk->cluster[trk->entry].dts +
6493 247 trk->cluster[trk->entry].cts + pkt->duration;
6494 else
6495 17073 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
6496 trk->cluster[trk->entry].cts +
6497 pkt->duration);
6498
6499
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17320 times.
17320 if (par->codec_id == AV_CODEC_ID_VC1) {
6500 mov_parse_vc1_frame(pkt, trk);
6501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17320 times.
17320 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
6502 mov_parse_truehd_frame(pkt, trk);
6503
2/2
✓ Branch 0 taken 13025 times.
✓ Branch 1 taken 4295 times.
17320 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
6504
4/4
✓ Branch 0 taken 6115 times.
✓ Branch 1 taken 6910 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6106 times.
13025 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
6505
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
6506 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
6507
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
6508 trk->flags |= MOV_TRACK_STPS;
6509 } else {
6510 13017 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
6511 }
6512
1/2
✓ Branch 0 taken 13025 times.
✗ Branch 1 not taken.
13025 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
6513 13025 trk->has_keyframes++;
6514 }
6515
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 17318 times.
17320 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
6516 2 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
6517 2 trk->has_disposable++;
6518 }
6519
6520 17320 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
6521
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17320 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17320 if (prft && prft_size == sizeof(AVProducerReferenceTime))
6522 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
6523 else
6524 17320 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
6525
6526 17320 trk->entry++;
6527 17320 trk->sample_count += samples_in_chunk;
6528 17320 mov->mdat_size += size;
6529
6530
3/4
✓ Branch 0 taken 17238 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
17320 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
6531 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
6532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
6533 : NULL, size);
6534
6535 17321 end:
6536 17321 err:
6537
6538
1/2
✓ Branch 0 taken 17321 times.
✗ Branch 1 not taken.
17321 if (pkt->data != reformatted_data)
6539 17321 av_free(reformatted_data);
6540 17321 return ret;
6541 }
6542
6543 17283 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
6544 {
6545 17283 MOVMuxContext *mov = s->priv_data;
6546 17283 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
6547 17283 AVCodecParameters *par = trk->par;
6548 17283 int64_t frag_duration = 0;
6549 17283 int size = pkt->size;
6550
6551 17283 int ret = check_pkt(s, trk, pkt);
6552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17283 times.
17283 if (ret < 0)
6553 return ret;
6554
6555
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 17278 times.
17283 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
6556
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
6557 10 mov->tracks[i].frag_discont = 1;
6558 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
6559 }
6560
6561
2/2
✓ Branch 0 taken 519 times.
✓ Branch 1 taken 16764 times.
17283 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
6562
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 510 times.
519 if (trk->dts_shift == AV_NOPTS_VALUE)
6563 9 trk->dts_shift = pkt->pts - pkt->dts;
6564 519 pkt->dts += trk->dts_shift;
6565 }
6566
6567
1/2
✓ Branch 0 taken 17283 times.
✗ Branch 1 not taken.
17283 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
6568
2/2
✓ Branch 0 taken 11912 times.
✓ Branch 1 taken 5371 times.
17283 trk->par->codec_id == AV_CODEC_ID_AAC ||
6569
2/2
✓ Branch 0 taken 11908 times.
✓ Branch 1 taken 4 times.
11912 trk->par->codec_id == AV_CODEC_ID_AV1 ||
6570
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 11864 times.
11908 trk->par->codec_id == AV_CODEC_ID_FLAC) {
6571 size_t side_size;
6572 5419 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
6573
6/8
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5414 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
5419 if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
6574 5 void *newextra = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
6575
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!newextra)
6576 return AVERROR(ENOMEM);
6577 5 av_free(par->extradata);
6578 5 par->extradata = newextra;
6579 5 memcpy(par->extradata, side, side_size);
6580 5 par->extradata_size = side_size;
6581
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (!pkt->size) // Flush packet
6582 4 mov->need_rewrite_extradata = 1;
6583 }
6584 }
6585
6586
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 17275 times.
17283 if (!pkt->size) {
6587
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
8 if (trk->start_dts == AV_NOPTS_VALUE && trk->frag_discont) {
6588 4 trk->start_dts = pkt->dts;
6589
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
6590 4 trk->start_cts = pkt->pts - pkt->dts;
6591 else
6592 trk->start_cts = 0;
6593 }
6594
6595 8 return 0; /* Discard 0 sized packets */
6596 }
6597
6598
3/4
✓ Branch 0 taken 16995 times.
✓ Branch 1 taken 280 times.
✓ Branch 2 taken 16995 times.
✗ Branch 3 not taken.
17275 if (trk->entry && pkt->stream_index < mov->nb_streams)
6599 16995 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
6600 16995 s->streams[pkt->stream_index]->time_base,
6601 16995 AV_TIME_BASE_Q);
6602
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 17102 times.
17275 if ((mov->max_fragment_duration &&
6603
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 3 times.
173 frag_duration >= mov->max_fragment_duration) ||
6604
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 17272 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
17272 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
6605
2/2
✓ Branch 0 taken 3637 times.
✓ Branch 1 taken 13635 times.
17272 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
6606
2/2
✓ Branch 0 taken 1100 times.
✓ Branch 1 taken 2537 times.
3637 par->codec_type == AVMEDIA_TYPE_VIDEO &&
6607
4/4
✓ Branch 0 taken 1077 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 1054 times.
✓ Branch 3 taken 23 times.
1100 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
6608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17249 times.
17249 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
6609
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if (frag_duration >= mov->min_fragment_duration) {
6610
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if (trk->entry) {
6611 // Set the duration of this track to line up with the next
6612 // sample in this track. This avoids relying on AVPacket
6613 // duration, but only helps for this particular track, not
6614 // for the other ones that are flushed at the same time.
6615 //
6616 // If we have trk->entry == 0, no fragment will be written
6617 // for this track, and we can't adjust the track end here.
6618 26 trk->track_duration = pkt->dts - trk->start_dts;
6619
1/2
✓ Branch 0 taken 26 times.
✗ Branch 1 not taken.
26 if (pkt->pts != AV_NOPTS_VALUE)
6620 26 trk->end_pts = pkt->pts;
6621 else
6622 trk->end_pts = pkt->dts;
6623 26 trk->end_reliable = 1;
6624 }
6625 26 mov_auto_flush_fragment(s, 0);
6626 }
6627 }
6628
6629 17275 return ff_mov_write_packet(s, pkt);
6630 }
6631
6632 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
6633 int stream_index,
6634 int64_t dts) {
6635 3 MOVMuxContext *mov = s->priv_data;
6636 3 AVPacket *end = mov->pkt;
6637 3 uint8_t data[2] = {0};
6638 int ret;
6639
6640 3 end->size = sizeof(data);
6641 3 end->data = data;
6642 3 end->pts = dts;
6643 3 end->dts = dts;
6644 3 end->duration = 0;
6645 3 end->stream_index = stream_index;
6646
6647 3 ret = mov_write_single_packet(s, end);
6648 3 av_packet_unref(end);
6649
6650 3 return ret;
6651 }
6652
6653 198 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6654 {
6655 int ret;
6656
6657
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 154 times.
198 if (pkt->stream_index == trk->first_iamf_idx) {
6658 44 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
6659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 44 times.
44 if (ret < 0)
6660 return ret;
6661 }
6662
6663 198 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
6664 198 s->streams[pkt->stream_index]->id, pkt);
6665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 198 times.
198 if (ret < 0)
6666 return ret;
6667
6668
2/2
✓ Branch 0 taken 44 times.
✓ Branch 1 taken 154 times.
198 if (pkt->stream_index == trk->last_iamf_idx) {
6669 uint8_t *data;
6670
6671 44 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
6672 44 trk->iamf_buf = NULL;
6673
6674
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 40 times.
44 if (!ret) {
6675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (pkt->size) {
6676 // Either all or none of the packets for a single
6677 // IA Sample may be empty.
6678 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
6679 "stream #%d\n", pkt->stream_index);
6680 ret = AVERROR_INVALIDDATA;
6681 }
6682 4 av_free(data);
6683 4 return ret;
6684 }
6685 40 av_buffer_unref(&pkt->buf);
6686 40 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
6687
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (!pkt->buf) {
6688 av_free(data);
6689 return AVERROR(ENOMEM);
6690 }
6691 40 pkt->data = data;
6692 40 pkt->size = ret;
6693 40 pkt->stream_index = trk->first_iamf_idx;
6694
6695 40 ret = avio_open_dyn_buf(&trk->iamf_buf);
6696
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0)
6697 return ret;
6698 } else
6699 154 ret = AVERROR(EAGAIN);
6700
6701 194 return ret;
6702 }
6703
6704 17542 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6705 {
6706 17542 MOVMuxContext *mov = s->priv_data;
6707 MOVTrack *trk;
6708
6709
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 17508 times.
17542 if (!pkt) {
6710 34 mov_flush_fragment(s, 1);
6711 34 return 1;
6712 }
6713
6714 17508 trk = s->streams[pkt->stream_index]->priv_data;
6715
6716
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 17310 times.
17508 if (trk->iamf) {
6717 198 int ret = mov_build_iamf_packet(s, trk, pkt);
6718
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 44 times.
198 if (ret < 0) {
6719
1/2
✓ Branch 0 taken 154 times.
✗ Branch 1 not taken.
154 if (ret == AVERROR(EAGAIN))
6720 154 return 0;
6721 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
6722 "for stream #%d\n", trk->st->index);
6723 return ret;
6724 }
6725 }
6726
6727
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 17352 times.
17354 if (is_cover_image(trk->st)) {
6728 int ret;
6729
6730
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
6731 if (trk->st->nb_frames == 1)
6732 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
6733 " ignoring.\n", pkt->stream_index);
6734 return 0;
6735 }
6736
6737
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
6738 return ret;
6739
6740 2 return 0;
6741 } else {
6742 int i;
6743
6744
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 17344 times.
17352 if (!pkt->size)
6745 8 return mov_write_single_packet(s, pkt); /* Passthrough. */
6746
6747 /*
6748 * Subtitles require special handling.
6749 *
6750 * 1) For full complaince, every track must have a sample at
6751 * dts == 0, which is rarely true for subtitles. So, as soon
6752 * as we see any packet with dts > 0, write an empty subtitle
6753 * at dts == 0 for any subtitle track with no samples in it.
6754 *
6755 * 2) For each subtitle track, check if the current packet's
6756 * dts is past the duration of the last subtitle sample. If
6757 * so, we now need to write an end sample for that subtitle.
6758 *
6759 * This must be done conditionally to allow for subtitles that
6760 * immediately replace each other, in which case an end sample
6761 * is not needed, and is, in fact, actively harmful.
6762 *
6763 * 3) See mov_write_trailer for how the final end sample is
6764 * handled.
6765 */
6766
2/2
✓ Branch 0 taken 31685 times.
✓ Branch 1 taken 17344 times.
49029 for (i = 0; i < mov->nb_tracks; i++) {
6767 31685 MOVTrack *trk = &mov->tracks[i];
6768 int ret;
6769
6770
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 31682 times.
31685 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
6771
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
6772
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)) {
6773 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
6774
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
6775 2 trk->last_sample_is_subtitle_end = 1;
6776 }
6777 }
6778
6779
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 17270 times.
17344 if (trk->squash_fragment_samples_to_one) {
6780 /*
6781 * If the track has to have its samples squashed into one sample,
6782 * we just take it into the track's queue.
6783 * This will then be utilized as the samples get written in either
6784 * mov_flush_fragment or when the mux is finalized in
6785 * mov_write_trailer.
6786 */
6787 74 int ret = AVERROR_BUG;
6788
6789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (pkt->pts == AV_NOPTS_VALUE) {
6790 av_log(s, AV_LOG_ERROR,
6791 "Packets without a valid presentation timestamp are "
6792 "not supported with packet squashing!\n");
6793 return AVERROR(EINVAL);
6794 }
6795
6796 /* The following will reset pkt and is only allowed to be used
6797 * because we return immediately. afterwards. */
6798
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
6799 pkt, NULL, 0)) < 0) {
6800 return ret;
6801 }
6802
6803 74 return 0;
6804 }
6805
6806
6807
4/4
✓ Branch 0 taken 7503 times.
✓ Branch 1 taken 9767 times.
✓ Branch 2 taken 3391 times.
✓ Branch 3 taken 4112 times.
17270 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6808 3391 AVPacket *opkt = pkt;
6809 int reshuffle_ret, ret;
6810
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3391 times.
3391 if (trk->is_unaligned_qt_rgb) {
6811 int64_t bpc = trk->par->bits_per_coded_sample != 15 ? trk->par->bits_per_coded_sample : 16;
6812 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
6813 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
6814 if (reshuffle_ret < 0)
6815 return reshuffle_ret;
6816 } else
6817 3391 reshuffle_ret = 0;
6818
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3153 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3391 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
6819 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
6820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
6821 goto fail;
6822
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
6823 5 trk->pal_done++;
6824
2/2
✓ Branch 0 taken 600 times.
✓ Branch 1 taken 2786 times.
3386 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
6825
1/2
✓ Branch 0 taken 600 times.
✗ Branch 1 not taken.
600 (trk->par->format == AV_PIX_FMT_GRAY8 ||
6826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 600 times.
600 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
6827 ret = av_packet_make_writable(pkt);
6828 if (ret < 0)
6829 goto fail;
6830 for (i = 0; i < pkt->size; i++)
6831 pkt->data[i] = ~pkt->data[i];
6832 }
6833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3391 times.
3391 if (reshuffle_ret) {
6834 ret = mov_write_single_packet(s, pkt);
6835 fail:
6836 if (reshuffle_ret)
6837 av_packet_free(&pkt);
6838 return ret;
6839 }
6840 }
6841
6842 17270 return mov_write_single_packet(s, pkt);
6843 }
6844 }
6845
6846 // QuickTime chapters involve an additional text track with the chapter names
6847 // as samples, and a tref pointing from the other tracks to the chapter one.
6848 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
6849 {
6850 static const uint8_t stub_header[] = {
6851 // TextSampleEntry
6852 0x00, 0x00, 0x00, 0x01, // displayFlags
6853 0x00, 0x00, // horizontal + vertical justification
6854 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
6855 // BoxRecord
6856 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
6857 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
6858 // StyleRecord
6859 0x00, 0x00, 0x00, 0x00, // startChar + endChar
6860 0x00, 0x01, // fontID
6861 0x00, 0x00, // fontStyleFlags + fontSize
6862 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
6863 // FontTableBox
6864 0x00, 0x00, 0x00, 0x0D, // box size
6865 'f', 't', 'a', 'b', // box atom name
6866 0x00, 0x01, // entry count
6867 // FontRecord
6868 0x00, 0x01, // font ID
6869 0x00, // font name length
6870 };
6871 1 MOVMuxContext *mov = s->priv_data;
6872 1 MOVTrack *track = &mov->tracks[tracknum];
6873 1 AVPacket *pkt = mov->pkt;
6874 int i, len;
6875 int ret;
6876
6877 1 track->mode = mov->mode;
6878 1 track->tag = MKTAG('t','e','x','t');
6879 1 track->timescale = mov->movie_timescale;
6880 1 track->par = avcodec_parameters_alloc();
6881
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
6882 return AVERROR(ENOMEM);
6883 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
6884 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
6885
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
6886 return ret;
6887 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
6888
6889 1 pkt->stream_index = tracknum;
6890 1 pkt->flags = AV_PKT_FLAG_KEY;
6891
6892
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
6893 4 AVChapter *c = s->chapters[i];
6894 AVDictionaryEntry *t;
6895
6896 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
6897 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
6898 4 pkt->duration = end - pkt->dts;
6899
6900
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
6901 static const char encd[12] = {
6902 0x00, 0x00, 0x00, 0x0C,
6903 'e', 'n', 'c', 'd',
6904 0x00, 0x00, 0x01, 0x00 };
6905 4 len = strlen(t->value);
6906 4 pkt->size = len + 2 + 12;
6907 4 pkt->data = av_malloc(pkt->size);
6908
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
6909 av_packet_unref(pkt);
6910 return AVERROR(ENOMEM);
6911 }
6912 4 AV_WB16(pkt->data, len);
6913 4 memcpy(pkt->data + 2, t->value, len);
6914 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
6915 4 ff_mov_write_packet(s, pkt);
6916 4 av_freep(&pkt->data);
6917 }
6918 }
6919
6920 1 av_packet_unref(mov->pkt);
6921
6922 1 return 0;
6923 }
6924
6925
6926 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
6927 {
6928 int ret;
6929
6930 /* compute the frame number */
6931 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
6932 13 return ret;
6933 }
6934
6935 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
6936 {
6937 6 MOVMuxContext *mov = s->priv_data;
6938 6 MOVTrack *track = &mov->tracks[index];
6939 6 AVStream *src_st = mov->tracks[src_index].st;
6940 uint8_t data[4];
6941 6 AVPacket *pkt = mov->pkt;
6942 6 AVRational rate = src_st->avg_frame_rate;
6943 int ret;
6944
6945 /* tmcd track based on video stream */
6946 6 track->mode = mov->mode;
6947 6 track->tag = MKTAG('t','m','c','d');
6948 6 track->src_track = src_index;
6949 6 track->timescale = mov->tracks[src_index].timescale;
6950
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
6951 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
6952
6953 /* set st to src_st for metadata access*/
6954 6 track->st = src_st;
6955
6956 /* encode context: tmcd data stream */
6957 6 track->par = avcodec_parameters_alloc();
6958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
6959 return AVERROR(ENOMEM);
6960 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
6961 6 track->par->codec_tag = track->tag;
6962 6 track->st->avg_frame_rate = rate;
6963
6964 /* the tmcd track just contains one packet with the frame number */
6965 6 pkt->data = data;
6966 6 pkt->stream_index = index;
6967 6 pkt->flags = AV_PKT_FLAG_KEY;
6968 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
6969 6 pkt->size = 4;
6970 6 AV_WB32(pkt->data, tc.start);
6971 6 ret = ff_mov_write_packet(s, pkt);
6972 6 av_packet_unref(pkt);
6973 6 return ret;
6974 }
6975
6976 /*
6977 * st->disposition controls the "enabled" flag in the tkhd tag.
6978 * QuickTime will not play a track if it is not enabled. So make sure
6979 * that one track of each type (audio, video, subtitle) is enabled.
6980 *
6981 * Subtitles are special. For audio and video, setting "enabled" also
6982 * makes the track "default" (i.e. it is rendered when played). For
6983 * subtitles, an "enabled" subtitle is not rendered by default, but
6984 * if no subtitle is enabled, the subtitle menu in QuickTime will be
6985 * empty!
6986 */
6987 197 static void enable_tracks(AVFormatContext *s)
6988 {
6989 197 MOVMuxContext *mov = s->priv_data;
6990 int i;
6991 int enabled[AVMEDIA_TYPE_NB];
6992 int first[AVMEDIA_TYPE_NB];
6993
6994
2/2
✓ Branch 0 taken 985 times.
✓ Branch 1 taken 197 times.
1182 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
6995 985 enabled[i] = 0;
6996 985 first[i] = -1;
6997 }
6998
6999
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 197 times.
448 for (i = 0; i < mov->nb_streams; i++) {
7000 251 AVStream *st = mov->tracks[i].st;
7001
7002
1/2
✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
251 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7003
3/4
✓ Branch 0 taken 251 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 249 times.
502 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
7004 251 is_cover_image(st))
7005 2 continue;
7006
7007
2/2
✓ Branch 0 taken 235 times.
✓ Branch 1 taken 14 times.
249 if (first[st->codecpar->codec_type] < 0)
7008 235 first[st->codecpar->codec_type] = i;
7009
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 222 times.
249 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7010 27 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7011 27 enabled[st->codecpar->codec_type]++;
7012 }
7013 }
7014
7015
2/2
✓ Branch 0 taken 985 times.
✓ Branch 1 taken 197 times.
1182 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7016
2/2
✓ Branch 0 taken 591 times.
✓ Branch 1 taken 394 times.
985 switch (i) {
7017 591 case AVMEDIA_TYPE_VIDEO:
7018 case AVMEDIA_TYPE_AUDIO:
7019 case AVMEDIA_TYPE_SUBTITLE:
7020
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 591 times.
591 if (enabled[i] > 1)
7021 mov->per_stream_grouping = 1;
7022
4/4
✓ Branch 0 taken 568 times.
✓ Branch 1 taken 23 times.
✓ Branch 2 taken 210 times.
✓ Branch 3 taken 358 times.
591 if (!enabled[i] && first[i] >= 0)
7023 210 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7024 591 break;
7025 }
7026 }
7027 197 }
7028
7029 197 static void mov_free(AVFormatContext *s)
7030 {
7031 197 MOVMuxContext *mov = s->priv_data;
7032
7033
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 197 times.
462 for (int i = 0; i < s->nb_streams; i++)
7034 265 s->streams[i]->priv_data = NULL;
7035
7036
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (!mov->tracks)
7037 return;
7038
7039
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 196 times.
197 if (mov->chapter_track) {
7040 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7041 }
7042
7043
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 197 times.
457 for (int i = 0; i < mov->nb_tracks; i++) {
7044 260 MOVTrack *const track = &mov->tracks[i];
7045
7046
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 258 times.
260 if (track->tag == MKTAG('r','t','p',' '))
7047 2 ff_mov_close_hinting(track);
7048
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 249 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
258 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
7049 6 av_freep(&track->par);
7050 260 av_freep(&track->cluster);
7051 260 av_freep(&track->frag_info);
7052 260 av_packet_free(&track->cover_image);
7053
7054
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 255 times.
260 if (track->eac3_priv) {
7055 5 struct eac3_info *info = track->eac3_priv;
7056 5 av_packet_free(&info->pkt);
7057 5 av_freep(&track->eac3_priv);
7058 }
7059
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 127 times.
260 if (track->vos_len)
7060 133 av_freep(&track->vos_data);
7061
7062 260 ff_mov_cenc_free(&track->cenc);
7063 260 ffio_free_dyn_buf(&track->mdat_buf);
7064
7065 260 ffio_free_dyn_buf(&track->iamf_buf);
7066
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 256 times.
260 if (track->iamf)
7067 4 ff_iamf_uninit_context(track->iamf);
7068 260 av_freep(&track->iamf);
7069
7070 260 avpriv_packet_list_free(&track->squashed_packet_queue);
7071 }
7072
7073 197 av_freep(&mov->tracks);
7074 197 ffio_free_dyn_buf(&mov->mdat_buf);
7075 }
7076
7077 static uint32_t rgb_to_yuv(uint32_t rgb)
7078 {
7079 uint8_t r, g, b;
7080 int y, cb, cr;
7081
7082 r = (rgb >> 16) & 0xFF;
7083 g = (rgb >> 8) & 0xFF;
7084 b = (rgb ) & 0xFF;
7085
7086 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7087 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7088 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7089
7090 return (y << 16) | (cr << 8) | cb;
7091 }
7092
7093 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7094 AVStream *st)
7095 {
7096 int i, width = 720, height = 480;
7097 int have_palette = 0, have_size = 0;
7098 uint32_t palette[16];
7099 char *cur = st->codecpar->extradata;
7100
7101 while (cur && *cur) {
7102 if (strncmp("palette:", cur, 8) == 0) {
7103 int i, count;
7104 count = sscanf(cur + 8,
7105 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7106 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7107 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7108 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7109 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7110 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7111 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7112 &palette[12], &palette[13], &palette[14], &palette[15]);
7113
7114 for (i = 0; i < count; i++) {
7115 palette[i] = rgb_to_yuv(palette[i]);
7116 }
7117 have_palette = 1;
7118 } else if (!strncmp("size:", cur, 5)) {
7119 sscanf(cur + 5, "%dx%d", &width, &height);
7120 have_size = 1;
7121 }
7122 if (have_palette && have_size)
7123 break;
7124 cur += strcspn(cur, "\n\r");
7125 cur += strspn(cur, "\n\r");
7126 }
7127 if (have_palette) {
7128 track->vos_data = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7129 if (!track->vos_data)
7130 return AVERROR(ENOMEM);
7131 for (i = 0; i < 16; i++) {
7132 AV_WB32(track->vos_data + i * 4, palette[i]);
7133 }
7134 memset(track->vos_data + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7135 track->vos_len = 16 * 4;
7136 }
7137 st->codecpar->width = width;
7138 st->codecpar->height = track->height = height;
7139
7140 return 0;
7141 }
7142
7143 197 static int mov_init_iamf_track(AVFormatContext *s)
7144 {
7145 197 MOVMuxContext *mov = s->priv_data;
7146 197 MOVTrack *track = &mov->tracks[0]; // IAMF if present is always the first track
7147 197 int nb_audio_elements = 0, nb_mix_presentations = 0;
7148 int ret;
7149
7150
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 197 times.
205 for (int i = 0; i < s->nb_stream_groups; i++) {
7151 8 const AVStreamGroup *stg = s->stream_groups[i];
7152
7153
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7154 4 nb_audio_elements++;
7155
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7156 4 nb_mix_presentations++;
7157 }
7158
7159
3/4
✓ Branch 0 taken 193 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 193 times.
✗ Branch 3 not taken.
197 if (!nb_audio_elements && !nb_mix_presentations)
7160 193 return 0;
7161
7162
3/6
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
4 if (nb_audio_elements < 1 || nb_audio_elements > 2 || nb_mix_presentations < 1) {
7163 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7164 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7165 return AVERROR(EINVAL);
7166 }
7167
7168 4 track->iamf = av_mallocz(sizeof(*track->iamf));
7169
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->iamf)
7170 return AVERROR(ENOMEM);
7171
7172
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (int i = 0; i < s->nb_stream_groups; i++) {
7173 8 const AVStreamGroup *stg = s->stream_groups[i];
7174
2/3
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 switch(stg->type) {
7175 4 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7176
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 for (int j = 0; j < stg->nb_streams; j++) {
7177 18 track->first_iamf_idx = FFMIN(stg->streams[j]->index, track->first_iamf_idx);
7178 18 track->last_iamf_idx = FFMAX(stg->streams[j]->index, track->last_iamf_idx);
7179 18 stg->streams[j]->priv_data = track;
7180 }
7181
7182 4 ret = ff_iamf_add_audio_element(track->iamf, stg, s);
7183 4 break;
7184 4 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7185 4 ret = ff_iamf_add_mix_presentation(track->iamf, stg, s);
7186 4 break;
7187 default:
7188 av_assert0(0);
7189 }
7190
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (ret < 0)
7191 return ret;
7192 }
7193
7194 4 track->tag = MKTAG('i','a','m','f');
7195
7196 4 ret = avio_open_dyn_buf(&track->iamf_buf);
7197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret < 0)
7198 return ret;
7199
7200 4 return 0;
7201 }
7202
7203 197 static int mov_init(AVFormatContext *s)
7204 {
7205 197 MOVMuxContext *mov = s->priv_data;
7206 int i, ret;
7207
7208 197 mov->fc = s;
7209 197 mov->pkt = ffformatcontext(s)->pkt;
7210
7211 /* Default mode == MP4 */
7212 197 mov->mode = MODE_MP4;
7213
7214 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7215
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7216
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7217
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 59 times.
197 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7218
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 58 times.
59 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7219
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 57 times.
58 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7220
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 53 times.
57 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7222
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7223 #undef IS_MODE
7224
7225
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 180 times.
197 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7226 17 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7227
7228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (mov->mode == MODE_AVIF)
7229 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7230
7231 /* Set the FRAGMENT flag if any of the fragmentation methods are
7232 * enabled. */
7233
3/4
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 196 times.
✗ Branch 3 not taken.
197 if (mov->max_fragment_duration || mov->max_fragment_size ||
7234
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 168 times.
196 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7235 FF_MOV_FLAG_FRAG_KEYFRAME |
7236 FF_MOV_FLAG_FRAG_CUSTOM |
7237 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7238 29 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7239
7240 /* Set other implicit flags immediately */
7241
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 193 times.
197 if (mov->mode == MODE_ISM)
7242 4 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
7243 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7244
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 186 times.
197 if (mov->flags & FF_MOV_FLAG_DASH)
7245 11 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7246 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
7247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (mov->flags & FF_MOV_FLAG_CMAF)
7248 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7249 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7250
7251
4/4
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 1 times.
197 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
7252 28 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7253 28 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
7254 }
7255
7256
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
197 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
7257 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
7258 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
7259 }
7260
7261
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 194 times.
197 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7262 3 mov->reserved_moov_size = -1;
7263 }
7264
7265
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 7 times.
197 if (mov->use_editlist < 0) {
7266 190 mov->use_editlist = 1;
7267
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 165 times.
190 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7268
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 15 times.
25 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7269 // If we can avoid needing an edit list by shifting the
7270 // tracks, prefer that over (trying to) write edit lists
7271 // in fragmented output.
7272
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
7273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
7274 9 mov->use_editlist = 0;
7275 }
7276
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 190 times.
190 if (mov->flags & FF_MOV_FLAG_CMAF) {
7277 // CMAF Track requires negative cts offsets without edit lists
7278 mov->use_editlist = 0;
7279 }
7280 }
7281
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 168 times.
197 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7282
4/4
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 11 times.
29 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
7283 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7284
7285
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
197 if (mov->flags & FF_MOV_FLAG_CMAF && mov->use_editlist) {
7286 av_log(s, AV_LOG_WARNING, "Edit list enabled; Assuming writing CMAF Track File\n");
7287 mov->flags &= ~FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7288 }
7289
4/4
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 182 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 1 times.
197 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
7290
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 5 times.
14 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
7291 9 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
7292
7293 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7294 * if the latter is set that's enough and omit_tfhd_offset doesn't
7295 * add anything extra on top of that. */
7296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
7297 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
7298 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
7299
7300
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (mov->frag_interleave &&
7301 mov->flags & (FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF)) {
7302 av_log(s, AV_LOG_ERROR,
7303 "Sample interleaving in fragments is mutually exclusive with "
7304 "omit_tfhd_offset and separate_moof\n");
7305 return AVERROR(EINVAL);
7306 }
7307
7308 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
7309 * is enabled, we don't support non-seekable output at all. */
7310
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 170 times.
197 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
7311
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
✗ Branch 3 not taken.
27 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
7312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 27 times.
27 mov->mode == MODE_AVIF)) {
7313 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
7314 return AVERROR(EINVAL);
7315 }
7316
7317 /* AVIF output must have at most two video streams (one for YUV and one for
7318 * alpha). */
7319
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (mov->mode == MODE_AVIF) {
7320 if (s->nb_streams > 2) {
7321 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
7322 return AVERROR(EINVAL);
7323 }
7324 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
7325 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
7326 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
7327 return AVERROR(EINVAL);
7328 }
7329 if (s->nb_streams > 1) {
7330 const AVPixFmtDescriptor *pixdesc =
7331 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
7332 if (pixdesc->nb_components != 1) {
7333 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
7334 return AVERROR(EINVAL);
7335 }
7336 }
7337 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
7338 }
7339
7340
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 197 times.
205 for (i = 0; i < s->nb_stream_groups; i++) {
7341 8 AVStreamGroup *stg = s->stream_groups[i];
7342
7343
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7344 4 continue;
7345
7346
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 4 times.
22 for (int j = 0; j < stg->nb_streams; j++) {
7347 18 AVStream *st = stg->streams[j];
7348
7349
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (st->priv_data) {
7350 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
7351 "IAMF Audio Element\n", j);
7352 return AVERROR(EINVAL);
7353 }
7354 18 st->priv_data = st;
7355 }
7356
7357
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (!mov->nb_tracks) // We support one track for the entire IAMF structure
7358 4 mov->nb_tracks++;
7359 }
7360
7361
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 197 times.
462 for (i = 0; i < s->nb_streams; i++) {
7362 265 AVStream *st = s->streams[i];
7363
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 247 times.
265 if (st->priv_data)
7364 18 continue;
7365 247 st->priv_data = st;
7366 247 mov->nb_tracks++;
7367 }
7368
7369 197 mov->nb_streams = mov->nb_tracks;
7370
7371
4/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 191 times.
197 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
7372 1 mov->chapter_track = mov->nb_tracks++;
7373
7374
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 196 times.
197 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
7375
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
7376
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
7377 2 mov->nb_tracks++;
7378 }
7379
7380
1/2
✓ Branch 0 taken 197 times.
✗ Branch 1 not taken.
197 if (mov->write_btrt < 0) {
7381 197 mov->write_btrt = mov->mode == MODE_MP4;
7382 }
7383
7384
6/6
✓ Branch 0 taken 194 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 138 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 53 times.
197 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
7385
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 || mov->write_tmcd == 1) {
7386 194 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
7387 NULL, 0);
7388
7389 /* +1 tmcd track for each video stream with a timecode */
7390
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 194 times.
454 for (i = 0; i < s->nb_streams; i++) {
7391 260 AVStream *st = s->streams[i];
7392 260 AVDictionaryEntry *t = global_tcr;
7393
4/4
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 95 times.
✓ Branch 2 taken 158 times.
✓ Branch 3 taken 7 times.
260 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
7394
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 158 times.
158 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
7395 AVTimecode tc;
7396 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
7397
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
7398 7 mov->nb_meta_tmcd++;
7399 }
7400 }
7401
7402 /* check if there is already a tmcd track to remux */
7403
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 187 times.
194 if (mov->nb_meta_tmcd) {
7404
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
7405 13 AVStream *st = s->streams[i];
7406
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
7407 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
7408 "so timecode metadata are now ignored\n");
7409 3 mov->nb_meta_tmcd = 0;
7410 }
7411 }
7412 }
7413
7414 194 mov->nb_tracks += mov->nb_meta_tmcd;
7415 }
7416
7417 // Reserve an extra stream for chapters for the case where chapters
7418 // are written in the trailer
7419 197 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
7420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (!mov->tracks)
7421 return AVERROR(ENOMEM);
7422
7423
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
197 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
7424 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
7425 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
7426
7427 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
7428 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
7429 mov->encryption_key_len, AES_CTR_KEY_SIZE);
7430 return AVERROR(EINVAL);
7431 }
7432
7433 if (mov->encryption_kid_len != CENC_KID_SIZE) {
7434 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
7435 mov->encryption_kid_len, CENC_KID_SIZE);
7436 return AVERROR(EINVAL);
7437 }
7438 } else {
7439 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
7440 mov->encryption_scheme_str);
7441 return AVERROR(EINVAL);
7442 }
7443 }
7444
7445 197 ret = mov_init_iamf_track(s);
7446
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (ret < 0)
7447 return ret;
7448
7449
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 197 times.
462 for (int j = 0, i = 0; j < s->nb_streams; j++) {
7450 265 AVStream *st = s->streams[j];
7451
7452
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 247 times.
265 if (st != st->priv_data)
7453 18 continue;
7454 247 st->priv_data = &mov->tracks[i++];
7455 }
7456
7457
2/2
✓ Branch 0 taken 265 times.
✓ Branch 1 taken 197 times.
462 for (i = 0; i < s->nb_streams; i++) {
7458 265 AVStream *st= s->streams[i];
7459 265 MOVTrack *track = st->priv_data;
7460 265 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
7461
7462
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 14 times.
265 if (!track->st) {
7463 251 track->st = st;
7464 251 track->par = st->codecpar;
7465 }
7466
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 242 times.
265 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
7467
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 119 times.
265 if (track->language < 0)
7468 146 track->language = 32767; // Unspecified Macintosh language code
7469 265 track->mode = mov->mode;
7470
2/2
✓ Branch 0 taken 247 times.
✓ Branch 1 taken 18 times.
265 if (!track->tag)
7471 247 track->tag = mov_find_codec_tag(s, track);
7472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
265 if (!track->tag) {
7473 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
7474 "codec not currently supported in container\n",
7475 avcodec_get_name(st->codecpar->codec_id), i);
7476 return AVERROR(EINVAL);
7477 }
7478 /* If hinting of this track is enabled by a later hint track,
7479 * this is updated. */
7480 265 track->hint_track = -1;
7481 265 track->start_dts = AV_NOPTS_VALUE;
7482 265 track->start_cts = AV_NOPTS_VALUE;
7483 265 track->end_pts = AV_NOPTS_VALUE;
7484 265 track->dts_shift = AV_NOPTS_VALUE;
7485
2/2
✓ Branch 0 taken 167 times.
✓ Branch 1 taken 98 times.
265 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
7486
2/4
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 167 times.
✗ Branch 3 not taken.
167 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
7487
2/4
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 167 times.
✗ Branch 3 not taken.
167 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
7488
2/4
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 167 times.
167 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
7489 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
7490 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
7491 return AVERROR(EINVAL);
7492 }
7493 track->height = track->tag >> 24 == 'n' ? 486 : 576;
7494 }
7495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 if (mov->video_track_timescale) {
7496 track->timescale = mov->video_track_timescale;
7497 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
7498 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
7499 } else {
7500 167 track->timescale = st->time_base.den;
7501
2/2
✓ Branch 0 taken 1381 times.
✓ Branch 1 taken 167 times.
1548 while(track->timescale < 10000)
7502 1381 track->timescale *= 2;
7503 }
7504
2/4
✓ Branch 0 taken 167 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 167 times.
167 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
7505 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
7506 return AVERROR(EINVAL);
7507 }
7508
4/4
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 121 times.
167 if (track->mode == MODE_MOV && track->timescale > 100000)
7509 1 av_log(s, AV_LOG_WARNING,
7510 "WARNING codec timebase is very high. If duration is too long,\n"
7511 "file may not be playable by quicktime. Specify a shorter timebase\n"
7512 "or choose different container.\n");
7513
2/2
✓ Branch 0 taken 122 times.
✓ Branch 1 taken 45 times.
167 if (track->mode == MODE_MOV &&
7514
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 110 times.
122 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 track->tag == MKTAG('r','a','w',' ')) {
7516 enum AVPixelFormat pix_fmt = track->par->format;
7517 if (pix_fmt == AV_PIX_FMT_NONE && track->par->bits_per_coded_sample == 1)
7518 pix_fmt = AV_PIX_FMT_MONOWHITE;
7519 track->is_unaligned_qt_rgb =
7520 pix_fmt == AV_PIX_FMT_RGB24 ||
7521 pix_fmt == AV_PIX_FMT_BGR24 ||
7522 pix_fmt == AV_PIX_FMT_PAL8 ||
7523 pix_fmt == AV_PIX_FMT_GRAY8 ||
7524 pix_fmt == AV_PIX_FMT_MONOWHITE ||
7525 pix_fmt == AV_PIX_FMT_MONOBLACK;
7526 }
7527
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
167 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
7528 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
7529 return AVERROR(EINVAL);
7530
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 166 times.
167 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
7531
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) {
7532 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
7533 return AVERROR(EINVAL);
7534
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 167 times.
167 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
7535 /* altref frames handling is not defined in the spec as of version v1.0,
7536 * so just forbid muxing VP8 streams altogether until a new version does */
7537 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
7538 return AVERROR_PATCHWELCOME;
7539 }
7540
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 165 times.
167 if (is_cover_image(st)) {
7541 2 track->cover_image = av_packet_alloc();
7542
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
7543 return AVERROR(ENOMEM);
7544 }
7545
2/2
✓ Branch 0 taken 91 times.
✓ Branch 1 taken 7 times.
98 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
7546 91 track->timescale = st->codecpar->sample_rate;
7547
4/4
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 34 times.
✓ Branch 3 taken 33 times.
✓ Branch 4 taken 24 times.
91 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
7548 33 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
7549 33 track->audio_vbr = 1;
7550
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
7551
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
7552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 58 times.
58 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
7553 if (!st->codecpar->block_align) {
7554 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
7555 return AVERROR(EINVAL);
7556 }
7557 track->sample_size = st->codecpar->block_align;
7558
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 24 times.
58 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
7559 34 track->audio_vbr = 1;
7560 }else{
7561 24 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
7562 24 st->codecpar->ch_layout.nb_channels;
7563 }
7564
1/2
✓ Branch 0 taken 91 times.
✗ Branch 1 not taken.
91 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
7565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 91 times.
91 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
7566 track->audio_vbr = 1;
7567 }
7568
2/2
✓ Branch 0 taken 60 times.
✓ Branch 1 taken 31 times.
91 if (track->mode != MODE_MOV &&
7569
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
60 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
7570 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
7571 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
7572 i, track->par->sample_rate);
7573 return AVERROR(EINVAL);
7574 } else {
7575 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
7576 i, track->par->sample_rate);
7577 }
7578 }
7579
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 18 times.
91 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
7580
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
7581
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 track->par->codec_id == AV_CODEC_ID_OPUS) {
7582
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (track->mode != MODE_MP4) {
7583 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
7584 return AVERROR(EINVAL);
7585 }
7586
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
7587 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
7588 av_log(s, AV_LOG_ERROR,
7589 "%s in MP4 support is experimental, add "
7590 "'-strict %d' if you want to use it.\n",
7591 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
7592 return AVERROR_EXPERIMENTAL;
7593 }
7594 }
7595
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
7596 3 track->timescale = st->time_base.den;
7597
7598
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (track->par->codec_id == AV_CODEC_ID_TTML) {
7599 /* 14496-30 requires us to use a single sample per fragment
7600 for TTML, for which we define a per-track flag.
7601
7602 We set the flag in case we are receiving TTML paragraphs
7603 from the input, in other words in case we are not doing
7604 stream copy. */
7605 2 track->squash_fragment_samples_to_one =
7606 2 ff_is_ttml_stream_paragraph_based(track->par);
7607
7608
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7609 track->squash_fragment_samples_to_one) {
7610 av_log(s, AV_LOG_ERROR,
7611 "Fragmentation is not currently supported for "
7612 "TTML in MP4/ISMV (track synchronization between "
7613 "subtitles and other media is not yet implemented)!\n");
7614 return AVERROR_PATCHWELCOME;
7615 }
7616
7617
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->mode != MODE_ISM &&
7618
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
7619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
7620 av_log(s, AV_LOG_ERROR,
7621 "ISMV style TTML support with the 'dfxp' tag in "
7622 "non-ISMV formats is not officially supported. Add "
7623 "'-strict unofficial' if you want to use it.\n");
7624 return AVERROR_EXPERIMENTAL;
7625 }
7626 }
7627
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
7628 4 track->timescale = st->time_base.den;
7629 } else {
7630 track->timescale = mov->movie_timescale;
7631 }
7632
1/2
✓ Branch 0 taken 265 times.
✗ Branch 1 not taken.
265 if (!track->height)
7633 265 track->height = st->codecpar->height;
7634 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
7635 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
7636 for video tracks, so if user-set, it isn't overwritten */
7637
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 260 times.
265 if (mov->mode == MODE_ISM &&
7638
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
7639
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))) {
7640 5 track->timescale = 10000000;
7641 }
7642
7643 265 avpriv_set_pts_info(st, 64, 1, track->timescale);
7644
7645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
265 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
7646 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
7647 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
7648 track->par->codec_id == AV_CODEC_ID_VVC),
7649 s->flags & AVFMT_FLAG_BITEXACT);
7650 if (ret)
7651 return ret;
7652 }
7653 }
7654
7655 197 enable_tracks(s);
7656 197 return 0;
7657 }
7658
7659 197 static int mov_write_header(AVFormatContext *s)
7660 {
7661 197 AVIOContext *pb = s->pb;
7662 197 MOVMuxContext *mov = s->priv_data;
7663 197 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
7664
7665
4/4
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 191 times.
197 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
7666 1 nb_tracks++;
7667
7668
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 196 times.
197 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
7669 1 hint_track = nb_tracks;
7670
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
7671
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
7672 2 nb_tracks++;
7673 }
7674 }
7675
7676
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 191 times.
197 if (mov->nb_meta_tmcd)
7677 6 tmcd_track = nb_tracks;
7678
7679
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 197 times.
448 for (int i = 0; i < mov->nb_streams; i++) {
7680 251 MOVTrack *track = &mov->tracks[i];
7681 251 AVStream *st = track->st;
7682
7683 /* copy extradata if it exists */
7684
2/2
✓ Branch 0 taken 107 times.
✓ Branch 1 taken 144 times.
251 if (st->codecpar->extradata_size) {
7685
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 107 times.
107 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
7686 mov_create_dvd_sub_decoder_specific_info(track, st);
7687
15/30
✓ Branch 0 taken 107 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 107 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 107 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 107 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 107 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 107 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 107 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 107 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 107 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 107 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 107 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 107 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 107 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 107 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 107 times.
✗ Branch 29 not taken.
107 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
7688 107 track->vos_len = st->codecpar->extradata_size;
7689 107 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
7690
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 107 times.
107 if (!track->vos_data) {
7691 return AVERROR(ENOMEM);
7692 }
7693 107 memcpy(track->vos_data, st->codecpar->extradata, track->vos_len);
7694 107 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7695 }
7696 }
7697
7698
4/4
✓ Branch 0 taken 77 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 64 times.
✓ Branch 3 taken 13 times.
328 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
7699 77 av_channel_layout_compare(&track->par->ch_layout,
7700 77 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
7701 238 continue;
7702
7703
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 13 times.
44 for (int j = 0; j < mov->nb_streams; j++) {
7704 31 AVStream *stj= mov->tracks[j].st;
7705 31 MOVTrack *trackj= &mov->tracks[j];
7706
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 18 times.
31 if (j == i)
7707 13 continue;
7708
7709
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
18 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
7710
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 ||
7711 7 !av_channel_layout_compare(&trackj->par->ch_layout,
7712 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
7713 )
7714 4 track->mono_as_fc = -1;
7715
7716
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
29 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
7717 11 av_channel_layout_compare(&trackj->par->ch_layout,
7718 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
7719
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
7720 )
7721 7 track->mono_as_fc++;
7722
7723
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
29 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
7724 11 av_channel_layout_compare(&trackj->par->ch_layout,
7725 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
7726 trackj->language != track->language ||
7727 trackj->tag != track->tag
7728 )
7729 18 continue;
7730 track->multichannel_as_mono++;
7731 }
7732 }
7733
7734
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 17 times.
197 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7735
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
180 if ((ret = mov_write_identification(pb, s)) < 0)
7736 return ret;
7737 }
7738
7739
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 194 times.
197 if (mov->reserved_moov_size){
7740 3 mov->reserved_header_pos = avio_tell(pb);
7741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
7742 avio_skip(pb, mov->reserved_moov_size);
7743 }
7744
7745
2/2
✓ Branch 0 taken 32 times.
✓ Branch 1 taken 165 times.
197 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
7746 /* If no fragmentation options have been set, set a default. */
7747
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 29 times.
32 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
7748 FF_MOV_FLAG_FRAG_CUSTOM |
7749 3 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
7750
2/4
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
3 !mov->max_fragment_duration && !mov->max_fragment_size)
7751 3 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
7752
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 } else if (mov->mode != MODE_AVIF) {
7753
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 162 times.
165 if (mov->flags & FF_MOV_FLAG_FASTSTART)
7754 3 mov->reserved_header_pos = avio_tell(pb);
7755 165 mov_write_mdat_tag(pb, mov);
7756 }
7757
7758 197 ff_parse_creation_time_metadata(s, &mov->time, 1);
7759
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (mov->time)
7760 mov->time += 0x7C25B080; // 1970 based -> 1904 based
7761
7762
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 196 times.
197 if (mov->chapter_track)
7763
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
7764 return ret;
7765
7766
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 196 times.
197 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
7767
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
7768
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
7769
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
7770 return ret;
7771 2 hint_track++;
7772 }
7773 }
7774 }
7775
7776
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 191 times.
197 if (mov->nb_meta_tmcd) {
7777 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
7778 "timecode", NULL, 0);
7779 /* Initialize the tmcd tracks */
7780
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
7781 8 AVStream *st = mov->tracks[i].st;
7782 8 t = global_tcr;
7783
7784
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
7785 AVTimecode tc;
7786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
7787 t = av_dict_get(st->metadata, "timecode", NULL, 0);
7788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
7789 continue;
7790
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
7791 continue;
7792
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
7793 return ret;
7794 6 tmcd_track++;
7795 }
7796 }
7797 }
7798
7799 197 avio_flush(pb);
7800
7801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 197 times.
197 if (mov->flags & FF_MOV_FLAG_ISML)
7802 mov_write_isml_manifest(pb, mov, s);
7803
7804
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 168 times.
197 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7805
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 17 times.
29 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7806
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
7807 return ret;
7808 12 mov->moov_written = 1;
7809
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
7810 mov->reserved_header_pos = avio_tell(pb);
7811 }
7812
7813 197 return 0;
7814 }
7815
7816 26 static int get_moov_size(AVFormatContext *s)
7817 {
7818 int ret;
7819 AVIOContext *moov_buf;
7820 26 MOVMuxContext *mov = s->priv_data;
7821
7822
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
7823 return ret;
7824
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 26 times.
26 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
7825 return ret;
7826 26 return ffio_close_null_buf(moov_buf);
7827 }
7828
7829 static int get_sidx_size(AVFormatContext *s)
7830 {
7831 int ret;
7832 AVIOContext *buf;
7833 MOVMuxContext *mov = s->priv_data;
7834
7835 if ((ret = ffio_open_null_buf(&buf)) < 0)
7836 return ret;
7837 mov_write_sidx_tags(buf, mov, -1, 0);
7838 return ffio_close_null_buf(buf);
7839 }
7840
7841 /*
7842 * This function gets the moov size if moved to the top of the file: the chunk
7843 * offset table can switch between stco (32-bit entries) to co64 (64-bit
7844 * entries) when the moov is moved to the beginning, so the size of the moov
7845 * would change. It also updates the chunk offset tables.
7846 */
7847 3 static int compute_moov_size(AVFormatContext *s)
7848 {
7849 int i, moov_size, moov_size2;
7850 3 MOVMuxContext *mov = s->priv_data;
7851
7852 3 moov_size = get_moov_size(s);
7853
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
7854 return moov_size;
7855
7856
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
7857 8 mov->tracks[i].data_offset += moov_size;
7858
7859 3 moov_size2 = get_moov_size(s);
7860
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
7861 return moov_size2;
7862
7863 /* if the size changed, we just switched from stco to co64 and need to
7864 * update the offsets */
7865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
7866 for (i = 0; i < mov->nb_tracks; i++)
7867 mov->tracks[i].data_offset += moov_size2 - moov_size;
7868
7869 3 return moov_size2;
7870 }
7871
7872 static int compute_sidx_size(AVFormatContext *s)
7873 {
7874 int i, sidx_size;
7875 MOVMuxContext *mov = s->priv_data;
7876
7877 sidx_size = get_sidx_size(s);
7878 if (sidx_size < 0)
7879 return sidx_size;
7880
7881 for (i = 0; i < mov->nb_tracks; i++)
7882 mov->tracks[i].data_offset += sidx_size;
7883
7884 return sidx_size;
7885 }
7886
7887 3 static int shift_data(AVFormatContext *s)
7888 {
7889 int moov_size;
7890 3 MOVMuxContext *mov = s->priv_data;
7891
7892
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
7893 moov_size = compute_sidx_size(s);
7894 else
7895 3 moov_size = compute_moov_size(s);
7896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
7897 return moov_size;
7898
7899 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
7900 }
7901
7902 197 static int mov_write_trailer(AVFormatContext *s)
7903 {
7904 197 MOVMuxContext *mov = s->priv_data;
7905 197 AVIOContext *pb = s->pb;
7906 197 int res = 0;
7907 int i;
7908 int64_t moov_pos;
7909
7910
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 193 times.
197 if (mov->need_rewrite_extradata) {
7911
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 4 times.
8 for (i = 0; i < mov->nb_streams; i++) {
7912 4 MOVTrack *track = &mov->tracks[i];
7913 4 AVCodecParameters *par = track->par;
7914
7915 4 track->vos_len = par->extradata_size;
7916 4 av_freep(&track->vos_data);
7917 4 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
7918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->vos_data)
7919 return AVERROR(ENOMEM);
7920 4 memcpy(track->vos_data, par->extradata, track->vos_len);
7921 4 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7922 }
7923 4 mov->need_rewrite_extradata = 0;
7924 }
7925
7926 /*
7927 * Before actually writing the trailer, make sure that there are no
7928 * dangling subtitles, that need a terminating sample.
7929 */
7930
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 197 times.
457 for (i = 0; i < mov->nb_tracks; i++) {
7931 260 MOVTrack *trk = &mov->tracks[i];
7932
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 259 times.
260 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7933
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
7934 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
7935 1 trk->last_sample_is_subtitle_end = 1;
7936 }
7937 }
7938
7939 // Check if we have any tracks that require squashing.
7940 // In that case, we'll have to write the packet here.
7941
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 197 times.
197 if ((res = mov_write_squashed_packets(s)) < 0)
7942 return res;
7943
7944 // If there were no chapters when the header was written, but there
7945 // are chapters now, write them in the trailer. This only works
7946 // when we are not doing fragments.
7947
4/4
✓ Branch 0 taken 196 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 164 times.
✓ Branch 3 taken 32 times.
197 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
7948
3/4
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 163 times.
164 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
7949 mov->chapter_track = mov->nb_tracks++;
7950 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
7951 return res;
7952 }
7953 }
7954
7955
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 32 times.
197 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
7956 165 moov_pos = avio_tell(pb);
7957
7958 /* Write size of mdat tag */
7959
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 if (mov->mdat_size + 8 <= UINT32_MAX) {
7960 165 avio_seek(pb, mov->mdat_pos, SEEK_SET);
7961 165 avio_wb32(pb, mov->mdat_size + 8);
7962 } else {
7963 /* overwrite 'wide' placeholder atom */
7964 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
7965 /* special value: real atom size will be 64 bit value after
7966 * tag field */
7967 avio_wb32(pb, 1);
7968 ffio_wfourcc(pb, "mdat");
7969 avio_wb64(pb, mov->mdat_size + 16);
7970 }
7971
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
165 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
7972
7973
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 162 times.
165 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7974 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
7975 3 res = shift_data(s);
7976
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
7977 return res;
7978 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
7979
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
7980 return res;
7981
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 162 times.
162 } else if (mov->reserved_moov_size > 0) {
7982 int64_t size;
7983 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
7984 return res;
7985 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
7986 if (size < 8){
7987 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
7988 return AVERROR(EINVAL);
7989 }
7990 avio_wb32(pb, size);
7991 ffio_wfourcc(pb, "free");
7992 ffio_fill(pb, 0, size - 8);
7993 avio_seek(pb, moov_pos, SEEK_SET);
7994 } else {
7995
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 162 times.
162 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
7996 return res;
7997 }
7998 165 res = 0;
7999 } else {
8000 32 mov_auto_flush_fragment(s, 1);
8001
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 32 times.
93 for (i = 0; i < mov->nb_tracks; i++)
8002 61 mov->tracks[i].data_offset = 0;
8003
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8004 int64_t end;
8005 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8006 res = shift_data(s);
8007 if (res < 0)
8008 return res;
8009 end = avio_tell(pb);
8010 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8011 mov_write_sidx_tags(pb, mov, -1, 0);
8012 avio_seek(pb, end, SEEK_SET);
8013 }
8014
1/2
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
32 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8015 32 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8016 32 res = mov_write_mfra_tag(pb, mov);
8017
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 if (res < 0)
8018 return res;
8019 }
8020 }
8021
8022 197 return res;
8023 }
8024
8025 212 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8026 const AVPacket *pkt)
8027 {
8028 212 int ret = 1;
8029
8030
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 203 times.
212 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8031
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)
8032 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8033
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 203 times.
203 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8034 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8035 }
8036
8037 212 return ret;
8038 }
8039
8040 #if CONFIG_AVIF_MUXER
8041 static int avif_write_trailer(AVFormatContext *s)
8042 {
8043 AVIOContext *pb = s->pb;
8044 MOVMuxContext *mov = s->priv_data;
8045 int64_t pos_backup, extent_offsets[2];
8046 uint8_t *buf;
8047 int buf_size, moov_size;
8048
8049 if (mov->moov_written) return 0;
8050
8051 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8052 if (mov->is_animated_avif && mov->nb_streams > 1) {
8053 // For animated avif with alpha channel, we need to write a tref tag
8054 // with type "auxl".
8055 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8056 mov->tracks[1].tref_id = 1;
8057 }
8058 mov_write_identification(pb, s);
8059 mov_write_meta_tag(pb, mov, s);
8060
8061 moov_size = get_moov_size(s);
8062 for (int i = 0; i < mov->nb_tracks; i++)
8063 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8064
8065 if (mov->is_animated_avif) {
8066 int ret;
8067 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8068 return ret;
8069 }
8070
8071 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8072 avio_wb32(pb, buf_size + 8);
8073 ffio_wfourcc(pb, "mdat");
8074
8075 // The offset for the YUV planes is the starting position of mdat.
8076 extent_offsets[0] = avio_tell(pb);
8077 // The offset for alpha plane is YUV offset + YUV size.
8078 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8079
8080 avio_write(pb, buf, buf_size);
8081
8082 // write extent offsets.
8083 pos_backup = avio_tell(pb);
8084 for (int i = 0; i < mov->nb_streams; i++) {
8085 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8086 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8087 return AVERROR_INVALIDDATA;
8088 }
8089 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8090 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8091 }
8092 avio_seek(pb, pos_backup, SEEK_SET);
8093
8094 return 0;
8095 }
8096 #endif
8097
8098 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8099 static const AVCodecTag codec_3gp_tags[] = {
8100 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8101 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8102 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8103 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8104 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8105 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8106 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8107 { AV_CODEC_ID_NONE, 0 },
8108 };
8109 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8110 #endif
8111
8112 static const AVCodecTag codec_mp4_tags[] = {
8113 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8114 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8115 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8116 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8117 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8118 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8119 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8120 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8121 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8122 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8123 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8124 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8125 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8126 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8127 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8128 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8129 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8130 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8131 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8132 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8133 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8134 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
8135 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
8136 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
8137 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
8138 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
8139 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
8140 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
8141 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
8142 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
8143 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
8144 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
8145 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
8146 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
8147 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
8148 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
8149 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
8150 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
8151 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
8152
8153 /* ISO/IEC 23003-5 integer formats */
8154 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
8155 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
8156 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
8157 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
8158 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
8159 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
8160 /* ISO/IEC 23003-5 floating-point formats */
8161 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
8162 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
8163 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
8164 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
8165
8166 { AV_CODEC_ID_NONE, 0 },
8167 };
8168 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8169 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
8170 #endif
8171
8172 static const AVCodecTag codec_ism_tags[] = {
8173 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
8174 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
8175 { AV_CODEC_ID_NONE , 0 },
8176 };
8177
8178 static const AVCodecTag codec_ipod_tags[] = {
8179 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8180 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8181 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8182 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
8183 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
8184 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8185 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
8186 { AV_CODEC_ID_NONE, 0 },
8187 };
8188
8189 static const AVCodecTag codec_f4v_tags[] = {
8190 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
8191 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8192 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8193 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
8194 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
8195 { AV_CODEC_ID_NONE, 0 },
8196 };
8197
8198 #if CONFIG_AVIF_MUXER
8199
8200 static const AVOption avif_options[] = {
8201 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
8202 { "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 },
8203 { NULL },
8204 };
8205 static const AVCodecTag codec_avif_tags[] = {
8206 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
8207 { AV_CODEC_ID_NONE, 0 },
8208 };
8209 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
8210
8211 static const AVClass mov_avif_muxer_class = {
8212 .class_name = "avif muxer",
8213 .item_name = av_default_item_name,
8214 .option = avif_options,
8215 .version = LIBAVUTIL_VERSION_INT,
8216 };
8217 #endif
8218
8219 #if CONFIG_MOV_MUXER
8220 const FFOutputFormat ff_mov_muxer = {
8221 .p.name = "mov",
8222 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8223 .p.extensions = "mov",
8224 .priv_data_size = sizeof(MOVMuxContext),
8225 .p.audio_codec = AV_CODEC_ID_AAC,
8226 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8227 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8228 .init = mov_init,
8229 .write_header = mov_write_header,
8230 .write_packet = mov_write_packet,
8231 .write_trailer = mov_write_trailer,
8232 .deinit = mov_free,
8233 #if FF_API_ALLOW_FLUSH
8234 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8235 #else
8236 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8237 #endif
8238 .p.codec_tag = (const AVCodecTag* const []){
8239 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
8240 },
8241 .check_bitstream = mov_check_bitstream,
8242 .p.priv_class = &mov_isobmff_muxer_class,
8243 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8244 };
8245 #endif
8246 #if CONFIG_TGP_MUXER
8247 const FFOutputFormat ff_tgp_muxer = {
8248 .p.name = "3gp",
8249 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
8250 .p.extensions = "3gp",
8251 .priv_data_size = sizeof(MOVMuxContext),
8252 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8253 .p.video_codec = AV_CODEC_ID_H263,
8254 .init = mov_init,
8255 .write_header = mov_write_header,
8256 .write_packet = mov_write_packet,
8257 .write_trailer = mov_write_trailer,
8258 .deinit = mov_free,
8259 #if FF_API_ALLOW_FLUSH
8260 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8261 #else
8262 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8263 #endif
8264 .p.codec_tag = codec_3gp_tags_list,
8265 .check_bitstream = mov_check_bitstream,
8266 .p.priv_class = &mov_isobmff_muxer_class,
8267 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8268 };
8269 #endif
8270 #if CONFIG_MP4_MUXER
8271 const FFOutputFormat ff_mp4_muxer = {
8272 .p.name = "mp4",
8273 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
8274 .p.mime_type = "video/mp4",
8275 .p.extensions = "mp4",
8276 .priv_data_size = sizeof(MOVMuxContext),
8277 .p.audio_codec = AV_CODEC_ID_AAC,
8278 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8279 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8280 .init = mov_init,
8281 .write_header = mov_write_header,
8282 .write_packet = mov_write_packet,
8283 .write_trailer = mov_write_trailer,
8284 .deinit = mov_free,
8285 #if FF_API_ALLOW_FLUSH
8286 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8287 #else
8288 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8289 #endif
8290 .p.codec_tag = mp4_codec_tags_list,
8291 .check_bitstream = mov_check_bitstream,
8292 .p.priv_class = &mov_isobmff_muxer_class,
8293 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8294 };
8295 #endif
8296 #if CONFIG_PSP_MUXER
8297 const FFOutputFormat ff_psp_muxer = {
8298 .p.name = "psp",
8299 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
8300 .p.extensions = "mp4,psp",
8301 .priv_data_size = sizeof(MOVMuxContext),
8302 .p.audio_codec = AV_CODEC_ID_AAC,
8303 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8304 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8305 .init = mov_init,
8306 .write_header = mov_write_header,
8307 .write_packet = mov_write_packet,
8308 .write_trailer = mov_write_trailer,
8309 .deinit = mov_free,
8310 #if FF_API_ALLOW_FLUSH
8311 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8312 #else
8313 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8314 #endif
8315 .p.codec_tag = mp4_codec_tags_list,
8316 .check_bitstream = mov_check_bitstream,
8317 .p.priv_class = &mov_isobmff_muxer_class,
8318 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8319 };
8320 #endif
8321 #if CONFIG_TG2_MUXER
8322 const FFOutputFormat ff_tg2_muxer = {
8323 .p.name = "3g2",
8324 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
8325 .p.extensions = "3g2",
8326 .priv_data_size = sizeof(MOVMuxContext),
8327 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8328 .p.video_codec = AV_CODEC_ID_H263,
8329 .init = mov_init,
8330 .write_header = mov_write_header,
8331 .write_packet = mov_write_packet,
8332 .write_trailer = mov_write_trailer,
8333 .deinit = mov_free,
8334 #if FF_API_ALLOW_FLUSH
8335 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8336 #else
8337 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8338 #endif
8339 .p.codec_tag = codec_3gp_tags_list,
8340 .check_bitstream = mov_check_bitstream,
8341 .p.priv_class = &mov_isobmff_muxer_class,
8342 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8343 };
8344 #endif
8345 #if CONFIG_IPOD_MUXER
8346 const FFOutputFormat ff_ipod_muxer = {
8347 .p.name = "ipod",
8348 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
8349 .p.mime_type = "video/mp4",
8350 .p.extensions = "m4v,m4a,m4b",
8351 .priv_data_size = sizeof(MOVMuxContext),
8352 .p.audio_codec = AV_CODEC_ID_AAC,
8353 .p.video_codec = AV_CODEC_ID_H264,
8354 .init = mov_init,
8355 .write_header = mov_write_header,
8356 .write_packet = mov_write_packet,
8357 .write_trailer = mov_write_trailer,
8358 .deinit = mov_free,
8359 #if FF_API_ALLOW_FLUSH
8360 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8361 #else
8362 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8363 #endif
8364 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
8365 .check_bitstream = mov_check_bitstream,
8366 .p.priv_class = &mov_isobmff_muxer_class,
8367 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8368 };
8369 #endif
8370 #if CONFIG_ISMV_MUXER
8371 const FFOutputFormat ff_ismv_muxer = {
8372 .p.name = "ismv",
8373 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
8374 .p.mime_type = "video/mp4",
8375 .p.extensions = "ismv,isma",
8376 .priv_data_size = sizeof(MOVMuxContext),
8377 .p.audio_codec = AV_CODEC_ID_AAC,
8378 .p.video_codec = AV_CODEC_ID_H264,
8379 .init = mov_init,
8380 .write_header = mov_write_header,
8381 .write_packet = mov_write_packet,
8382 .write_trailer = mov_write_trailer,
8383 .deinit = mov_free,
8384 #if FF_API_ALLOW_FLUSH
8385 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8386 #else
8387 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8388 #endif
8389 .p.codec_tag = (const AVCodecTag* const []){
8390 codec_mp4_tags, codec_ism_tags, 0 },
8391 .check_bitstream = mov_check_bitstream,
8392 .p.priv_class = &mov_isobmff_muxer_class,
8393 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8394 };
8395 #endif
8396 #if CONFIG_F4V_MUXER
8397 const FFOutputFormat ff_f4v_muxer = {
8398 .p.name = "f4v",
8399 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
8400 .p.mime_type = "application/f4v",
8401 .p.extensions = "f4v",
8402 .priv_data_size = sizeof(MOVMuxContext),
8403 .p.audio_codec = AV_CODEC_ID_AAC,
8404 .p.video_codec = AV_CODEC_ID_H264,
8405 .init = mov_init,
8406 .write_header = mov_write_header,
8407 .write_packet = mov_write_packet,
8408 .write_trailer = mov_write_trailer,
8409 .deinit = mov_free,
8410 #if FF_API_ALLOW_FLUSH
8411 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
8412 #else
8413 .p.flags = AVFMT_GLOBALHEADER,
8414 #endif
8415 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
8416 .check_bitstream = mov_check_bitstream,
8417 .p.priv_class = &mov_isobmff_muxer_class,
8418 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8419 };
8420 #endif
8421 #if CONFIG_AVIF_MUXER
8422 const FFOutputFormat ff_avif_muxer = {
8423 .p.name = "avif",
8424 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
8425 .p.mime_type = "image/avif",
8426 .p.extensions = "avif",
8427 .priv_data_size = sizeof(MOVMuxContext),
8428 .p.video_codec = AV_CODEC_ID_AV1,
8429 .init = mov_init,
8430 .write_header = mov_write_header,
8431 .write_packet = mov_write_packet,
8432 .write_trailer = avif_write_trailer,
8433 .deinit = mov_free,
8434 #if FF_API_ALLOW_FLUSH
8435 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
8436 #else
8437 .p.flags = AVFMT_GLOBALHEADER,
8438 #endif
8439 .p.codec_tag = codec_avif_tags_list,
8440 .p.priv_class = &mov_avif_muxer_class,
8441 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8442 };
8443 #endif
8444