FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2025-01-20 09:27:23
Exec Total Coverage
Lines: 3591 5367 66.9%
Functions: 172 224 76.8%
Branches: 2102 3681 57.1%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <stdint.h>
27 #include <inttypes.h>
28
29 #include "movenc.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
33 #include "riff.h"
34 #include "avio.h"
35 #include "iamf_writer.h"
36 #include "isom.h"
37 #include "av1.h"
38 #include "avc.h"
39 #include "evc.h"
40 #include "libavcodec/ac3_parser_internal.h"
41 #include "libavcodec/dnxhddata.h"
42 #include "libavcodec/flac.h"
43 #include "libavcodec/get_bits.h"
44
45 #include "libavcodec/internal.h"
46 #include "libavcodec/put_bits.h"
47 #include "libavcodec/vc1_common.h"
48 #include "libavcodec/raw.h"
49 #include "internal.h"
50 #include "libavutil/avstring.h"
51 #include "libavutil/channel_layout.h"
52 #include "libavutil/csp.h"
53 #include "libavutil/intfloat.h"
54 #include "libavutil/mathematics.h"
55 #include "libavutil/libm.h"
56 #include "libavutil/mem.h"
57 #include "libavutil/opt.h"
58 #include "libavutil/dict.h"
59 #include "libavutil/pixdesc.h"
60 #include "libavutil/stereo3d.h"
61 #include "libavutil/timecode.h"
62 #include "libavutil/dovi_meta.h"
63 #include "libavutil/uuid.h"
64 #include "hevc.h"
65 #include "rtpenc.h"
66 #include "nal.h"
67 #include "mov_chan.h"
68 #include "movenc_ttml.h"
69 #include "mux.h"
70 #include "rawutils.h"
71 #include "ttmlenc.h"
72 #include "version.h"
73 #include "vpcc.h"
74 #include "vvc.h"
75
76 static const AVOption options[] = {
77 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
78 { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext, empty_hdlr_name), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
79 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
80 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext, encryption_scheme_str), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
82 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
83 { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
84 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
85 { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
86 { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
87 { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
88 { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 255, AV_OPT_FLAG_ENCODING_PARAM},
89 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
90 { "cmaf", "Write CMAF compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_CMAF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
91 { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
92 { "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
93 { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
94 { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
95 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
96 { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
97 { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
98 { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
99 { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
100 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
101 { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
102 { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
103 { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = 0 },
104 { "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
105 { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
106 { "prefer_icc", "If writing colr atom prioritise usage of ICC profile if it exists in stream packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_PREFER_ICC}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
107 { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
108 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
109 { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
110 { "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_TRAILER}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
111 { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
112 { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
113 { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
114 { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_HYBRID_FRAGMENTED}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
115 { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext, min_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
116 { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM},
117 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
118 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
119 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
120 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
121 { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
122 { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
123 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
124 { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
125 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
126 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
127 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
128 { NULL },
129 };
130
131 static const AVClass mov_isobmff_muxer_class = {
132 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
133 .item_name = av_default_item_name,
134 .option = options,
135 .version = LIBAVUTIL_VERSION_INT,
136 };
137
138 static int get_moov_size(AVFormatContext *s);
139 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
140
141 24 static int utf8len(const uint8_t *b)
142 {
143 24 int len = 0;
144 int val;
145
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 24 times.
497 while (*b) {
146
3/8
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 473 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 473 times.
473 GET_UTF8(val, *b++, return -1;)
147 473 len++;
148 }
149 24 return len;
150 }
151
152 //FIXME support 64 bit variant with wide placeholders
153 6185 static int64_t update_size(AVIOContext *pb, int64_t pos)
154 {
155 6185 int64_t curpos = avio_tell(pb);
156 6185 avio_seek(pb, pos, SEEK_SET);
157 6185 avio_wb32(pb, curpos - pos); /* rewrite size */
158 6185 avio_seek(pb, curpos, SEEK_SET);
159
160 6185 return curpos - pos;
161 }
162
163 333 static int co64_required(const MOVTrack *track)
164 {
165
3/4
✓ Branch 0 taken 243 times.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 243 times.
333 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
166 return 1;
167 333 return 0;
168 }
169
170 19261 static int is_cover_image(const AVStream *st)
171 {
172 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
173 * is encoded as sparse video track */
174
3/4
✓ Branch 0 taken 19261 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 19249 times.
19261 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
175 }
176
177 6 static int rtp_hinting_needed(const AVStream *st)
178 {
179 /* Add hint tracks for each real audio and video stream */
180
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
181 return 0;
182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
183
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
184 }
185
186 /* Chunk offset atom */
187 333 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
188 {
189 int i;
190 333 int mode64 = co64_required(track); // use 32 bit size variant if possible
191 333 int64_t pos = avio_tell(pb);
192 333 avio_wb32(pb, 0); /* size */
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mode64)
194 ffio_wfourcc(pb, "co64");
195 else
196 333 ffio_wfourcc(pb, "stco");
197 333 avio_wb32(pb, 0); /* version & flags */
198 333 avio_wb32(pb, track->chunkCount); /* entry count */
199
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
200
2/2
✓ Branch 0 taken 10483 times.
✓ Branch 1 taken 3098 times.
13581 if (!track->cluster[i].chunkNum)
201 10483 continue;
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3098 times.
3098 if (mode64 == 1)
203 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
204 else
205 3098 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
206 }
207 333 return update_size(pb, pos);
208 }
209
210 /* Sample size atom */
211 333 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
212 {
213 333 int equalChunks = 1;
214 333 int i, j, entries = 0, tst = -1, oldtst = -1;
215
216 333 int64_t pos = avio_tell(pb);
217 333 avio_wb32(pb, 0); /* size */
218 333 ffio_wfourcc(pb, "stsz");
219 333 avio_wb32(pb, 0); /* version & flags */
220
221
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
222 13581 tst = track->cluster[i].size / track->cluster[i].entries;
223
4/4
✓ Branch 0 taken 13338 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 8730 times.
✓ Branch 3 taken 4608 times.
13581 if (oldtst != -1 && tst != oldtst)
224 8730 equalChunks = 0;
225 13581 oldtst = tst;
226 13581 entries += track->cluster[i].entries;
227 }
228
4/4
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 90 times.
442 if (equalChunks && track->entry) {
229
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
230 109 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
231 109 avio_wb32(pb, sSize); // sample size
232 109 avio_wb32(pb, entries); // sample count
233 } else {
234 224 avio_wb32(pb, 0); // sample size
235 224 avio_wb32(pb, entries); // sample count
236
2/2
✓ Branch 0 taken 9892 times.
✓ Branch 1 taken 224 times.
10116 for (i = 0; i < track->entry; i++) {
237
2/2
✓ Branch 0 taken 9892 times.
✓ Branch 1 taken 9892 times.
19784 for (j = 0; j < track->cluster[i].entries; j++) {
238 9892 avio_wb32(pb, track->cluster[i].size /
239 9892 track->cluster[i].entries);
240 }
241 }
242 }
243 333 return update_size(pb, pos);
244 }
245
246 /* Sample to chunk atom */
247 333 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
248 {
249 333 int index = 0, oldval = -1, i;
250 int64_t entryPos, curpos;
251
252 333 int64_t pos = avio_tell(pb);
253 333 avio_wb32(pb, 0); /* size */
254 333 ffio_wfourcc(pb, "stsc");
255 333 avio_wb32(pb, 0); // version & flags
256 333 entryPos = avio_tell(pb);
257 333 avio_wb32(pb, track->chunkCount); // entry count
258
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
259
4/4
✓ Branch 0 taken 11299 times.
✓ Branch 1 taken 2282 times.
✓ Branch 2 taken 816 times.
✓ Branch 3 taken 10483 times.
13581 if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) {
260 816 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
261 816 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
262 816 avio_wb32(pb, 0x1); // sample description index
263 816 oldval = track->cluster[i].samples_in_chunk;
264 816 index++;
265 }
266 }
267 333 curpos = avio_tell(pb);
268 333 avio_seek(pb, entryPos, SEEK_SET);
269 333 avio_wb32(pb, index); // rewrite size
270 333 avio_seek(pb, curpos, SEEK_SET);
271
272 333 return update_size(pb, pos);
273 }
274
275 /* Sync sample atom */
276 58 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
277 {
278 int64_t curpos, entryPos;
279 58 int i, index = 0;
280 58 int64_t pos = avio_tell(pb);
281 58 avio_wb32(pb, 0); // size
282
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
283 58 avio_wb32(pb, 0); // version & flags
284 58 entryPos = avio_tell(pb);
285 58 avio_wb32(pb, track->entry); // entry count
286
2/2
✓ Branch 0 taken 3209 times.
✓ Branch 1 taken 58 times.
3267 for (i = 0; i < track->entry; i++) {
287
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 3002 times.
3209 if (track->cluster[i].flags & flag) {
288 207 avio_wb32(pb, i + 1);
289 207 index++;
290 }
291 }
292 58 curpos = avio_tell(pb);
293 58 avio_seek(pb, entryPos, SEEK_SET);
294 58 avio_wb32(pb, index); // rewrite size
295 58 avio_seek(pb, curpos, SEEK_SET);
296 58 return update_size(pb, pos);
297 }
298
299 /* Sample dependency atom */
300 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
301 {
302 int i;
303 uint8_t leading, dependent, reference, redundancy;
304 3 int64_t pos = avio_tell(pb);
305 3 avio_wb32(pb, 0); // size
306 3 ffio_wfourcc(pb, "sdtp");
307 3 avio_wb32(pb, 0); // version & flags
308
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
309 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
310 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
311
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
312 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
313 }
314
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
315 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
316 }
317 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
318 13 (reference << 2) | redundancy);
319 }
320 3 return update_size(pb, pos);
321 }
322
323 #if CONFIG_IAMFENC
324 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
325 {
326 AVIOContext *dyn_bc;
327 5 int64_t pos = avio_tell(pb);
328 5 uint8_t *dyn_buf = NULL;
329 int dyn_size;
330 5 int ret = avio_open_dyn_buf(&dyn_bc);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
332 return ret;
333
334 5 avio_wb32(pb, 0);
335 5 ffio_wfourcc(pb, "iacb");
336 5 avio_w8(pb, 1); // configurationVersion
337
338 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
340 return ret;
341
342 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
343 5 ffio_write_leb(pb, dyn_size);
344 5 avio_write(pb, dyn_buf, dyn_size);
345 5 av_free(dyn_buf);
346
347 5 return update_size(pb, pos);
348 }
349 #endif
350
351 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
352 {
353 avio_wb32(pb, 0x11); /* size */
354 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
355 else ffio_wfourcc(pb, "damr");
356 ffio_wfourcc(pb, "FFMP");
357 avio_w8(pb, 0); /* decoder version */
358
359 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
360 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
361 avio_w8(pb, 0x01); /* Frames per sample */
362 return 0x11;
363 }
364
365 struct eac3_info {
366 AVPacket *pkt;
367 uint8_t ec3_done;
368 uint8_t num_blocks;
369
370 /* Layout of the EC3SpecificBox */
371 /* maximum bitrate */
372 uint16_t data_rate;
373 int8_t ac3_bit_rate_code;
374 /* number of independent substreams */
375 uint8_t num_ind_sub;
376 struct {
377 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
378 uint8_t fscod;
379 /* bit stream identification 5 bits */
380 uint8_t bsid;
381 /* one bit reserved */
382 /* audio service mixing (not supported yet) 1 bit */
383 /* bit stream mode 3 bits */
384 uint8_t bsmod;
385 /* audio coding mode 3 bits */
386 uint8_t acmod;
387 /* sub woofer on 1 bit */
388 uint8_t lfeon;
389 /* 3 bits reserved */
390 /* number of dependent substreams associated with this substream 4 bits */
391 uint8_t num_dep_sub;
392 /* channel locations of the dependent substream(s), if any, 9 bits */
393 uint16_t chan_loc;
394 /* if there is no dependent substream, then one bit reserved instead */
395 } substream[1]; /* TODO: support 8 independent substreams */
396 };
397
398 5 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
399 {
400 5 struct eac3_info *info = track->eac3_priv;
401 PutBitContext pbc;
402 uint8_t buf[3];
403
404
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (!info || !info->ec3_done) {
405 av_log(s, AV_LOG_ERROR,
406 "Cannot write moov atom before AC3 packets."
407 " Set the delay_moov flag to fix this.\n");
408 return AVERROR(EINVAL);
409 }
410
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->substream[0].bsid > 8) {
412 av_log(s, AV_LOG_ERROR,
413 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
414 "ISOBMFF specification in ETSI TS 102 366!\n",
415 info->substream[0].bsid);
416 return AVERROR(EINVAL);
417 }
418
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->ac3_bit_rate_code < 0) {
420 av_log(s, AV_LOG_ERROR,
421 "No valid AC3 bit rate code for data rate of %d!\n",
422 info->data_rate);
423 return AVERROR(EINVAL);
424 }
425
426 5 avio_wb32(pb, 11);
427 5 ffio_wfourcc(pb, "dac3");
428
429 5 init_put_bits(&pbc, buf, sizeof(buf));
430 5 put_bits(&pbc, 2, info->substream[0].fscod);
431 5 put_bits(&pbc, 5, info->substream[0].bsid);
432 5 put_bits(&pbc, 3, info->substream[0].bsmod);
433 5 put_bits(&pbc, 3, info->substream[0].acmod);
434 5 put_bits(&pbc, 1, info->substream[0].lfeon);
435 5 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
436 5 put_bits(&pbc, 5, 0); // reserved
437
438 5 flush_put_bits(&pbc);
439 5 avio_write(pb, buf, sizeof(buf));
440
441 5 return 11;
442 }
443
444 1039 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
445 {
446 1039 AC3HeaderInfo *hdr = NULL;
447 struct eac3_info *info;
448 int num_blocks, ret;
449
450
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
1039 if (!track->eac3_priv) {
451
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
452 return AVERROR(ENOMEM);
453
454 5 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
455 }
456 1039 info = track->eac3_priv;
457
458
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
1039 if (!info->pkt && !(info->pkt = av_packet_alloc()))
459 return AVERROR(ENOMEM);
460
461
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1038 times.
1039 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
463 goto end;
464
465 /* drop the packets until we see a good one */
466
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
467 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
468 1 ret = 0;
469 } else
470 ret = AVERROR_INVALIDDATA;
471 1 goto end;
472 }
473
474 1038 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
475 1038 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
476 hdr->ac3_bit_rate_code);
477 1038 num_blocks = hdr->num_blocks;
478
479
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6 times.
1038 if (!info->ec3_done) {
480 /* AC-3 substream must be the first one */
481
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
6 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
482 ret = AVERROR(EINVAL);
483 goto end;
484 }
485
486 /* this should always be the case, given that our AC-3 parser
487 * concatenates dependent frames to their independent parent */
488
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
489
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
490 /* substream ids must be incremental */
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid > info->num_ind_sub + 1) {
492 ret = AVERROR(EINVAL);
493 goto end;
494 }
495
496
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid == info->num_ind_sub + 1) {
497 //info->num_ind_sub++;
498 avpriv_request_sample(mov->fc, "Multiple independent substreams");
499 ret = AVERROR_PATCHWELCOME;
500 goto end;
501
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (hdr->substreamid < info->num_ind_sub ||
502
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
6 hdr->substreamid == 0 && info->substream[0].bsid) {
503 1 info->ec3_done = 1;
504 1 goto concatenate;
505 }
506 } else {
507 if (hdr->substreamid != 0) {
508 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
509 ret = AVERROR_PATCHWELCOME;
510 goto end;
511 }
512 }
513
514 /* fill the info needed for the "dec3" atom */
515 5 info->substream[hdr->substreamid].fscod = hdr->sr_code;
516 5 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
517 5 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
518 5 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
519 5 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
520
521
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_AC3) {
522 // with AC-3 we only require the information of a single packet,
523 // so we can finish as soon as the basic values of the bit stream
524 // have been set to the track's informational structure.
525 4 info->ec3_done = 1;
526 4 goto concatenate;
527 }
528
529 /* Parse dependent substream(s), if any */
530
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pkt->size != hdr->frame_size) {
531 int cumul_size = hdr->frame_size;
532 int parent = hdr->substreamid;
533
534 while (cumul_size != pkt->size) {
535 GetBitContext gbc;
536 int i;
537 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
538 if (ret < 0)
539 goto end;
540 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
541 ret = AVERROR(EINVAL);
542 goto end;
543 }
544 info->substream[parent].num_dep_sub++;
545 ret /= 8;
546
547 /* header is parsed up to lfeon, but custom channel map may be needed */
548 init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret);
549 /* skip bsid */
550 skip_bits(&gbc, 5);
551 /* skip volume control params */
552 for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
553 skip_bits(&gbc, 5); // skip dialog normalization
554 if (get_bits1(&gbc)) {
555 skip_bits(&gbc, 8); // skip compression gain word
556 }
557 }
558 /* get the dependent stream channel map, if exists */
559 if (get_bits1(&gbc))
560 info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f;
561 else
562 info->substream[parent].chan_loc |= hdr->channel_mode;
563 cumul_size += hdr->frame_size;
564 }
565 }
566 }
567
568 1033 concatenate:
569
2/4
✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
1038 if (!info->num_blocks && num_blocks == 6) {
570 1038 ret = pkt->size;
571 1038 goto end;
572 }
573 else if (info->num_blocks + num_blocks > 6) {
574 ret = AVERROR_INVALIDDATA;
575 goto end;
576 }
577
578 if (!info->num_blocks) {
579 ret = av_packet_ref(info->pkt, pkt);
580 if (!ret)
581 info->num_blocks = num_blocks;
582 goto end;
583 } else {
584 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
585 goto end;
586 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
587 info->num_blocks += num_blocks;
588 info->pkt->duration += pkt->duration;
589 if (info->num_blocks != 6)
590 goto end;
591 av_packet_unref(pkt);
592 av_packet_move_ref(pkt, info->pkt);
593 info->num_blocks = 0;
594 }
595 ret = pkt->size;
596
597 1039 end:
598 1039 av_free(hdr);
599
600 1039 return ret;
601 }
602
603 1 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
604 {
605 PutBitContext pbc;
606 uint8_t *buf;
607 struct eac3_info *info;
608 int size, i;
609
610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->eac3_priv) {
611 av_log(s, AV_LOG_ERROR,
612 "Cannot write moov atom before EAC3 packets parsed.\n");
613 return AVERROR(EINVAL);
614 }
615
616 1 info = track->eac3_priv;
617 1 size = 2 + ((34 * (info->num_ind_sub + 1) + 7) >> 3);
618 1 buf = av_malloc(size);
619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buf) {
620 return AVERROR(ENOMEM);
621 }
622
623 1 init_put_bits(&pbc, buf, size);
624 1 put_bits(&pbc, 13, info->data_rate);
625 1 put_bits(&pbc, 3, info->num_ind_sub);
626
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i <= info->num_ind_sub; i++) {
627 1 put_bits(&pbc, 2, info->substream[i].fscod);
628 1 put_bits(&pbc, 5, info->substream[i].bsid);
629 1 put_bits(&pbc, 1, 0); /* reserved */
630 1 put_bits(&pbc, 1, 0); /* asvc */
631 1 put_bits(&pbc, 3, info->substream[i].bsmod);
632 1 put_bits(&pbc, 3, info->substream[i].acmod);
633 1 put_bits(&pbc, 1, info->substream[i].lfeon);
634 1 put_bits(&pbc, 5, 0); /* reserved */
635 1 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
636
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!info->substream[i].num_dep_sub) {
637 1 put_bits(&pbc, 1, 0); /* reserved */
638 } else {
639 put_bits(&pbc, 9, info->substream[i].chan_loc);
640 }
641 }
642 1 flush_put_bits(&pbc);
643 1 size = put_bytes_output(&pbc);
644
645 1 avio_wb32(pb, size + 8);
646 1 ffio_wfourcc(pb, "dec3");
647 1 avio_write(pb, buf, size);
648
649 1 av_free(buf);
650
651 1 return size;
652 }
653
654 /**
655 * This function writes extradata "as is".
656 * Extradata must be formatted like a valid atom (with size and tag).
657 */
658 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
659 {
660 12 avio_write(pb, track->par->extradata, track->par->extradata_size);
661 12 return track->par->extradata_size;
662 }
663
664 static int mov_write_enda_tag(AVIOContext *pb)
665 {
666 avio_wb32(pb, 10);
667 ffio_wfourcc(pb, "enda");
668 avio_wb16(pb, 1); /* little endian */
669 return 10;
670 }
671
672 2 static int mov_write_enda_tag_be(AVIOContext *pb)
673 {
674 2 avio_wb32(pb, 10);
675 2 ffio_wfourcc(pb, "enda");
676 2 avio_wb16(pb, 0); /* big endian */
677 2 return 10;
678 }
679
680 316 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
681 {
682 316 int i = 3;
683 316 avio_w8(pb, tag);
684
2/2
✓ Branch 0 taken 948 times.
✓ Branch 1 taken 316 times.
1264 for (; i > 0; i--)
685 948 avio_w8(pb, (size >> (7 * i)) | 0x80);
686 316 avio_w8(pb, size & 0x7F);
687 316 }
688
689 210 static unsigned compute_avg_bitrate(MOVTrack *track)
690 {
691 210 uint64_t size = 0;
692 int i;
693
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 173 times.
210 if (!track->track_duration)
694 37 return 0;
695
2/2
✓ Branch 0 taken 8974 times.
✓ Branch 1 taken 173 times.
9147 for (i = 0; i < track->entry; i++)
696 8974 size += track->cluster[i].size;
697 173 return size * 8 * track->timescale / track->track_duration;
698 }
699
700 struct mpeg4_bit_rate_values {
701 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
702 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
703 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
704 };
705
706 210 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
707 {
708 420 const AVPacketSideData *sd = track->st ?
709 209 av_packet_side_data_get(track->st->codecpar->coded_side_data,
710 209 track->st->codecpar->nb_coded_side_data,
711
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 1 times.
210 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
712
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 176 times.
210 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
713 210 struct mpeg4_bit_rate_values bit_rates = { 0 };
714
715 210 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
716
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 83 times.
210 if (!bit_rates.avg_bit_rate) {
717 // if the average bit rate cannot be calculated at this point, such as
718 // in the case of fragmented MP4, utilize the following values as
719 // fall-back in priority order:
720 //
721 // 1. average bit rate property
722 // 2. bit rate (usually average over the whole clip)
723 // 3. maximum bit rate property
724
725
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
127 if (props && props->avg_bitrate) {
726 3 bit_rates.avg_bit_rate = props->avg_bitrate;
727
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 122 times.
124 } else if (track->par->bit_rate) {
728 2 bit_rates.avg_bit_rate = track->par->bit_rate;
729
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
122 } else if (props && props->max_bitrate) {
730 bit_rates.avg_bit_rate = props->max_bitrate;
731 }
732 }
733
734 // (FIXME should be max rate in any 1 sec window)
735 210 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
736 bit_rates.avg_bit_rate);
737
738 // utilize values from properties if we have them available
739
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 176 times.
210 if (props) {
740 // no avg_bitrate signals that the track is VBR
741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (!props->avg_bitrate)
742 bit_rates.avg_bit_rate = props->avg_bitrate;
743 34 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
744 props->max_bitrate);
745 34 bit_rates.buffer_size = props->buffer_size / 8;
746 }
747
748 210 return bit_rates;
749 }
750
751 79 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
752 {
753 79 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
754 79 int64_t pos = avio_tell(pb);
755
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 int decoder_specific_info_len = track->vos_len ? 5 + track->vos_len : 0;
756
757 79 avio_wb32(pb, 0); // size
758 79 ffio_wfourcc(pb, "esds");
759 79 avio_wb32(pb, 0); // Version
760
761 // ES descriptor
762 79 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
763 79 avio_wb16(pb, track->track_id);
764 79 avio_w8(pb, 0x00); // flags (= no flags)
765
766 // DecoderConfig descriptor
767 79 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
768
769 // Object type indication
770
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 track->par->codec_id == AV_CODEC_ID_MP3) &&
772 track->par->sample_rate > 24000)
773 avio_w8(pb, 0x6B); // 11172-3
774 else
775 79 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
776
777 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
778 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
780 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
781
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 25 times.
79 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
782 54 avio_w8(pb, 0x15); // flags (= Audiostream)
783 else
784 25 avio_w8(pb, 0x11); // flags (= Visualstream)
785
786 79 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
787 79 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
788 79 avio_wb32(pb, bit_rates.avg_bit_rate);
789
790
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if (track->vos_len) {
791 // DecoderSpecific info descriptor
792 79 put_descr(pb, 0x05, track->vos_len);
793 79 avio_write(pb, track->vos_data, track->vos_len);
794 }
795
796 // SL descriptor
797 79 put_descr(pb, 0x06, 1);
798 79 avio_w8(pb, 0x02);
799 79 return update_size(pb, pos);
800 }
801
802 77 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
803 {
804
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 return codec_id == AV_CODEC_ID_PCM_S24LE ||
805
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 codec_id == AV_CODEC_ID_PCM_S32LE ||
806
2/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
154 codec_id == AV_CODEC_ID_PCM_F32LE ||
807 codec_id == AV_CODEC_ID_PCM_F64LE;
808 }
809
810 77 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
811 {
812
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 4 times.
73 return codec_id == AV_CODEC_ID_PCM_S24BE ||
813
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 codec_id == AV_CODEC_ID_PCM_S32BE ||
814
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
150 codec_id == AV_CODEC_ID_PCM_F32BE ||
815 codec_id == AV_CODEC_ID_PCM_F64BE;
816 }
817
818 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
819 {
820 int ret;
821 int64_t pos = avio_tell(pb);
822 avio_wb32(pb, 0);
823 avio_wl32(pb, track->tag); // store it byteswapped
824 track->par->codec_tag = av_bswap16(track->tag >> 16);
825 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
826 return ret;
827 return update_size(pb, pos);
828 }
829
830 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
831 {
832 int ret;
833 int64_t pos = avio_tell(pb);
834 avio_wb32(pb, 0);
835 ffio_wfourcc(pb, "wfex");
836 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
837 return ret;
838 return update_size(pb, pos);
839 }
840
841 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
842 {
843 int64_t pos = avio_tell(pb);
844 avio_wb32(pb, 0);
845 ffio_wfourcc(pb, "dfLa");
846 avio_w8(pb, 0); /* version */
847 avio_wb24(pb, 0); /* flags */
848
849 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
850 if (track->par->extradata_size != FLAC_STREAMINFO_SIZE)
851 return AVERROR_INVALIDDATA;
852
853 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
854 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
855 avio_wb24(pb, track->par->extradata_size); /* Length */
856 avio_write(pb, track->par->extradata, track->par->extradata_size); /* BlockData[Length] */
857
858 return update_size(pb, pos);
859 }
860
861 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
862 {
863 int64_t pos = avio_tell(pb);
864 int channels, channel_map;
865 avio_wb32(pb, 0);
866 ffio_wfourcc(pb, "dOps");
867 avio_w8(pb, 0); /* Version */
868 if (track->par->extradata_size < 19) {
869 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
870 return AVERROR_INVALIDDATA;
871 }
872 /* extradata contains an Ogg OpusHead, other than byte-ordering and
873 OpusHead's preceeding magic/version, OpusSpecificBox is currently
874 identical. */
875 channels = AV_RB8(track->par->extradata + 9);
876 channel_map = AV_RB8(track->par->extradata + 18);
877
878 avio_w8(pb, channels); /* OuputChannelCount */
879 avio_wb16(pb, AV_RL16(track->par->extradata + 10)); /* PreSkip */
880 avio_wb32(pb, AV_RL32(track->par->extradata + 12)); /* InputSampleRate */
881 avio_wb16(pb, AV_RL16(track->par->extradata + 16)); /* OutputGain */
882 avio_w8(pb, channel_map); /* ChannelMappingFamily */
883 /* Write the rest of the header out without byte-swapping. */
884 if (channel_map) {
885 if (track->par->extradata_size < 21 + channels) {
886 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
887 return AVERROR_INVALIDDATA;
888 }
889 avio_write(pb, track->par->extradata + 19, 2 + channels); /* ChannelMappingTable */
890 }
891
892 return update_size(pb, pos);
893 }
894
895 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
896 {
897 int64_t pos = avio_tell(pb);
898 int length;
899 avio_wb32(pb, 0);
900 ffio_wfourcc(pb, "dmlp");
901
902 if (track->vos_len < 20) {
903 av_log(s, AV_LOG_ERROR,
904 "Cannot write moov atom before TrueHD packets."
905 " Set the delay_moov flag to fix this.\n");
906 return AVERROR(EINVAL);
907 }
908
909 length = (AV_RB16(track->vos_data) & 0xFFF) * 2;
910 if (length < 20 || length > track->vos_len)
911 return AVERROR_INVALIDDATA;
912
913 // Only TrueHD is supported
914 if (AV_RB32(track->vos_data + 4) != 0xF8726FBA)
915 return AVERROR_INVALIDDATA;
916
917 avio_wb32(pb, AV_RB32(track->vos_data + 8)); /* format_info */
918 avio_wb16(pb, AV_RB16(track->vos_data + 18) << 1); /* peak_data_rate */
919 avio_wb32(pb, 0); /* reserved */
920
921 return update_size(pb, pos);
922 }
923
924 65 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
925 {
926 65 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
927 65 AVChannelLayout ch_layout = { 0 };
928 int64_t pos;
929 int ambisonic_order, ambi_channels, non_diegetic_channels;
930 int i, ret;
931
932
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 if (!str)
933 65 return 0;
934
935 ret = av_channel_layout_from_string(&ch_layout, str->value);
936 if (ret < 0) {
937 if (ret == AVERROR(EINVAL)) {
938 invalid:
939 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
940 ret = 0;
941 }
942 av_channel_layout_uninit(&ch_layout);
943 return ret;
944 }
945
946 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
947 goto invalid;
948
949 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
950 if (ambisonic_order < 0)
951 goto invalid;
952
953 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
954 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
955 if (non_diegetic_channels &&
956 (non_diegetic_channels != 2 ||
957 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
958 goto invalid;
959
960 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
961
962 pos = avio_tell(pb);
963
964 avio_wb32(pb, 0); // Size
965 ffio_wfourcc(pb, "SA3D");
966 avio_w8(pb, 0); // version
967 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
968 avio_wb32(pb, ambisonic_order); // ambisonic_order
969 avio_w8(pb, 0); // ambisonic_channel_ordering
970 avio_w8(pb, 0); // ambisonic_normalization
971 avio_wb32(pb, ch_layout.nb_channels); // num_channels
972 for (i = 0; i < ambi_channels; i++)
973 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
974 for (; i < ch_layout.nb_channels; i++)
975 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
976
977 av_channel_layout_uninit(&ch_layout);
978
979 return update_size(pb, pos);
980 }
981
982 40 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
983 {
984 uint32_t layout_tag, bitmap, *channel_desc;
985 40 int64_t pos = avio_tell(pb);
986 int num_desc, ret;
987
988
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (track->multichannel_as_mono)
989 return 0;
990
991 40 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
992 &bitmap, &channel_desc);
993
994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0) {
995 if (ret == AVERROR(ENOSYS)) {
996 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
997 "lack of channel information\n");
998 ret = 0;
999 }
1000
1001 return ret;
1002 }
1003
1004
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
40 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1006 1 channel_desc = av_malloc(sizeof(*channel_desc));
1007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1008 return AVERROR(ENOMEM);
1009
1010 1 layout_tag = 0;
1011 1 bitmap = 0;
1012 1 *channel_desc = 3; // channel label "Center"
1013 }
1014
1015
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1016
1017 40 avio_wb32(pb, 0); // Size
1018 40 ffio_wfourcc(pb, "chan"); // Type
1019 40 avio_w8(pb, 0); // Version
1020 40 avio_wb24(pb, 0); // Flags
1021 40 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1022 40 avio_wb32(pb, bitmap); // mChannelBitmap
1023 40 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1024
1025
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 for (int i = 0; i < num_desc; i++) {
1026 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1027 3 avio_wb32(pb, 0); // mChannelFlags
1028 3 avio_wl32(pb, 0); // mCoordinates[0]
1029 3 avio_wl32(pb, 0); // mCoordinates[1]
1030 3 avio_wl32(pb, 0); // mCoordinates[2]
1031 }
1032
1033 40 av_free(channel_desc);
1034
1035 40 return update_size(pb, pos);
1036 }
1037
1038 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1039 {
1040 15 int64_t pos = avio_tell(pb);
1041
1042 15 avio_wb32(pb, 0); /* size */
1043 15 ffio_wfourcc(pb, "wave");
1044
1045
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1046 15 avio_wb32(pb, 12); /* size */
1047 15 ffio_wfourcc(pb, "frma");
1048 15 avio_wl32(pb, track->tag);
1049 }
1050
1051
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1052 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1053 3 avio_wb32(pb, 12); /* size */
1054 3 ffio_wfourcc(pb, "mp4a");
1055 3 avio_wb32(pb, 0);
1056 3 mov_write_esds_tag(pb, track);
1057
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1058 mov_write_enda_tag(pb);
1059
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1060 2 mov_write_enda_tag_be(pb);
1061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1062 mov_write_amr_tag(pb, track);
1063
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1064 1 mov_write_ac3_tag(s, pb, track);
1065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1066 mov_write_eac3_tag(s, pb, track);
1067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1068 track->par->codec_id == AV_CODEC_ID_QDM2) {
1069 9 mov_write_extradata_tag(pb, track);
1070 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1071 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1072 mov_write_ms_tag(s, pb, track);
1073 }
1074
1075 15 avio_wb32(pb, 8); /* size */
1076 15 avio_wb32(pb, 0); /* null tag */
1077
1078 15 return update_size(pb, pos);
1079 }
1080
1081 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1082 {
1083 uint8_t *unescaped;
1084 const uint8_t *start, *next, *end = track->vos_data + track->vos_len;
1085 int unescaped_size, seq_found = 0;
1086 int level = 0, interlace = 0;
1087 int packet_seq = track->vc1_info.packet_seq;
1088 int packet_entry = track->vc1_info.packet_entry;
1089 int slices = track->vc1_info.slices;
1090 PutBitContext pbc;
1091
1092 if (track->start_dts == AV_NOPTS_VALUE) {
1093 /* No packets written yet, vc1_info isn't authoritative yet. */
1094 /* Assume inline sequence and entry headers. */
1095 packet_seq = packet_entry = 1;
1096 av_log(NULL, AV_LOG_WARNING,
1097 "moov atom written before any packets, unable to write correct "
1098 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1099 }
1100
1101 unescaped = av_mallocz(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
1102 if (!unescaped)
1103 return AVERROR(ENOMEM);
1104 start = find_next_marker(track->vos_data, end);
1105 for (next = start; next < end; start = next) {
1106 GetBitContext gb;
1107 int size;
1108 next = find_next_marker(start + 4, end);
1109 size = next - start - 4;
1110 if (size <= 0)
1111 continue;
1112 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1113 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1114 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1115 int profile = get_bits(&gb, 2);
1116 if (profile != PROFILE_ADVANCED) {
1117 av_free(unescaped);
1118 return AVERROR(ENOSYS);
1119 }
1120 seq_found = 1;
1121 level = get_bits(&gb, 3);
1122 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1123 * width, height */
1124 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1125 skip_bits(&gb, 1); /* broadcast */
1126 interlace = get_bits1(&gb);
1127 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1128 }
1129 }
1130 if (!seq_found) {
1131 av_free(unescaped);
1132 return AVERROR(ENOSYS);
1133 }
1134
1135 init_put_bits(&pbc, buf, 7);
1136 /* VC1DecSpecStruc */
1137 put_bits(&pbc, 4, 12); /* profile - advanced */
1138 put_bits(&pbc, 3, level);
1139 put_bits(&pbc, 1, 0); /* reserved */
1140 /* VC1AdvDecSpecStruc */
1141 put_bits(&pbc, 3, level);
1142 put_bits(&pbc, 1, 0); /* cbr */
1143 put_bits(&pbc, 6, 0); /* reserved */
1144 put_bits(&pbc, 1, !interlace); /* no interlace */
1145 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1146 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1147 put_bits(&pbc, 1, !slices); /* no slice code */
1148 put_bits(&pbc, 1, 0); /* no bframe */
1149 put_bits(&pbc, 1, 0); /* reserved */
1150
1151 /* framerate */
1152 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1153 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1154 else
1155 put_bits32(&pbc, 0xffffffff);
1156
1157 flush_put_bits(&pbc);
1158
1159 av_free(unescaped);
1160
1161 return 0;
1162 }
1163
1164 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1165 {
1166 uint8_t buf[7] = { 0 };
1167 int ret;
1168
1169 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1170 return ret;
1171
1172 avio_wb32(pb, track->vos_len + 8 + sizeof(buf));
1173 ffio_wfourcc(pb, "dvc1");
1174 avio_write(pb, buf, sizeof(buf));
1175 avio_write(pb, track->vos_data, track->vos_len);
1176
1177 return 0;
1178 }
1179
1180 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1181 {
1182 4 avio_wb32(pb, track->vos_len + 8);
1183 4 ffio_wfourcc(pb, "glbl");
1184 4 avio_write(pb, track->vos_data, track->vos_len);
1185 4 return 8 + track->vos_len;
1186 }
1187
1188 /**
1189 * Compute flags for 'lpcm' tag.
1190 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1191 */
1192 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1193 {
1194
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 switch (codec_id) {
1195 case AV_CODEC_ID_PCM_F32BE:
1196 case AV_CODEC_ID_PCM_F64BE:
1197 return 11;
1198 case AV_CODEC_ID_PCM_F32LE:
1199 case AV_CODEC_ID_PCM_F64LE:
1200 return 9;
1201 case AV_CODEC_ID_PCM_U8:
1202 return 10;
1203 case AV_CODEC_ID_PCM_S16BE:
1204 case AV_CODEC_ID_PCM_S24BE:
1205 case AV_CODEC_ID_PCM_S32BE:
1206 return 14;
1207 case AV_CODEC_ID_PCM_S8:
1208 case AV_CODEC_ID_PCM_S16LE:
1209 case AV_CODEC_ID_PCM_S24LE:
1210 case AV_CODEC_ID_PCM_S32LE:
1211 return 12;
1212 8 default:
1213 8 return 0;
1214 }
1215 }
1216
1217 25209 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1218 {
1219 int64_t next_dts;
1220
1221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 if (cluster_idx >= track->entry)
1222 return 0;
1223
1224
2/2
✓ Branch 0 taken 643 times.
✓ Branch 1 taken 24566 times.
25209 if (cluster_idx + 1 == track->entry)
1225 643 next_dts = track->track_duration + track->start_dts;
1226 else
1227 24566 next_dts = track->cluster[cluster_idx + 1].dts;
1228
1229 25209 next_dts -= track->cluster[cluster_idx].dts;
1230
1231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 av_assert0(next_dts >= 0);
1232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 av_assert0(next_dts <= INT_MAX);
1233
1234 25209 return next_dts;
1235 }
1236
1237 4 static int get_samples_per_packet(MOVTrack *track)
1238 {
1239 int i, first_duration;
1240
1241 /* use 1 for raw PCM */
1242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1243 return 1;
1244
1245 /* check to see if duration is constant for all clusters */
1246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1247 return 0;
1248 4 first_duration = get_cluster_duration(track, 0);
1249
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1250
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1251 4 return 0;
1252 }
1253 return first_duration;
1254 }
1255
1256 131 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1257 {
1258 131 int64_t pos = avio_tell(pb);
1259 131 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1260
3/4
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
131 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1261
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 !bit_rates.buffer_size)
1262 // no useful data to be written, skip
1263 81 return 0;
1264
1265 50 avio_wb32(pb, 0); /* size */
1266 50 ffio_wfourcc(pb, "btrt");
1267
1268 50 avio_wb32(pb, bit_rates.buffer_size);
1269 50 avio_wb32(pb, bit_rates.max_bit_rate);
1270 50 avio_wb32(pb, bit_rates.avg_bit_rate);
1271
1272 50 return update_size(pb, pos);
1273 }
1274
1275 5 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1276 {
1277 5 int64_t pos = avio_tell(pb);
1278 5 int config = 0;
1279 int ret;
1280 5 uint8_t *speaker_pos = NULL;
1281 5 const AVChannelLayout *layout = &track->par->ch_layout;
1282
1283 5 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1284
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
5 if (ret || !config) {
1285 4 config = 0;
1286 4 speaker_pos = av_malloc(layout->nb_channels);
1287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1288 return AVERROR(ENOMEM);
1289 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1290 4 speaker_pos, layout->nb_channels);
1291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1292 char buf[128] = {0};
1293
1294 av_freep(&speaker_pos);
1295 av_channel_layout_describe(layout, buf, sizeof(buf));
1296 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1297 return ret;
1298 }
1299 }
1300
1301 5 avio_wb32(pb, 0); /* size */
1302 5 ffio_wfourcc(pb, "chnl");
1303 5 avio_wb32(pb, 0); /* version & flags */
1304
1305 5 avio_w8(pb, 1); /* stream_structure */
1306 5 avio_w8(pb, config);
1307
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (config) {
1308 1 avio_wb64(pb, 0);
1309 } else {
1310 4 avio_write(pb, speaker_pos, layout->nb_channels);
1311 4 av_freep(&speaker_pos);
1312 }
1313
1314 5 return update_size(pb, pos);
1315 }
1316
1317 7 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1318 {
1319 7 int64_t pos = avio_tell(pb);
1320 int format_flags;
1321 int sample_size;
1322
1323 7 avio_wb32(pb, 0); /* size */
1324 7 ffio_wfourcc(pb, "pcmC");
1325 7 avio_wb32(pb, 0); /* version & flags */
1326
1327 /* 0x01: indicates little-endian format */
1328 20 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1329
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1331
2/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13 track->par->codec_id == AV_CODEC_ID_PCM_S24LE ||
1332 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1333 7 avio_w8(pb, format_flags);
1334 7 sample_size = track->par->bits_per_raw_sample;
1335
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (!sample_size)
1336 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 av_assert0(sample_size);
1338 7 avio_w8(pb, sample_size);
1339
1340 7 return update_size(pb, pos);
1341 }
1342
1343 108 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1344 {
1345 108 int64_t pos = avio_tell(pb);
1346 108 int version = 0;
1347 108 uint32_t tag = track->tag;
1348 108 int ret = 0;
1349
1350
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
108 if (track->mode == MODE_MOV) {
1351
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
40 if (track->timescale > UINT16_MAX || !track->par->ch_layout.nb_channels) {
1352
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1353 tag = AV_RL32("lpcm");
1354 4 version = 2;
1355
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
62 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1356 26 mov_pcm_be_gt16(track->par->codec_id) ||
1357
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1358
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1360 12 version = 1;
1361 }
1362 }
1363
1364 108 avio_wb32(pb, 0); /* size */
1365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (mov->encryption_scheme != MOV_ENC_NONE) {
1366 ffio_wfourcc(pb, "enca");
1367 } else {
1368 108 avio_wl32(pb, tag); // store it byteswapped
1369 }
1370 108 avio_wb32(pb, 0); /* Reserved */
1371 108 avio_wb16(pb, 0); /* Reserved */
1372 108 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1373
1374 /* SoundDescription */
1375 108 avio_wb16(pb, version); /* Version */
1376 108 avio_wb16(pb, 0); /* Revision level */
1377 108 avio_wb32(pb, 0); /* Reserved */
1378
1379
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 104 times.
108 if (version == 2) {
1380 4 avio_wb16(pb, 3);
1381 4 avio_wb16(pb, 16);
1382 4 avio_wb16(pb, 0xfffe);
1383 4 avio_wb16(pb, 0);
1384 4 avio_wb32(pb, 0x00010000);
1385 4 avio_wb32(pb, 72);
1386 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1387 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1388 4 avio_wb32(pb, 0x7F000000);
1389 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1390 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1391 4 avio_wb32(pb, track->sample_size);
1392 4 avio_wb32(pb, get_samples_per_packet(track));
1393 } else {
1394
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 68 times.
104 if (track->mode == MODE_MOV) {
1395 36 avio_wb16(pb, track->par->ch_layout.nb_channels);
1396
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1397
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1398 1 avio_wb16(pb, 8); /* bits per sample */
1399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1400 avio_wb16(pb, track->par->bits_per_coded_sample);
1401 else
1402 35 avio_wb16(pb, 16);
1403
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1404 } else { /* reserved for mp4/3gp */
1405
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 5 times.
131 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1406 63 0 : track->par->ch_layout.nb_channels);
1407
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 5 times.
68 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 track->par->codec_id == AV_CODEC_ID_ALAC) {
1409 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1410 } else {
1411 63 avio_wb16(pb, 16);
1412 }
1413 68 avio_wb16(pb, 0);
1414 }
1415
1416 104 avio_wb16(pb, 0); /* packet size (= 0) */
1417
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 99 times.
104 if (track->tag == MKTAG('i','a','m','f'))
1418 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1420 avio_wb16(pb, 48000);
1421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1422 avio_wb32(pb, track->par->sample_rate);
1423 else
1424
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
198 avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ?
1425 99 track->par->sample_rate : 0);
1426
1427
1/2
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
104 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1428 104 avio_wb16(pb, 0); /* Reserved */
1429 }
1430
1431
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 96 times.
108 if (version == 1) { /* SoundDescription V1 extended info */
1432
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 10 times.
24 if (mov_pcm_le_gt16(track->par->codec_id) ||
1433 12 mov_pcm_be_gt16(track->par->codec_id))
1434 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1435 else
1436 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1437 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1438 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1439 12 avio_wb32(pb, 2); /* Bytes per sample */
1440 }
1441
1442
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
108 if (track->mode == MODE_MOV &&
1443
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 (track->par->codec_id == AV_CODEC_ID_AAC ||
1444
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
37 track->par->codec_id == AV_CODEC_ID_AC3 ||
1445
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1446
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1447
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1448
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1449
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1450
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 track->par->codec_id == AV_CODEC_ID_QDM2 ||
1451
2/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 25 times.
54 (mov_pcm_le_gt16(track->par->codec_id) && version==1) ||
1452
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1453 15 ret = mov_write_wave_tag(s, pb, track);
1454
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 42 times.
93 else if (track->tag == MKTAG('m','p','4','a'))
1455 51 ret = mov_write_esds_tag(pb, track);
1456 #if CONFIG_IAMFENC
1457
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 37 times.
42 else if (track->tag == MKTAG('i','a','m','f'))
1458 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1459 #endif
1460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1461 ret = mov_write_amr_tag(pb, track);
1462
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 33 times.
37 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1463 4 ret = mov_write_ac3_tag(s, pb, track);
1464
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 32 times.
33 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1465 1 ret = mov_write_eac3_tag(s, pb, track);
1466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1467 ret = mov_write_extradata_tag(pb, track);
1468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1469 ret = mov_write_wfex_tag(s, pb, track);
1470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1471 ret = mov_write_dfla_tag(pb, track);
1472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1473 ret = mov_write_dops_tag(s, pb, track);
1474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1475 ret = mov_write_dmlp_tag(s, pb, track);
1476
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
32 else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) {
1477
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (track->par->ch_layout.nb_channels > 1)
1478 5 ret = mov_write_chnl_tag(s, pb, track);
1479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ret < 0)
1480 return ret;
1481 7 ret = mov_write_pcmc_tag(s, pb, track);
1482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->vos_len > 0)
1483 ret = mov_write_glbl_tag(pb, track);
1484
1485
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (ret < 0)
1486 return ret;
1487
1488
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
108 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1489
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
65 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1490 return ret;
1491 }
1492
1493
3/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
108 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1494
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1495 return ret;
1496 }
1497
1498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (mov->encryption_scheme != MOV_ENC_NONE
1499 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1500 return ret;
1501 }
1502
1503
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
173 if (mov->write_btrt &&
1504 65 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1505 return ret;
1506
1507 108 ret = update_size(pb, pos);
1508 108 return ret;
1509 }
1510
1511 static int mov_write_d263_tag(AVIOContext *pb)
1512 {
1513 avio_wb32(pb, 0xf); /* size */
1514 ffio_wfourcc(pb, "d263");
1515 ffio_wfourcc(pb, "FFMP");
1516 avio_w8(pb, 0); /* decoder version */
1517 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1518 avio_w8(pb, 0xa); /* level */
1519 avio_w8(pb, 0); /* profile */
1520 return 0xf;
1521 }
1522
1523 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1524 {
1525 1 int64_t pos = avio_tell(pb);
1526
1527 1 avio_wb32(pb, 0);
1528 1 ffio_wfourcc(pb, "av1C");
1529 1 ff_isom_write_av1c(pb, track->vos_data, track->vos_len, track->mode != MODE_AVIF);
1530 1 return update_size(pb, pos);
1531 }
1532
1533 53 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1534 {
1535 53 int64_t pos = avio_tell(pb);
1536
1537 53 avio_wb32(pb, 0);
1538 53 ffio_wfourcc(pb, "avcC");
1539 53 ff_isom_write_avcc(pb, track->vos_data, track->vos_len);
1540 53 return update_size(pb, pos);
1541 }
1542
1543 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1544 {
1545 int64_t pos = avio_tell(pb);
1546
1547 avio_wb32(pb, 0);
1548 ffio_wfourcc(pb, "vpcC");
1549 ff_isom_write_vpcc(s, pb, track->vos_data, track->vos_len, track->par);
1550 return update_size(pb, pos);
1551 }
1552
1553 3 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1554 {
1555 3 int64_t pos = avio_tell(pb);
1556
1557 3 avio_wb32(pb, 0);
1558 3 ffio_wfourcc(pb, "hvcC");
1559
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->tag == MKTAG('h','v','c','1'))
1560 1 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 1, s);
1561 else
1562 2 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0, s);
1563 3 return update_size(pb, pos);
1564 }
1565
1566 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1567 {
1568 1 int64_t pos = avio_tell(pb);
1569 int ret;
1570
1571 1 avio_wb32(pb, 0);
1572 1 ffio_wfourcc(pb, "lhvC");
1573
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1574 1 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 1, s);
1575 else
1576 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 0, s);
1577
1578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1579 avio_seek(pb, pos, SEEK_SET);
1580 return ret;
1581 }
1582
1583 1 return update_size(pb, pos);
1584 }
1585
1586 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1587 {
1588 1 int64_t pos = avio_tell(pb);
1589
1590 1 avio_wb32(pb, 0);
1591 1 ffio_wfourcc(pb, "evcC");
1592
1593
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1594 1 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 1);
1595 else
1596 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 0);
1597
1598 1 return update_size(pb, pos);
1599 }
1600
1601 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1602 {
1603 1 int64_t pos = avio_tell(pb);
1604
1605 1 avio_wb32(pb, 0);
1606 1 ffio_wfourcc(pb, "vvcC");
1607
1608 1 avio_w8 (pb, 0); /* version */
1609 1 avio_wb24(pb, 0); /* flags */
1610
1611
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1612 1 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 1);
1613 else
1614 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 0);
1615 1 return update_size(pb, pos);
1616 }
1617
1618 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1619 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1620 {
1621 int interlaced;
1622 int cid;
1623 23 int display_width = track->par->width;
1624
1625
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) {
1626
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->vos_data) != 0) {
1627 /* looks like a DNxHD bit stream */
1628 23 interlaced = (track->vos_data[5] & 2);
1629 23 cid = AV_RB32(track->vos_data + 0x28);
1630 } else {
1631 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1632 return 0;
1633 }
1634 } else {
1635 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1636 return 0;
1637 }
1638
1639 23 avio_wb32(pb, 24); /* size */
1640 23 ffio_wfourcc(pb, "ACLR");
1641 23 ffio_wfourcc(pb, "ACLR");
1642 23 ffio_wfourcc(pb, "0001");
1643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1644 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1645 23 avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */
1646 } else { /* Full range (0-255) */
1647 avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */
1648 }
1649 23 avio_wb32(pb, 0); /* unknown */
1650
1651
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1652 12 avio_wb32(pb, 32);
1653 12 ffio_wfourcc(pb, "ADHR");
1654 12 ffio_wfourcc(pb, "0001");
1655 12 avio_wb32(pb, cid);
1656 12 avio_wb32(pb, 0); /* unknown */
1657 12 avio_wb32(pb, 1); /* unknown */
1658 12 avio_wb32(pb, 0); /* unknown */
1659 12 avio_wb32(pb, 0); /* unknown */
1660 12 return 0;
1661 }
1662
1663 11 avio_wb32(pb, 24); /* size */
1664 11 ffio_wfourcc(pb, "APRG");
1665 11 ffio_wfourcc(pb, "APRG");
1666 11 ffio_wfourcc(pb, "0001");
1667 11 avio_wb32(pb, 1); /* unknown */
1668 11 avio_wb32(pb, 0); /* unknown */
1669
1670 11 avio_wb32(pb, 120); /* size */
1671 11 ffio_wfourcc(pb, "ARES");
1672 11 ffio_wfourcc(pb, "ARES");
1673 11 ffio_wfourcc(pb, "0001");
1674 11 avio_wb32(pb, cid); /* dnxhd cid, some id ? */
1675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1676 && track->par->sample_aspect_ratio.den > 0)
1677 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1678 11 avio_wb32(pb, display_width);
1679 /* values below are based on samples created with quicktime and avid codecs */
1680
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1681 11 avio_wb32(pb, track->par->height / 2);
1682 11 avio_wb32(pb, 2); /* unknown */
1683 11 avio_wb32(pb, 0); /* unknown */
1684 11 avio_wb32(pb, 4); /* unknown */
1685 } else {
1686 avio_wb32(pb, track->par->height);
1687 avio_wb32(pb, 1); /* unknown */
1688 avio_wb32(pb, 0); /* unknown */
1689 if (track->par->height == 1080)
1690 avio_wb32(pb, 5); /* unknown */
1691 else
1692 avio_wb32(pb, 6); /* unknown */
1693 }
1694 /* padding */
1695 11 ffio_fill(pb, 0, 10 * 8);
1696
1697 11 return 0;
1698 }
1699
1700 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1701 {
1702 avio_wb32(pb, 12);
1703 ffio_wfourcc(pb, "DpxE");
1704 if (track->par->extradata_size >= 12 &&
1705 !memcmp(&track->par->extradata[4], "DpxE", 4)) {
1706 avio_wb32(pb, track->par->extradata[11]);
1707 } else {
1708 avio_wb32(pb, 1);
1709 }
1710 return 0;
1711 }
1712
1713 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1714 {
1715 int tag;
1716
1717
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1718
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1719
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');
1720 1 else tag = MKTAG('d','v','c',' ');
1721 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1722 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1723 else tag = MKTAG('d','v','p','p');
1724 } else if (track->par->height == 720) { /* HD 720 line */
1725 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1726 else tag = MKTAG('d','v','h','p');
1727 } else if (track->par->height == 1080) { /* HD 1080 line */
1728 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1729 else tag = MKTAG('d','v','h','6');
1730 } else {
1731 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1732 return 0;
1733 }
1734
1735 1 return tag;
1736 }
1737
1738 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1739 {
1740 3 AVRational rational_framerate = st->avg_frame_rate;
1741 3 int rate = 0;
1742
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1743 3 rate = av_q2d(rational_framerate);
1744 3 return rate;
1745 }
1746
1747 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1748 {
1749 1 int tag = track->par->codec_tag;
1750 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1751 1 AVStream *st = track->st;
1752 1 int rate = defined_frame_rate(s, st);
1753
1754
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1755 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1756
1757
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1758
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) {
1759 if (!interlaced) {
1760 if (rate == 24) tag = MKTAG('x','d','v','4');
1761 else if (rate == 25) tag = MKTAG('x','d','v','5');
1762 else if (rate == 30) tag = MKTAG('x','d','v','1');
1763 else if (rate == 50) tag = MKTAG('x','d','v','a');
1764 else if (rate == 60) tag = MKTAG('x','d','v','9');
1765 }
1766
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) {
1767 if (!interlaced) {
1768 if (rate == 24) tag = MKTAG('x','d','v','6');
1769 else if (rate == 25) tag = MKTAG('x','d','v','7');
1770 else if (rate == 30) tag = MKTAG('x','d','v','8');
1771 } else {
1772 if (rate == 25) tag = MKTAG('x','d','v','3');
1773 else if (rate == 30) tag = MKTAG('x','d','v','2');
1774 }
1775
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) {
1776 if (!interlaced) {
1777 if (rate == 24) tag = MKTAG('x','d','v','d');
1778 else if (rate == 25) tag = MKTAG('x','d','v','e');
1779 else if (rate == 30) tag = MKTAG('x','d','v','f');
1780 } else {
1781 if (rate == 25) tag = MKTAG('x','d','v','c');
1782 else if (rate == 30) tag = MKTAG('x','d','v','b');
1783 }
1784 }
1785 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1786 if (track->par->width == 1280 && track->par->height == 720) {
1787 if (!interlaced) {
1788 if (rate == 24) tag = MKTAG('x','d','5','4');
1789 else if (rate == 25) tag = MKTAG('x','d','5','5');
1790 else if (rate == 30) tag = MKTAG('x','d','5','1');
1791 else if (rate == 50) tag = MKTAG('x','d','5','a');
1792 else if (rate == 60) tag = MKTAG('x','d','5','9');
1793 }
1794 } else if (track->par->width == 1920 && track->par->height == 1080) {
1795 if (!interlaced) {
1796 if (rate == 24) tag = MKTAG('x','d','5','d');
1797 else if (rate == 25) tag = MKTAG('x','d','5','e');
1798 else if (rate == 30) tag = MKTAG('x','d','5','f');
1799 } else {
1800 if (rate == 25) tag = MKTAG('x','d','5','c');
1801 else if (rate == 30) tag = MKTAG('x','d','5','b');
1802 }
1803 }
1804 }
1805
1806 1 return tag;
1807 }
1808
1809 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1810 {
1811 2 int tag = track->par->codec_tag;
1812 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1813 2 AVStream *st = track->st;
1814 2 int rate = defined_frame_rate(s, st);
1815
1816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
1817 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1818
1819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1820 if (track->par->width == 960 && track->par->height == 720) {
1821 if (!interlaced) {
1822 if (rate == 24) tag = MKTAG('a','i','5','p');
1823 else if (rate == 25) tag = MKTAG('a','i','5','q');
1824 else if (rate == 30) tag = MKTAG('a','i','5','p');
1825 else if (rate == 50) tag = MKTAG('a','i','5','q');
1826 else if (rate == 60) tag = MKTAG('a','i','5','p');
1827 }
1828 } else if (track->par->width == 1440 && track->par->height == 1080) {
1829 if (!interlaced) {
1830 if (rate == 24) tag = MKTAG('a','i','5','3');
1831 else if (rate == 25) tag = MKTAG('a','i','5','2');
1832 else if (rate == 30) tag = MKTAG('a','i','5','3');
1833 } else {
1834 if (rate == 50) tag = MKTAG('a','i','5','5');
1835 else if (rate == 60) tag = MKTAG('a','i','5','6');
1836 }
1837 }
1838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1839 if (track->par->width == 1280 && track->par->height == 720) {
1840 if (!interlaced) {
1841 if (rate == 24) tag = MKTAG('a','i','1','p');
1842 else if (rate == 25) tag = MKTAG('a','i','1','q');
1843 else if (rate == 30) tag = MKTAG('a','i','1','p');
1844 else if (rate == 50) tag = MKTAG('a','i','1','q');
1845 else if (rate == 60) tag = MKTAG('a','i','1','p');
1846 }
1847 } else if (track->par->width == 1920 && track->par->height == 1080) {
1848 if (!interlaced) {
1849 if (rate == 24) tag = MKTAG('a','i','1','3');
1850 else if (rate == 25) tag = MKTAG('a','i','1','2');
1851 else if (rate == 30) tag = MKTAG('a','i','1','3');
1852 } else {
1853 if (rate == 25) tag = MKTAG('a','i','1','5');
1854 else if (rate == 50) tag = MKTAG('a','i','1','5');
1855 else if (rate == 60) tag = MKTAG('a','i','1','6');
1856 }
1857 } else if ( track->par->width == 4096 && track->par->height == 2160
1858 || track->par->width == 3840 && track->par->height == 2160
1859 || track->par->width == 2048 && track->par->height == 1080) {
1860 tag = MKTAG('a','i','v','x');
1861 }
1862 }
1863
1864 2 return tag;
1865 }
1866
1867 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
1868 {
1869 int tag = track->par->codec_tag;
1870
1871 if (!tag)
1872 tag = MKTAG('e', 'v', 'c', '1');
1873
1874 return tag;
1875 }
1876
1877 static const struct {
1878 enum AVPixelFormat pix_fmt;
1879 uint32_t tag;
1880 unsigned bps;
1881 } mov_pix_fmt_tags[] = {
1882 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
1883 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
1884 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
1885 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
1886 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
1887 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
1888 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
1889 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
1890 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
1891 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
1892 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
1893 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
1894 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
1895 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
1896 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
1897 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
1898 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
1899 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
1900 };
1901
1902 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
1903 {
1904 23 int tag = MKTAG('A','V','d','n');
1905
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
1906
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
1907 12 tag = MKTAG('A','V','d','h');
1908 23 return tag;
1909 }
1910
1911 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
1912 {
1913 17 int tag = track->par->codec_tag;
1914 int i;
1915 enum AVPixelFormat pix_fmt;
1916
1917
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 12 times.
264 for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
1918
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
1919 17 tag = mov_pix_fmt_tags[i].tag;
1920 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
1921
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
1922 5 break;
1923 }
1924 }
1925
1926 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
1927 17 track->par->bits_per_coded_sample);
1928
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
1929
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
1930 track->par->format != AV_PIX_FMT_GRAY8 &&
1931 track->par->format != AV_PIX_FMT_NONE)
1932 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
1933 av_get_pix_fmt_name(track->par->format));
1934 17 return tag;
1935 }
1936
1937 165 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
1938 {
1939 165 unsigned int tag = track->par->codec_tag;
1940
1941 // "rtp " is used to distinguish internally created RTP-hint tracks
1942 // (with rtp_ctx) from other tracks.
1943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
165 if (tag == MKTAG('r','t','p',' '))
1944 tag = 0;
1945
3/4
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 129 times.
✓ Branch 3 taken 36 times.
165 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
1946
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 1 times.
129 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
1947
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 17 times.
128 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
1948
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 track->par->codec_id == AV_CODEC_ID_H263 ||
1949
2/2
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 2 times.
111 track->par->codec_id == AV_CODEC_ID_H264 ||
1950
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 23 times.
109 track->par->codec_id == AV_CODEC_ID_DNXHD ||
1951
4/4
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 67 times.
171 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
1952 85 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
1953
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
1954 1 tag = mov_get_dv_codec_tag(s, track);
1955
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
1956 17 tag = mov_get_rawvideo_codec_tag(s, track);
1957
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
1958 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
1959
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
1960 2 tag = mov_get_h264_codec_tag(s, track);
1961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
1962 tag = mov_get_evc_codec_tag(s, track);
1963
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
1964 23 tag = mov_get_dnxhd_codec_tag(s, track);
1965
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
1966 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
1967 if (!tag) { // if no mac fcc found, try with Microsoft tags
1968 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
1969 if (tag)
1970 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
1971 "the file may be unplayable!\n");
1972 }
1973
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
1974 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
1975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
1976 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
1977 if (ms_tag) {
1978 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
1979 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
1980 "the file may be unplayable!\n");
1981 }
1982 }
1983 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
1984 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
1985 }
1986
1987 165 return tag;
1988 }
1989
1990 static const AVCodecTag codec_cover_image_tags[] = {
1991 { AV_CODEC_ID_MJPEG, 0xD },
1992 { AV_CODEC_ID_PNG, 0xE },
1993 { AV_CODEC_ID_BMP, 0x1B },
1994 { AV_CODEC_ID_NONE, 0 },
1995 };
1996
1997 95 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
1998 unsigned int tag, int codec_id)
1999 {
2000 int i;
2001
2002 /**
2003 * Check that tag + id is in the table
2004 */
2005
2/4
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95 times.
✗ Branch 3 not taken.
95 for (i = 0; tags && tags[i]; i++) {
2006 95 const AVCodecTag *codec_tags = tags[i];
2007
1/2
✓ Branch 0 taken 1298 times.
✗ Branch 1 not taken.
1298 while (codec_tags->id != AV_CODEC_ID_NONE) {
2008
2/2
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 1191 times.
1298 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2009
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 12 times.
107 codec_tags->id == codec_id)
2010 95 return codec_tags->tag;
2011 1203 codec_tags++;
2012 }
2013 }
2014 return 0;
2015 }
2016
2017 262 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2018 {
2019
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 260 times.
262 if (is_cover_image(track->st))
2020 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2021
2022
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 259 times.
260 if (track->mode == MODE_IPOD)
2023
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") &&
2024
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2025 1 !av_match_ext(s->url, "m4b"))
2026 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2027 "Quicktime/Ipod might not play the file\n");
2028
2029
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 95 times.
260 if (track->mode == MODE_MOV) {
2030 165 return mov_get_codec_tag(s, track);
2031 } else
2032 95 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2033 95 track->par->codec_id);
2034 }
2035
2036 /** Write uuid atom.
2037 * Needed to make file play in iPods running newest firmware
2038 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2039 */
2040 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2041 {
2042 avio_wb32(pb, 28);
2043 ffio_wfourcc(pb, "uuid");
2044 avio_wb32(pb, 0x6b6840f2);
2045 avio_wb32(pb, 0x5f244fc5);
2046 avio_wb32(pb, 0xba39a51b);
2047 avio_wb32(pb, 0xcf0323f3);
2048 avio_wb32(pb, 0x0);
2049 return 28;
2050 }
2051
2052 static const uint16_t fiel_data[] = {
2053 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2054 };
2055
2056 95 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2057 {
2058 95 unsigned mov_field_order = 0;
2059
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2060 95 mov_field_order = fiel_data[field_order];
2061 else
2062 return 0;
2063 95 avio_wb32(pb, 10);
2064 95 ffio_wfourcc(pb, "fiel");
2065 95 avio_wb16(pb, mov_field_order);
2066 95 return 10;
2067 }
2068
2069 4 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2070 {
2071 4 MOVMuxContext *mov = s->priv_data;
2072 4 int ret = AVERROR_BUG;
2073 4 int64_t pos = avio_tell(pb);
2074 4 avio_wb32(pb, 0); /* size */
2075 4 avio_wl32(pb, track->tag); // store it byteswapped
2076 4 avio_wb32(pb, 0); /* Reserved */
2077 4 avio_wb16(pb, 0); /* Reserved */
2078 4 avio_wb16(pb, 1); /* Data-reference index */
2079
2080
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2081 mov_write_esds_tag(pb, track);
2082
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2083
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (track->par->codec_tag) {
2084 1 case MOV_ISMV_TTML_TAG:
2085 // ISMV dfxp requires no extradata.
2086 2 break;
2087 1 case MOV_MP4_TTML_TAG:
2088 // As specified in 14496-30, XMLSubtitleSampleEntry
2089 // Namespace
2090 1 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2091 // Empty schema_location
2092 1 avio_w8(pb, 0);
2093 // Empty auxiliary_mime_types
2094 1 avio_w8(pb, 0);
2095 1 break;
2096 default:
2097 av_log(NULL, AV_LOG_ERROR,
2098 "Unknown codec tag '%s' utilized for TTML stream with "
2099 "index %d (track id %d)!\n",
2100 av_fourcc2str(track->par->codec_tag), track->st->index,
2101 track->track_id);
2102 return AVERROR(EINVAL);
2103 }
2104
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->par->extradata_size)
2105 2 avio_write(pb, track->par->extradata, track->par->extradata_size);
2106
2107
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 &&
2108 4 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2109 return ret;
2110
2111 4 return update_size(pb, pos);
2112 }
2113
2114 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2115 {
2116 int8_t stereo_mode;
2117
2118 if (stereo_3d->flags != 0) {
2119 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2120 return 0;
2121 }
2122
2123 switch (stereo_3d->type) {
2124 case AV_STEREO3D_2D:
2125 stereo_mode = 0;
2126 break;
2127 case AV_STEREO3D_TOPBOTTOM:
2128 stereo_mode = 1;
2129 break;
2130 case AV_STEREO3D_SIDEBYSIDE:
2131 stereo_mode = 2;
2132 break;
2133 default:
2134 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2135 return 0;
2136 }
2137 avio_wb32(pb, 13); /* size */
2138 ffio_wfourcc(pb, "st3d");
2139 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2140 avio_w8(pb, stereo_mode);
2141 return 13;
2142 }
2143
2144 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2145 {
2146 int64_t sv3d_pos, svhd_pos, proj_pos;
2147 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2148
2149 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2150 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2151 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2152 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2153 return 0;
2154 }
2155
2156 sv3d_pos = avio_tell(pb);
2157 avio_wb32(pb, 0); /* size */
2158 ffio_wfourcc(pb, "sv3d");
2159
2160 svhd_pos = avio_tell(pb);
2161 avio_wb32(pb, 0); /* size */
2162 ffio_wfourcc(pb, "svhd");
2163 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2164 avio_put_str(pb, metadata_source);
2165 update_size(pb, svhd_pos);
2166
2167 proj_pos = avio_tell(pb);
2168 avio_wb32(pb, 0); /* size */
2169 ffio_wfourcc(pb, "proj");
2170
2171 avio_wb32(pb, 24); /* size */
2172 ffio_wfourcc(pb, "prhd");
2173 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2174 avio_wb32(pb, spherical_mapping->yaw);
2175 avio_wb32(pb, spherical_mapping->pitch);
2176 avio_wb32(pb, spherical_mapping->roll);
2177
2178 switch (spherical_mapping->projection) {
2179 case AV_SPHERICAL_EQUIRECTANGULAR:
2180 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2181 avio_wb32(pb, 28); /* size */
2182 ffio_wfourcc(pb, "equi");
2183 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2184 avio_wb32(pb, spherical_mapping->bound_top);
2185 avio_wb32(pb, spherical_mapping->bound_bottom);
2186 avio_wb32(pb, spherical_mapping->bound_left);
2187 avio_wb32(pb, spherical_mapping->bound_right);
2188 break;
2189 case AV_SPHERICAL_CUBEMAP:
2190 avio_wb32(pb, 20); /* size */
2191 ffio_wfourcc(pb, "cbmp");
2192 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2193 avio_wb32(pb, 0); /* layout */
2194 avio_wb32(pb, spherical_mapping->padding); /* padding */
2195 break;
2196 }
2197 update_size(pb, proj_pos);
2198
2199 return update_size(pb, sv3d_pos);
2200 }
2201
2202 5 static inline int64_t rescale_rational(AVRational q, int b)
2203 {
2204 5 return av_rescale(q.num, b, q.den);
2205 }
2206
2207 1 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2208 const AVStereo3D *stereo3d)
2209 {
2210
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!stereo3d->horizontal_field_of_view.num)
2211 return;
2212
2213 1 avio_wb32(pb, 12); /* size */
2214 1 ffio_wfourcc(pb, "hfov");
2215 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2216 }
2217
2218 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2219 const AVSphericalMapping *spherical_mapping)
2220 {
2221 1 avio_wb32(pb, 24); /* size */
2222 1 ffio_wfourcc(pb, "proj");
2223 1 avio_wb32(pb, 16); /* size */
2224 1 ffio_wfourcc(pb, "prji");
2225 1 avio_wb32(pb, 0); /* version + flags */
2226
2227
1/5
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 switch (spherical_mapping->projection) {
2228 1 case AV_SPHERICAL_RECTILINEAR:
2229 1 ffio_wfourcc(pb, "rect");
2230 1 break;
2231 case AV_SPHERICAL_EQUIRECTANGULAR:
2232 ffio_wfourcc(pb, "equi");
2233 break;
2234 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2235 ffio_wfourcc(pb, "hequ");
2236 break;
2237 case AV_SPHERICAL_FISHEYE:
2238 ffio_wfourcc(pb, "fish");
2239 break;
2240 default:
2241 av_assert0(0);
2242 }
2243 1 }
2244
2245 1 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2246 const AVStereo3D *stereo3d)
2247 {
2248 1 int64_t pos = avio_tell(pb);
2249 1 int view = 0;
2250
2251 1 avio_wb32(pb, 0); /* size */
2252 1 ffio_wfourcc(pb, "eyes");
2253
2254 // stri is mandatory
2255 1 avio_wb32(pb, 13); /* size */
2256 1 ffio_wfourcc(pb, "stri");
2257 1 avio_wb32(pb, 0); /* version + flags */
2258
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo3d->view) {
2259 case AV_STEREO3D_VIEW_LEFT:
2260 view |= 1 << 0;
2261 break;
2262 case AV_STEREO3D_VIEW_RIGHT:
2263 view |= 1 << 1;
2264 break;
2265 1 case AV_STEREO3D_VIEW_PACKED:
2266 1 view |= (1 << 0) | (1 << 1);
2267 1 break;
2268 }
2269 1 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2270 1 avio_w8(pb, view);
2271
2272 // hero is optional
2273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2274 avio_wb32(pb, 13); /* size */
2275 ffio_wfourcc(pb, "hero");
2276 avio_wb32(pb, 0); /* version + flags */
2277 avio_w8(pb, stereo3d->primary_eye);
2278 }
2279
2280 // it's not clear if cams is mandatory or optional
2281
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->baseline) {
2282 1 avio_wb32(pb, 24); /* size */
2283 1 ffio_wfourcc(pb, "cams");
2284 1 avio_wb32(pb, 16); /* size */
2285 1 ffio_wfourcc(pb, "blin");
2286 1 avio_wb32(pb, 0); /* version + flags */
2287 1 avio_wb32(pb, stereo3d->baseline);
2288 }
2289
2290 // it's not clear if cmfy is mandatory or optional
2291
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->horizontal_disparity_adjustment.num) {
2292 1 avio_wb32(pb, 24); /* size */
2293 1 ffio_wfourcc(pb, "cmfy");
2294 1 avio_wb32(pb, 16); /* size */
2295 1 ffio_wfourcc(pb, "dadj");
2296 1 avio_wb32(pb, 0); /* version + flags */
2297 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2298 }
2299
2300 1 return update_size(pb, pos);
2301 }
2302
2303 1 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2304 const AVStereo3D *stereo3d,
2305 const AVSphericalMapping *spherical_mapping)
2306 {
2307 int64_t pos;
2308
2309
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping &&
2310
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2311 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2312 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2313 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2314 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2315 spherical_mapping->projection);
2316 spherical_mapping = NULL;
2317 }
2318
2319
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2320
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2322 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2323 !stereo3d->baseline &&
2324 !stereo3d->horizontal_disparity_adjustment.num))) {
2325 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2326 stereo3d = NULL;
2327 }
2328
2329
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!spherical_mapping && !stereo3d)
2330 return 0;
2331
2332 1 pos = avio_tell(pb);
2333 1 avio_wb32(pb, 0); /* size */
2334 1 ffio_wfourcc(pb, "vexu");
2335
2336
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping)
2337 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2338
2339
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d)
2340 1 mov_write_eyes_tag(s, pb, stereo3d);
2341
2342 1 return update_size(pb, pos);
2343 }
2344
2345 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2346 {
2347 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2348
2349 avio_wb32(pb, 32); /* size = 8 + 24 */
2350 if (dovi->dv_profile > 10)
2351 ffio_wfourcc(pb, "dvwC");
2352 else if (dovi->dv_profile > 7)
2353 ffio_wfourcc(pb, "dvvC");
2354 else
2355 ffio_wfourcc(pb, "dvcC");
2356
2357 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2358 avio_write(pb, buf, sizeof(buf));
2359
2360 return 32; /* 8 + 24 */
2361 }
2362
2363 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2364 uint32_t top, uint32_t bottom,
2365 uint32_t left, uint32_t right)
2366 {
2367 5 uint32_t cropped_width = track->par->width - left - right;
2368 5 uint32_t cropped_height = track->height - top - bottom;
2369 AVRational horizOff =
2370 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2371 5 (AVRational) { left, 1 });
2372 AVRational vertOff =
2373 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2374 5 (AVRational) { top, 1 });
2375
2376 5 avio_wb32(pb, 40);
2377 5 ffio_wfourcc(pb, "clap");
2378 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2379 5 avio_wb32(pb, 1); /* apertureWidthD */
2380 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2381 5 avio_wb32(pb, 1); /* apertureHeightD */
2382
2383 5 avio_wb32(pb, -horizOff.num);
2384 5 avio_wb32(pb, horizOff.den);
2385 5 avio_wb32(pb, -vertOff.num);
2386 5 avio_wb32(pb, vertOff.den);
2387
2388 5 return 40;
2389 }
2390
2391 6 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2392 {
2393 AVRational sar;
2394 6 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2395 6 track->par->sample_aspect_ratio.den, INT_MAX);
2396
2397 6 avio_wb32(pb, 16);
2398 6 ffio_wfourcc(pb, "pasp");
2399 6 avio_wb32(pb, sar.num);
2400 6 avio_wb32(pb, sar.den);
2401 6 return 16;
2402 }
2403
2404 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2405 {
2406 uint32_t gama = 0;
2407 if (gamma <= 0.0)
2408 gamma = av_csp_approximate_trc_gamma(track->par->color_trc);
2409 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2410
2411 if (gamma > 1e-6) {
2412 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2413 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2414
2415 av_assert0(track->mode == MODE_MOV);
2416 avio_wb32(pb, 12);
2417 ffio_wfourcc(pb, "gama");
2418 avio_wb32(pb, gama);
2419 return 12;
2420 } else {
2421 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2422 }
2423 return 0;
2424 }
2425
2426 9 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2427 {
2428 9 int64_t pos = avio_tell(pb);
2429
2430 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2431 // Ref (MP4): ISO/IEC 14496-12:2012
2432
2433
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 if (prefer_icc) {
2434 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2435 4 track->st->codecpar->nb_coded_side_data,
2436 AV_PKT_DATA_ICC_PROFILE);
2437
2438
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2439 avio_wb32(pb, 12 + sd->size);
2440 ffio_wfourcc(pb, "colr");
2441 ffio_wfourcc(pb, "prof");
2442 avio_write(pb, sd->data, sd->size);
2443 return 12 + sd->size;
2444 }
2445 else {
2446 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2447 }
2448 }
2449
2450 /* We should only ever be called for MOV, MP4 and AVIF. */
2451
3/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
9 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2452 track->mode == MODE_AVIF);
2453
2454 9 avio_wb32(pb, 0); /* size */
2455 9 ffio_wfourcc(pb, "colr");
2456
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2457 1 ffio_wfourcc(pb, "nclx");
2458 else
2459 8 ffio_wfourcc(pb, "nclc");
2460 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2461 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2462 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2463 9 avio_wb16(pb, track->par->color_primaries);
2464 9 avio_wb16(pb, track->par->color_trc);
2465 9 avio_wb16(pb, track->par->color_space);
2466
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2467 1 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2468 1 avio_w8(pb, full_range << 7);
2469 }
2470
2471 9 return update_size(pb, pos);
2472 }
2473
2474 200 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2475 {
2476 const AVPacketSideData *side_data;
2477 const AVContentLightMetadata *content_light_metadata;
2478
2479 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2480 200 track->st->codecpar->nb_coded_side_data,
2481 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2482
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (!side_data) {
2483 200 return 0;
2484 }
2485 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2486
2487 avio_wb32(pb, 12); // size
2488 ffio_wfourcc(pb, "clli");
2489 avio_wb16(pb, content_light_metadata->MaxCLL);
2490 avio_wb16(pb, content_light_metadata->MaxFALL);
2491 return 12;
2492 }
2493
2494 200 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2495 {
2496 200 const int chroma_den = 50000;
2497 200 const int luma_den = 10000;
2498 const AVPacketSideData *side_data;
2499 200 const AVMasteringDisplayMetadata *metadata = NULL;
2500
2501 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2502 200 track->st->codecpar->nb_coded_side_data,
2503 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if (side_data)
2505 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2506
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
200 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2507 200 return 0;
2508 }
2509
2510 avio_wb32(pb, 32); // size
2511 ffio_wfourcc(pb, "mdcv");
2512 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2513 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2514 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2515 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2516 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2517 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2518 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2519 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2520 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2521 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2522 return 32;
2523 }
2524
2525 200 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2526 {
2527 200 const int illuminance_den = 10000;
2528 200 const int ambient_den = 50000;
2529 const AVPacketSideData *side_data;
2530 const AVAmbientViewingEnvironment *ambient;
2531
2532
2533 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2534 200 track->st->codecpar->nb_coded_side_data,
2535 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2536
2537
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 1 times.
200 if (!side_data)
2538 199 return 0;
2539
2540 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2541
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)
2542 return 0;
2543
2544 1 avio_wb32(pb, 16); // size
2545 1 ffio_wfourcc(pb, "amve");
2546 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2547 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2548 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2549 1 return 16;
2550 }
2551
2552 205 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2553 {
2554 AVDictionaryEntry *encoder;
2555
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2556
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
204 || (track->par->width == 1440 && track->par->height == 1080)
2557
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 204 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 191 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
410 || (track->par->width == 1920 && track->par->height == 1080);
2558
2559
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 if ((track->mode == MODE_AVIF ||
2560
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
205 track->mode == MODE_MOV ||
2561
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 145 times.
✓ Branch 3 taken 55 times.
267 track->mode == MODE_MP4) &&
2562 200 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2563 145 av_strlcpy(compressor_name, encoder->value, 32);
2564
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
60 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2565 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2566 AVStream *st = track->st;
2567 int rate = defined_frame_rate(NULL, st);
2568 av_strlcatf(compressor_name, len, "XDCAM");
2569 if (track->par->format == AV_PIX_FMT_YUV422P) {
2570 av_strlcatf(compressor_name, len, " HD422");
2571 } else if(track->par->width == 1440) {
2572 av_strlcatf(compressor_name, len, " HD");
2573 } else
2574 av_strlcatf(compressor_name, len, " EX");
2575
2576 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2577
2578 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2579 }
2580 205 }
2581
2582 static int mov_write_ccst_tag(AVIOContext *pb)
2583 {
2584 int64_t pos = avio_tell(pb);
2585 // Write sane defaults:
2586 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2587 // intra_pred_used = 1 : intra prediction may or may not be used.
2588 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2589 // reference images can be used.
2590 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2591 (1 << 6) | /* intra_pred_used */
2592 (15 << 2); /* max_ref_per_pic */
2593 avio_wb32(pb, 0); /* size */
2594 ffio_wfourcc(pb, "ccst");
2595 avio_wb32(pb, 0); /* Version & flags */
2596 avio_w8(pb, ccstValue);
2597 avio_wb24(pb, 0); /* reserved */
2598 return update_size(pb, pos);
2599 }
2600
2601 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2602 {
2603 int64_t pos = avio_tell(pb);
2604 avio_wb32(pb, 0); /* size */
2605 ffio_wfourcc(pb, aux_type);
2606 avio_wb32(pb, 0); /* Version & flags */
2607 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2608 return update_size(pb, pos);
2609 }
2610
2611 205 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2612 {
2613 205 int ret = AVERROR_BUG;
2614 205 int64_t pos = avio_tell(pb);
2615 const AVPacketSideData *sd;
2616 205 char compressor_name[32] = { 0 };
2617 205 int avid = 0;
2618
2619
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 int uncompressed_ycbcr = ((track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVY422)
2620
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2621
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2622
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2623
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2624 #if FF_API_V408_CODECID
2625
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V308
2626
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V408
2627
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V410
2628 #endif
2629
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 201 times.
410 || track->par->codec_id == AV_CODEC_ID_V210);
2630
2631 205 avio_wb32(pb, 0); /* size */
2632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->encryption_scheme != MOV_ENC_NONE) {
2633 ffio_wfourcc(pb, "encv");
2634 } else {
2635 205 avio_wl32(pb, track->tag); // store it byteswapped
2636 }
2637 205 avio_wb32(pb, 0); /* Reserved */
2638 205 avio_wb16(pb, 0); /* Reserved */
2639 205 avio_wb16(pb, 1); /* Data-reference index */
2640
2641
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 201 times.
205 if (uncompressed_ycbcr) {
2642 4 avio_wb16(pb, 2); /* Codec stream version */
2643 } else {
2644 201 avio_wb16(pb, 0); /* Codec stream version */
2645 }
2646 205 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2647
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
205 if (track->mode == MODE_MOV) {
2648 138 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2649
3/4
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 121 times.
138 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2650 17 avio_wb32(pb, 0); /* Temporal Quality */
2651 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2652 } else {
2653 121 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2654 121 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2655 }
2656 } else {
2657 67 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2658 }
2659 205 avio_wb16(pb, track->par->width); /* Video width */
2660 205 avio_wb16(pb, track->height); /* Video height */
2661 205 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2662 205 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2663 205 avio_wb32(pb, 0); /* Data size (= 0) */
2664 205 avio_wb16(pb, 1); /* Frame count (= 1) */
2665
2666 205 find_compressor(compressor_name, 32, track);
2667 205 avio_w8(pb, strlen(compressor_name));
2668 205 avio_write(pb, compressor_name, 31);
2669
2670
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
205 if (track->mode == MODE_MOV &&
2671
2/4
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 138 times.
138 (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210))
2672 avio_wb16(pb, 0x18);
2673
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 107 times.
205 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2674 31 avio_wb16(pb, track->par->bits_per_coded_sample |
2675
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 28 times.
31 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2676 else
2677 174 avio_wb16(pb, 0x18); /* Reserved */
2678
2679
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 133 times.
210 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2680 int pal_size, i;
2681 5 avio_wb16(pb, 0); /* Color table ID */
2682 5 avio_wb32(pb, 0); /* Color table seed */
2683 5 avio_wb16(pb, 0x8000); /* Color table flags */
2684
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)
2685 return AVERROR(EINVAL);
2686 5 pal_size = 1 << track->par->bits_per_coded_sample;
2687 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2688
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2689 1040 uint32_t rgb = track->palette[i];
2690 1040 uint16_t r = (rgb >> 16) & 0xff;
2691 1040 uint16_t g = (rgb >> 8) & 0xff;
2692 1040 uint16_t b = rgb & 0xff;
2693 1040 avio_wb16(pb, 0);
2694 1040 avio_wb16(pb, (r << 8) | r);
2695 1040 avio_wb16(pb, (g << 8) | g);
2696 1040 avio_wb16(pb, (b << 8) | b);
2697 }
2698 } else
2699 200 avio_wb16(pb, 0xffff); /* Reserved */
2700
2701
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 180 times.
205 if (track->tag == MKTAG('m','p','4','v'))
2702 25 mov_write_esds_tag(pb, track);
2703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 else if (track->par->codec_id == AV_CODEC_ID_H263)
2704 mov_write_d263_tag(pb);
2705
2/2
✓ Branch 0 taken 177 times.
✓ Branch 1 taken 3 times.
180 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2706
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 177 times.
177 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2707 3 mov_write_extradata_tag(pb, track);
2708 3 avio_wb32(pb, 0);
2709
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 154 times.
177 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2710 23 mov_write_avid_tag(pb, track);
2711 23 avid = 1;
2712
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 151 times.
154 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2713 3 mov_write_hvcc_tag(mov->fc, pb, track);
2714
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2715 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2717 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2718 }
2719
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 150 times.
151 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2720 1 mov_write_vvcc_tag(pb, track);
2721
16/30
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 53 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 53 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 53 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 53 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 53 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 53 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 53 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 53 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 53 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 53 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 53 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 53 times.
✗ Branch 29 not taken.
150 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2722 53 mov_write_avcc_tag(pb, track);
2723
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (track->mode == MODE_IPOD)
2724 mov_write_uuid_tag_ipod(pb);
2725 }
2726
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 96 times.
97 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2727 1 mov_write_evcc_tag(pb, track);
2728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2729 mov_write_vpcc_tag(mov->fc, pb, track);
2730
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
96 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2731 1 mov_write_av1c_tag(pb, track);
2732
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
95 } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
2733 mov_write_dvc1_tag(pb, track);
2734
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2735
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 track->par->codec_id == AV_CODEC_ID_VP6A) {
2736 /* Don't write any potential extradata here - the cropping
2737 * is signalled via the normal width/height fields. */
2738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2739 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2740 mov_write_dpxe_tag(pb, track);
2741
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 91 times.
95 } else if (track->vos_len > 0)
2742 4 mov_write_glbl_tag(pb, track);
2743
2744
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 53 times.
205 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2745
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 25 times.
152 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2746
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 23 times.
127 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2747 104 int field_order = track->par->field_order;
2748
2749
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 9 times.
104 if (field_order != AV_FIELD_UNKNOWN)
2750 95 mov_write_fiel_tag(pb, track, field_order);
2751 }
2752
2753
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2754 if (track->mode == MODE_MOV)
2755 mov_write_gama_tag(s, pb, track, mov->gamma);
2756 else
2757 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2758 }
2759
5/6
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 62 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
405 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2760 405 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2761
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
205 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2762
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2763
5/6
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 191 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 191 times.
391 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2764 191 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2765 AV_PKT_DATA_ICC_PROFILE)) {
2766
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5 times.
9 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
2767 9 mov_write_colr_tag(pb, track, prefer_icc);
2768 }
2769
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2770 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2771 }
2772
2773
4/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 5 times.
205 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2774 200 mov_write_clli_tag(pb, track);
2775 200 mov_write_mdcv_tag(pb, track);
2776 200 mov_write_amve_tag(pb, track);
2777 }
2778
2779
3/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62 times.
205 if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2780 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2781 track->st->codecpar->nb_coded_side_data,
2782 AV_PKT_DATA_STEREO3D);
2783 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2784 track->st->codecpar->nb_coded_side_data,
2785 AV_PKT_DATA_SPHERICAL);
2786 if (stereo_3d)
2787 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2788 if (spherical_mapping)
2789 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2790 }
2791
2792
4/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 5 times.
205 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
2793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
2794 138 const AVStereo3D *stereo3d = NULL;
2795 138 const AVSphericalMapping *spherical_mapping = NULL;
2796
2797 138 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2798 138 track->st->codecpar->nb_coded_side_data,
2799 AV_PKT_DATA_STEREO3D);
2800
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (sd)
2801 1 stereo3d = (AVStereo3D *)sd->data;
2802
2803 138 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2804 138 track->st->codecpar->nb_coded_side_data,
2805 AV_PKT_DATA_SPHERICAL);
2806
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (sd)
2807 1 spherical_mapping = (AVSphericalMapping *)sd->data;
2808
2809
3/4
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 137 times.
138 if (stereo3d || spherical_mapping)
2810 1 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
2811
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (stereo3d)
2812 1 mov_write_hfov_tag(s, pb, stereo3d);
2813 }
2814
2815
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
205 if (track->mode == MODE_MP4) {
2816 62 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2817 62 track->st->codecpar->nb_coded_side_data,
2818 AV_PKT_DATA_DOVI_CONF);
2819
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
62 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2820 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2821
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 } else if (dovi) {
2822 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2823 }
2824 }
2825
2826
3/4
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 199 times.
205 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
2827 6 mov_write_pasp_tag(pb, track);
2828 }
2829
2830 205 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2831 205 track->st->codecpar->nb_coded_side_data,
2832 AV_PKT_DATA_FRAME_CROPPING);
2833
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 204 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
206 if (sd && sd->size >= sizeof(uint32_t) * 4) {
2834 1 uint64_t top = AV_RL32(sd->data + 0);
2835 1 uint64_t bottom = AV_RL32(sd->data + 4);
2836 1 uint64_t left = AV_RL32(sd->data + 8);
2837 1 uint64_t right = AV_RL32(sd->data + 12);
2838
2839
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
2840
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
2841 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
2842 return AVERROR(EINVAL);
2843 }
2844
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 if (top || bottom || left || right)
2845 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
2846
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 200 times.
204 } else if (uncompressed_ycbcr)
2847 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
2848
2849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->encryption_scheme != MOV_ENC_NONE) {
2850 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
2851 }
2852
2853
3/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62 times.
267 if (mov->write_btrt &&
2854 62 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2855 return ret;
2856
2857 /* extra padding for avid stsd */
2858 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
2859
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 182 times.
205 if (avid)
2860 23 avio_wb32(pb, 0);
2861
2862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (track->mode == MODE_AVIF) {
2863 mov_write_ccst_tag(pb);
2864 if (mov->nb_streams > 0 && track == &mov->tracks[1])
2865 mov_write_aux_tag(pb, "auxi");
2866 }
2867
2868 205 return update_size(pb, pos);
2869 }
2870
2871 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
2872 {
2873 2 int64_t pos = avio_tell(pb);
2874 2 avio_wb32(pb, 0); /* size */
2875 2 ffio_wfourcc(pb, "rtp ");
2876 2 avio_wb32(pb, 0); /* Reserved */
2877 2 avio_wb16(pb, 0); /* Reserved */
2878 2 avio_wb16(pb, 1); /* Data-reference index */
2879
2880 2 avio_wb16(pb, 1); /* Hint track version */
2881 2 avio_wb16(pb, 1); /* Highest compatible version */
2882 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
2883
2884 2 avio_wb32(pb, 12); /* size */
2885 2 ffio_wfourcc(pb, "tims");
2886 2 avio_wb32(pb, track->timescale);
2887
2888 2 return update_size(pb, pos);
2889 }
2890
2891 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
2892 {
2893 2 uint64_t str_size =strlen(reel_name);
2894 2 int64_t pos = avio_tell(pb);
2895
2896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
2897 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
2898 avio_wb16(pb, 0);
2899 return AVERROR(EINVAL);
2900 }
2901
2902 2 avio_wb32(pb, 0); /* size */
2903 2 ffio_wfourcc(pb, "name"); /* Data format */
2904 2 avio_wb16(pb, str_size); /* string size */
2905 2 avio_wb16(pb, track->language); /* langcode */
2906 2 avio_write(pb, reel_name, str_size); /* reel name */
2907 2 return update_size(pb,pos);
2908 }
2909
2910 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
2911 {
2912 13 int64_t pos = avio_tell(pb);
2913 #if 1
2914 int frame_duration;
2915 int nb_frames;
2916 13 AVDictionaryEntry *t = NULL;
2917
2918
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) {
2919 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
2920 return AVERROR(EINVAL);
2921 } else {
2922 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
2923
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);
2924 }
2925
2926
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
2927 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
2928 return AVERROR(EINVAL);
2929 }
2930
2931 13 avio_wb32(pb, 0); /* size */
2932 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
2933 13 avio_wb32(pb, 0); /* Reserved */
2934 13 avio_wb32(pb, 1); /* Data reference index */
2935 13 avio_wb32(pb, 0); /* Flags */
2936 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
2937 13 avio_wb32(pb, track->timescale); /* Timescale */
2938 13 avio_wb32(pb, frame_duration); /* Frame duration */
2939 13 avio_w8(pb, nb_frames); /* Number of frames */
2940 13 avio_w8(pb, 0); /* Reserved */
2941
2942 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
2943
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)
2944 2 mov_write_source_reference_tag(pb, track, t->value);
2945 else
2946 11 avio_wb16(pb, 0); /* zero size */
2947 #else
2948
2949 avio_wb32(pb, 0); /* size */
2950 ffio_wfourcc(pb, "tmcd"); /* Data format */
2951 avio_wb32(pb, 0); /* Reserved */
2952 avio_wb32(pb, 1); /* Data reference index */
2953 if (track->par->extradata_size)
2954 avio_write(pb, track->par->extradata, track->par->extradata_size);
2955 #endif
2956 13 return update_size(pb, pos);
2957 }
2958
2959 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
2960 {
2961 1 int64_t pos = avio_tell(pb);
2962 1 avio_wb32(pb, 0); /* size */
2963 1 ffio_wfourcc(pb, "gpmd");
2964 1 avio_wb32(pb, 0); /* Reserved */
2965 1 avio_wb16(pb, 0); /* Reserved */
2966 1 avio_wb16(pb, 1); /* Data-reference index */
2967 1 avio_wb32(pb, 0); /* Reserved */
2968 1 return update_size(pb, pos);
2969 }
2970
2971 333 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2972 {
2973 333 int64_t pos = avio_tell(pb);
2974 333 int ret = 0;
2975 333 avio_wb32(pb, 0); /* size */
2976 333 ffio_wfourcc(pb, "stsd");
2977 333 avio_wb32(pb, 0); /* version & flags */
2978 333 avio_wb32(pb, 1); /* entry count */
2979
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
2980 205 ret = mov_write_video_tag(s, pb, mov, track);
2981
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
2982 108 ret = mov_write_audio_tag(s, pb, mov, track);
2983
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2984 4 ret = mov_write_subtitle_tag(s, pb, track);
2985
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
2986 2 ret = mov_write_rtp_tag(pb, track);
2987
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
2988 13 ret = mov_write_tmcd_tag(pb, track);
2989
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
2990 1 ret = mov_write_gpmd_tag(pb, track);
2991
2992
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (ret < 0)
2993 return ret;
2994
2995 333 return update_size(pb, pos);
2996 }
2997
2998 9 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2999 {
3000 9 MOVMuxContext *mov = s->priv_data;
3001 MOVCtts *ctts_entries;
3002 9 uint32_t entries = 0;
3003 uint32_t atom_size;
3004 int i;
3005
3006 9 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ctts_entries)
3008 return AVERROR(ENOMEM);
3009 9 ctts_entries[0].count = 1;
3010 9 ctts_entries[0].offset = track->cluster[0].cts;
3011
2/2
✓ Branch 0 taken 551 times.
✓ Branch 1 taken 9 times.
560 for (i = 1; i < track->entry; i++) {
3012
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 421 times.
551 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3013 130 ctts_entries[entries].count++; /* compress */
3014 } else {
3015 421 entries++;
3016 421 ctts_entries[entries].offset = track->cluster[i].cts;
3017 421 ctts_entries[entries].count = 1;
3018 }
3019 }
3020 9 entries++; /* last one */
3021 9 atom_size = 16 + (entries * 8);
3022 9 avio_wb32(pb, atom_size); /* size */
3023 9 ffio_wfourcc(pb, "ctts");
3024
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3025 avio_w8(pb, 1); /* version */
3026 else
3027 9 avio_w8(pb, 0); /* version */
3028 9 avio_wb24(pb, 0); /* flags */
3029 9 avio_wb32(pb, entries); /* entry count */
3030
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 9 times.
439 for (i = 0; i < entries; i++) {
3031 430 avio_wb32(pb, ctts_entries[i].count);
3032 430 avio_wb32(pb, ctts_entries[i].offset);
3033 }
3034 9 av_free(ctts_entries);
3035 9 return atom_size;
3036 }
3037
3038 /* Time to sample atom */
3039 333 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3040 {
3041 333 MOVStts *stts_entries = NULL;
3042 333 uint32_t entries = -1;
3043 uint32_t atom_size;
3044 int i;
3045
3046
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 75 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3047 33 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!stts_entries)
3049 return AVERROR(ENOMEM);
3050 33 stts_entries[0].count = track->sample_count;
3051 33 stts_entries[0].duration = 1;
3052 33 entries = 1;
3053 } else {
3054
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 90 times.
300 if (track->entry) {
3055 210 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3056
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (!stts_entries)
3057 return AVERROR(ENOMEM);
3058 }
3059
2/2
✓ Branch 0 taken 12206 times.
✓ Branch 1 taken 300 times.
12506 for (i = 0; i < track->entry; i++) {
3060 12206 int duration = get_cluster_duration(track, i);
3061
4/4
✓ Branch 0 taken 11996 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 11593 times.
✓ Branch 3 taken 403 times.
12206 if (i && duration == stts_entries[entries].duration) {
3062 11593 stts_entries[entries].count++; /* compress */
3063 } else {
3064 613 entries++;
3065 613 stts_entries[entries].duration = duration;
3066 613 stts_entries[entries].count = 1;
3067 }
3068 }
3069 300 entries++; /* last one */
3070 }
3071 333 atom_size = 16 + (entries * 8);
3072 333 avio_wb32(pb, atom_size); /* size */
3073 333 ffio_wfourcc(pb, "stts");
3074 333 avio_wb32(pb, 0); /* version & flags */
3075 333 avio_wb32(pb, entries); /* entry count */
3076
2/2
✓ Branch 0 taken 646 times.
✓ Branch 1 taken 333 times.
979 for (i = 0; i < entries; i++) {
3077 646 avio_wb32(pb, stts_entries[i].count);
3078 646 avio_wb32(pb, stts_entries[i].duration);
3079 }
3080 333 av_free(stts_entries);
3081 333 return atom_size;
3082 }
3083
3084 333 static int mov_write_dref_tag(AVIOContext *pb)
3085 {
3086 333 avio_wb32(pb, 28); /* size */
3087 333 ffio_wfourcc(pb, "dref");
3088 333 avio_wb32(pb, 0); /* version & flags */
3089 333 avio_wb32(pb, 1); /* entry count */
3090
3091 333 avio_wb32(pb, 0xc); /* size */
3092 //FIXME add the alis and rsrc atom
3093 333 ffio_wfourcc(pb, "url ");
3094 333 avio_wb32(pb, 1); /* version & flags */
3095
3096 333 return 28;
3097 }
3098
3099 53 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3100 {
3101 struct sgpd_entry {
3102 int count;
3103 int16_t roll_distance;
3104 int group_description_index;
3105 };
3106
3107 53 struct sgpd_entry *sgpd_entries = NULL;
3108 53 int entries = -1;
3109 53 int group = 0;
3110 int i, j;
3111
3112 53 const int OPUS_SEEK_PREROLL_MS = 80;
3113 53 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3114 53 (AVRational){1, 1000},
3115 53 (AVRational){1, 48000});
3116
3117
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 12 times.
53 if (!track->entry)
3118 41 return 0;
3119
3120 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3121
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
3122 return AVERROR(ENOMEM);
3123
3124
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);
3125
3126
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3127 for (i = 0; i < track->entry; i++) {
3128 int roll_samples_remaining = roll_samples;
3129 int distance = 0;
3130 for (j = i - 1; j >= 0; j--) {
3131 roll_samples_remaining -= get_cluster_duration(track, j);
3132 distance++;
3133 if (roll_samples_remaining <= 0)
3134 break;
3135 }
3136 /* We don't have enough preceeding samples to compute a valid
3137 roll_distance here, so this sample can't be independently
3138 decoded. */
3139 if (roll_samples_remaining > 0)
3140 distance = 0;
3141 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3142 if (distance > 32)
3143 return AVERROR_INVALIDDATA;
3144 if (i && distance == sgpd_entries[entries].roll_distance) {
3145 sgpd_entries[entries].count++;
3146 } else {
3147 entries++;
3148 sgpd_entries[entries].count = 1;
3149 sgpd_entries[entries].roll_distance = distance;
3150 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3151 }
3152 }
3153 } else {
3154 12 entries++;
3155 12 sgpd_entries[entries].count = track->sample_count;
3156 12 sgpd_entries[entries].roll_distance = 1;
3157 12 sgpd_entries[entries].group_description_index = ++group;
3158 }
3159 12 entries++;
3160
3161
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
3162 av_free(sgpd_entries);
3163 return 0;
3164 }
3165
3166 /* Write sgpd tag */
3167 12 avio_wb32(pb, 24 + (group * 2)); /* size */
3168 12 ffio_wfourcc(pb, "sgpd");
3169 12 avio_wb32(pb, 1 << 24); /* fullbox */
3170 12 ffio_wfourcc(pb, "roll");
3171 12 avio_wb32(pb, 2); /* default_length */
3172 12 avio_wb32(pb, group); /* entry_count */
3173
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3174
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
3175 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3176 }
3177 }
3178
3179 /* Write sbgp tag */
3180 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
3181 12 ffio_wfourcc(pb, "sbgp");
3182 12 avio_wb32(pb, 0); /* fullbox */
3183 12 ffio_wfourcc(pb, "roll");
3184 12 avio_wb32(pb, entries); /* entry_count */
3185
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3186 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3187 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3188 }
3189
3190 12 av_free(sgpd_entries);
3191 12 return 0;
3192 }
3193
3194 333 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3195 {
3196 333 int64_t pos = avio_tell(pb);
3197 333 int ret = 0;
3198
3199 333 avio_wb32(pb, 0); /* size */
3200 333 ffio_wfourcc(pb, "stbl");
3201
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3202 return ret;
3203 333 mov_write_stts_tag(pb, track);
3204
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 205 times.
333 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3205
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3206
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3207
3/4
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 75 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
128 (track->par->codec_id == AV_CODEC_ID_AAC && track->par->profile == AV_PROFILE_AAC_USAC) ||
3208
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 126 times.
128 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3209
4/4
✓ Branch 0 taken 158 times.
✓ Branch 1 taken 49 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 100 times.
207 track->has_keyframes && track->has_keyframes < track->entry)
3210 58 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3211
4/4
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 202 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && track->has_disposable)
3212 3 mov_write_sdtp_tag(pb, track);
3213
3/4
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 187 times.
333 if (track->mode == MODE_MOV && track->flags & MOV_TRACK_STPS)
3214 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3215
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3216
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 174 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 22 times.
205 track->flags & MOV_TRACK_CTTS && track->entry) {
3217
3218
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3219 return ret;
3220 }
3221 333 mov_write_stsc_tag(pb, track);
3222 333 mov_write_stsz_tag(pb, track);
3223 333 mov_write_stco_tag(pb, track);
3224
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
333 if (track->cenc.aes_ctr && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
3225 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3226 }
3227
3/4
✓ Branch 0 taken 333 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 53 times.
✓ Branch 3 taken 280 times.
333 if (track->par->codec_id == AV_CODEC_ID_OPUS || track->par->codec_id == AV_CODEC_ID_AAC) {
3228 53 mov_preroll_write_stbl_atoms(pb, track);
3229 }
3230 333 return update_size(pb, pos);
3231 }
3232
3233 333 static int mov_write_dinf_tag(AVIOContext *pb)
3234 {
3235 333 int64_t pos = avio_tell(pb);
3236 333 avio_wb32(pb, 0); /* size */
3237 333 ffio_wfourcc(pb, "dinf");
3238 333 mov_write_dref_tag(pb);
3239 333 return update_size(pb, pos);
3240 }
3241
3242 6 static int mov_write_nmhd_tag(AVIOContext *pb)
3243 {
3244 6 avio_wb32(pb, 12);
3245 6 ffio_wfourcc(pb, "nmhd");
3246 6 avio_wb32(pb, 0);
3247 6 return 12;
3248 }
3249
3250 1 static int mov_write_sthd_tag(AVIOContext *pb)
3251 {
3252 1 avio_wb32(pb, 12);
3253 1 ffio_wfourcc(pb, "sthd");
3254 1 avio_wb32(pb, 0);
3255 1 return 12;
3256 }
3257
3258 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3259 {
3260 9 int64_t pos = avio_tell(pb);
3261 9 const char *font = "Lucida Grande";
3262 9 avio_wb32(pb, 0); /* size */
3263 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3264 9 avio_wb32(pb, 0); /* version & flags */
3265 9 avio_wb16(pb, 0); /* text font */
3266 9 avio_wb16(pb, 0); /* text face */
3267 9 avio_wb16(pb, 12); /* text size */
3268 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3269 9 avio_wb16(pb, 0x0000); /* text color (red) */
3270 9 avio_wb16(pb, 0x0000); /* text color (green) */
3271 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3272 9 avio_wb16(pb, 0xffff); /* background color (red) */
3273 9 avio_wb16(pb, 0xffff); /* background color (green) */
3274 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3275 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3276 9 avio_write(pb, font, strlen(font)); /* font name */
3277 9 return update_size(pb, pos);
3278 }
3279
3280 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3281 {
3282 11 int64_t pos = avio_tell(pb);
3283 11 avio_wb32(pb, 0); /* size */
3284 11 ffio_wfourcc(pb, "gmhd");
3285 11 avio_wb32(pb, 0x18); /* gmin size */
3286 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3287 11 avio_wb32(pb, 0); /* version & flags */
3288 11 avio_wb16(pb, 0x40); /* graphics mode = */
3289 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3290 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3291 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3292 11 avio_wb16(pb, 0); /* balance */
3293 11 avio_wb16(pb, 0); /* reserved */
3294
3295 /*
3296 * This special text atom is required for
3297 * Apple Quicktime chapters. The contents
3298 * don't appear to be documented, so the
3299 * bytes are copied verbatim.
3300 */
3301
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3302 11 avio_wb32(pb, 0x2C); /* size */
3303 11 ffio_wfourcc(pb, "text");
3304 11 avio_wb16(pb, 0x01);
3305 11 avio_wb32(pb, 0x00);
3306 11 avio_wb32(pb, 0x00);
3307 11 avio_wb32(pb, 0x00);
3308 11 avio_wb32(pb, 0x01);
3309 11 avio_wb32(pb, 0x00);
3310 11 avio_wb32(pb, 0x00);
3311 11 avio_wb32(pb, 0x00);
3312 11 avio_wb32(pb, 0x00004000);
3313 11 avio_wb16(pb, 0x0000);
3314 }
3315
3316
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3317 9 int64_t tmcd_pos = avio_tell(pb);
3318 9 avio_wb32(pb, 0); /* size */
3319 9 ffio_wfourcc(pb, "tmcd");
3320 9 mov_write_tcmi_tag(pb, track);
3321 9 update_size(pb, tmcd_pos);
3322
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3323 1 int64_t gpmd_pos = avio_tell(pb);
3324 1 avio_wb32(pb, 0); /* size */
3325 1 ffio_wfourcc(pb, "gpmd");
3326 1 avio_wb32(pb, 0); /* version */
3327 1 update_size(pb, gpmd_pos);
3328 }
3329 11 return update_size(pb, pos);
3330 }
3331
3332 108 static int mov_write_smhd_tag(AVIOContext *pb)
3333 {
3334 108 avio_wb32(pb, 16); /* size */
3335 108 ffio_wfourcc(pb, "smhd");
3336 108 avio_wb32(pb, 0); /* version & flags */
3337 108 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3338 108 avio_wb16(pb, 0); /* reserved */
3339 108 return 16;
3340 }
3341
3342 205 static int mov_write_vmhd_tag(AVIOContext *pb)
3343 {
3344 205 avio_wb32(pb, 0x14); /* size (always 0x14) */
3345 205 ffio_wfourcc(pb, "vmhd");
3346 205 avio_wb32(pb, 0x01); /* version & flags */
3347 205 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3348 205 return 0x14;
3349 }
3350
3351 218 static int is_clcp_track(MOVTrack *track)
3352 {
3353
1/2
✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
436 return track->tag == MKTAG('c','7','0','8') ||
3354
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
218 track->tag == MKTAG('c','6','0','8');
3355 }
3356
3357 520 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3358 {
3359 520 MOVMuxContext *mov = s->priv_data;
3360 520 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3361 520 int64_t pos = avio_tell(pb);
3362 size_t descr_len;
3363
3364 520 hdlr = "dhlr";
3365 520 hdlr_type = "url ";
3366 520 descr = "DataHandler";
3367
3368
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 187 times.
520 if (track) {
3369
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3370
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (track->mode == MODE_AVIF) {
3372 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3373 descr = "PictureHandler";
3374 } else {
3375 205 hdlr_type = "vide";
3376 205 descr = "VideoHandler";
3377 }
3378
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3379 108 hdlr_type = "soun";
3380 108 descr = "SoundHandler";
3381
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3382
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (is_clcp_track(track)) {
3383 hdlr_type = "clcp";
3384 descr = "ClosedCaptionHandler";
3385 } else {
3386
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (track->tag == MKTAG('t','x','3','g')) {
3387 1 hdlr_type = "sbtl";
3388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (track->tag == MKTAG('m','p','4','s')) {
3389 hdlr_type = "subp";
3390
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3391 1 hdlr_type = "subt";
3392 } else {
3393 2 hdlr_type = "text";
3394 }
3395 4 descr = "SubtitleHandler";
3396 }
3397
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3398 2 hdlr_type = "hint";
3399 2 descr = "HintHandler";
3400
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3401 13 hdlr_type = "tmcd";
3402 13 descr = "TimeCodeHandler";
3403
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3404 1 hdlr_type = "meta";
3405 1 descr = "GoPro MET"; // GoPro Metadata
3406 } else {
3407 av_log(s, AV_LOG_WARNING,
3408 "Unknown hdlr_type for %s, writing dummy values\n",
3409 av_fourcc2str(track->par->codec_tag));
3410 }
3411
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 3 times.
333 if (track->st) {
3412 // hdlr.name is used by some players to identify the content title
3413 // of the track. So if an alternate handler description is
3414 // specified, use it.
3415 AVDictionaryEntry *t;
3416 330 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3417
3/4
✓ Branch 0 taken 21 times.
✓ Branch 1 taken 309 times.
✓ Branch 3 taken 21 times.
✗ Branch 4 not taken.
330 if (t && utf8len(t->value))
3418 21 descr = t->value;
3419 }
3420 }
3421
3422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 520 times.
520 if (mov->empty_hdlr_name) /* expressly allowed by QTFF and not prohibited in ISO 14496-12 8.4.3.3 */
3423 descr = "";
3424
3425 520 avio_wb32(pb, 0); /* size */
3426 520 ffio_wfourcc(pb, "hdlr");
3427 520 avio_wb32(pb, 0); /* Version & flags */
3428 520 avio_write(pb, hdlr, 4); /* handler */
3429 520 ffio_wfourcc(pb, hdlr_type); /* handler type */
3430 520 avio_wb32(pb, 0); /* reserved */
3431 520 avio_wb32(pb, 0); /* reserved */
3432 520 avio_wb32(pb, 0); /* reserved */
3433 520 descr_len = strlen(descr);
3434
4/4
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 187 times.
✓ Branch 2 taken 187 times.
✓ Branch 3 taken 146 times.
520 if (!track || track->mode == MODE_MOV)
3435 374 avio_w8(pb, descr_len); /* pascal string */
3436 520 avio_write(pb, descr, descr_len); /* handler description */
3437
4/4
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 187 times.
✓ Branch 2 taken 146 times.
✓ Branch 3 taken 187 times.
520 if (track && track->mode != MODE_MOV)
3438 146 avio_w8(pb, 0); /* c string */
3439 520 return update_size(pb, pos);
3440 }
3441
3442 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3443 {
3444 int64_t pos = avio_tell(pb);
3445 avio_wb32(pb, 0); /* size */
3446 ffio_wfourcc(pb, "pitm");
3447 avio_wb32(pb, 0); /* Version & flags */
3448 avio_wb16(pb, item_id); /* item_id */
3449 return update_size(pb, pos);
3450 }
3451
3452 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3453 {
3454 int64_t pos = avio_tell(pb);
3455 avio_wb32(pb, 0); /* size */
3456 ffio_wfourcc(pb, "iloc");
3457 avio_wb32(pb, 0); /* Version & flags */
3458 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3459 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3460 avio_wb16(pb, mov->nb_streams); /* item_count */
3461
3462 for (int i = 0; i < mov->nb_streams; i++) {
3463 avio_wb16(pb, i + 1); /* item_id */
3464 avio_wb16(pb, 0); /* data_reference_index */
3465 avio_wb16(pb, 1); /* extent_count */
3466 mov->avif_extent_pos[i] = avio_tell(pb);
3467 avio_wb32(pb, 0); /* extent_offset (written later) */
3468 // For animated AVIF, we simply write the first packet's size.
3469 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3470 }
3471
3472 return update_size(pb, pos);
3473 }
3474
3475 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3476 {
3477 int64_t iinf_pos = avio_tell(pb);
3478 avio_wb32(pb, 0); /* size */
3479 ffio_wfourcc(pb, "iinf");
3480 avio_wb32(pb, 0); /* Version & flags */
3481 avio_wb16(pb, mov->nb_streams); /* entry_count */
3482
3483 for (int i = 0; i < mov->nb_streams; i++) {
3484 int64_t infe_pos = avio_tell(pb);
3485 avio_wb32(pb, 0); /* size */
3486 ffio_wfourcc(pb, "infe");
3487 avio_w8(pb, 0x2); /* Version */
3488 avio_wb24(pb, 0); /* flags */
3489 avio_wb16(pb, i + 1); /* item_id */
3490 avio_wb16(pb, 0); /* item_protection_index */
3491 avio_write(pb, "av01", 4); /* item_type */
3492 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3493 update_size(pb, infe_pos);
3494 }
3495
3496 return update_size(pb, iinf_pos);
3497 }
3498
3499
3500 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3501 {
3502 int64_t auxl_pos;
3503 int64_t iref_pos = avio_tell(pb);
3504 avio_wb32(pb, 0); /* size */
3505 ffio_wfourcc(pb, "iref");
3506 avio_wb32(pb, 0); /* Version & flags */
3507
3508 auxl_pos = avio_tell(pb);
3509 avio_wb32(pb, 0); /* size */
3510 ffio_wfourcc(pb, "auxl");
3511 avio_wb16(pb, 2); /* from_item_ID */
3512 avio_wb16(pb, 1); /* reference_count */
3513 avio_wb16(pb, 1); /* to_item_ID */
3514 update_size(pb, auxl_pos);
3515
3516 return update_size(pb, iref_pos);
3517 }
3518
3519 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3520 int stream_index)
3521 {
3522 int64_t pos = avio_tell(pb);
3523 avio_wb32(pb, 0); /* size */
3524 ffio_wfourcc(pb, "ispe");
3525 avio_wb32(pb, 0); /* Version & flags */
3526 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3527 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3528 return update_size(pb, pos);
3529 }
3530
3531 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3532 int stream_index)
3533 {
3534 int64_t pos = avio_tell(pb);
3535 const AVPixFmtDescriptor *pixdesc =
3536 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3537 avio_wb32(pb, 0); /* size */
3538 ffio_wfourcc(pb, "pixi");
3539 avio_wb32(pb, 0); /* Version & flags */
3540 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3541 for (int i = 0; i < pixdesc->nb_components; ++i) {
3542 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3543 }
3544 return update_size(pb, pos);
3545 }
3546
3547 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3548 {
3549 int64_t pos = avio_tell(pb);
3550 avio_wb32(pb, 0); /* size */
3551 ffio_wfourcc(pb, "ipco");
3552 for (int i = 0; i < mov->nb_streams; i++) {
3553 mov_write_ispe_tag(pb, mov, s, i);
3554 mov_write_pixi_tag(pb, mov, s, i);
3555 mov_write_av1c_tag(pb, &mov->tracks[i]);
3556 if (!i)
3557 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3558 else
3559 mov_write_aux_tag(pb, "auxC");
3560 }
3561 return update_size(pb, pos);
3562 }
3563
3564 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3565 {
3566 int64_t pos = avio_tell(pb);
3567 avio_wb32(pb, 0); /* size */
3568 ffio_wfourcc(pb, "ipma");
3569 avio_wb32(pb, 0); /* Version & flags */
3570 avio_wb32(pb, mov->nb_streams); /* entry_count */
3571
3572 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3573 avio_wb16(pb, i + 1); /* item_ID */
3574 avio_w8(pb, 4); /* association_count */
3575
3576 // ispe association.
3577 avio_w8(pb, index++); /* essential and property_index */
3578 // pixi association.
3579 avio_w8(pb, index++); /* essential and property_index */
3580 // av1C association.
3581 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3582 // colr/auxC association.
3583 avio_w8(pb, index++); /* essential and property_index */
3584 }
3585 return update_size(pb, pos);
3586 }
3587
3588 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3589 {
3590 int64_t pos = avio_tell(pb);
3591 avio_wb32(pb, 0); /* size */
3592 ffio_wfourcc(pb, "iprp");
3593 mov_write_ipco_tag(pb, mov, s);
3594 mov_write_ipma_tag(pb, mov, s);
3595 return update_size(pb, pos);
3596 }
3597
3598 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3599 {
3600 /* This atom must be present, but leaving the values at zero
3601 * seems harmless. */
3602 2 avio_wb32(pb, 28); /* size */
3603 2 ffio_wfourcc(pb, "hmhd");
3604 2 avio_wb32(pb, 0); /* version, flags */
3605 2 avio_wb16(pb, 0); /* maxPDUsize */
3606 2 avio_wb16(pb, 0); /* avgPDUsize */
3607 2 avio_wb32(pb, 0); /* maxbitrate */
3608 2 avio_wb32(pb, 0); /* avgbitrate */
3609 2 avio_wb32(pb, 0); /* reserved */
3610 2 return 28;
3611 }
3612
3613 333 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3614 {
3615 333 int64_t pos = avio_tell(pb);
3616 int ret;
3617
3618 333 avio_wb32(pb, 0); /* size */
3619 333 ffio_wfourcc(pb, "minf");
3620
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3621 205 mov_write_vmhd_tag(pb);
3622
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3623 108 mov_write_smhd_tag(pb);
3624
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3625
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)) {
3626 1 mov_write_gmhd_tag(pb, track);
3627
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3628 1 mov_write_sthd_tag(pb);
3629 } else {
3630 2 mov_write_nmhd_tag(pb);
3631 }
3632
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3633 2 mov_write_hmhd_tag(pb);
3634
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3635
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3636 4 mov_write_nmhd_tag(pb);
3637 else
3638 9 mov_write_gmhd_tag(pb, track);
3639
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3640 1 mov_write_gmhd_tag(pb, track);
3641 }
3642
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 if (track->mode == MODE_MOV) /* ISO 14496-12 8.4.3.1 specifies hdlr only within mdia or meta boxes */
3643 187 mov_write_hdlr_tag(s, pb, NULL);
3644 333 mov_write_dinf_tag(pb);
3645
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3646 return ret;
3647 333 return update_size(pb, pos);
3648 }
3649
3650 1294 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3651 int64_t *start, int64_t *end)
3652 {
3653
4/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 1244 times.
✓ Branch 2 taken 38 times.
✓ Branch 3 taken 12 times.
1294 if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd) {
3654 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3655 // another track's duration, while the end_pts may be left at zero.
3656 // Calculate the pts duration for that track instead.
3657 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end);
3658 38 *start = av_rescale(*start, track->timescale,
3659 38 mov->tracks[track->src_track].timescale);
3660 38 *end = av_rescale(*end, track->timescale,
3661 38 mov->tracks[track->src_track].timescale);
3662 38 return;
3663 }
3664
2/2
✓ Branch 0 taken 1198 times.
✓ Branch 1 taken 58 times.
1256 if (track->end_pts != AV_NOPTS_VALUE &&
3665
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 track->start_dts != AV_NOPTS_VALUE &&
3666
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 track->start_cts != AV_NOPTS_VALUE) {
3667 1198 *start = track->start_dts + track->start_cts;
3668 1198 *end = track->end_pts;
3669 1198 return;
3670 }
3671 58 *start = 0;
3672 58 *end = track->track_duration;
3673 }
3674
3675 616 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3676 {
3677 int64_t start, end;
3678 616 get_pts_range(mov, track, &start, &end);
3679 616 return end - start;
3680 }
3681
3682 // Calculate the actual duration of the track, after edits.
3683 // If it starts with a pts < 0, that is removed by the edit list.
3684 // If it starts with a pts > 0, the edit list adds a delay before that.
3685 // Thus, with edit lists enabled, the post-edit output of the file is
3686 // starting with pts=0.
3687 640 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3688 {
3689 int64_t start, end;
3690 640 get_pts_range(mov, track, &start, &end);
3691
2/2
✓ Branch 0 taken 572 times.
✓ Branch 1 taken 68 times.
640 if (mov->use_editlist != 0)
3692 572 start = 0;
3693 640 return end - start;
3694 }
3695
3696 903 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3697 {
3698
4/4
✓ Branch 0 taken 666 times.
✓ Branch 1 taken 237 times.
✓ Branch 2 taken 14 times.
✓ Branch 3 taken 652 times.
903 if (track && track->mode == MODE_ISM)
3699 14 return 1;
3700
2/2
✓ Branch 0 taken 885 times.
✓ Branch 1 taken 4 times.
889 if (duration < INT32_MAX)
3701 885 return 0;
3702 4 return 1;
3703 }
3704
3705 333 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3706 MOVTrack *track)
3707 {
3708 333 int64_t duration = calc_samples_pts_duration(mov, track);
3709 333 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3710
3711
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
333 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3712 333 ffio_wfourcc(pb, "mdhd");
3713 333 avio_w8(pb, version);
3714 333 avio_wb24(pb, 0); /* flags */
3715
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
333 if (version == 1) {
3716 11 avio_wb64(pb, track->time);
3717 11 avio_wb64(pb, track->time);
3718 } else {
3719 322 avio_wb32(pb, track->time); /* creation time */
3720 322 avio_wb32(pb, track->time); /* modification time */
3721 }
3722 333 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3723
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 83 times.
333 if (!track->entry && mov->mode == MODE_ISM)
3724
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3725
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 243 times.
326 else if (!track->entry)
3726
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 79 times.
83 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3727 else
3728
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3729 333 avio_wb16(pb, track->language); /* language */
3730 333 avio_wb16(pb, 0); /* reserved (quality) */
3731
3732
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
333 if (version != 0 && track->mode == MODE_MOV) {
3733 av_log(NULL, AV_LOG_ERROR,
3734 "FATAL error, file duration too long for timebase, this file will not be\n"
3735 "playable with QuickTime. Choose a different timebase with "
3736 "-video_track_timescale or a different container format\n");
3737 }
3738
3739 333 return 32;
3740 }
3741
3742 333 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3743 MOVMuxContext *mov, MOVTrack *track)
3744 {
3745 333 int64_t pos = avio_tell(pb);
3746 int ret;
3747
3748 333 avio_wb32(pb, 0); /* size */
3749 333 ffio_wfourcc(pb, "mdia");
3750 333 mov_write_mdhd_tag(pb, mov, track);
3751 333 mov_write_hdlr_tag(s, pb, track);
3752
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3753 return ret;
3754 333 return update_size(pb, pos);
3755 }
3756
3757 /* transformation matrix
3758 |a b u|
3759 |c d v|
3760 |tx ty w| */
3761 569 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3762 int16_t d, int16_t tx, int16_t ty)
3763 {
3764 569 avio_wb32(pb, a << 16); /* 16.16 format */
3765 569 avio_wb32(pb, b << 16); /* 16.16 format */
3766 569 avio_wb32(pb, 0); /* u in 2.30 format */
3767 569 avio_wb32(pb, c << 16); /* 16.16 format */
3768 569 avio_wb32(pb, d << 16); /* 16.16 format */
3769 569 avio_wb32(pb, 0); /* v in 2.30 format */
3770 569 avio_wb32(pb, tx << 16); /* 16.16 format */
3771 569 avio_wb32(pb, ty << 16); /* 16.16 format */
3772 569 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3773 569 }
3774
3775 333 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3776 MOVTrack *track, AVStream *st)
3777 {
3778 666 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3779 333 mov->movie_timescale, track->timescale,
3780 AV_ROUND_UP);
3781 int version;
3782 333 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3783 333 int group = 0;
3784
3785 333 uint32_t *display_matrix = NULL;
3786 int i;
3787
3788
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mov->mode == MODE_AVIF)
3789 if (!mov->avif_loop_count)
3790 duration = INT64_MAX;
3791 else
3792 duration *= mov->avif_loop_count;
3793
3794
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 13 times.
333 if (st) {
3795 const AVPacketSideData *sd;
3796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (mov->per_stream_grouping)
3797 group = st->index;
3798 else
3799 320 group = st->codecpar->codec_type;
3800
3801 320 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3802 320 st->codecpar->nb_coded_side_data,
3803 AV_PKT_DATA_DISPLAYMATRIX);
3804
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 319 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
320 if (sd && sd->size == 9 * sizeof(*display_matrix))
3805 1 display_matrix = (uint32_t *)sd->data;
3806 }
3807
3808
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 25 times.
333 if (track->flags & MOV_TRACK_ENABLED)
3809 308 flags |= MOV_TKHD_FLAG_ENABLED;
3810
3811 333 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3812
3813
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 326 times.
333 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
3814 333 ffio_wfourcc(pb, "tkhd");
3815 333 avio_w8(pb, version);
3816 333 avio_wb24(pb, flags);
3817
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 326 times.
333 if (version == 1) {
3818 7 avio_wb64(pb, track->time);
3819 7 avio_wb64(pb, track->time);
3820 } else {
3821 326 avio_wb32(pb, track->time); /* creation time */
3822 326 avio_wb32(pb, track->time); /* modification time */
3823 }
3824 333 avio_wb32(pb, track->track_id); /* track-id */
3825 333 avio_wb32(pb, 0); /* reserved */
3826
4/4
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 7 times.
✓ Branch 3 taken 83 times.
333 if (!track->entry && mov->mode == MODE_ISM)
3827
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3828
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 243 times.
326 else if (!track->entry)
3829
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3830 else
3831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
3832
3833 333 avio_wb32(pb, 0); /* reserved */
3834 333 avio_wb32(pb, 0); /* reserved */
3835 333 avio_wb16(pb, 0); /* layer */
3836 333 avio_wb16(pb, group); /* alternate group) */
3837 /* Volume, only for audio */
3838
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3839 108 avio_wb16(pb, 0x0100);
3840 else
3841 225 avio_wb16(pb, 0);
3842 333 avio_wb16(pb, 0); /* reserved */
3843
3844 /* Matrix structure */
3845
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 332 times.
333 if (display_matrix) {
3846
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
3847 9 avio_wb32(pb, display_matrix[i]);
3848 } else {
3849 332 write_matrix(pb, 1, 0, 0, 1, 0, 0);
3850 }
3851 /* Track width and height, for visual only */
3852
4/4
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 13 times.
✓ Branch 2 taken 115 times.
✓ Branch 3 taken 205 times.
333 if (st && (track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3853
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 112 times.
323 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
3854 int64_t track_width_1616;
3855
3/4
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 138 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 70 times.
208 if (track->mode == MODE_MOV || track->mode == MODE_AVIF) {
3856 138 track_width_1616 = track->par->width * 0x10000ULL;
3857 } else {
3858 70 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
3859 70 track->par->width * 0x10000LL,
3860 70 st->sample_aspect_ratio.den);
3861
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 68 times.
70 if (!track_width_1616 ||
3862
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 ||
3863 track_width_1616 > UINT32_MAX)
3864 68 track_width_1616 = track->par->width * 0x10000ULL;
3865 }
3866
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (track_width_1616 > UINT32_MAX) {
3867 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
3868 track_width_1616 = 0;
3869 }
3870 208 avio_wb32(pb, track_width_1616);
3871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (track->height > 0xFFFF) {
3872 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
3873 avio_wb32(pb, 0);
3874 } else
3875 208 avio_wb32(pb, track->height * 0x10000U);
3876 } else {
3877 125 avio_wb32(pb, 0);
3878 125 avio_wb32(pb, 0);
3879 }
3880 333 return 0x5c;
3881 }
3882
3883 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
3884 {
3885 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
3886 1 track->par->sample_aspect_ratio.den);
3887
3888 1 int64_t pos = avio_tell(pb);
3889
3890 1 avio_wb32(pb, 0); /* size */
3891 1 ffio_wfourcc(pb, "tapt");
3892
3893 1 avio_wb32(pb, 20);
3894 1 ffio_wfourcc(pb, "clef");
3895 1 avio_wb32(pb, 0);
3896 1 avio_wb32(pb, width << 16);
3897 1 avio_wb32(pb, track->par->height << 16);
3898
3899 1 avio_wb32(pb, 20);
3900 1 ffio_wfourcc(pb, "prof");
3901 1 avio_wb32(pb, 0);
3902 1 avio_wb32(pb, width << 16);
3903 1 avio_wb32(pb, track->par->height << 16);
3904
3905 1 avio_wb32(pb, 20);
3906 1 ffio_wfourcc(pb, "enof");
3907 1 avio_wb32(pb, 0);
3908 1 avio_wb32(pb, track->par->width << 16);
3909 1 avio_wb32(pb, track->par->height << 16);
3910
3911 1 return update_size(pb, pos);
3912 }
3913
3914 // This box is written in the following cases:
3915 // * Seems important for the psp playback. Without it the movie seems to hang.
3916 // * Used for specifying the looping behavior of animated AVIF (as specified
3917 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
3918 283 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
3919 MOVTrack *track)
3920 {
3921 566 int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track),
3922 283 mov->movie_timescale, track->timescale,
3923 AV_ROUND_UP);
3924 283 int version = duration < INT32_MAX ? 0 : 1;
3925 int entry_size, entry_count, size;
3926 283 int64_t delay, start_ct = track->start_cts;
3927 283 int64_t start_dts = track->start_dts;
3928 283 int flags = 0;
3929
3930
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 54 times.
283 if (track->entry) {
3931
2/4
✓ Branch 0 taken 229 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 229 times.
229 if (start_dts != track->cluster[0].dts || start_ct != track->cluster[0].cts) {
3932
3933 av_log(mov->fc, AV_LOG_DEBUG,
3934 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
3935 track->cluster[0].dts, track->cluster[0].cts,
3936 start_dts, start_ct, track->track_id);
3937 start_dts = track->cluster[0].dts;
3938 start_ct = track->cluster[0].cts;
3939 }
3940 }
3941
3942 283 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
3943 283 track->timescale, AV_ROUND_DOWN);
3944
3945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (mov->mode == MODE_AVIF) {
3946 delay = 0;
3947 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
3948 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
3949 // list is not repeated, while (flags & 1) equal to 1 specifies that the
3950 // edit list is repeated.
3951 flags = mov->avif_loop_count != 1;
3952 start_ct = 0;
3953 }
3954
3955 283 version |= delay < INT32_MAX ? 0 : 1;
3956
3957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 entry_size = (version == 1) ? 20 : 12;
3958
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 entry_count = 1 + (delay > 0);
3959 283 size = 24 + entry_count * entry_size;
3960
3961 /* write the atom data */
3962 283 avio_wb32(pb, size);
3963 283 ffio_wfourcc(pb, "edts");
3964 283 avio_wb32(pb, size - 8);
3965 283 ffio_wfourcc(pb, "elst");
3966 283 avio_w8(pb, version);
3967 283 avio_wb24(pb, flags); /* flags */
3968
3969 283 avio_wb32(pb, entry_count);
3970
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 if (delay > 0) { /* add an empty edit to delay presentation */
3971 /* In the positive delay case, the delay includes the cts
3972 * offset, and the second edit list entry below trims out
3973 * the same amount from the actual content. This makes sure
3974 * that the offset last sample is included in the edit
3975 * list duration as well. */
3976
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
3977 avio_wb64(pb, delay);
3978 avio_wb64(pb, -1);
3979 } else {
3980 2 avio_wb32(pb, delay);
3981 2 avio_wb32(pb, -1);
3982 }
3983 2 avio_wb32(pb, 0x00010000);
3984
1/2
✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
281 } else if (mov->mode != MODE_AVIF) {
3985 /* Avoid accidentally ending up with start_ct = -1 which has got a
3986 * special meaning. Normally start_ct should end up positive or zero
3987 * here, but use FFMIN in case dts is a small positive integer
3988 * rounded to 0 when represented in movie timescale units. */
3989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 281 times.
281 av_assert0(av_rescale_rnd(start_dts, mov->movie_timescale, track->timescale, AV_ROUND_DOWN) <= 0);
3990 281 start_ct = -FFMIN(start_dts, 0);
3991 /* Note, this delay is calculated from the pts of the first sample,
3992 * ensuring that we don't reduce the duration for cases with
3993 * dts<0 pts=0. */
3994 281 duration += delay;
3995 }
3996
3997 /* For fragmented files, we don't know the full length yet. Setting
3998 * duration to 0 allows us to only specify the offset, including
3999 * the rest of the content (from all future fragments) without specifying
4000 * an explicit duration. */
4001
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 225 times.
283 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
4002 58 duration = 0;
4003
4004 /* duration */
4005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (version == 1) {
4006 avio_wb64(pb, duration);
4007 avio_wb64(pb, start_ct);
4008 } else {
4009 283 avio_wb32(pb, duration);
4010 283 avio_wb32(pb, start_ct);
4011 }
4012 283 avio_wb32(pb, 0x00010000);
4013 283 return size;
4014 }
4015
4016 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4017 {
4018 14 avio_wb32(pb, 20); // size
4019 14 ffio_wfourcc(pb, "tref");
4020 14 avio_wb32(pb, 12); // size (subatom)
4021 14 avio_wl32(pb, track->tref_tag);
4022 14 avio_wb32(pb, track->tref_id);
4023 14 return 20;
4024 }
4025
4026 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4027 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4028 {
4029 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4030 2 ffio_wfourcc(pb, "uuid");
4031 2 ffio_wfourcc(pb, "USMT");
4032 2 avio_wb32(pb, 0x21d24fce);
4033 2 avio_wb32(pb, 0xbb88695c);
4034 2 avio_wb32(pb, 0xfac9c740);
4035 2 avio_wb32(pb, 0x1c); // another size here!
4036 2 ffio_wfourcc(pb, "MTDT");
4037 2 avio_wb32(pb, 0x00010012);
4038 2 avio_wb32(pb, 0x0a);
4039 2 avio_wb32(pb, 0x55c40000);
4040 2 avio_wb32(pb, 0x1);
4041 2 avio_wb32(pb, 0x0);
4042 2 return 0x34;
4043 }
4044
4045 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4046 {
4047 2 AVFormatContext *ctx = track->rtp_ctx;
4048 2 char buf[1000] = "";
4049 int len;
4050
4051 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
4052 NULL, NULL, 0, 0, ctx);
4053 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4054 2 len = strlen(buf);
4055
4056 2 avio_wb32(pb, len + 24);
4057 2 ffio_wfourcc(pb, "udta");
4058 2 avio_wb32(pb, len + 16);
4059 2 ffio_wfourcc(pb, "hnti");
4060 2 avio_wb32(pb, len + 8);
4061 2 ffio_wfourcc(pb, "sdp ");
4062 2 avio_write(pb, buf, len);
4063 2 return len + 24;
4064 }
4065
4066 312 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4067 const char *tag, const char *str)
4068 {
4069 312 int64_t pos = avio_tell(pb);
4070 312 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4071
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 311 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
312 if (!t || !utf8len(t->value))
4072 311 return 0;
4073
4074 1 avio_wb32(pb, 0); /* size */
4075 1 ffio_wfourcc(pb, tag); /* type */
4076 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4077 1 return update_size(pb, pos);
4078 }
4079
4080 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4081 const char *value)
4082 {
4083 2 int64_t pos = avio_tell(pb);
4084
4085 /* Box|FullBox basics */
4086 2 avio_wb32(pb, 0); /* size placeholder */
4087 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4088 2 avio_w8(pb, 0); /* version = 0 */
4089 2 avio_wb24(pb, 0); /* flags = 0 */
4090
4091 /* Required null-terminated scheme URI */
4092 2 avio_write(pb, (const unsigned char *)scheme_uri,
4093 2 strlen(scheme_uri));
4094 2 avio_w8(pb, 0);
4095
4096 /* Optional value string */
4097
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])
4098 2 avio_write(pb, (const unsigned char *)value,
4099 2 strlen(value));
4100
4101 2 avio_w8(pb, 0);
4102
4103 2 return update_size(pb, pos);
4104 }
4105
4106 131 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4107 {
4108 131 int ret = AVERROR_BUG;
4109
4110
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 131 times.
262 for (int i = 0; ff_mov_track_kind_table[i].scheme_uri; i++) {
4111 131 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4112
4113
2/2
✓ Branch 0 taken 655 times.
✓ Branch 1 taken 131 times.
786 for (int j = 0; map.value_maps[j].disposition; j++) {
4114 655 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4115
2/2
✓ Branch 0 taken 653 times.
✓ Branch 1 taken 2 times.
655 if (!(st->disposition & value_map.disposition))
4116 653 continue;
4117
4118
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)
4119 return ret;
4120 }
4121 }
4122
4123 131 return 0;
4124 }
4125
4126 333 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4127 AVStream *st)
4128 {
4129 AVIOContext *pb_buf;
4130 int ret, size;
4131 uint8_t *buf;
4132
4133
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 320 times.
333 if (!st)
4134 13 return 0;
4135
4136 320 ret = avio_open_dyn_buf(&pb_buf);
4137
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (ret < 0)
4138 return ret;
4139
4140
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 8 times.
320 if (mov->mode & (MODE_MP4|MODE_MOV))
4141 312 mov_write_track_metadata(pb_buf, st, "name", "title");
4142
4143
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 189 times.
320 if (mov->mode & MODE_MP4) {
4144
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
131 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4145 return ret;
4146 }
4147
4148
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 317 times.
320 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4149 3 avio_wb32(pb, size + 8);
4150 3 ffio_wfourcc(pb, "udta");
4151 3 avio_write(pb, buf, size);
4152 }
4153 320 ffio_free_dyn_buf(&pb_buf);
4154
4155 320 return 0;
4156 }
4157
4158 333 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4159 MOVTrack *track, AVStream *st)
4160 {
4161 333 int64_t pos = avio_tell(pb);
4162 333 int entry_backup = track->entry;
4163 333 int chunk_backup = track->chunkCount;
4164 int ret;
4165
4166 /* If we want to have an empty moov, but some samples already have been
4167 * buffered (delay_moov), pretend that no samples have been written yet. */
4168
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 243 times.
333 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4169 90 track->chunkCount = track->entry = 0;
4170
4171 333 avio_wb32(pb, 0); /* size */
4172 333 ffio_wfourcc(pb, "trak");
4173 333 mov_write_tkhd_tag(pb, mov, track, st);
4174
4175 av_assert2(mov->use_editlist >= 0);
4176
4177
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 26 times.
333 if (track->start_dts != AV_NOPTS_VALUE) {
4178
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 24 times.
307 if (mov->use_editlist)
4179 283 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4180
5/8
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 24 times.
24 else if ((track->entry && track->cluster[0].dts) || track->mode == MODE_PSP || is_clcp_track(track))
4181 av_log(mov->fc, AV_LOG_WARNING,
4182 "Not writing any edit list even though one would have been required\n");
4183 }
4184
4185
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mov->is_animated_avif)
4186 mov_write_edts_tag(pb, mov, track);
4187
4188
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 319 times.
333 if (track->tref_tag)
4189 14 mov_write_tref_tag(pb, track);
4190
4191
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4192 return ret;
4193
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
333 if (track->mode == MODE_PSP)
4194 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4195
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
333 if (track->tag == MKTAG('r','t','p',' '))
4196 2 mov_write_udta_sdp(pb, track);
4197
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 if (track->mode == MODE_MOV) {
4198
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 49 times.
187 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4199 138 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4200
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
138 if (st->sample_aspect_ratio.num && 1.0 != sample_aspect_ratio) {
4201 1 mov_write_tapt_tag(pb, track);
4202 }
4203 }
4204
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 187 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
187 if (is_clcp_track(track) && st->sample_aspect_ratio.num) {
4205 mov_write_tapt_tag(pb, track);
4206 }
4207 }
4208 333 mov_write_track_udta_tag(pb, mov, st);
4209 333 track->entry = entry_backup;
4210 333 track->chunkCount = chunk_backup;
4211 333 return update_size(pb, pos);
4212 }
4213
4214 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4215 {
4216 int i, has_audio = 0, has_video = 0;
4217 int64_t pos = avio_tell(pb);
4218 int audio_profile = mov->iods_audio_profile;
4219 int video_profile = mov->iods_video_profile;
4220 for (i = 0; i < mov->nb_tracks; i++) {
4221 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4222 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4223 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4224 }
4225 }
4226 if (audio_profile < 0)
4227 audio_profile = 0xFF - has_audio;
4228 if (video_profile < 0)
4229 video_profile = 0xFF - has_video;
4230 avio_wb32(pb, 0x0); /* size */
4231 ffio_wfourcc(pb, "iods");
4232 avio_wb32(pb, 0); /* version & flags */
4233 put_descr(pb, 0x10, 7);
4234 avio_wb16(pb, 0x004f);
4235 avio_w8(pb, 0xff);
4236 avio_w8(pb, 0xff);
4237 avio_w8(pb, audio_profile);
4238 avio_w8(pb, video_profile);
4239 avio_w8(pb, 0xff);
4240 return update_size(pb, pos);
4241 }
4242
4243 108 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4244 {
4245 108 avio_wb32(pb, 0x20); /* size */
4246 108 ffio_wfourcc(pb, "trex");
4247 108 avio_wb32(pb, 0); /* version & flags */
4248 108 avio_wb32(pb, track->track_id); /* track ID */
4249 108 avio_wb32(pb, 1); /* default sample description index */
4250 108 avio_wb32(pb, 0); /* default sample duration */
4251 108 avio_wb32(pb, 0); /* default sample size */
4252 108 avio_wb32(pb, 0); /* default sample flags */
4253 108 return 0;
4254 }
4255
4256 56 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4257 {
4258 56 int64_t pos = avio_tell(pb);
4259 int i;
4260 56 avio_wb32(pb, 0x0); /* size */
4261 56 ffio_wfourcc(pb, "mvex");
4262
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 56 times.
164 for (i = 0; i < mov->nb_tracks; i++)
4263 108 mov_write_trex_tag(pb, &mov->tracks[i]);
4264 56 return update_size(pb, pos);
4265 }
4266
4267 237 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4268 {
4269 237 int max_track_id = 1, i;
4270 237 int64_t max_track_len = 0;
4271 int version;
4272 int timescale;
4273
4274
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
4275
3/4
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 307 times.
✗ Branch 3 not taken.
335 if (mov->tracks[i].entry > 0 && mov->tracks[i].timescale) {
4276 614 int64_t max_track_len_temp = av_rescale_rnd(
4277 307 calc_pts_duration(mov, &mov->tracks[i]),
4278 307 mov->movie_timescale,
4279 307 mov->tracks[i].timescale,
4280 AV_ROUND_UP);
4281
2/2
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 69 times.
307 if (max_track_len < max_track_len_temp)
4282 238 max_track_len = max_track_len_temp;
4283
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 224 times.
307 if (max_track_id < mov->tracks[i].track_id)
4284 83 max_track_id = mov->tracks[i].track_id;
4285 }
4286 }
4287 /* If using delay_moov, make sure the output is the same as if no
4288 * samples had been written yet. */
4289
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 190 times.
237 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4290 47 max_track_len = 0;
4291 47 max_track_id = 1;
4292 }
4293
4294 237 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4295
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4296
4297 237 ffio_wfourcc(pb, "mvhd");
4298 237 avio_w8(pb, version);
4299 237 avio_wb24(pb, 0); /* flags */
4300
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (version == 1) {
4301 avio_wb64(pb, mov->time);
4302 avio_wb64(pb, mov->time);
4303 } else {
4304 237 avio_wb32(pb, mov->time); /* creation time */
4305 237 avio_wb32(pb, mov->time); /* modification time */
4306 }
4307
4308 237 timescale = mov->movie_timescale;
4309
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
237 if (mov->mode == MODE_AVIF && !timescale)
4310 timescale = mov->tracks[0].timescale;
4311
4312 237 avio_wb32(pb, timescale);
4313
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 (version == 1) ? avio_wb64(pb, max_track_len) : avio_wb32(pb, max_track_len); /* duration of longest track */
4314
4315 237 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4316 237 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4317 237 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4318
4319 /* Matrix structure */
4320 237 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4321
4322 237 avio_wb32(pb, 0); /* reserved (preview time) */
4323 237 avio_wb32(pb, 0); /* reserved (preview duration) */
4324 237 avio_wb32(pb, 0); /* reserved (poster time) */
4325 237 avio_wb32(pb, 0); /* reserved (selection time) */
4326 237 avio_wb32(pb, 0); /* reserved (selection duration) */
4327 237 avio_wb32(pb, 0); /* reserved (current time) */
4328 237 avio_wb32(pb, max_track_id + 1); /* Next track id */
4329 237 return 0x6c;
4330 }
4331
4332 82 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4333 AVFormatContext *s)
4334 {
4335 82 avio_wb32(pb, 33); /* size */
4336 82 ffio_wfourcc(pb, "hdlr");
4337 82 avio_wb32(pb, 0);
4338 82 avio_wb32(pb, 0);
4339 82 ffio_wfourcc(pb, "mdir");
4340 82 ffio_wfourcc(pb, "appl");
4341 82 avio_wb32(pb, 0);
4342 82 avio_wb32(pb, 0);
4343 82 avio_w8(pb, 0);
4344 82 return 33;
4345 }
4346
4347 /* helper function to write a data tag with the specified string as data */
4348 54 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4349 {
4350 54 size_t data_len = strlen(data);
4351
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 34 times.
54 if (long_style) {
4352 20 int size = 16 + data_len;
4353 20 avio_wb32(pb, size); /* size */
4354 20 ffio_wfourcc(pb, "data");
4355 20 avio_wb32(pb, 1);
4356 20 avio_wb32(pb, 0);
4357 20 avio_write(pb, data, data_len);
4358 20 return size;
4359 } else {
4360 34 avio_wb16(pb, data_len); /* string length */
4361
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4362 26 lang = ff_mov_iso639_to_lang("und", 1);
4363 34 avio_wb16(pb, lang);
4364 34 avio_write(pb, data, data_len);
4365 34 return data_len + 4;
4366 }
4367 }
4368
4369 54 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4370 const char *value, int lang, int long_style)
4371 {
4372 54 int size = 0;
4373
2/4
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
54 if (value && value[0]) {
4374 54 int64_t pos = avio_tell(pb);
4375 54 avio_wb32(pb, 0); /* size */
4376 54 ffio_wfourcc(pb, name);
4377 54 mov_write_string_data_tag(pb, value, lang, long_style);
4378 54 size = update_size(pb, pos);
4379 }
4380 54 return size;
4381 }
4382
4383 3714 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4384 const char *tag, int *lang)
4385 {
4386 int l, len, len2;
4387 3714 AVDictionaryEntry *t, *t2 = NULL;
4388 char tag2[16];
4389
4390 3714 *lang = 0;
4391
4392
2/2
✓ Branch 1 taken 3662 times.
✓ Branch 2 taken 52 times.
3714 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4393 3662 return NULL;
4394
4395 52 len = strlen(t->key);
4396 52 snprintf(tag2, sizeof(tag2), "%s-", tag);
4397
2/2
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 44 times.
52 while ((t2 = av_dict_get(s->metadata, tag2, t2, AV_DICT_IGNORE_SUFFIX))) {
4398 8 len2 = strlen(t2->key);
4399
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)
4400
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4401 8 *lang = l;
4402 8 return t;
4403 }
4404 }
4405 44 return t;
4406 }
4407
4408 3632 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4409 const char *name, const char *tag,
4410 int long_style)
4411 {
4412 int lang;
4413 3632 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4414
2/2
✓ Branch 0 taken 3580 times.
✓ Branch 1 taken 52 times.
3632 if (!t)
4415 3580 return 0;
4416 52 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4417 }
4418
4419 /* iTunes bpm number */
4420 82 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4421 {
4422 82 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4423
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 int size = 0, tmpo = t ? atoi(t->value) : 0;
4424
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (tmpo) {
4425 size = 26;
4426 avio_wb32(pb, size);
4427 ffio_wfourcc(pb, "tmpo");
4428 avio_wb32(pb, size-8); /* size */
4429 ffio_wfourcc(pb, "data");
4430 avio_wb32(pb, 0x15); //type specifier
4431 avio_wb32(pb, 0);
4432 avio_wb16(pb, tmpo); // data
4433 }
4434 82 return size;
4435 }
4436
4437 /* 3GPP TS 26.244 */
4438 82 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4439 {
4440 int lang;
4441 82 int64_t pos = avio_tell(pb);
4442 double latitude, longitude, altitude;
4443 int32_t latitude_fix, longitude_fix, altitude_fix;
4444 82 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4445 82 const char *ptr, *place = "";
4446 char *end;
4447 static const char *astronomical_body = "earth";
4448
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 if (!t)
4449 82 return 0;
4450
4451 ptr = t->value;
4452 latitude = strtod(ptr, &end);
4453 if (end == ptr) {
4454 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4455 return 0;
4456 }
4457 ptr = end;
4458 longitude = strtod(ptr, &end);
4459 if (end == ptr) {
4460 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4461 return 0;
4462 }
4463 ptr = end;
4464 altitude = strtod(ptr, &end);
4465 /* If no altitude was present, the default 0 should be fine */
4466 if (*end == '/')
4467 place = end + 1;
4468
4469 latitude_fix = (int32_t) ((1 << 16) * latitude);
4470 longitude_fix = (int32_t) ((1 << 16) * longitude);
4471 altitude_fix = (int32_t) ((1 << 16) * altitude);
4472
4473 avio_wb32(pb, 0); /* size */
4474 ffio_wfourcc(pb, "loci"); /* type */
4475 avio_wb32(pb, 0); /* version + flags */
4476 avio_wb16(pb, lang);
4477 avio_write(pb, place, strlen(place) + 1);
4478 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4479 avio_wb32(pb, longitude_fix);
4480 avio_wb32(pb, latitude_fix);
4481 avio_wb32(pb, altitude_fix);
4482 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4483 avio_w8(pb, 0); /* additional notes, null terminated string */
4484
4485 return update_size(pb, pos);
4486 }
4487
4488 /* iTunes track or disc number */
4489 164 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4490 AVFormatContext *s, int disc)
4491 {
4492
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 82 times.
164 AVDictionaryEntry *t = av_dict_get(s->metadata,
4493 disc ? "disc" : "track",
4494 NULL, 0);
4495
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 162 times.
164 int size = 0, track = t ? atoi(t->value) : 0;
4496
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 162 times.
164 if (track) {
4497 2 int tracks = 0;
4498 2 char *slash = strchr(t->value, '/');
4499
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4500 2 tracks = atoi(slash + 1);
4501 2 avio_wb32(pb, 32); /* size */
4502
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4503 2 avio_wb32(pb, 24); /* size */
4504 2 ffio_wfourcc(pb, "data");
4505 2 avio_wb32(pb, 0); // 8 bytes empty
4506 2 avio_wb32(pb, 0);
4507 2 avio_wb16(pb, 0); // empty
4508 2 avio_wb16(pb, track); // track / disc number
4509 2 avio_wb16(pb, tracks); // total track / disc number
4510 2 avio_wb16(pb, 0); // empty
4511 2 size = 32;
4512 }
4513 164 return size;
4514 }
4515
4516 492 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4517 const char *name, const char *tag,
4518 int len)
4519 {
4520 492 AVDictionaryEntry *t = NULL;
4521 uint8_t num;
4522 492 int size = 24 + len;
4523
4524
3/4
✓ Branch 0 taken 164 times.
✓ Branch 1 taken 328 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 164 times.
492 if (len != 1 && len != 4)
4525 return -1;
4526
4527
2/2
✓ Branch 1 taken 490 times.
✓ Branch 2 taken 2 times.
492 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4528 490 return 0;
4529 2 num = atoi(t->value);
4530
4531 2 avio_wb32(pb, size);
4532 2 ffio_wfourcc(pb, name);
4533 2 avio_wb32(pb, size - 8);
4534 2 ffio_wfourcc(pb, "data");
4535 2 avio_wb32(pb, 0x15);
4536 2 avio_wb32(pb, 0);
4537
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4538 2 else avio_w8 (pb, num);
4539
4540 2 return size;
4541 }
4542
4543 82 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4544 {
4545 82 MOVMuxContext *mov = s->priv_data;
4546 82 int64_t pos = 0;
4547
4548
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 82 times.
221 for (int i = 0; i < mov->nb_streams; i++) {
4549 139 MOVTrack *trk = &mov->tracks[i];
4550
4551
3/4
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 137 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2 times.
139 if (!is_cover_image(trk->st) || trk->cover_image->size <= 0)
4552 137 continue;
4553
4554
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4555 1 pos = avio_tell(pb);
4556 1 avio_wb32(pb, 0);
4557 1 ffio_wfourcc(pb, "covr");
4558 }
4559 2 avio_wb32(pb, 16 + trk->cover_image->size);
4560 2 ffio_wfourcc(pb, "data");
4561 2 avio_wb32(pb, trk->tag);
4562 2 avio_wb32(pb , 0);
4563 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4564 }
4565
4566
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 81 times.
82 return pos ? update_size(pb, pos) : 0;
4567 }
4568
4569 /* iTunes meta data list */
4570 82 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4571 AVFormatContext *s)
4572 {
4573 82 int64_t pos = avio_tell(pb);
4574 82 avio_wb32(pb, 0); /* size */
4575 82 ffio_wfourcc(pb, "ilst");
4576 82 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4577 82 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4578 82 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4579 82 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4580 82 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4581 82 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4582
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4583
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 80 times.
82 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4584 2 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4585 }
4586 82 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4587 82 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4588 82 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4589 82 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4590 82 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4591 82 mov_write_string_metadata(s, pb, "desc", "description",1);
4592 82 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4593 82 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4594 82 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4595 82 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4596 82 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4597 82 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4598 82 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4599 82 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4600 82 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4601 82 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4602 82 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4603 82 mov_write_covr(pb, s);
4604 82 mov_write_trkn_tag(pb, mov, s, 0); // track number
4605 82 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4606 82 mov_write_tmpo_tag(pb, s);
4607 82 return update_size(pb, pos);
4608 }
4609
4610 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4611 AVFormatContext *s)
4612 {
4613 avio_wb32(pb, 33); /* size */
4614 ffio_wfourcc(pb, "hdlr");
4615 avio_wb32(pb, 0);
4616 avio_wb32(pb, 0);
4617 ffio_wfourcc(pb, "mdta");
4618 avio_wb32(pb, 0);
4619 avio_wb32(pb, 0);
4620 avio_wb32(pb, 0);
4621 avio_w8(pb, 0);
4622 return 33;
4623 }
4624
4625 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4626 AVFormatContext *s)
4627 {
4628 const AVDictionaryEntry *t = NULL;
4629 int64_t pos = avio_tell(pb);
4630 int64_t curpos, entry_pos;
4631 int count = 0;
4632
4633 avio_wb32(pb, 0); /* size */
4634 ffio_wfourcc(pb, "keys");
4635 avio_wb32(pb, 0);
4636 entry_pos = avio_tell(pb);
4637 avio_wb32(pb, 0); /* entry count */
4638
4639 while (t = av_dict_iterate(s->metadata, t)) {
4640 size_t key_len = strlen(t->key);
4641 avio_wb32(pb, key_len + 8);
4642 ffio_wfourcc(pb, "mdta");
4643 avio_write(pb, t->key, key_len);
4644 count += 1;
4645 }
4646 curpos = avio_tell(pb);
4647 avio_seek(pb, entry_pos, SEEK_SET);
4648 avio_wb32(pb, count); // rewrite entry count
4649 avio_seek(pb, curpos, SEEK_SET);
4650
4651 return update_size(pb, pos);
4652 }
4653
4654 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4655 AVFormatContext *s)
4656 {
4657 const AVDictionaryEntry *t = NULL;
4658 int64_t pos = avio_tell(pb);
4659 int count = 1; /* keys are 1-index based */
4660
4661 avio_wb32(pb, 0); /* size */
4662 ffio_wfourcc(pb, "ilst");
4663
4664 while (t = av_dict_iterate(s->metadata, t)) {
4665 int64_t entry_pos = avio_tell(pb);
4666 avio_wb32(pb, 0); /* size */
4667 avio_wb32(pb, count); /* key */
4668 mov_write_string_data_tag(pb, t->value, 0, 1);
4669 update_size(pb, entry_pos);
4670 count += 1;
4671 }
4672 return update_size(pb, pos);
4673 }
4674
4675 /* meta data tags */
4676 82 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4677 AVFormatContext *s)
4678 {
4679 82 int size = 0;
4680 82 int64_t pos = avio_tell(pb);
4681 82 avio_wb32(pb, 0); /* size */
4682 82 ffio_wfourcc(pb, "meta");
4683 82 avio_wb32(pb, 0);
4684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4685 mov_write_mdta_hdlr_tag(pb, mov, s);
4686 mov_write_mdta_keys_tag(pb, mov, s);
4687 mov_write_mdta_ilst_tag(pb, mov, s);
4688
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (mov->mode == MODE_AVIF) {
4689 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4690 // We always write the primary item id as 1 since only one track is
4691 // supported for AVIF.
4692 mov_write_pitm_tag(pb, 1);
4693 mov_write_iloc_tag(pb, mov, s);
4694 mov_write_iinf_tag(pb, mov, s);
4695 if (mov->nb_streams > 1)
4696 mov_write_iref_tag(pb, mov, s);
4697 mov_write_iprp_tag(pb, mov, s);
4698 } else {
4699 /* iTunes metadata tag */
4700 82 mov_write_itunes_hdlr_tag(pb, mov, s);
4701 82 mov_write_ilst_tag(pb, mov, s);
4702 }
4703 82 size = update_size(pb, pos);
4704 82 return size;
4705 }
4706
4707 154 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4708 const char *name, const char *key)
4709 {
4710 int len;
4711 AVDictionaryEntry *t;
4712
4713
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4714 154 return 0;
4715
4716 len = strlen(t->value);
4717 if (len > 0) {
4718 int size = len + 8;
4719 avio_wb32(pb, size);
4720 ffio_wfourcc(pb, name);
4721 avio_write(pb, t->value, len);
4722 return size;
4723 }
4724 return 0;
4725 }
4726
4727 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4728 {
4729 int val;
4730 while (*b) {
4731 GET_UTF8(val, *b++, return -1;)
4732 avio_wb16(pb, val);
4733 }
4734 avio_wb16(pb, 0x00);
4735 return 0;
4736 }
4737
4738 static uint16_t language_code(const char *str)
4739 {
4740 return (((str[0] - 0x60) & 0x1F) << 10) +
4741 (((str[1] - 0x60) & 0x1F) << 5) +
4742 (( str[2] - 0x60) & 0x1F);
4743 }
4744
4745 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4746 const char *tag, const char *str)
4747 {
4748 int64_t pos = avio_tell(pb);
4749 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4750 if (!t || !utf8len(t->value))
4751 return 0;
4752 avio_wb32(pb, 0); /* size */
4753 ffio_wfourcc(pb, tag); /* type */
4754 avio_wb32(pb, 0); /* version + flags */
4755 if (!strcmp(tag, "yrrc"))
4756 avio_wb16(pb, atoi(t->value));
4757 else {
4758 avio_wb16(pb, language_code("eng")); /* language */
4759 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4760 if (!strcmp(tag, "albm") &&
4761 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4762 avio_w8(pb, atoi(t->value));
4763 }
4764 return update_size(pb, pos);
4765 }
4766
4767 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4768 {
4769 1 int64_t pos = avio_tell(pb);
4770 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4771
4772 1 avio_wb32(pb, 0); // size
4773 1 ffio_wfourcc(pb, "chpl");
4774 1 avio_wb32(pb, 0x01000000); // version + flags
4775 1 avio_wb32(pb, 0); // unknown
4776 1 avio_w8(pb, nb_chapters);
4777
4778
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4779 4 AVChapter *c = s->chapters[i];
4780 AVDictionaryEntry *t;
4781 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4782
4783
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4784
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4785 4 avio_w8(pb, len);
4786 4 avio_write(pb, t->value, len);
4787 } else
4788 avio_w8(pb, 0);
4789 }
4790 1 return update_size(pb, pos);
4791 }
4792
4793 236 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4794 AVFormatContext *s)
4795 {
4796 AVIOContext *pb_buf;
4797 int ret, size;
4798 uint8_t *buf;
4799
4800 236 ret = avio_open_dyn_buf(&pb_buf);
4801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (ret < 0)
4802 return ret;
4803
4804
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (mov->mode & MODE_3GP) {
4805 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
4806 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
4807 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
4808 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
4809 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
4810 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
4811 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
4812 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
4813 mov_write_loci_tag(s, pb_buf);
4814
3/4
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 82 times.
✓ Branch 2 taken 154 times.
✗ Branch 3 not taken.
236 } else if (mov->mode == MODE_MOV && !(mov->flags & FF_MOV_FLAG_USE_MDTA)) { // the title field breaks gtkpod with mp4 and my suspicion is that stuff is not valid in mp4
4815 154 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
4816 154 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
4817 154 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
4818 154 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
4819 154 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
4820 154 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
4821 // currently ignored by mov.c
4822 154 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
4823 // add support for libquicktime, this atom is also actually read by mov.c
4824 154 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
4825 154 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
4826 154 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
4827 154 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
4828 154 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
4829 154 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
4830 154 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
4831 154 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
4832 } else {
4833 /* iTunes meta data */
4834 82 mov_write_meta_tag(pb_buf, mov, s);
4835 82 mov_write_loci_tag(s, pb_buf);
4836 }
4837
4838
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 235 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
236 if (s->nb_chapters && !(mov->flags & FF_MOV_FLAG_DISABLE_CHPL))
4839 1 mov_write_chpl_tag(pb_buf, s);
4840
4841
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 126 times.
236 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4842 110 avio_wb32(pb, size + 8);
4843 110 ffio_wfourcc(pb, "udta");
4844 110 avio_write(pb, buf, size);
4845 }
4846 236 ffio_free_dyn_buf(&pb_buf);
4847
4848 236 return 0;
4849 }
4850
4851 static void mov_write_psp_udta_tag(AVIOContext *pb,
4852 const char *str, const char *lang, int type)
4853 {
4854 int len = utf8len(str) + 1;
4855 if (len <= 0)
4856 return;
4857 avio_wb16(pb, len * 2 + 10); /* size */
4858 avio_wb32(pb, type); /* type */
4859 avio_wb16(pb, language_code(lang)); /* language */
4860 avio_wb16(pb, 0x01); /* ? */
4861 ascii_to_wc(pb, str);
4862 }
4863
4864 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
4865 {
4866 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
4867 int64_t pos, pos2;
4868
4869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
4870 pos = avio_tell(pb);
4871 avio_wb32(pb, 0); /* size placeholder*/
4872 ffio_wfourcc(pb, "uuid");
4873 ffio_wfourcc(pb, "USMT");
4874 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
4875 avio_wb32(pb, 0xbb88695c);
4876 avio_wb32(pb, 0xfac9c740);
4877
4878 pos2 = avio_tell(pb);
4879 avio_wb32(pb, 0); /* size placeholder*/
4880 ffio_wfourcc(pb, "MTDT");
4881 avio_wb16(pb, 4);
4882
4883 // ?
4884 avio_wb16(pb, 0x0C); /* size */
4885 avio_wb32(pb, 0x0B); /* type */
4886 avio_wb16(pb, language_code("und")); /* language */
4887 avio_wb16(pb, 0x0); /* ? */
4888 avio_wb16(pb, 0x021C); /* data */
4889
4890 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4891 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
4892 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
4893 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
4894
4895 update_size(pb, pos2);
4896 return update_size(pb, pos);
4897 }
4898
4899 1 return 0;
4900 }
4901
4902 322 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
4903 {
4904 AVEncryptionInitInfo *info;
4905 322 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4906 322 st->codecpar->nb_coded_side_data,
4907 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
4908
1/2
✓ Branch 0 taken 322 times.
✗ Branch 1 not taken.
322 if (!sd)
4909 322 return 0;
4910
4911 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
4912 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
4913 int64_t pos;
4914
4915 if (!copy->data_size && !copy->num_key_ids)
4916 continue;
4917
4918 pos = avio_tell(pb);
4919 avio_wb32(pb, 0); /* size placeholder */
4920 ffio_wfourcc(pb, "pssh");
4921 avio_w8(pb, 1); /* version */
4922 avio_wb24(pb, 0);
4923 for (int i = 0; i < copy->system_id_size; i++)
4924 avio_w8(pb, copy->system_id[i]);
4925 avio_wb32(pb, copy->num_key_ids);
4926 for (int i = 0; i < copy->num_key_ids; i++)
4927 for (int j = 0; j < copy->key_id_size; j++)
4928 avio_w8(pb, copy->key_ids[i][j]);
4929 avio_wb32(pb, copy->data_size);
4930 avio_write(pb, copy->data, copy->data_size);
4931 update_size(pb, pos);
4932 }
4933
4934 av_encryption_init_info_free(info);
4935
4936 return 0;
4937 }
4938
4939 307 static void build_chunks(MOVTrack *trk)
4940 {
4941 int i;
4942 307 MOVIentry *chunk = &trk->cluster[0];
4943 307 uint64_t chunkSize = chunk->size;
4944 307 chunk->chunkNum = 1;
4945
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 252 times.
307 if (trk->chunkCount)
4946 55 return;
4947 252 trk->chunkCount = 1;
4948
2/2
✓ Branch 0 taken 14753 times.
✓ Branch 1 taken 252 times.
15005 for (i = 1; i<trk->entry; i++){
4949
2/2
✓ Branch 0 taken 12852 times.
✓ Branch 1 taken 1901 times.
14753 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
4950
2/2
✓ Branch 0 taken 12207 times.
✓ Branch 1 taken 645 times.
12852 chunkSize + trk->cluster[i].size < (1<<20)){
4951 12207 chunkSize += trk->cluster[i].size;
4952 12207 chunk->samples_in_chunk += trk->cluster[i].entries;
4953 } else {
4954 2546 trk->cluster[i].chunkNum = chunk->chunkNum+1;
4955 2546 chunk=&trk->cluster[i];
4956 2546 chunkSize = chunk->size;
4957 2546 trk->chunkCount++;
4958 }
4959 }
4960 }
4961
4962 /**
4963 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
4964 * the stream ids are used as track ids.
4965 *
4966 * This assumes mov->tracks and s->streams are in the same order and
4967 * there are no gaps in either of them (so mov->tracks[n] refers to
4968 * s->streams[n]).
4969 *
4970 * As an exception, there can be more entries in
4971 * s->streams than in mov->tracks, in which case new track ids are
4972 * generated (starting after the largest found stream id).
4973 */
4974 237 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
4975 {
4976 int i;
4977
4978
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 209 times.
237 if (mov->track_ids_ok)
4979 28 return 0;
4980
4981
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->use_stream_ids_as_track_ids) {
4982 1 int next_generated_track_id = 0;
4983
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
4984 2 AVStream *st = mov->tracks[i].st;
4985
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
4986 2 next_generated_track_id = st->id;
4987 }
4988
4989
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
4990
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
2 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
4991 continue;
4992
4993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->tracks[i].track_id = i >= mov->nb_streams ? ++next_generated_track_id : mov->tracks[i].st->id;
4994 }
4995 } else {
4996 208 int last_track_id = 0;
4997
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 208 times.
482 for (i = 0; i < mov->nb_tracks; i++) {
4998
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 248 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 24 times.
274 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
4999 2 continue;
5000
5001 272 last_track_id =
5002 272 mov->tracks[i].track_id = (mov->tracks[i].st
5003 269 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5004
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 3 times.
272 : FFMAX(i, last_track_id)) + 1;
5005 }
5006 }
5007
5008 209 mov->track_ids_ok = 1;
5009
5010 209 return 0;
5011 }
5012
5013 237 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5014 AVFormatContext *s)
5015 {
5016 int i;
5017 237 int64_t pos = avio_tell(pb);
5018 237 avio_wb32(pb, 0); /* size placeholder*/
5019 237 ffio_wfourcc(pb, "moov");
5020
5021 237 mov_setup_track_ids(mov, s);
5022
5023
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5024
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 307 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 26 times.
335 if (mov->tracks[i].entry <= 0 && !(mov->flags & FF_MOV_FLAG_FRAGMENT))
5025 2 continue;
5026
5027 333 mov->tracks[i].time = mov->time;
5028
5029
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 26 times.
333 if (mov->tracks[i].entry)
5030 307 build_chunks(&mov->tracks[i]);
5031 }
5032
5033
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
237 if (mov->chapter_track)
5034
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5035 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
5036 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
5037 }
5038
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5039 335 MOVTrack *track = &mov->tracks[i];
5040
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 333 times.
335 if (track->tag == MKTAG('r','t','p',' ')) {
5041 2 track->tref_tag = MKTAG('h','i','n','t');
5042 2 track->tref_id = mov->tracks[track->src_track].track_id;
5043
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
333 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5044 108 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5045 108 track->st->codecpar->nb_coded_side_data,
5046 AV_PKT_DATA_FALLBACK_TRACK );
5047
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
108 if (sd && sd->size == sizeof(int)) {
5048 int *fallback = (int *)sd->data;
5049 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5050 track->tref_tag = MKTAG('f','a','l','l');
5051 track->tref_id = mov->tracks[*fallback].track_id;
5052 }
5053 }
5054 }
5055 }
5056
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5057
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 322 times.
335 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
5058 13 int src_trk = mov->tracks[i].src_track;
5059 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
5060 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
5061 //src_trk may have a different timescale than the tmcd track
5062 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5063 13 mov->tracks[i].timescale,
5064 13 mov->tracks[src_trk].timescale);
5065 }
5066 }
5067
5068 237 mov_write_mvhd_tag(pb, mov);
5069
4/6
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 154 times.
✓ Branch 2 taken 83 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 83 times.
237 if (mov->mode != MODE_MOV && mov->mode != MODE_AVIF && !mov->iods_skip)
5070 mov_write_iods_tag(pb, mov);
5071
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5072
4/4
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 307 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 26 times.
335 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_FRAGMENT ||
5073
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5074
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 13 times.
333 int ret = mov_write_trak_tag(s, pb, mov, &(mov->tracks[i]), i < mov->nb_streams ? mov->tracks[i].st : NULL);
5075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (ret < 0)
5076 return ret;
5077 }
5078 }
5079
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 181 times.
237 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5080 56 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5081
5082
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
237 if (mov->mode == MODE_PSP)
5083 1 mov_write_uuidusmt_tag(pb, s);
5084
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 else if (mov->mode != MODE_AVIF)
5085 236 mov_write_udta_tag(pb, mov, s);
5086
2/2
✓ Branch 0 taken 322 times.
✓ Branch 1 taken 237 times.
559 for (i = 0; i < mov->nb_streams; i++)
5087 322 mov_write_pssh_tag(pb, mov->tracks[i].st);
5088
5089 237 return update_size(pb, pos);
5090 }
5091
5092 static void param_write_int(AVIOContext *pb, const char *name, int value)
5093 {
5094 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5095 }
5096
5097 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5098 {
5099 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5100 }
5101
5102 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5103 {
5104 char buf[150];
5105 len = FFMIN(sizeof(buf) / 2 - 1, len);
5106 ff_data_to_hex(buf, value, len, 0);
5107 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5108 }
5109
5110 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5111 {
5112 int64_t pos = avio_tell(pb);
5113 int i;
5114
5115 static const AVUUID uuid = {
5116 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5117 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5118 };
5119
5120 avio_wb32(pb, 0);
5121 ffio_wfourcc(pb, "uuid");
5122 avio_write(pb, uuid, AV_UUID_LEN);
5123 avio_wb32(pb, 0);
5124
5125 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5126 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5127 avio_printf(pb, "<head>\n");
5128 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5129 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5130 LIBAVFORMAT_IDENT);
5131 avio_printf(pb, "</head>\n");
5132 avio_printf(pb, "<body>\n");
5133 avio_printf(pb, "<switch>\n");
5134
5135 mov_setup_track_ids(mov, s);
5136
5137 for (i = 0; i < mov->nb_tracks; i++) {
5138 MOVTrack *track = &mov->tracks[i];
5139 struct mpeg4_bit_rate_values bit_rates =
5140 calculate_mpeg4_bit_rates(track);
5141 const char *type;
5142 int track_id = track->track_id;
5143 char track_name_buf[32] = { 0 };
5144
5145 AVStream *st = track->st;
5146 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5147
5148 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5149 type = "video";
5150 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5151 type = "audio";
5152 } else {
5153 continue;
5154 }
5155
5156 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5157 bit_rates.avg_bit_rate);
5158 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5159 param_write_int(pb, "trackID", track_id);
5160 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5161
5162 /* Build track name piece by piece: */
5163 /* 1. track type */
5164 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5165 /* 2. track language, if available */
5166 if (lang)
5167 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5168 "_%s", lang->value);
5169 /* 3. special type suffix */
5170 /* "_cc" = closed captions, "_ad" = audio_description */
5171 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5172 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5173 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5174 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5175
5176 param_write_string(pb, "trackName", track_name_buf);
5177
5178 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5179 if (track->par->codec_id == AV_CODEC_ID_H264) {
5180 uint8_t *ptr;
5181 int size = track->par->extradata_size;
5182 if (!ff_avc_write_annexb_extradata(track->par->extradata, &ptr,
5183 &size)) {
5184 param_write_hex(pb, "CodecPrivateData",
5185 ptr ? ptr : track->par->extradata,
5186 size);
5187 av_free(ptr);
5188 }
5189 param_write_string(pb, "FourCC", "H264");
5190 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5191 param_write_string(pb, "FourCC", "WVC1");
5192 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5193 track->par->extradata_size);
5194 }
5195 param_write_int(pb, "MaxWidth", track->par->width);
5196 param_write_int(pb, "MaxHeight", track->par->height);
5197 param_write_int(pb, "DisplayWidth", track->par->width);
5198 param_write_int(pb, "DisplayHeight", track->par->height);
5199 } else {
5200 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5201 switch (track->par->profile) {
5202 case AV_PROFILE_AAC_HE_V2:
5203 param_write_string(pb, "FourCC", "AACP");
5204 break;
5205 case AV_PROFILE_AAC_HE:
5206 param_write_string(pb, "FourCC", "AACH");
5207 break;
5208 default:
5209 param_write_string(pb, "FourCC", "AACL");
5210 }
5211 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5212 param_write_string(pb, "FourCC", "WMAP");
5213 }
5214 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5215 track->par->extradata_size);
5216 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5217 track->par->codec_id));
5218 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5219 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5220 0 : track->par->sample_rate);
5221 param_write_int(pb, "BitsPerSample", 16);
5222 param_write_int(pb, "PacketSize", track->par->block_align ?
5223 track->par->block_align : 4);
5224 }
5225 avio_printf(pb, "</%s>\n", type);
5226 }
5227 avio_printf(pb, "</switch>\n");
5228 avio_printf(pb, "</body>\n");
5229 avio_printf(pb, "</smil>\n");
5230
5231 return update_size(pb, pos);
5232 }
5233
5234 142 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5235 {
5236 142 avio_wb32(pb, 16);
5237 142 ffio_wfourcc(pb, "mfhd");
5238 142 avio_wb32(pb, 0);
5239 142 avio_wb32(pb, mov->fragments);
5240 142 return 0;
5241 }
5242
5243 10742 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5244 {
5245
2/2
✓ Branch 0 taken 7200 times.
✓ Branch 1 taken 3542 times.
10742 return entry->flags & MOV_SYNC_SAMPLE ? MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO :
5246 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5247 }
5248
5249 234 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5250 MOVTrack *track, int64_t moof_offset)
5251 {
5252 234 int64_t pos = avio_tell(pb);
5253 234 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5254 MOV_TFHD_BASE_DATA_OFFSET;
5255
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (!track->entry) {
5256 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5257 } else {
5258 234 flags |= MOV_TFHD_DEFAULT_FLAGS;
5259 }
5260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5261 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5262
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 156 times.
234 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5263 78 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5264 78 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5265 }
5266 /* CMAF requires all values to be explicit in tfhd atoms */
5267
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 226 times.
234 if (mov->flags & FF_MOV_FLAG_CMAF)
5268 8 flags |= MOV_TFHD_STSD_ID;
5269
5270 /* Don't set a default sample size, the silverlight player refuses
5271 * to play files with that set. Don't set a default sample duration,
5272 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5273 * file format says it MUST NOT be set. */
5274
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (track->mode == MODE_ISM)
5275 30 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5276 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5277
5278 234 avio_wb32(pb, 0); /* size placeholder */
5279 234 ffio_wfourcc(pb, "tfhd");
5280 234 avio_w8(pb, 0); /* version */
5281 234 avio_wb24(pb, flags);
5282
5283 234 avio_wb32(pb, track->track_id); /* track-id */
5284
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 108 times.
234 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5285 126 avio_wb64(pb, moof_offset);
5286
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 226 times.
234 if (flags & MOV_TFHD_STSD_ID) {
5287 8 avio_wb32(pb, 1);
5288 }
5289
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5290 204 track->default_duration = get_cluster_duration(track, 0);
5291 204 avio_wb32(pb, track->default_duration);
5292 }
5293
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5294
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 track->default_size = track->entry ? track->cluster[0].size : 1;
5295 204 avio_wb32(pb, track->default_size);
5296 } else
5297 30 track->default_size = -1;
5298
5299
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5300 /* Set the default flags based on the second sample, if available.
5301 * If the first sample is different, that can be signaled via a separate field. */
5302
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 10 times.
234 if (track->entry > 1)
5303 224 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5304 else
5305 10 track->default_sample_flags =
5306 10 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5307
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 4 times.
10 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC) :
5308 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5309 234 avio_wb32(pb, track->default_sample_flags);
5310 }
5311
5312 234 return update_size(pb, pos);
5313 }
5314
5315 234 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5316 MOVTrack *track, int moof_size,
5317 int first, int end)
5318 {
5319 234 int64_t pos = avio_tell(pb);
5320 234 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5321 int i;
5322
5323
2/2
✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 234 times.
10278 for (i = first; i < end; i++) {
5324
2/2
✓ Branch 1 taken 618 times.
✓ Branch 2 taken 9426 times.
10044 if (get_cluster_duration(track, i) != track->default_duration)
5325 618 flags |= MOV_TRUN_SAMPLE_DURATION;
5326
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 9544 times.
10044 if (track->cluster[i].size != track->default_size)
5327 500 flags |= MOV_TRUN_SAMPLE_SIZE;
5328
4/4
✓ Branch 0 taken 9810 times.
✓ Branch 1 taken 234 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 9800 times.
10044 if (i > first && get_sample_flags(track, &track->cluster[i]) != track->default_sample_flags)
5329 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5330 }
5331
3/4
✓ Branch 0 taken 226 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 226 times.
✗ Branch 3 not taken.
234 if (!(flags & MOV_TRUN_SAMPLE_FLAGS) && track->entry > first &&
5332
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 116 times.
226 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5333 110 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5334
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 166 times.
234 if (track->flags & MOV_TRACK_CTTS)
5335 68 flags |= MOV_TRUN_SAMPLE_CTS;
5336
5337 234 avio_wb32(pb, 0); /* size placeholder */
5338 234 ffio_wfourcc(pb, "trun");
5339
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 180 times.
234 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5340 54 avio_w8(pb, 1); /* version */
5341 else
5342 180 avio_w8(pb, 0); /* version */
5343 234 avio_wb24(pb, flags);
5344
5345 234 avio_wb32(pb, end - first); /* sample count */
5346
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5347 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5348 !mov->first_trun)
5349 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5350 else
5351 234 avio_wb32(pb, moof_size + 8 + track->data_offset +
5352 234 track->cluster[first].pos); /* data offset */
5353
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 124 times.
234 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5354 110 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5355
5356
2/2
✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 234 times.
10278 for (i = first; i < end; i++) {
5357
2/2
✓ Branch 0 taken 722 times.
✓ Branch 1 taken 9322 times.
10044 if (flags & MOV_TRUN_SAMPLE_DURATION)
5358 722 avio_wb32(pb, get_cluster_duration(track, i));
5359
2/2
✓ Branch 0 taken 1064 times.
✓ Branch 1 taken 8980 times.
10044 if (flags & MOV_TRUN_SAMPLE_SIZE)
5360 1064 avio_wb32(pb, track->cluster[i].size);
5361
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 9672 times.
10044 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5362 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5363
2/2
✓ Branch 0 taken 1980 times.
✓ Branch 1 taken 8064 times.
10044 if (flags & MOV_TRUN_SAMPLE_CTS)
5364 1980 avio_wb32(pb, track->cluster[i].cts);
5365 }
5366
5367 234 mov->first_trun = 0;
5368 234 return update_size(pb, pos);
5369 }
5370
5371 30 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5372 {
5373 30 int64_t pos = avio_tell(pb);
5374 static const uint8_t uuid[] = {
5375 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5376 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5377 };
5378
5379 30 avio_wb32(pb, 0); /* size placeholder */
5380 30 ffio_wfourcc(pb, "uuid");
5381 30 avio_write(pb, uuid, AV_UUID_LEN);
5382 30 avio_w8(pb, 1);
5383 30 avio_wb24(pb, 0);
5384 30 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5385 30 avio_wb64(pb, track->end_pts -
5386 30 (track->cluster[0].dts + track->cluster[0].cts));
5387
5388 30 return update_size(pb, pos);
5389 }
5390
5391 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5392 MOVTrack *track, int entry)
5393 {
5394 int n = track->nb_frag_info - 1 - entry, i;
5395 int size = 8 + 16 + 4 + 1 + 16*n;
5396 static const uint8_t uuid[] = {
5397 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5398 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5399 };
5400
5401 if (entry < 0)
5402 return 0;
5403
5404 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5405 avio_wb32(pb, size);
5406 ffio_wfourcc(pb, "uuid");
5407 avio_write(pb, uuid, AV_UUID_LEN);
5408 avio_w8(pb, 1);
5409 avio_wb24(pb, 0);
5410 avio_w8(pb, n);
5411 for (i = 0; i < n; i++) {
5412 int index = entry + 1 + i;
5413 avio_wb64(pb, track->frag_info[index].time);
5414 avio_wb64(pb, track->frag_info[index].duration);
5415 }
5416 if (n < mov->ism_lookahead) {
5417 int free_size = 16 * (mov->ism_lookahead - n);
5418 avio_wb32(pb, free_size);
5419 ffio_wfourcc(pb, "free");
5420 ffio_fill(pb, 0, free_size - 8);
5421 }
5422
5423 return 0;
5424 }
5425
5426 117 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5427 MOVTrack *track)
5428 {
5429 117 int64_t pos = avio_tell(pb);
5430 int i;
5431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 for (i = 0; i < mov->ism_lookahead; i++) {
5432 /* Update the tfrf tag for the last ism_lookahead fragments,
5433 * nb_frag_info - 1 is the next fragment to be written. */
5434 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5435 }
5436 117 avio_seek(pb, pos, SEEK_SET);
5437 117 return 0;
5438 }
5439
5440 71 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5441 int size)
5442 {
5443 int i;
5444
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 71 times.
204 for (i = 0; i < mov->nb_tracks; i++) {
5445 133 MOVTrack *track = &mov->tracks[i];
5446 MOVFragmentInfo *info;
5447
6/6
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 106 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 12 times.
✓ Branch 4 taken 4 times.
✓ Branch 5 taken 117 times.
133 if ((tracks >= 0 && i != tracks) || !track->entry)
5448 16 continue;
5449 117 track->nb_frag_info++;
5450
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 54 times.
117 if (track->nb_frag_info >= track->frag_info_capacity) {
5451 63 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5452
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
63 if (av_reallocp_array(&track->frag_info,
5453 new_capacity,
5454 sizeof(*track->frag_info)))
5455 return AVERROR(ENOMEM);
5456 63 track->frag_info_capacity = new_capacity;
5457 }
5458 117 info = &track->frag_info[track->nb_frag_info - 1];
5459 117 info->offset = avio_tell(pb);
5460 117 info->size = size;
5461 // Try to recreate the original pts for the first packet
5462 // from the fields we have stored
5463 117 info->time = track->cluster[0].dts + track->cluster[0].cts;
5464 117 info->duration = track->end_pts -
5465 117 (track->cluster[0].dts + track->cluster[0].cts);
5466 // If the pts is less than zero, we will have trimmed
5467 // away parts of the media track using an edit list,
5468 // and the corresponding start presentation time is zero.
5469
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 109 times.
117 if (info->time < 0) {
5470 8 info->duration += info->time;
5471 8 info->time = 0;
5472 }
5473 117 info->tfrf_offset = 0;
5474 117 mov_write_tfrf_tags(pb, mov, track);
5475 }
5476 71 return 0;
5477 }
5478
5479 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5480 {
5481 int i;
5482 for (i = 0; i < mov->nb_tracks; i++) {
5483 MOVTrack *track = &mov->tracks[i];
5484 if ((tracks >= 0 && i != tracks) || !track->entry)
5485 continue;
5486 if (track->nb_frag_info > max) {
5487 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5488 track->nb_frag_info = max;
5489 }
5490 }
5491 }
5492
5493 204 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5494 {
5495 204 int64_t pos = avio_tell(pb);
5496
5497 204 avio_wb32(pb, 0); /* size */
5498 204 ffio_wfourcc(pb, "tfdt");
5499 204 avio_w8(pb, 1); /* version */
5500 204 avio_wb24(pb, 0);
5501 204 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5502 204 return update_size(pb, pos);
5503 }
5504
5505 234 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5506 MOVTrack *track, int64_t moof_offset,
5507 int moof_size)
5508 {
5509 234 int64_t pos = avio_tell(pb);
5510 234 int i, start = 0;
5511 234 avio_wb32(pb, 0); /* size placeholder */
5512 234 ffio_wfourcc(pb, "traf");
5513
5514 234 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5515
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (mov->mode != MODE_ISM)
5516 204 mov_write_tfdt_tag(pb, track);
5517
2/2
✓ Branch 0 taken 9810 times.
✓ Branch 1 taken 234 times.
10044 for (i = 1; i < track->entry; i++) {
5518
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9810 times.
9810 if (track->cluster[i].pos != track->cluster[i - 1].pos + track->cluster[i - 1].size) {
5519 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5520 start = i;
5521 }
5522 }
5523 234 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5524
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (mov->mode == MODE_ISM) {
5525 30 mov_write_tfxd_tag(pb, track);
5526
5527
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (mov->ism_lookahead) {
5528 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5529
5530 if (track->nb_frag_info > 0) {
5531 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5532 if (!info->tfrf_offset)
5533 info->tfrf_offset = avio_tell(pb);
5534 }
5535 avio_wb32(pb, 8 + size);
5536 ffio_wfourcc(pb, "free");
5537 ffio_fill(pb, 0, size);
5538 }
5539 }
5540
5541
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
234 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5542 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5543
5544 234 return update_size(pb, pos);
5545 }
5546
5547 142 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5548 int tracks, int moof_size)
5549 {
5550 142 int64_t pos = avio_tell(pb);
5551 int i;
5552
5553 142 avio_wb32(pb, 0); /* size placeholder */
5554 142 ffio_wfourcc(pb, "moof");
5555 142 mov->first_trun = 1;
5556
5557 142 mov_write_mfhd_tag(pb, mov);
5558
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 142 times.
408 for (i = 0; i < mov->nb_tracks; i++) {
5559 266 MOVTrack *track = &mov->tracks[i];
5560
4/4
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 212 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 30 times.
266 if (tracks >= 0 && i != tracks)
5561 24 continue;
5562
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 234 times.
242 if (!track->entry)
5563 8 continue;
5564
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
234 if (track->cenc.aes_ctr && (mov->flags & FF_MOV_FLAG_FRAGMENT))
5565 mov_write_pssh_tag(pb, track->st);
5566 234 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5567 }
5568
5569 142 return update_size(pb, pos);
5570 }
5571
5572 70 static int mov_write_sidx_tag(AVIOContext *pb,
5573 MOVTrack *track, int ref_size, int total_sidx_size)
5574 {
5575 70 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5576 int64_t presentation_time, duration, offset;
5577 unsigned starts_with_SAP;
5578 int i, entries;
5579
5580
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 if (track->entry) {
5581 70 entries = 1;
5582 70 presentation_time = track->cluster[0].dts + track->cluster[0].cts -
5583 70 track->start_dts - track->start_cts;
5584 70 duration = track->end_pts -
5585 70 (track->cluster[0].dts + track->cluster[0].cts);
5586 70 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5587
5588 // pts<0 should be cut away using edts
5589
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (presentation_time < 0) {
5590 duration += presentation_time;
5591 presentation_time = 0;
5592 }
5593 } else {
5594 entries = track->nb_frag_info;
5595 if (entries <= 0)
5596 return 0;
5597 presentation_time = track->frag_info[0].time;
5598 /* presentation_time <= 0 is handled by mov_add_tfra_entries() */
5599 if (presentation_time > 0)
5600 presentation_time -= track->start_dts + track->start_cts;
5601 }
5602
5603 70 avio_wb32(pb, 0); /* size */
5604 70 ffio_wfourcc(pb, "sidx");
5605 70 avio_w8(pb, 1); /* version */
5606 70 avio_wb24(pb, 0);
5607 70 avio_wb32(pb, track->track_id); /* reference_ID */
5608 70 avio_wb32(pb, track->timescale); /* timescale */
5609 70 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5610 70 offset_pos = avio_tell(pb);
5611 70 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5612 70 avio_wb16(pb, 0); /* reserved */
5613
5614 70 avio_wb16(pb, entries); /* reference_count */
5615
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 70 times.
140 for (i = 0; i < entries; i++) {
5616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (!track->entry) {
5617 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5618 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5619 }
5620 duration = track->frag_info[i].duration;
5621 ref_size = track->frag_info[i].size;
5622 starts_with_SAP = 1;
5623 }
5624 70 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5625 70 avio_wb32(pb, duration); /* subsegment_duration */
5626 70 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5627 }
5628
5629 70 end_pos = avio_tell(pb);
5630 70 offset = pos + total_sidx_size - end_pos;
5631 70 avio_seek(pb, offset_pos, SEEK_SET);
5632 70 avio_wb64(pb, offset);
5633 70 avio_seek(pb, end_pos, SEEK_SET);
5634 70 return update_size(pb, pos);
5635 }
5636
5637 20 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5638 int tracks, int ref_size)
5639 {
5640 int i, round, ret;
5641 AVIOContext *avio_buf;
5642 20 int total_size = 0;
5643
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (round = 0; round < 2; round++) {
5644 // First run one round to calculate the total size of all
5645 // sidx atoms.
5646 // This would be much simpler if we'd only write one sidx
5647 // atom, for the first track in the moof.
5648
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0) {
5649
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5650 return ret;
5651 } else {
5652 20 avio_buf = pb;
5653 }
5654
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 40 times.
110 for (i = 0; i < mov->nb_tracks; i++) {
5655 70 MOVTrack *track = &mov->tracks[i];
5656
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)
5657 continue;
5658 // When writing a sidx for the full file, entry is 0, but
5659 // we want to include all tracks. ref_size is 0 in this case,
5660 // since we read it from frag_info instead.
5661
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)
5662 continue;
5663 70 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5664 total_size);
5665 }
5666
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0)
5667 20 total_size = ffio_close_null_buf(avio_buf);
5668 }
5669 20 return 0;
5670 }
5671
5672 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5673 {
5674 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5675 MOVTrack *first_track;
5676 int flags = 24;
5677
5678 /* PRFT should be associated with at most one track. So, choosing only the
5679 * first track. */
5680 if (tracks > 0)
5681 return 0;
5682 first_track = &(mov->tracks[0]);
5683
5684 if (!first_track->entry) {
5685 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5686 return 0;
5687 }
5688
5689 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5690 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5691 return 0;
5692 }
5693
5694 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5695 if (first_track->cluster[0].prft.wallclock) {
5696 /* Round the NTP time to whole milliseconds. */
5697 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5698 NTP_OFFSET_US);
5699 flags = first_track->cluster[0].prft.flags;
5700 } else
5701 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5702 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5703 pts_us = av_rescale_q(first_track->cluster[0].pts,
5704 first_track->st->time_base, AV_TIME_BASE_Q);
5705 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5706 } else {
5707 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5708 mov->write_prft);
5709 return 0;
5710 }
5711
5712 avio_wb32(pb, 0); // Size place holder
5713 ffio_wfourcc(pb, "prft"); // Type
5714 avio_w8(pb, 1); // Version
5715 avio_wb24(pb, flags); // Flags
5716 avio_wb32(pb, first_track->track_id); // reference track ID
5717 avio_wb64(pb, ntp_ts); // NTP time stamp
5718 avio_wb64(pb, first_track->cluster[0].pts); //media time
5719 return update_size(pb, pos);
5720 }
5721
5722 71 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5723 int64_t mdat_size)
5724 {
5725 AVIOContext *avio_buf;
5726 int ret, moof_size;
5727
5728
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
71 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5729 return ret;
5730 71 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5731 71 moof_size = ffio_close_null_buf(avio_buf);
5732
5733
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 51 times.
71 if (mov->flags & FF_MOV_FLAG_DASH &&
5734
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5735 20 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5736
5737
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
71 if (mov->write_prft > MOV_PRFT_NONE && mov->write_prft < MOV_PRFT_NB)
5738 mov_write_prft_tag(pb, mov, tracks);
5739
5740
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5742 mov->ism_lookahead) {
5743
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
71 if ((ret = mov_add_tfra_entries(pb, mov, tracks, moof_size + 8 + mdat_size)) < 0)
5744 return ret;
5745
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5746
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5747 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5748 }
5749 }
5750
5751 71 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5752 }
5753
5754 61 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5755 {
5756 61 int64_t pos = avio_tell(pb);
5757 int i;
5758
5759 61 avio_wb32(pb, 0); /* size placeholder */
5760 61 ffio_wfourcc(pb, "tfra");
5761 61 avio_w8(pb, 1); /* version */
5762 61 avio_wb24(pb, 0);
5763
5764 61 avio_wb32(pb, track->track_id);
5765 61 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5766 61 avio_wb32(pb, track->nb_frag_info);
5767
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 61 times.
175 for (i = 0; i < track->nb_frag_info; i++) {
5768 114 avio_wb64(pb, track->frag_info[i].time);
5769 114 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5770 114 avio_w8(pb, 1); /* traf number */
5771 114 avio_w8(pb, 1); /* trun number */
5772 114 avio_w8(pb, 1); /* sample number */
5773 }
5774
5775 61 return update_size(pb, pos);
5776 }
5777
5778 33 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5779 {
5780 AVIOContext *mfra_pb;
5781 int i, ret, sz;
5782 uint8_t *buf;
5783
5784 33 ret = avio_open_dyn_buf(&mfra_pb);
5785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret < 0)
5786 return ret;
5787
5788 33 avio_wb32(mfra_pb, 0); /* size placeholder */
5789 33 ffio_wfourcc(mfra_pb, "mfra");
5790 /* An empty mfra atom is enough to indicate to the publishing point that
5791 * the stream has ended. */
5792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_ISML)
5793 goto done_mfra;
5794
5795
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++) {
5796 63 MOVTrack *track = &mov->tracks[i];
5797
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2 times.
63 if (track->nb_frag_info)
5798 61 mov_write_tfra_tag(mfra_pb, track);
5799 }
5800
5801 33 avio_wb32(mfra_pb, 16);
5802 33 ffio_wfourcc(mfra_pb, "mfro");
5803 33 avio_wb32(mfra_pb, 0); /* version + flags */
5804 33 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
5805
5806 33 done_mfra:
5807
5808 33 sz = update_size(mfra_pb, 0);
5809 33 ret = avio_get_dyn_buf(mfra_pb, &buf);
5810 33 avio_write(pb, buf, ret);
5811 33 ffio_free_dyn_buf(&mfra_pb);
5812
5813 33 return sz;
5814 }
5815
5816 175 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
5817 {
5818 175 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
5819
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 30 times.
175 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
5820
5821 175 mov->mdat_pos = avio_tell(pb);
5822 175 avio_wb32(pb, 0); /* size placeholder*/
5823 175 ffio_wfourcc(pb, "mdat");
5824 175 return 0;
5825 }
5826
5827 418 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
5828 int has_h264, int has_video, int write_minor)
5829 {
5830 418 MOVMuxContext *mov = s->priv_data;
5831 418 int minor = 0x200;
5832
5833
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
418 if (mov->major_brand && strlen(mov->major_brand) >= 4)
5834 ffio_wfourcc(pb, mov->major_brand);
5835
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 else if (mov->mode == MODE_3GP) {
5836 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
5837 minor = has_h264 ? 0x100 : 0x200;
5838
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 } else if (mov->mode == MODE_AVIF) {
5839 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
5840 minor = 0;
5841
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 } else if (mov->mode & MODE_3G2) {
5842 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
5843 minor = has_h264 ? 0x20000 : 0x10000;
5844
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 416 times.
418 } else if (mov->mode == MODE_PSP)
5845 2 ffio_wfourcc(pb, "MSNV");
5846
4/4
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 302 times.
✓ Branch 2 taken 58 times.
✓ Branch 3 taken 56 times.
416 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_FRAGMENT &&
5847
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 52 times.
58 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5848 6 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
5849
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 302 times.
✓ Branch 2 taken 22 times.
✓ Branch 3 taken 86 times.
410 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5850 22 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
5851
3/4
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 302 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
388 else if (mov->mode == MODE_MP4 && mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5852 ffio_wfourcc(pb, "iso4");
5853
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 302 times.
388 else if (mov->mode == MODE_MP4)
5854 86 ffio_wfourcc(pb, "isom");
5855
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 300 times.
302 else if (mov->mode == MODE_IPOD)
5856
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
5857
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 292 times.
300 else if (mov->mode == MODE_ISM)
5858 8 ffio_wfourcc(pb, "isml");
5859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 else if (mov->mode == MODE_F4V)
5860 ffio_wfourcc(pb, "f4v ");
5861 else
5862 292 ffio_wfourcc(pb, "qt ");
5863
5864
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 209 times.
418 if (write_minor)
5865 209 avio_wb32(pb, minor);
5866 418 }
5867
5868 209 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
5869 {
5870 209 MOVMuxContext *mov = s->priv_data;
5871 209 int64_t pos = avio_tell(pb);
5872 209 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
5873 209 int has_iamf = 0;
5874
5875 #if CONFIG_IAMFENC
5876
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 204 times.
209 for (int i = 0; i < s->nb_stream_groups; i++) {
5877 5 const AVStreamGroup *stg = s->stream_groups[i];
5878
5879
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
5880 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
5881 5 has_iamf = 1;
5882 5 break;
5883 }
5884 }
5885 #endif
5886
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (int i = 0; i < mov->nb_streams; i++) {
5887 267 AVStream *st = mov->tracks[i].st;
5888
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 265 times.
267 if (is_cover_image(st))
5889 2 continue;
5890
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 87 times.
265 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5891 178 has_video = 1;
5892
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 231 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
5893 34 has_h264 = 1;
5894
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 264 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
5895 1 has_av1 = 1;
5896
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 4 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
5897
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 1 times.
261 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
5898
2/4
✓ Branch 0 taken 260 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 260 times.
520 st->codecpar->codec_id == AV_CODEC_ID_TRUEHD ||
5899 260 av_packet_side_data_get(st->codecpar->coded_side_data,
5900 260 st->codecpar->nb_coded_side_data,
5901 AV_PKT_DATA_DOVI_CONF))
5902 5 has_dolby = 1;
5903
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
5904 has_id3 = 1;
5905 }
5906
5907 209 avio_wb32(pb, 0); /* size */
5908 209 ffio_wfourcc(pb, "ftyp");
5909
5910 // Write major brand
5911 209 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
5912 // Write the major brand as the first compatible brand as well
5913 209 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
5914
5915 // Write compatible brands, ensuring that we don't write the major brand as a
5916 // compatible brand a second time.
5917
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (mov->mode == MODE_ISM) {
5918 4 ffio_wfourcc(pb, "piff");
5919
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 } else if (mov->mode == MODE_AVIF) {
5920 const AVPixFmtDescriptor *pix_fmt_desc =
5921 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
5922 const int depth = pix_fmt_desc->comp[0].depth;
5923 if (mov->is_animated_avif) {
5924 // For animated AVIF, major brand is "avis". Add "avif" as a
5925 // compatible brand.
5926 ffio_wfourcc(pb, "avif");
5927 ffio_wfourcc(pb, "msf1");
5928 ffio_wfourcc(pb, "iso8");
5929 }
5930 ffio_wfourcc(pb, "mif1");
5931 ffio_wfourcc(pb, "miaf");
5932 if (depth == 8 || depth == 10) {
5933 // MA1B and MA1A brands are based on AV1 profile. Short hand for
5934 // computing that is based on chroma subsampling type. 420 chroma
5935 // subsampling is MA1B. 444 chroma subsampling is MA1A.
5936 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
5937 // 444 chroma subsampling.
5938 ffio_wfourcc(pb, "MA1A");
5939 } else {
5940 // 420 chroma subsampling.
5941 ffio_wfourcc(pb, "MA1B");
5942 }
5943 }
5944
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 146 times.
205 } else if (mov->mode != MODE_MOV) {
5945 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
5946 // brand, if not already the major brand. This is compatible with users that
5947 // don't understand tfdt.
5948
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 2 times.
59 if (mov->mode == MODE_MP4) {
5949
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
57 if (mov->flags & FF_MOV_FLAG_CMAF)
5950 1 ffio_wfourcc(pb, "cmfc");
5951
4/4
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 3 times.
57 if (mov->flags & FF_MOV_FLAG_FRAGMENT && !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
5952 26 ffio_wfourcc(pb, "iso6");
5953
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
57 if (has_av1)
5954 1 ffio_wfourcc(pb, "av01");
5955
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 54 times.
57 if (has_dolby)
5956 3 ffio_wfourcc(pb, "dby1");
5957
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 52 times.
57 if (has_iamf)
5958 5 ffio_wfourcc(pb, "iamf");
5959 } else {
5960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5961 ffio_wfourcc(pb, "iso6");
5962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5963 ffio_wfourcc(pb, "iso5");
5964
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5965 ffio_wfourcc(pb, "iso4");
5966 }
5967 // Brands prior to iso5 can't be signaled when using default-base-is-moof
5968
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 12 times.
59 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
5969 // write isom for mp4 only if it it's not the major brand already.
5970
4/4
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 43 times.
47 if (mov->mode != MODE_MP4 || mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5971 4 ffio_wfourcc(pb, "isom");
5972 47 ffio_wfourcc(pb, "iso2");
5973
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 27 times.
47 if (has_h264)
5974 20 ffio_wfourcc(pb, "avc1");
5975 }
5976 }
5977
5978
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 152 times.
209 if (mov->mode == MODE_MP4)
5979 57 ffio_wfourcc(pb, "mp41");
5980
5981
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 198 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
209 if (mov->flags & FF_MOV_FLAG_DASH && mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
5982 ffio_wfourcc(pb, "dash");
5983
5984
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (has_id3)
5985 ffio_wfourcc(pb, "aid3");
5986
5987 209 return update_size(pb, pos);
5988 }
5989
5990 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
5991 {
5992 1 AVStream *video_st = s->streams[0];
5993 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
5994 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
5995 1 int audio_rate = audio_par->sample_rate;
5996 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
5997
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 :
5998 0;
5999 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6000 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6001
6002
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) {
6003 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6004 return AVERROR(EINVAL);
6005 }
6006
6007 1 avio_wb32(pb, 0x94); /* size */
6008 1 ffio_wfourcc(pb, "uuid");
6009 1 ffio_wfourcc(pb, "PROF");
6010
6011 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6012 1 avio_wb32(pb, 0xbb88695c);
6013 1 avio_wb32(pb, 0xfac9c740);
6014
6015 1 avio_wb32(pb, 0x0); /* ? */
6016 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6017
6018 1 avio_wb32(pb, 0x14); /* size */
6019 1 ffio_wfourcc(pb, "FPRF");
6020 1 avio_wb32(pb, 0x0); /* ? */
6021 1 avio_wb32(pb, 0x0); /* ? */
6022 1 avio_wb32(pb, 0x0); /* ? */
6023
6024 1 avio_wb32(pb, 0x2c); /* size */
6025 1 ffio_wfourcc(pb, "APRF"); /* audio */
6026 1 avio_wb32(pb, 0x0);
6027 1 avio_wb32(pb, 0x2); /* TrackID */
6028 1 ffio_wfourcc(pb, "mp4a");
6029 1 avio_wb32(pb, 0x20f);
6030 1 avio_wb32(pb, 0x0);
6031 1 avio_wb32(pb, audio_kbitrate);
6032 1 avio_wb32(pb, audio_kbitrate);
6033 1 avio_wb32(pb, audio_rate);
6034 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6035
6036 1 avio_wb32(pb, 0x34); /* size */
6037 1 ffio_wfourcc(pb, "VPRF"); /* video */
6038 1 avio_wb32(pb, 0x0);
6039 1 avio_wb32(pb, 0x1); /* TrackID */
6040
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6041 1 ffio_wfourcc(pb, "avc1");
6042 1 avio_wb16(pb, 0x014D);
6043 1 avio_wb16(pb, 0x0015);
6044 } else {
6045 ffio_wfourcc(pb, "mp4v");
6046 avio_wb16(pb, 0x0000);
6047 avio_wb16(pb, 0x0103);
6048 }
6049 1 avio_wb32(pb, 0x0);
6050 1 avio_wb32(pb, video_kbitrate);
6051 1 avio_wb32(pb, video_kbitrate);
6052 1 avio_wb32(pb, frame_rate);
6053 1 avio_wb32(pb, frame_rate);
6054 1 avio_wb16(pb, video_par->width);
6055 1 avio_wb16(pb, video_par->height);
6056 1 avio_wb32(pb, 0x010001); /* ? */
6057
6058 1 return 0;
6059 }
6060
6061 209 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6062 {
6063 209 MOVMuxContext *mov = s->priv_data;
6064 int i;
6065
6066 209 mov_write_ftyp_tag(pb,s);
6067
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->mode == MODE_PSP) {
6068 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6069
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6070 2 AVStream *st = mov->tracks[i].st;
6071
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6072 continue;
6073
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6074 1 video_streams_nb++;
6075
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6076 1 audio_streams_nb++;
6077 else
6078 other_streams_nb++;
6079 }
6080
6081
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) {
6082 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6083 return AVERROR(EINVAL);
6084 }
6085 1 return mov_write_uuidprof_tag(pb, s);
6086 }
6087 208 return 0;
6088 }
6089
6090 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6091 {
6092 8 uint32_t c = -1;
6093 8 int i, closed_gop = 0;
6094
6095
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6096 368 c = (c << 8) + pkt->data[i];
6097
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6098 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6099
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6100 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6101
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
6102 8 *flags = MOV_SYNC_SAMPLE;
6103 else
6104 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6105 8 break;
6106 }
6107 }
6108 8 return 0;
6109 }
6110
6111 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6112 {
6113 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6114 int seq = 0, entry = 0;
6115 int key = pkt->flags & AV_PKT_FLAG_KEY;
6116 start = find_next_marker(pkt->data, end);
6117 for (next = start; next < end; start = next) {
6118 next = find_next_marker(start + 4, end);
6119 switch (AV_RB32(start)) {
6120 case VC1_CODE_SEQHDR:
6121 seq = 1;
6122 break;
6123 case VC1_CODE_ENTRYPOINT:
6124 entry = 1;
6125 break;
6126 case VC1_CODE_SLICE:
6127 trk->vc1_info.slices = 1;
6128 break;
6129 }
6130 }
6131 if (!trk->entry && trk->vc1_info.first_packet_seen)
6132 trk->vc1_info.first_frag_written = 1;
6133 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6134 /* First packet in first fragment */
6135 trk->vc1_info.first_packet_seq = seq;
6136 trk->vc1_info.first_packet_entry = entry;
6137 trk->vc1_info.first_packet_seen = 1;
6138 } else if ((seq && !trk->vc1_info.packet_seq) ||
6139 (entry && !trk->vc1_info.packet_entry)) {
6140 int i;
6141 for (i = 0; i < trk->entry; i++)
6142 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6143 trk->has_keyframes = 0;
6144 if (seq)
6145 trk->vc1_info.packet_seq = 1;
6146 if (entry)
6147 trk->vc1_info.packet_entry = 1;
6148 if (!trk->vc1_info.first_frag_written) {
6149 /* First fragment */
6150 if ((!seq || trk->vc1_info.first_packet_seq) &&
6151 (!entry || trk->vc1_info.first_packet_entry)) {
6152 /* First packet had the same headers as this one, readd the
6153 * sync sample flag. */
6154 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6155 trk->has_keyframes = 1;
6156 }
6157 }
6158 }
6159 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6160 key = seq && entry;
6161 else if (trk->vc1_info.packet_seq)
6162 key = seq;
6163 else if (trk->vc1_info.packet_entry)
6164 key = entry;
6165 if (key) {
6166 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6167 trk->has_keyframes++;
6168 }
6169 }
6170
6171 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6172 {
6173 int length;
6174
6175 if (pkt->size < 8)
6176 return;
6177
6178 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6179 if (length < 8 || length > pkt->size)
6180 return;
6181
6182 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6183 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6184 trk->has_keyframes++;
6185 }
6186
6187 return;
6188 }
6189
6190 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6191 {
6192 MOVMuxContext *mov = s->priv_data;
6193 int ret, buf_size;
6194 uint8_t *buf;
6195 int i, offset;
6196
6197 if (!track->mdat_buf)
6198 return 0;
6199 if (!mov->mdat_buf) {
6200 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6201 return ret;
6202 }
6203 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6204
6205 offset = avio_tell(mov->mdat_buf);
6206 avio_write(mov->mdat_buf, buf, buf_size);
6207 ffio_free_dyn_buf(&track->mdat_buf);
6208
6209 for (i = track->entries_flushed; i < track->entry; i++)
6210 track->cluster[i].pos += offset;
6211 track->entries_flushed = track->entry;
6212 return 0;
6213 }
6214
6215 2 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6216 {
6217 2 MOVMuxContext *mov = s->priv_data;
6218 2 AVPacket *squashed_packet = mov->pkt;
6219 2 int ret = AVERROR_BUG;
6220
6221
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 switch (track->st->codecpar->codec_id) {
6222 2 case AV_CODEC_ID_TTML: {
6223 2 int had_packets = !!track->squashed_packet_queue.head;
6224
6225
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) {
6226 goto finish_squash;
6227 }
6228
6229 // We have generated a padding packet (no actual input packets in
6230 // queue) and its duration is zero. Skipping writing it.
6231
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) {
6232 goto finish_squash;
6233 }
6234
6235 2 track->end_reliable = 1;
6236 2 break;
6237 }
6238 default:
6239 ret = AVERROR(EINVAL);
6240 goto finish_squash;
6241 }
6242
6243 2 squashed_packet->stream_index = track->st->index;
6244
6245 2 ret = mov_write_single_packet(s, squashed_packet);
6246
6247 2 finish_squash:
6248 2 av_packet_unref(squashed_packet);
6249
6250 2 return ret;
6251 }
6252
6253 315 static int mov_write_squashed_packets(AVFormatContext *s)
6254 {
6255 315 MOVMuxContext *mov = s->priv_data;
6256
6257
2/2
✓ Branch 0 taken 459 times.
✓ Branch 1 taken 315 times.
774 for (int i = 0; i < mov->nb_streams; i++) {
6258 459 MOVTrack *track = &mov->tracks[i];
6259 459 int ret = AVERROR_BUG;
6260
6261
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 457 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
459 if (track->squash_fragment_samples_to_one && !track->entry) {
6262
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6263 av_log(s, AV_LOG_ERROR,
6264 "Failed to write squashed packet for %s stream with "
6265 "index %d and track id %d. Error: %s\n",
6266 avcodec_get_name(track->st->codecpar->codec_id),
6267 track->st->index, track->track_id,
6268 av_err2str(ret));
6269 return ret;
6270 }
6271 }
6272 }
6273
6274 315 return 0;
6275 }
6276
6277 129 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6278 int64_t ref_pos)
6279 {
6280 int i;
6281
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 125 times.
129 if (!track->entry)
6282 4 return 0;
6283
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 120 times.
125 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6284
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 5 times.
41 for (i = 0; i < track->entry; i++)
6285 36 track->cluster[i].pos += ref_pos + track->data_offset;
6286
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
5 if (track->cluster_written == 0 && !(mov->flags & FF_MOV_FLAG_EMPTY_MOOV)) {
6287 // First flush. If this was a case of not using empty moov, reset chunking.
6288
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (i = 0; i < track->entry; i++) {
6289 18 track->cluster[i].chunkNum = 0;
6290 18 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6291 }
6292 }
6293
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (av_reallocp_array(&track->cluster_written,
6294 5 track->entry_written + track->entry,
6295 sizeof(*track->cluster)))
6296 return AVERROR(ENOMEM);
6297 5 memcpy(&track->cluster_written[track->entry_written],
6298 5 track->cluster, track->entry * sizeof(*track->cluster));
6299 5 track->entry_written += track->entry;
6300 }
6301 125 track->entry = 0;
6302 125 track->entries_flushed = 0;
6303 125 track->end_reliable = 0;
6304 125 return 0;
6305 }
6306
6307 106 static int mov_flush_fragment(AVFormatContext *s, int force)
6308 {
6309 106 MOVMuxContext *mov = s->priv_data;
6310 106 int i, first_track = -1;
6311 106 int64_t mdat_size = 0, mdat_start = 0;
6312 int ret;
6313 106 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6314
6315
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
106 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6316 return 0;
6317
6318 // Check if we have any tracks that require squashing.
6319 // In that case, we'll have to write the packet here.
6320
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 106 times.
106 if ((ret = mov_write_squashed_packets(s)) < 0)
6321 return ret;
6322
6323 // Try to fill in the duration of the last packet in each stream
6324 // from queued packets in the interleave queues. If the flushing
6325 // of fragments was triggered automatically by an AVPacket, we
6326 // already have reliable info for the end of that track, but other
6327 // tracks may need to be filled in.
6328
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 106 times.
298 for (i = 0; i < mov->nb_streams; i++) {
6329 192 MOVTrack *track = &mov->tracks[i];
6330
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 38 times.
192 if (!track->end_reliable) {
6331 154 const AVPacket *pkt = ff_interleaved_peek(s, i);
6332
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 148 times.
154 if (pkt) {
6333 int64_t offset, dts, pts;
6334 6 ff_get_muxer_ts_offset(s, i, &offset);
6335 6 pts = pkt->pts + offset;
6336 6 dts = pkt->dts + offset;
6337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6338 dts += track->dts_shift;
6339 6 track->track_duration = dts - track->start_dts;
6340
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6341 6 track->end_pts = pts;
6342 else
6343 track->end_pts = dts;
6344 }
6345 }
6346 }
6347
6348
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 106 times.
304 for (i = 0; i < mov->nb_tracks; i++) {
6349 198 MOVTrack *track = &mov->tracks[i];
6350
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 153 times.
198 if (track->entry <= 1)
6351 45 continue;
6352 // Sample durations are calculated as the diff of dts values,
6353 // but for the last sample in a fragment, we don't know the dts
6354 // of the first sample in the next fragment, so we have to rely
6355 // on what was set as duration in the AVPacket. Not all callers
6356 // set this though, so we might want to replace it with an
6357 // estimate if it currently is zero.
6358
2/2
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 2 times.
153 if (get_cluster_duration(track, track->entry - 1) != 0)
6359 151 continue;
6360 // Use the duration (i.e. dts diff) of the second last sample for
6361 // the last one. This is a wild guess (and fatal if it turns out
6362 // to be too long), but probably the best we can do - having a zero
6363 // duration is bad as well.
6364 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6365 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6366
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6367 2 av_log(s, AV_LOG_WARNING,
6368 "Estimating the duration of the last packet in a "
6369 "fragment, consider setting the duration field in "
6370 "AVPacket instead.\n");
6371 2 mov->missing_duration_warned = 1;
6372 }
6373 }
6374
6375
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 83 times.
106 if (!mov->moov_written) {
6376 23 int64_t pos = avio_tell(s->pb);
6377 uint8_t *buf;
6378 int buf_size, moov_size;
6379
6380
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 19 times.
64 for (i = 0; i < mov->nb_tracks; i++)
6381
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 41 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
45 if (!mov->tracks[i].entry && !is_cover_image(mov->tracks[i].st))
6382 4 break;
6383 /* Don't write the initial moov unless all tracks have data */
6384
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2 times.
23 if (i < mov->nb_tracks && !force)
6385 2 return 0;
6386
6387 21 moov_size = get_moov_size(s);
6388
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 21 times.
62 for (i = 0; i < mov->nb_tracks; i++)
6389 41 mov->tracks[i].data_offset = pos + moov_size + 8;
6390
6391 21 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6392
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6393 17 mov_write_identification(s->pb, s);
6394
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6395 return ret;
6396
6397
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6398
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6399 mov->reserved_header_pos = avio_tell(s->pb);
6400 17 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6401 17 mov->moov_written = 1;
6402 17 return 0;
6403 }
6404
6405 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6406 4 avio_wb32(s->pb, buf_size + 8);
6407 4 ffio_wfourcc(s->pb, "mdat");
6408 4 avio_write(s->pb, buf, buf_size);
6409 4 ffio_free_dyn_buf(&mov->mdat_buf);
6410
6411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6412 mov->reserved_header_pos = avio_tell(s->pb);
6413
6414 4 mov->moov_written = 1;
6415 4 mov->mdat_size = 0;
6416
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (i = 0; i < mov->nb_tracks; i++)
6417 8 mov_finish_fragment(mov, &mov->tracks[i], 0);
6418 4 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6419 4 return 0;
6420 }
6421
6422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 if (mov->frag_interleave) {
6423 for (i = 0; i < mov->nb_tracks; i++) {
6424 MOVTrack *track = &mov->tracks[i];
6425 int ret;
6426 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6427 return ret;
6428 }
6429
6430 if (!mov->mdat_buf)
6431 return 0;
6432 mdat_size = avio_tell(mov->mdat_buf);
6433 }
6434
6435
2/2
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 83 times.
236 for (i = 0; i < mov->nb_tracks; i++) {
6436 153 MOVTrack *track = &mov->tracks[i];
6437
3/4
✓ Branch 0 taken 134 times.
✓ Branch 1 taken 19 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 134 times.
153 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF || mov->frag_interleave)
6438 19 track->data_offset = 0;
6439 else
6440 134 track->data_offset = mdat_size;
6441
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 80 times.
153 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6442 73 has_video = 1;
6443
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if (first_video_track) {
6444
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 12 times.
73 if (track->entry)
6445 61 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6446 73 first_video_track = 0;
6447 }
6448 }
6449
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 117 times.
153 if (!track->entry)
6450 36 continue;
6451
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 if (track->mdat_buf)
6452 117 mdat_size += avio_tell(track->mdat_buf);
6453
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 50 times.
117 if (first_track < 0)
6454 67 first_track = i;
6455 }
6456
6457
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 67 times.
83 if (!mdat_size)
6458 16 return 0;
6459
6460
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 3 times.
67 avio_write_marker(s->pb,
6461 67 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6462
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 6 times.
67 (has_video ? starts_with_key : mov->tracks[first_track].cluster[0].flags & MOV_SYNC_SAMPLE) ? AVIO_DATA_MARKER_SYNC_POINT : AVIO_DATA_MARKER_BOUNDARY_POINT);
6463
6464
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 67 times.
192 for (i = 0; i < mov->nb_tracks; i++) {
6465 125 MOVTrack *track = &mov->tracks[i];
6466 125 int buf_size, write_moof = 1, moof_tracks = -1;
6467 uint8_t *buf;
6468
6469
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 106 times.
125 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6470
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
19 if (!track->entry)
6471 8 continue;
6472 15 mdat_size = avio_tell(track->mdat_buf);
6473 15 moof_tracks = i;
6474 } else {
6475 106 write_moof = i == first_track;
6476 }
6477
6478
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 50 times.
121 if (write_moof) {
6479 71 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6480
6481 71 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6482 71 mov->fragments++;
6483
6484 71 avio_wb32(s->pb, mdat_size + 8);
6485 71 ffio_wfourcc(s->pb, "mdat");
6486 71 mdat_start = avio_tell(s->pb);
6487 }
6488
6489 121 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6490
1/2
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
121 if (!mov->frag_interleave) {
6491
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 117 times.
121 if (!track->mdat_buf)
6492 4 continue;
6493 117 buf_size = avio_close_dyn_buf(track->mdat_buf, &buf);
6494 117 track->mdat_buf = NULL;
6495 } else {
6496 if (!mov->mdat_buf)
6497 continue;
6498 buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf);
6499 mov->mdat_buf = NULL;
6500 }
6501
6502 117 avio_write(s->pb, buf, buf_size);
6503 117 av_free(buf);
6504 }
6505
6506 67 mov->mdat_size = 0;
6507
6508 67 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6509 67 return 0;
6510 }
6511
6512 61 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6513 {
6514 61 MOVMuxContext *mov = s->priv_data;
6515 61 int had_moov = mov->moov_written;
6516 61 int ret = mov_flush_fragment(s, force);
6517
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if (ret < 0)
6518 return ret;
6519 // If using delay_moov, the first flush only wrote the moov,
6520 // not the actual moof+mdat pair, thus flush once again.
6521
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 48 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 4 times.
61 if (!had_moov && mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6522 9 ret = mov_flush_fragment(s, force);
6523 61 return ret;
6524 }
6525
6526 36163 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6527 {
6528 int64_t ref;
6529 uint64_t duration;
6530
6531
2/2
✓ Branch 0 taken 35525 times.
✓ Branch 1 taken 638 times.
36163 if (trk->entry) {
6532 35525 ref = trk->cluster[trk->entry - 1].dts;
6533
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 524 times.
638 } else if ( trk->start_dts != AV_NOPTS_VALUE
6534
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 8 times.
114 && !trk->frag_discont) {
6535 106 ref = trk->start_dts + trk->track_duration;
6536 } else
6537 532 ref = pkt->dts; // Skip tests for the first packet
6538
6539
2/2
✓ Branch 0 taken 1655 times.
✓ Branch 1 taken 34508 times.
36163 if (trk->dts_shift != AV_NOPTS_VALUE) {
6540 /* With negative CTS offsets we have set an offset to the DTS,
6541 * reverse this for the check. */
6542 1655 ref -= trk->dts_shift;
6543 }
6544
6545 36163 duration = pkt->dts - ref;
6546
2/4
✓ Branch 0 taken 36163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36163 times.
36163 if (pkt->dts < ref || duration >= INT_MAX) {
6547 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6548 duration, pkt->dts, pkt->stream_index);
6549
6550 pkt->dts = ref + 1;
6551 pkt->pts = AV_NOPTS_VALUE;
6552 }
6553
6554
2/4
✓ Branch 0 taken 36163 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 36163 times.
36163 if (pkt->duration < 0 || pkt->duration > INT_MAX) {
6555 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6556 return AVERROR(EINVAL);
6557 }
6558 36163 return 0;
6559 }
6560
6561 18100 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6562 {
6563 18100 MOVMuxContext *mov = s->priv_data;
6564 18100 AVIOContext *pb = s->pb;
6565 MOVTrack *trk;
6566 AVCodecParameters *par;
6567 AVProducerReferenceTime *prft;
6568 18100 unsigned int samples_in_chunk = 0;
6569 18100 int size = pkt->size, ret = 0, offset = 0;
6570 size_t prft_size;
6571 18100 uint8_t *reformatted_data = NULL;
6572
6573
2/2
✓ Branch 0 taken 18054 times.
✓ Branch 1 taken 46 times.
18100 if (pkt->stream_index < s->nb_streams)
6574 18054 trk = s->streams[pkt->stream_index]->priv_data;
6575 else // Timecode or chapter
6576 46 trk = &mov->tracks[pkt->stream_index];
6577 18100 par = trk->par;
6578
6579 18100 ret = check_pkt(s, trk, pkt);
6580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (ret < 0)
6581 return ret;
6582
6583
2/2
✓ Branch 0 taken 17498 times.
✓ Branch 1 taken 602 times.
18100 if (pkt->pts != AV_NOPTS_VALUE &&
6584
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17498 times.
17498 (uint64_t)pkt->dts - pkt->pts != (int32_t)((uint64_t)pkt->dts - pkt->pts)) {
6585 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
6586 return AVERROR_PATCHWELCOME;
6587 }
6588
6589
3/4
✓ Branch 0 taken 12840 times.
✓ Branch 1 taken 5260 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12840 times.
18100 if (mov->flags & FF_MOV_FLAG_FRAGMENT || mov->mode == MODE_AVIF) {
6590 int ret;
6591
4/4
✓ Branch 0 taken 2130 times.
✓ Branch 1 taken 3130 times.
✓ Branch 2 taken 1892 times.
✓ Branch 3 taken 238 times.
5260 if (mov->moov_written || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
6592
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 5022 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
5022 if (mov->frag_interleave && mov->fragments > 0) {
6593 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6594 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6595 return ret;
6596 }
6597 }
6598
6599
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 4905 times.
5022 if (!trk->mdat_buf) {
6600
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
117 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6601 return ret;
6602 }
6603 5022 pb = trk->mdat_buf;
6604 } else {
6605
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
6606
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6607 return ret;
6608 }
6609 238 pb = mov->mdat_buf;
6610 }
6611 }
6612
6613
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6614 /* We must find out how many AMR blocks there are in one packet */
6615 static const uint16_t packed_size[16] =
6616 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6617 int len = 0;
6618
6619 while (len < size && samples_in_chunk < 100) {
6620 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6621 samples_in_chunk++;
6622 }
6623 if (samples_in_chunk > 1) {
6624 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6625 return -1;
6626 }
6627
1/2
✓ Branch 0 taken 18100 times.
✗ Branch 1 not taken.
18100 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6628
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6629 samples_in_chunk = trk->par->frame_size;
6630
2/2
✓ Branch 0 taken 1297 times.
✓ Branch 1 taken 16803 times.
18100 } else if (trk->sample_size)
6631 1297 samples_in_chunk = size / trk->sample_size;
6632 else
6633 16803 samples_in_chunk = 1;
6634
6635
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (samples_in_chunk < 1) {
6636 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6637 return AVERROR_PATCHWELCOME;
6638 }
6639
6640 /* copy extradata if it exists */
6641
4/4
✓ Branch 0 taken 5375 times.
✓ Branch 1 taken 12725 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 5373 times.
18100 if (trk->vos_len == 0 && par->extradata_size > 0 &&
6642
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) &&
6643
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6644 2 trk->vos_len = par->extradata_size;
6645 2 trk->vos_data = av_malloc(trk->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
6646
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->vos_data) {
6647 ret = AVERROR(ENOMEM);
6648 goto err;
6649 }
6650 2 memcpy(trk->vos_data, par->extradata, trk->vos_len);
6651 2 memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6652 }
6653
6654
2/2
✓ Branch 0 taken 17985 times.
✓ Branch 1 taken 115 times.
18100 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6655
2/2
✓ Branch 0 taken 15397 times.
✓ Branch 1 taken 2588 times.
17985 par->codec_id == AV_CODEC_ID_H264 ||
6656
2/2
✓ Branch 0 taken 15242 times.
✓ Branch 1 taken 155 times.
15397 par->codec_id == AV_CODEC_ID_HEVC ||
6657
2/2
✓ Branch 0 taken 15232 times.
✓ Branch 1 taken 10 times.
15242 par->codec_id == AV_CODEC_ID_VVC ||
6658
1/2
✓ Branch 0 taken 15232 times.
✗ Branch 1 not taken.
15232 par->codec_id == AV_CODEC_ID_VP9 ||
6659
2/2
✓ Branch 0 taken 14932 times.
✓ Branch 1 taken 300 times.
15232 par->codec_id == AV_CODEC_ID_EVC ||
6660
3/4
✗ Branch 0 not taken.
✓ Branch 1 taken 14932 times.
✓ Branch 2 taken 24 times.
✓ Branch 3 taken 3144 times.
18100 par->codec_id == AV_CODEC_ID_TRUEHD) && !trk->vos_len &&
6661
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)) {
6662 /* copy frame to create needed atoms */
6663 24 trk->vos_len = size;
6664 24 trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->vos_data) {
6666 ret = AVERROR(ENOMEM);
6667 goto err;
6668 }
6669 24 memcpy(trk->vos_data, pkt->data, size);
6670 24 memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6671 }
6672
6673
3/4
✓ Branch 0 taken 5540 times.
✓ Branch 1 taken 12560 times.
✓ Branch 2 taken 5540 times.
✗ Branch 3 not taken.
18100 if (par->codec_id == AV_CODEC_ID_AAC && pkt->size > 2 &&
6674
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5540 times.
5540 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6675 if (!trk->st->nb_frames) {
6676 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6677 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6678 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6679 return -1;
6680 }
6681 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6682 }
6683
19/34
✓ Branch 0 taken 2588 times.
✓ Branch 1 taken 15512 times.
✓ Branch 2 taken 2588 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 498 times.
✓ Branch 5 taken 2090 times.
✓ Branch 6 taken 498 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 498 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 498 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 498 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 498 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 498 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 498 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 498 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 498 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 498 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 498 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 498 times.
✗ Branch 29 not taken.
✓ Branch 30 taken 498 times.
✗ Branch 31 not taken.
✓ Branch 32 taken 498 times.
✗ Branch 33 not taken.
18100 if (par->codec_id == AV_CODEC_ID_H264 && trk->vos_len > 0 && *(uint8_t *)trk->vos_data != 1 && !TAG_IS_AVCI(trk->tag)) {
6684 /* from x264 or from bytestream H.264 */
6685 /* NAL reformatting needed */
6686
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
498 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6687 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
6688 &size);
6689 if (ret < 0)
6690 return ret;
6691 avio_write(pb, reformatted_data, size);
6692 } else {
6693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 if (trk->cenc.aes_ctr) {
6694 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6695 if (size < 0) {
6696 ret = size;
6697 goto err;
6698 }
6699 } else {
6700 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
6701 }
6702 }
6703
3/4
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 17447 times.
✓ Branch 2 taken 155 times.
✗ Branch 3 not taken.
17602 } else if (par->codec_id == AV_CODEC_ID_HEVC && trk->vos_len > 6 &&
6704
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
299 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6705 /* extradata is Annex B, assume the bitstream is too and convert it */
6706 144 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
6707
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
144 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6708 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6709 &size, filter_ps, NULL);
6710 if (ret < 0)
6711 return ret;
6712 avio_write(pb, reformatted_data, size);
6713 } else {
6714
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
144 if (trk->cenc.aes_ctr) {
6715 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6716 if (size < 0) {
6717 ret = size;
6718 goto err;
6719 }
6720 } else {
6721 144 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
6722 }
6723 }
6724
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 17448 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
17458 } else if (par->codec_id == AV_CODEC_ID_VVC && trk->vos_len > 6 &&
6725
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6726 /* extradata is Annex B, assume the bitstream is too and convert it */
6727
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
10 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks) {
6728 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6729 &size, 0, NULL);
6730 if (ret < 0)
6731 return ret;
6732 avio_write(pb, reformatted_data, size);
6733 } else {
6734 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6735 }
6736
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 17444 times.
17448 } else if (par->codec_id == AV_CODEC_ID_AV1) {
6737
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) {
6738 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
6739 &size, &offset);
6740 if (ret < 0)
6741 return ret;
6742 avio_write(pb, reformatted_data, size);
6743 } else {
6744 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
6745
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]) {
6746 mov->avif_extent_length[pkt->stream_index] = size;
6747 }
6748 }
6749
6750
2/2
✓ Branch 0 taken 17057 times.
✓ Branch 1 taken 387 times.
17444 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
6751
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 16405 times.
17057 par->codec_id == AV_CODEC_ID_EAC3) {
6752 1039 size = handle_eac3(mov, pkt, trk);
6753
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
6754 return size;
6755
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
6756 1 goto end;
6757 1038 avio_write(pb, pkt->data, size);
6758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16405 times.
16405 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
6759 size = 8;
6760
6761 for (int i = 0; i < pkt->size; i += 3) {
6762 if (pkt->data[i] == 0xFC) {
6763 size += 2;
6764 }
6765 }
6766 avio_wb32(pb, size);
6767 ffio_wfourcc(pb, "cdat");
6768 for (int i = 0; i < pkt->size; i += 3) {
6769 if (pkt->data[i] == 0xFC) {
6770 avio_w8(pb, pkt->data[i + 1]);
6771 avio_w8(pb, pkt->data[i + 2]);
6772 }
6773 }
6774 } else {
6775
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16405 times.
16405 if (trk->cenc.aes_ctr) {
6776 if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 4) {
6777 int nal_size_length = (par->extradata[4] & 0x3) + 1;
6778 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6779 } else if(par->codec_id == AV_CODEC_ID_HEVC && par->extradata_size > 21) {
6780 int nal_size_length = (par->extradata[21] & 0x3) + 1;
6781 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6782 } else if(par->codec_id == AV_CODEC_ID_VVC) {
6783 ret = AVERROR_PATCHWELCOME;
6784 } else {
6785 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
6786 }
6787
6788 if (ret) {
6789 goto err;
6790 }
6791 } else {
6792 16405 avio_write(pb, pkt->data, size);
6793 }
6794 }
6795
6796
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 17826 times.
18099 if (trk->entry >= trk->cluster_capacity) {
6797 273 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
6798 273 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
6799
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273 times.
273 if (!cluster) {
6800 ret = AVERROR(ENOMEM);
6801 goto err;
6802 }
6803 273 trk->cluster = cluster;
6804 273 trk->cluster_capacity = new_capacity;
6805 }
6806
6807 18099 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6808 18099 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
6809 18099 trk->cluster[trk->entry].chunkNum = 0;
6810 18099 trk->cluster[trk->entry].size = size;
6811 18099 trk->cluster[trk->entry].entries = samples_in_chunk;
6812 18099 trk->cluster[trk->entry].dts = pkt->dts;
6813 18099 trk->cluster[trk->entry].pts = pkt->pts;
6814
2/2
✓ Branch 0 taken 18097 times.
✓ Branch 1 taken 2 times.
18099 if (!trk->squash_fragment_samples_to_one &&
6815
4/4
✓ Branch 0 taken 332 times.
✓ Branch 1 taken 17765 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 257 times.
18097 !trk->entry && trk->start_dts != AV_NOPTS_VALUE) {
6816
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 4 times.
75 if (!trk->frag_discont) {
6817 /* First packet of a new fragment. We already wrote the duration
6818 * of the last packet of the previous fragment based on track_duration,
6819 * which might not exactly match our dts. Therefore adjust the dts
6820 * of this packet to be what the previous packets duration implies. */
6821 71 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
6822 /* We also may have written the pts and the corresponding duration
6823 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
6824 * the next fragment. This means the cts of the first sample must
6825 * be the same in all fragments, unless end_pts was updated by
6826 * the packet causing the fragment to be written. */
6827
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 57 times.
71 if ((mov->flags & FF_MOV_FLAG_DASH &&
6828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
6829
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 47 times.
57 mov->mode == MODE_ISM)
6830 24 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
6831 } else {
6832 /* New fragment, but discontinuous from previous fragments.
6833 * Pretend the duration sum of the earlier fragments is
6834 * pkt->dts - trk->start_dts. */
6835 4 trk->end_pts = AV_NOPTS_VALUE;
6836 4 trk->frag_discont = 0;
6837 }
6838 }
6839
6840
6/6
✓ Branch 0 taken 334 times.
✓ Branch 1 taken 17765 times.
✓ Branch 2 taken 259 times.
✓ Branch 3 taken 75 times.
✓ Branch 4 taken 30 times.
✓ Branch 5 taken 229 times.
18099 if (!trk->entry && trk->start_dts == AV_NOPTS_VALUE && !mov->use_editlist &&
6841
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 11 times.
30 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
6842 /* Not using edit lists and shifting the first track to start from zero.
6843 * If the other streams start from a later timestamp, we won't be able
6844 * to signal the difference in starting time without an edit list.
6845 * Thus move the timestamp for this first sample to 0, increasing
6846 * its duration instead. */
6847 19 trk->cluster[trk->entry].dts = trk->start_dts = 0;
6848 }
6849
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 17859 times.
18099 if (trk->start_dts == AV_NOPTS_VALUE) {
6850 240 trk->start_dts = pkt->dts;
6851
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 234 times.
240 if (trk->frag_discont) {
6852
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
6853 /* Pretend the whole stream started at pts=0, with earlier fragments
6854 * already written. If the stream started at pts=0, the duration sum
6855 * of earlier fragments would have been pkt->pts. */
6856 4 trk->start_dts = pkt->dts - pkt->pts;
6857 } else {
6858 /* Pretend the whole stream started at dts=0, with earlier fragments
6859 * already written, with a duration summing up to pkt->dts. */
6860 2 trk->start_dts = 0;
6861 }
6862 6 trk->frag_discont = 0;
6863
4/4
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 201 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 31 times.
234 } else if (pkt->dts && mov->moov_written)
6864 2 av_log(s, AV_LOG_WARNING,
6865 "Track %d starts with a nonzero dts %"PRId64", while the moov "
6866 "already has been written. Set the delay_moov flag to handle "
6867 "this case.\n",
6868 pkt->stream_index, pkt->dts);
6869 }
6870 18099 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
6871 18099 trk->last_sample_is_subtitle_end = 0;
6872
6873
2/2
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 17497 times.
18099 if (pkt->pts == AV_NOPTS_VALUE) {
6874 602 av_log(s, AV_LOG_WARNING, "pts has no value\n");
6875 602 pkt->pts = pkt->dts;
6876 }
6877
2/2
✓ Branch 0 taken 1018 times.
✓ Branch 1 taken 17081 times.
18099 if (pkt->dts != pkt->pts)
6878 1018 trk->flags |= MOV_TRACK_CTTS;
6879 18099 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
6880 18099 trk->cluster[trk->entry].flags = 0;
6881
2/2
✓ Branch 0 taken 259 times.
✓ Branch 1 taken 17840 times.
18099 if (trk->start_cts == AV_NOPTS_VALUE)
6882 259 trk->start_cts = pkt->pts - pkt->dts;
6883
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 17836 times.
18099 if (trk->end_pts == AV_NOPTS_VALUE)
6884 263 trk->end_pts = trk->cluster[trk->entry].dts +
6885 263 trk->cluster[trk->entry].cts + pkt->duration;
6886 else
6887 17836 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
6888 trk->cluster[trk->entry].cts +
6889 pkt->duration);
6890
6891
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
18099 if (par->codec_id == AV_CODEC_ID_VC1) {
6892 mov_parse_vc1_frame(pkt, trk);
6893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
18099 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
6894 mov_parse_truehd_frame(pkt, trk);
6895
2/2
✓ Branch 0 taken 13459 times.
✓ Branch 1 taken 4640 times.
18099 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
6896
4/4
✓ Branch 0 taken 6356 times.
✓ Branch 1 taken 7103 times.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 6347 times.
13459 if (mov->mode == MODE_MOV && par->codec_id == AV_CODEC_ID_MPEG2VIDEO &&
6897
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
6898 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
6899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
6900 trk->flags |= MOV_TRACK_STPS;
6901 } else {
6902 13451 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
6903 }
6904
1/2
✓ Branch 0 taken 13459 times.
✗ Branch 1 not taken.
13459 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
6905 13459 trk->has_keyframes++;
6906 }
6907
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18092 times.
18099 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
6908 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
6909 7 trk->has_disposable++;
6910 }
6911
6912 18099 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
6913
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18099 if (prft && prft_size == sizeof(AVProducerReferenceTime))
6914 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
6915 else
6916 18099 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
6917
6918 18099 trk->entry++;
6919 18099 trk->sample_count += samples_in_chunk;
6920 18099 mov->mdat_size += size;
6921
6922
3/4
✓ Branch 0 taken 18017 times.
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 82 times.
18099 if (trk->hint_track >= 0 && trk->hint_track < mov->nb_tracks)
6923 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
6924
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
6925 : NULL, size);
6926
6927 18100 end:
6928 18100 err:
6929
6930
1/2
✓ Branch 0 taken 18100 times.
✗ Branch 1 not taken.
18100 if (pkt->data != reformatted_data)
6931 18100 av_free(reformatted_data);
6932 18100 return ret;
6933 }
6934
6935 18063 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
6936 {
6937 18063 MOVMuxContext *mov = s->priv_data;
6938 18063 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
6939 18063 AVCodecParameters *par = trk->par;
6940 18063 int64_t frag_duration = 0;
6941 18063 int size = pkt->size;
6942
6943 18063 int ret = check_pkt(s, trk, pkt);
6944
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18063 times.
18063 if (ret < 0)
6945 return ret;
6946
6947
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18058 times.
18063 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
6948
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
6949 10 mov->tracks[i].frag_discont = 1;
6950 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
6951 }
6952
6953
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 17253 times.
18063 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
6954
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 799 times.
810 if (trk->dts_shift == AV_NOPTS_VALUE)
6955 11 trk->dts_shift = pkt->pts - pkt->dts;
6956 810 pkt->dts += trk->dts_shift;
6957 }
6958
6959
1/2
✓ Branch 0 taken 18063 times.
✗ Branch 1 not taken.
18063 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
6960
2/2
✓ Branch 0 taken 12521 times.
✓ Branch 1 taken 5542 times.
18063 trk->par->codec_id == AV_CODEC_ID_AAC ||
6961
2/2
✓ Branch 0 taken 12517 times.
✓ Branch 1 taken 4 times.
12521 trk->par->codec_id == AV_CODEC_ID_AV1 ||
6962
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12462 times.
12517 trk->par->codec_id == AV_CODEC_ID_FLAC) {
6963 size_t side_size;
6964 5601 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
6965
6/8
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 5595 times.
✓ Branch 2 taken 6 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 5 times.
✗ Branch 7 not taken.
5601 if (side && side_size > 0 && (side_size != par->extradata_size || memcmp(side, par->extradata, side_size))) {
6966 6 void *newextra = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
6967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
6968 return AVERROR(ENOMEM);
6969 6 av_free(par->extradata);
6970 6 par->extradata = newextra;
6971 6 memcpy(par->extradata, side, side_size);
6972 6 par->extradata_size = side_size;
6973
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (!pkt->size) // Flush packet
6974 5 mov->need_rewrite_extradata = 1;
6975 }
6976 }
6977
6978
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18054 times.
18063 if (!pkt->size) {
6979
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
9 if (trk->start_dts == AV_NOPTS_VALUE && trk->frag_discont) {
6980 4 trk->start_dts = pkt->dts;
6981
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
6982 4 trk->start_cts = pkt->pts - pkt->dts;
6983 else
6984 trk->start_cts = 0;
6985 }
6986
6987 9 return 0; /* Discard 0 sized packets */
6988 }
6989
6990
4/4
✓ Branch 0 taken 17755 times.
✓ Branch 1 taken 299 times.
✓ Branch 2 taken 17731 times.
✓ Branch 3 taken 24 times.
18054 if (trk->entry && pkt->stream_index < mov->nb_streams)
6991 17731 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
6992 17731 s->streams[pkt->stream_index]->time_base,
6993 17731 AV_TIME_BASE_Q);
6994
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 17881 times.
18054 if ((mov->max_fragment_duration &&
6995
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 3 times.
173 frag_duration >= mov->max_fragment_duration) ||
6996
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 18051 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
18051 (mov->max_fragment_size && mov->mdat_size + size >= mov->max_fragment_size) ||
6997
2/2
✓ Branch 0 taken 3673 times.
✓ Branch 1 taken 14378 times.
18051 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
6998
2/2
✓ Branch 0 taken 1125 times.
✓ Branch 1 taken 2548 times.
3673 par->codec_type == AVMEDIA_TYPE_VIDEO &&
6999
4/4
✓ Branch 0 taken 1101 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 1076 times.
✓ Branch 3 taken 25 times.
1125 trk->entry && pkt->flags & AV_PKT_FLAG_KEY) ||
7000
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18026 times.
18026 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7001
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (frag_duration >= mov->min_fragment_duration) {
7002
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (trk->entry) {
7003 // Set the duration of this track to line up with the next
7004 // sample in this track. This avoids relying on AVPacket
7005 // duration, but only helps for this particular track, not
7006 // for the other ones that are flushed at the same time.
7007 //
7008 // If we have trk->entry == 0, no fragment will be written
7009 // for this track, and we can't adjust the track end here.
7010 28 trk->track_duration = pkt->dts - trk->start_dts;
7011
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (pkt->pts != AV_NOPTS_VALUE)
7012 28 trk->end_pts = pkt->pts;
7013 else
7014 trk->end_pts = pkt->dts;
7015 28 trk->end_reliable = 1;
7016 }
7017 28 mov_auto_flush_fragment(s, 0);
7018 }
7019 }
7020
7021 18054 return ff_mov_write_packet(s, pkt);
7022 }
7023
7024 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7025 int stream_index,
7026 int64_t dts) {
7027 3 MOVMuxContext *mov = s->priv_data;
7028 3 AVPacket *end = mov->pkt;
7029 3 uint8_t data[2] = {0};
7030 int ret;
7031
7032 3 end->size = sizeof(data);
7033 3 end->data = data;
7034 3 end->pts = dts;
7035 3 end->dts = dts;
7036 3 end->duration = 0;
7037 3 end->stream_index = stream_index;
7038
7039 3 ret = mov_write_single_packet(s, end);
7040 3 av_packet_unref(end);
7041
7042 3 return ret;
7043 }
7044
7045 #if CONFIG_IAMFENC
7046 275 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7047 {
7048 uint8_t *data;
7049 int ret;
7050
7051
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 220 times.
275 if (pkt->stream_index == trk->first_iamf_idx) {
7052 55 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7053
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (ret < 0)
7054 return ret;
7055 }
7056
7057 275 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7058 275 s->streams[pkt->stream_index]->id, pkt);
7059
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 if (ret < 0)
7060 return ret;
7061
7062
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (pkt->stream_index != trk->last_iamf_idx)
7063 220 return AVERROR(EAGAIN);
7064
7065 55 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7066 55 trk->iamf_buf = NULL;
7067
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
55 if (!ret) {
7068
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7069 // Either all or none of the packets for a single
7070 // IA Sample may be empty.
7071 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7072 "stream #%d\n", pkt->stream_index);
7073 ret = AVERROR_INVALIDDATA;
7074 }
7075 5 av_free(data);
7076 5 return ret;
7077 }
7078
7079 50 av_buffer_unref(&pkt->buf);
7080 50 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7081
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!pkt->buf) {
7082 av_free(data);
7083 return AVERROR(ENOMEM);
7084 }
7085 50 pkt->data = data;
7086 50 pkt->size = ret;
7087 50 pkt->stream_index = trk->first_iamf_idx;
7088
7089 50 return avio_open_dyn_buf(&trk->iamf_buf);
7090 }
7091 #endif
7092
7093 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7094 {
7095 2 int64_t pos = avio_tell(pb);
7096 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7097 2 const char *value = "";
7098
7099
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7100
7101 2 avio_write_marker(pb,
7102 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7103 AVIO_DATA_MARKER_BOUNDARY_POINT);
7104
7105 2 avio_wb32(pb, 0); /* size */
7106 2 ffio_wfourcc(pb, "emsg");
7107 2 avio_w8(pb, 1); /* version */
7108 2 avio_wb24(pb, 0);
7109 2 avio_wb32(pb, st->time_base.den); /* timescale */
7110 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7111 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7112 2 avio_wb32(pb, 0); /* id */
7113 /* null terminated UTF8 strings */
7114 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7115 2 avio_write(pb, value, strlen(value) + 1);
7116 2 avio_write(pb, pkt->data, pkt->size);
7117
7118 2 return update_size(pb, pos);
7119 }
7120
7121 18391 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7122 {
7123 18391 MOVMuxContext *mov = s->priv_data;
7124 MOVTrack *trk;
7125
7126
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 18356 times.
18391 if (!pkt) {
7127 35 mov_flush_fragment(s, 1);
7128 35 return 1;
7129 }
7130
7131
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18354 times.
18356 if (s->streams[pkt->stream_index]->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7132 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7133 2 return 0;
7134 }
7135
7136 18354 trk = s->streams[pkt->stream_index]->priv_data;
7137
7138 #if CONFIG_IAMFENC
7139
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 18079 times.
18354 if (trk->iamf) {
7140 275 int ret = mov_build_iamf_packet(s, trk, pkt);
7141
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (ret < 0) {
7142
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (ret == AVERROR(EAGAIN))
7143 220 return 0;
7144 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7145 "for stream #%d\n", trk->st->index);
7146 return ret;
7147 }
7148 }
7149 #endif
7150
7151
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18132 times.
18134 if (is_cover_image(trk->st)) {
7152 int ret;
7153
7154
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7155 if (trk->st->nb_frames == 1)
7156 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7157 " ignoring.\n", pkt->stream_index);
7158 return 0;
7159 }
7160
7161
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7162 return ret;
7163
7164 2 return 0;
7165 } else {
7166 int i;
7167
7168
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18123 times.
18132 if (!pkt->size)
7169 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7170
7171 /*
7172 * Subtitles require special handling.
7173 *
7174 * 1) For full complaince, every track must have a sample at
7175 * dts == 0, which is rarely true for subtitles. So, as soon
7176 * as we see any packet with dts > 0, write an empty subtitle
7177 * at dts == 0 for any subtitle track with no samples in it.
7178 *
7179 * 2) For each subtitle track, check if the current packet's
7180 * dts is past the duration of the last subtitle sample. If
7181 * so, we now need to write an end sample for that subtitle.
7182 *
7183 * This must be done conditionally to allow for subtitles that
7184 * immediately replace each other, in which case an end sample
7185 * is not needed, and is, in fact, actively harmful.
7186 *
7187 * 3) See mov_write_trailer for how the final end sample is
7188 * handled.
7189 */
7190
2/2
✓ Branch 0 taken 32861 times.
✓ Branch 1 taken 18123 times.
50984 for (i = 0; i < mov->nb_tracks; i++) {
7191 32861 MOVTrack *trk = &mov->tracks[i];
7192 int ret;
7193
7194
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 32858 times.
32861 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7195
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7196
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)) {
7197 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7198
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7199 2 trk->last_sample_is_subtitle_end = 1;
7200 }
7201 }
7202
7203
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 18049 times.
18123 if (trk->squash_fragment_samples_to_one) {
7204 /*
7205 * If the track has to have its samples squashed into one sample,
7206 * we just take it into the track's queue.
7207 * This will then be utilized as the samples get written in either
7208 * mov_flush_fragment or when the mux is finalized in
7209 * mov_write_trailer.
7210 */
7211 74 int ret = AVERROR_BUG;
7212
7213
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (pkt->pts == AV_NOPTS_VALUE) {
7214 av_log(s, AV_LOG_ERROR,
7215 "Packets without a valid presentation timestamp are "
7216 "not supported with packet squashing!\n");
7217 return AVERROR(EINVAL);
7218 }
7219
7220 /* The following will reset pkt and is only allowed to be used
7221 * because we return immediately. afterwards. */
7222
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
7223 pkt, NULL, 0)) < 0) {
7224 return ret;
7225 }
7226
7227 74 return 0;
7228 }
7229
7230
7231
4/4
✓ Branch 0 taken 7825 times.
✓ Branch 1 taken 10224 times.
✓ Branch 2 taken 3702 times.
✓ Branch 3 taken 4123 times.
18049 if (trk->mode == MODE_MOV && trk->par->codec_type == AVMEDIA_TYPE_VIDEO) {
7232 3702 AVPacket *opkt = pkt;
7233 int reshuffle_ret, ret;
7234
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3677 times.
3702 if (trk->is_unaligned_qt_rgb) {
7235
1/2
✓ Branch 0 taken 25 times.
✗ Branch 1 not taken.
25 int64_t bpc = trk->par->bits_per_coded_sample != 15 ? trk->par->bits_per_coded_sample : 16;
7236 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7237 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7238
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7239 return reshuffle_ret;
7240 } else
7241 3677 reshuffle_ret = 0;
7242
4/4
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 3464 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 233 times.
3702 if (trk->par->format == AV_PIX_FMT_PAL8 && !trk->pal_done) {
7243 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7244
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7245 goto fail;
7246
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7247 5 trk->pal_done++;
7248
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 2872 times.
3697 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7249
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7250
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7251 ret = av_packet_make_writable(pkt);
7252 if (ret < 0)
7253 goto fail;
7254 for (i = 0; i < pkt->size; i++)
7255 pkt->data[i] = ~pkt->data[i];
7256 }
7257
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3702 times.
3702 if (reshuffle_ret) {
7258 ret = mov_write_single_packet(s, pkt);
7259 fail:
7260 if (reshuffle_ret)
7261 av_packet_free(&pkt);
7262 return ret;
7263 }
7264 }
7265
7266 18049 return mov_write_single_packet(s, pkt);
7267 }
7268 }
7269
7270 // QuickTime chapters involve an additional text track with the chapter names
7271 // as samples, and a tref pointing from the other tracks to the chapter one.
7272 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7273 {
7274 static const uint8_t stub_header[] = {
7275 // TextSampleEntry
7276 0x00, 0x00, 0x00, 0x01, // displayFlags
7277 0x00, 0x00, // horizontal + vertical justification
7278 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7279 // BoxRecord
7280 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7281 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7282 // StyleRecord
7283 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7284 0x00, 0x01, // fontID
7285 0x00, 0x00, // fontStyleFlags + fontSize
7286 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7287 // FontTableBox
7288 0x00, 0x00, 0x00, 0x0D, // box size
7289 'f', 't', 'a', 'b', // box atom name
7290 0x00, 0x01, // entry count
7291 // FontRecord
7292 0x00, 0x01, // font ID
7293 0x00, // font name length
7294 };
7295 1 MOVMuxContext *mov = s->priv_data;
7296 1 MOVTrack *track = &mov->tracks[tracknum];
7297 1 AVPacket *pkt = mov->pkt;
7298 int i, len;
7299 int ret;
7300
7301 1 track->mode = mov->mode;
7302 1 track->tag = MKTAG('t','e','x','t');
7303 1 track->timescale = mov->movie_timescale;
7304 1 track->par = avcodec_parameters_alloc();
7305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7306 return AVERROR(ENOMEM);
7307 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7308 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7309
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7310 return ret;
7311 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7312
7313 1 pkt->stream_index = tracknum;
7314 1 pkt->flags = AV_PKT_FLAG_KEY;
7315
7316
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7317 4 AVChapter *c = s->chapters[i];
7318 AVDictionaryEntry *t;
7319
7320 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7321 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7322 4 pkt->duration = end - pkt->dts;
7323
7324
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7325 static const char encd[12] = {
7326 0x00, 0x00, 0x00, 0x0C,
7327 'e', 'n', 'c', 'd',
7328 0x00, 0x00, 0x01, 0x00 };
7329 4 len = strlen(t->value);
7330 4 pkt->size = len + 2 + 12;
7331 4 pkt->data = av_malloc(pkt->size);
7332
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7333 av_packet_unref(pkt);
7334 return AVERROR(ENOMEM);
7335 }
7336 4 AV_WB16(pkt->data, len);
7337 4 memcpy(pkt->data + 2, t->value, len);
7338 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7339 4 ff_mov_write_packet(s, pkt);
7340 4 av_freep(&pkt->data);
7341 }
7342 }
7343
7344 1 av_packet_unref(mov->pkt);
7345
7346 1 return 0;
7347 }
7348
7349
7350 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7351 {
7352 int ret;
7353
7354 /* compute the frame number */
7355 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7356 13 return ret;
7357 }
7358
7359 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7360 {
7361 6 MOVMuxContext *mov = s->priv_data;
7362 6 MOVTrack *track = &mov->tracks[index];
7363 6 AVStream *src_st = mov->tracks[src_index].st;
7364 uint8_t data[4];
7365 6 AVPacket *pkt = mov->pkt;
7366 6 AVRational rate = src_st->avg_frame_rate;
7367 int ret;
7368
7369 /* tmcd track based on video stream */
7370 6 track->mode = mov->mode;
7371 6 track->tag = MKTAG('t','m','c','d');
7372 6 track->src_track = src_index;
7373 6 track->timescale = mov->tracks[src_index].timescale;
7374
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7375 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7376
7377 /* set st to src_st for metadata access*/
7378 6 track->st = src_st;
7379
7380 /* encode context: tmcd data stream */
7381 6 track->par = avcodec_parameters_alloc();
7382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7383 return AVERROR(ENOMEM);
7384 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7385 6 track->par->codec_tag = track->tag;
7386 6 track->st->avg_frame_rate = rate;
7387
7388 /* the tmcd track just contains one packet with the frame number */
7389 6 pkt->data = data;
7390 6 pkt->stream_index = index;
7391 6 pkt->flags = AV_PKT_FLAG_KEY;
7392 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
7393 6 pkt->size = 4;
7394 6 AV_WB32(pkt->data, tc.start);
7395 6 ret = ff_mov_write_packet(s, pkt);
7396 6 av_packet_unref(pkt);
7397 6 return ret;
7398 }
7399
7400 /*
7401 * st->disposition controls the "enabled" flag in the tkhd tag.
7402 * QuickTime will not play a track if it is not enabled. So make sure
7403 * that one track of each type (audio, video, subtitle) is enabled.
7404 *
7405 * Subtitles are special. For audio and video, setting "enabled" also
7406 * makes the track "default" (i.e. it is rendered when played). For
7407 * subtitles, an "enabled" subtitle is not rendered by default, but
7408 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7409 * empty!
7410 */
7411 209 static void enable_tracks(AVFormatContext *s)
7412 {
7413 209 MOVMuxContext *mov = s->priv_data;
7414 int i;
7415 int enabled[AVMEDIA_TYPE_NB];
7416 int first[AVMEDIA_TYPE_NB];
7417
7418
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 209 times.
1254 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7419 1045 enabled[i] = 0;
7420 1045 first[i] = -1;
7421 }
7422
7423
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (i = 0; i < mov->nb_streams; i++) {
7424 267 AVStream *st = mov->tracks[i].st;
7425
7426
1/2
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
267 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7427
3/4
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 265 times.
534 st->codecpar->codec_type >= AVMEDIA_TYPE_NB ||
7428 267 is_cover_image(st))
7429 2 continue;
7430
7431
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 14 times.
265 if (first[st->codecpar->codec_type] < 0)
7432 251 first[st->codecpar->codec_type] = i;
7433
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 236 times.
265 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7434 29 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7435 29 enabled[st->codecpar->codec_type]++;
7436 }
7437 }
7438
7439
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 209 times.
1254 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7440
2/2
✓ Branch 0 taken 627 times.
✓ Branch 1 taken 418 times.
1045 switch (i) {
7441 627 case AVMEDIA_TYPE_VIDEO:
7442 case AVMEDIA_TYPE_AUDIO:
7443 case AVMEDIA_TYPE_SUBTITLE:
7444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 627 times.
627 if (enabled[i] > 1)
7445 mov->per_stream_grouping = 1;
7446
4/4
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 224 times.
✓ Branch 3 taken 378 times.
627 if (!enabled[i] && first[i] >= 0)
7447 224 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7448 627 break;
7449 }
7450 }
7451 209 }
7452
7453 209 static void mov_free(AVFormatContext *s)
7454 {
7455 209 MOVMuxContext *mov = s->priv_data;
7456
7457
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (int i = 0; i < s->nb_streams; i++)
7458 288 s->streams[i]->priv_data = NULL;
7459
7460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!mov->tracks)
7461 return;
7462
7463
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->chapter_track) {
7464 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7465 }
7466
7467
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 209 times.
485 for (int i = 0; i < mov->nb_tracks; i++) {
7468 276 MOVTrack *const track = &mov->tracks[i];
7469
7470
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 274 times.
276 if (track->tag == MKTAG('r','t','p',' '))
7471 2 ff_mov_close_hinting(track);
7472
4/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 3 times.
274 else if (track->tag == MKTAG('t','m','c','d') && mov->nb_meta_tmcd)
7473 6 av_freep(&track->par);
7474 276 av_freep(&track->cluster);
7475 276 av_freep(&track->cluster_written);
7476 276 av_freep(&track->frag_info);
7477 276 av_packet_free(&track->cover_image);
7478
7479
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 271 times.
276 if (track->eac3_priv) {
7480 5 struct eac3_info *info = track->eac3_priv;
7481 5 av_packet_free(&info->pkt);
7482 5 av_freep(&track->eac3_priv);
7483 }
7484
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 133 times.
276 if (track->vos_len)
7485 143 av_freep(&track->vos_data);
7486
7487 276 ff_mov_cenc_free(&track->cenc);
7488 276 ffio_free_dyn_buf(&track->mdat_buf);
7489
7490 #if CONFIG_IAMFENC
7491 276 ffio_free_dyn_buf(&track->iamf_buf);
7492
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 271 times.
276 if (track->iamf)
7493 5 ff_iamf_uninit_context(track->iamf);
7494 276 av_freep(&track->iamf);
7495 #endif
7496
7497 276 avpriv_packet_list_free(&track->squashed_packet_queue);
7498 }
7499
7500 209 av_freep(&mov->tracks);
7501 209 ffio_free_dyn_buf(&mov->mdat_buf);
7502 }
7503
7504 static uint32_t rgb_to_yuv(uint32_t rgb)
7505 {
7506 uint8_t r, g, b;
7507 int y, cb, cr;
7508
7509 r = (rgb >> 16) & 0xFF;
7510 g = (rgb >> 8) & 0xFF;
7511 b = (rgb ) & 0xFF;
7512
7513 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7514 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7515 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7516
7517 return (y << 16) | (cr << 8) | cb;
7518 }
7519
7520 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7521 AVStream *st)
7522 {
7523 int i, width = 720, height = 480;
7524 int have_palette = 0, have_size = 0;
7525 uint32_t palette[16];
7526 char *cur = st->codecpar->extradata;
7527
7528 while (cur && *cur) {
7529 if (strncmp("palette:", cur, 8) == 0) {
7530 int i, count;
7531 count = sscanf(cur + 8,
7532 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7533 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7534 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7535 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7536 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7537 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7538 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7539 &palette[12], &palette[13], &palette[14], &palette[15]);
7540
7541 for (i = 0; i < count; i++) {
7542 palette[i] = rgb_to_yuv(palette[i]);
7543 }
7544 have_palette = 1;
7545 } else if (!strncmp("size:", cur, 5)) {
7546 sscanf(cur + 5, "%dx%d", &width, &height);
7547 have_size = 1;
7548 }
7549 if (have_palette && have_size)
7550 break;
7551 cur += strcspn(cur, "\n\r");
7552 cur += strspn(cur, "\n\r");
7553 }
7554 if (have_palette) {
7555 track->vos_data = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7556 if (!track->vos_data)
7557 return AVERROR(ENOMEM);
7558 for (i = 0; i < 16; i++) {
7559 AV_WB32(track->vos_data + i * 4, palette[i]);
7560 }
7561 memset(track->vos_data + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7562 track->vos_len = 16 * 4;
7563 }
7564 st->codecpar->width = width;
7565 st->codecpar->height = track->height = height;
7566
7567 return 0;
7568 }
7569
7570 #if CONFIG_IAMFENC
7571 209 static int mov_init_iamf_track(AVFormatContext *s)
7572 {
7573 209 MOVMuxContext *mov = s->priv_data;
7574 MOVTrack *track;
7575 IAMFContext *iamf;
7576 209 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
7577 209 int nb_audio_elements = 0, nb_mix_presentations = 0;
7578 int ret;
7579
7580
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209 times.
219 for (int i = 0; i < s->nb_stream_groups; i++) {
7581 10 const AVStreamGroup *stg = s->stream_groups[i];
7582
7583
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7584 5 nb_audio_elements++;
7585
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7586 5 nb_mix_presentations++;
7587 }
7588
7589
3/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 204 times.
✗ Branch 3 not taken.
209 if (!nb_audio_elements && !nb_mix_presentations)
7590 204 return 0;
7591
7592
3/6
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
5 if (nb_audio_elements < 1 || nb_audio_elements > 2 || nb_mix_presentations < 1) {
7593 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7594 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7595 return AVERROR(EINVAL);
7596 }
7597
7598 5 iamf = av_mallocz(sizeof(*iamf));
7599
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
7600 return AVERROR(ENOMEM);
7601
7602
7603
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7604 10 const AVStreamGroup *stg = s->stream_groups[i];
7605
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
7606 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7607
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7608 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
7609 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
7610 }
7611
7612 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
7613 5 break;
7614 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7615 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
7616 5 break;
7617 default:
7618 av_assert0(0);
7619 }
7620
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
7621 return ret;
7622 }
7623
7624 5 track = &mov->tracks[first_iamf_idx];
7625 5 track->iamf = iamf;
7626 5 track->first_iamf_idx = first_iamf_idx;
7627 5 track->last_iamf_idx = last_iamf_idx;
7628 5 track->tag = MKTAG('i','a','m','f');
7629
7630
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7631 10 AVStreamGroup *stg = s->stream_groups[i];
7632
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7633 5 continue;
7634
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
7635 25 stg->streams[j]->priv_data = track;
7636 }
7637
7638 5 ret = avio_open_dyn_buf(&track->iamf_buf);
7639
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7640 return ret;
7641
7642 5 return 0;
7643 }
7644 #endif
7645
7646 209 static int mov_init(AVFormatContext *s)
7647 {
7648 209 MOVMuxContext *mov = s->priv_data;
7649 209 int has_iamf = 0;
7650 int i, ret;
7651
7652 209 mov->fc = s;
7653 209 mov->pkt = ffformatcontext(s)->pkt;
7654
7655 /* Default mode == MP4 */
7656 209 mov->mode = MODE_MP4;
7657
7658 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7660
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7661
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 63 times.
209 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7662
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 62 times.
63 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7663
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7664
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 57 times.
61 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7666
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7667 #undef IS_MODE
7668
7669
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
209 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7670 17 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7671
7672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->mode == MODE_AVIF)
7673 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7674
7675 /* Set the FRAGMENT flag if any of the fragmentation methods are
7676 * enabled. */
7677
3/4
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 208 times.
✗ Branch 3 not taken.
209 if (mov->max_fragment_duration || mov->max_fragment_size ||
7678
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 179 times.
208 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7679 FF_MOV_FLAG_FRAG_KEYFRAME |
7680 FF_MOV_FLAG_FRAG_CUSTOM |
7681 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7682 30 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7683
7684 /* Set other implicit flags immediately */
7685
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
7686 1 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7687
7688
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (mov->mode == MODE_ISM)
7689 4 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
7690 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7691
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 198 times.
209 if (mov->flags & FF_MOV_FLAG_DASH)
7692 11 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7693 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
7694
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_CMAF)
7695 1 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7696 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7697
7698
4/4
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
✓ Branch 2 taken 29 times.
✓ Branch 3 taken 1 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV && s->flags & AVFMT_FLAG_AUTO_BSF) {
7699 29 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7700 29 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
7701 }
7702
7703
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
209 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX && mov->flags & FF_MOV_FLAG_SKIP_SIDX) {
7704 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
7705 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
7706 }
7707
7708
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7709 3 mov->reserved_moov_size = -1;
7710 }
7711
7712
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 7 times.
209 if (mov->use_editlist < 0) {
7713 202 mov->use_editlist = 1;
7714
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 175 times.
202 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7715
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 15 times.
27 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7716 // If we can avoid needing an edit list by shifting the
7717 // tracks, prefer that over (trying to) write edit lists
7718 // in fragmented output.
7719
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
7720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
7721 11 mov->use_editlist = 0;
7722 }
7723 }
7724
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7725
4/4
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 17 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 12 times.
30 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV) && mov->use_editlist)
7726 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7727
7728
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
✓ Branch 2 taken 16 times.
✓ Branch 3 taken 1 times.
209 if (!mov->use_editlist && s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO &&
7729
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
7730 10 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
7731
7732 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7733 * if the latter is set that's enough and omit_tfhd_offset doesn't
7734 * add anything extra on top of that. */
7735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
7736 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
7737 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
7738
7739
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->frag_interleave &&
7740 mov->flags & (FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF)) {
7741 av_log(s, AV_LOG_ERROR,
7742 "Sample interleaving in fragments is mutually exclusive with "
7743 "omit_tfhd_offset and separate_moof\n");
7744 return AVERROR(EINVAL);
7745 }
7746
7747 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
7748 * is enabled, we don't support non-seekable output at all. */
7749
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 181 times.
209 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
7750
2/4
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 28 times.
✗ Branch 3 not taken.
28 (!(mov->flags & FF_MOV_FLAG_FRAGMENT) || mov->ism_lookahead ||
7751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 mov->mode == MODE_AVIF)) {
7752 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
7753 return AVERROR(EINVAL);
7754 }
7755
7756 /* AVIF output must have at most two video streams (one for YUV and one for
7757 * alpha). */
7758
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->mode == MODE_AVIF) {
7759 if (s->nb_streams > 2) {
7760 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
7761 return AVERROR(EINVAL);
7762 }
7763 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
7764 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
7765 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
7766 return AVERROR(EINVAL);
7767 }
7768 if (s->nb_streams > 1) {
7769 const AVPixFmtDescriptor *pixdesc =
7770 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
7771 if (pixdesc->nb_components != 1) {
7772 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
7773 return AVERROR(EINVAL);
7774 }
7775 }
7776 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
7777 }
7778
7779 #if CONFIG_IAMFENC
7780
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209 times.
219 for (i = 0; i < s->nb_stream_groups; i++) {
7781 10 AVStreamGroup *stg = s->stream_groups[i];
7782
7783
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7784 5 continue;
7785
7786
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7787 25 AVStream *st = stg->streams[j];
7788
7789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
7790 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
7791 "IAMF Audio Element\n", j);
7792 return AVERROR(EINVAL);
7793 }
7794 25 st->priv_data = st;
7795 }
7796 5 has_iamf = 1;
7797
7798
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (!mov->nb_tracks) // We support one track for the entire IAMF structure
7799 5 mov->nb_tracks++;
7800 }
7801 #endif
7802
7803
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (i = 0; i < s->nb_streams; i++) {
7804 288 AVStream *st = s->streams[i];
7805
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 263 times.
288 if (st->priv_data)
7806 25 continue;
7807 // Don't produce a track in the output file for timed ID3 streams.
7808
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 262 times.
263 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7809 // Leave priv_data set to NULL for these AVStreams that don't
7810 // have a corresponding track.
7811 1 continue;
7812 }
7813 262 st->priv_data = st;
7814 262 mov->nb_tracks++;
7815 }
7816
7817 209 mov->nb_streams = mov->nb_tracks;
7818
7819
4/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 203 times.
209 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
7820 1 mov->chapter_track = mov->nb_tracks++;
7821
7822
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
7823
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
7824
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
7825 2 mov->nb_tracks++;
7826 }
7827
7828
1/2
✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
209 if (mov->write_btrt < 0) {
7829 209 mov->write_btrt = mov->mode == MODE_MP4;
7830 }
7831
7832
6/6
✓ Branch 0 taken 206 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 146 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 57 times.
209 if ( mov->write_tmcd == -1 && (mov->mode == MODE_MOV || mov->mode == MODE_MP4)
7833
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 || mov->write_tmcd == 1) {
7834 206 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
7835 NULL, 0);
7836
7837 /* +1 tmcd track for each video stream with a timecode */
7838
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 206 times.
489 for (i = 0; i < s->nb_streams; i++) {
7839 283 AVStream *st = s->streams[i];
7840 283 AVDictionaryEntry *t = global_tcr;
7841
4/4
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 105 times.
✓ Branch 2 taken 171 times.
✓ Branch 3 taken 7 times.
283 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO &&
7842
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 171 times.
171 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
7843 AVTimecode tc;
7844 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
7845
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
7846 7 mov->nb_meta_tmcd++;
7847 }
7848 }
7849
7850 /* check if there is already a tmcd track to remux */
7851
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 199 times.
206 if (mov->nb_meta_tmcd) {
7852
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
7853 13 AVStream *st = s->streams[i];
7854
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
7855 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
7856 "so timecode metadata are now ignored\n");
7857 3 mov->nb_meta_tmcd = 0;
7858 }
7859 }
7860 }
7861
7862 206 mov->nb_tracks += mov->nb_meta_tmcd;
7863 }
7864
7865 // Reserve an extra stream for chapters for the case where chapters
7866 // are written in the trailer
7867 209 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
7868
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!mov->tracks)
7869 return AVERROR(ENOMEM);
7870
7871
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
209 if (mov->encryption_scheme_str != NULL && strcmp(mov->encryption_scheme_str, "none") != 0) {
7872 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
7873 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
7874
7875 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
7876 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
7877 mov->encryption_key_len, AES_CTR_KEY_SIZE);
7878 return AVERROR(EINVAL);
7879 }
7880
7881 if (mov->encryption_kid_len != CENC_KID_SIZE) {
7882 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
7883 mov->encryption_kid_len, CENC_KID_SIZE);
7884 return AVERROR(EINVAL);
7885 }
7886 } else {
7887 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
7888 mov->encryption_scheme_str);
7889 return AVERROR(EINVAL);
7890 }
7891 }
7892
7893 #if CONFIG_IAMFENC
7894 209 ret = mov_init_iamf_track(s);
7895
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (ret < 0)
7896 return ret;
7897 #endif
7898
7899
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (int j = 0, i = 0; j < s->nb_streams; j++) {
7900 288 AVStream *st = s->streams[j];
7901
7902
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 262 times.
288 if (st != st->priv_data) {
7903
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
7904 5 i += has_iamf--;
7905 26 continue;
7906 }
7907 262 st->priv_data = &mov->tracks[i++];
7908 }
7909
7910
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (i = 0; i < s->nb_streams; i++) {
7911 288 AVStream *st= s->streams[i];
7912 288 MOVTrack *track = st->priv_data;
7913 288 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
7914
7915
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 287 times.
288 if (!track)
7916 1 continue;
7917
7918
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 20 times.
287 if (!track->st) {
7919 267 track->st = st;
7920 267 track->par = st->codecpar;
7921 }
7922
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 263 times.
287 track->language = ff_mov_iso639_to_lang(lang?lang->value:"und", mov->mode!=MODE_MOV);
7923
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 132 times.
287 if (track->language < 0)
7924 155 track->language = 32767; // Unspecified Macintosh language code
7925 287 track->mode = mov->mode;
7926
2/2
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 25 times.
287 if (!track->tag)
7927 262 track->tag = mov_find_codec_tag(s, track);
7928
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (!track->tag) {
7929 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
7930 "codec not currently supported in container\n",
7931 avcodec_get_name(st->codecpar->codec_id), i);
7932 return AVERROR(EINVAL);
7933 }
7934 /* If hinting of this track is enabled by a later hint track,
7935 * this is updated. */
7936 287 track->hint_track = -1;
7937 287 track->start_dts = AV_NOPTS_VALUE;
7938 287 track->start_cts = AV_NOPTS_VALUE;
7939 287 track->end_pts = AV_NOPTS_VALUE;
7940 287 track->dts_shift = AV_NOPTS_VALUE;
7941
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 107 times.
287 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
7942
2/4
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✗ Branch 3 not taken.
180 if (track->tag == MKTAG('m','x','3','p') || track->tag == MKTAG('m','x','3','n') ||
7943
2/4
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 180 times.
✗ Branch 3 not taken.
180 track->tag == MKTAG('m','x','4','p') || track->tag == MKTAG('m','x','4','n') ||
7944
2/4
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 180 times.
180 track->tag == MKTAG('m','x','5','p') || track->tag == MKTAG('m','x','5','n')) {
7945 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
7946 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
7947 return AVERROR(EINVAL);
7948 }
7949 track->height = track->tag >> 24 == 'n' ? 486 : 576;
7950 }
7951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 if (mov->video_track_timescale) {
7952 track->timescale = mov->video_track_timescale;
7953 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
7954 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
7955 } else {
7956 180 track->timescale = st->time_base.den;
7957
2/2
✓ Branch 0 taken 1467 times.
✓ Branch 1 taken 180 times.
1647 while(track->timescale < 10000)
7958 1467 track->timescale *= 2;
7959 }
7960
2/4
✓ Branch 0 taken 180 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 180 times.
180 if (st->codecpar->width > 65535 || st->codecpar->height > 65535) {
7961 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
7962 return AVERROR(EINVAL);
7963 }
7964
4/4
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 128 times.
180 if (track->mode == MODE_MOV && track->timescale > 100000)
7965 2 av_log(s, AV_LOG_WARNING,
7966 "WARNING codec timebase is very high. If duration is too long,\n"
7967 "file may not be playable by quicktime. Specify a shorter timebase\n"
7968 "or choose different container.\n");
7969
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 50 times.
180 if (track->mode == MODE_MOV &&
7970
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 113 times.
130 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7971
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
7972 1 enum AVPixelFormat pix_fmt = track->par->format;
7973
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (pix_fmt == AV_PIX_FMT_NONE && track->par->bits_per_coded_sample == 1)
7974 pix_fmt = AV_PIX_FMT_MONOWHITE;
7975 1 track->is_unaligned_qt_rgb =
7976 pix_fmt == AV_PIX_FMT_RGB24 ||
7977 pix_fmt == AV_PIX_FMT_BGR24 ||
7978 pix_fmt == AV_PIX_FMT_PAL8 ||
7979 pix_fmt == AV_PIX_FMT_GRAY8 ||
7980
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 pix_fmt == AV_PIX_FMT_MONOWHITE ||
7981 pix_fmt == AV_PIX_FMT_MONOBLACK;
7982 }
7983
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
180 if (track->par->codec_id == AV_CODEC_ID_VP9 && track->mode != MODE_MP4) {
7984 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
7985 return AVERROR(EINVAL);
7986
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 179 times.
180 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
7987
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) {
7988 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
7989 return AVERROR(EINVAL);
7990
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
7991 /* altref frames handling is not defined in the spec as of version v1.0,
7992 * so just forbid muxing VP8 streams altogether until a new version does */
7993 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
7994 return AVERROR_PATCHWELCOME;
7995 }
7996
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 178 times.
180 if (is_cover_image(st)) {
7997 2 track->cover_image = av_packet_alloc();
7998
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
7999 return AVERROR(ENOMEM);
8000 }
8001
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 7 times.
107 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8002 100 track->timescale = st->codecpar->sample_rate;
8003
4/4
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 69 times.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 25 times.
100 if (!st->codecpar->frame_size && !av_get_bits_per_sample(st->codecpar->codec_id)) {
8004 6 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8005 6 track->audio_vbr = 1;
8006
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8007
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8008
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8009 if (!st->codecpar->block_align) {
8010 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8011 return AVERROR(EINVAL);
8012 }
8013 track->sample_size = st->codecpar->block_align;
8014
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 25 times.
94 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8015 69 track->audio_vbr = 1;
8016 }else{
8017 25 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8018 25 st->codecpar->ch_layout.nb_channels;
8019 }
8020
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8021
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8022 track->audio_vbr = 1;
8023 }
8024
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 32 times.
100 if (track->mode != MODE_MOV &&
8025
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 68 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
68 track->par->codec_id == AV_CODEC_ID_MP3 && track->timescale < 16000) {
8026 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8027 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8028 i, track->par->sample_rate);
8029 return AVERROR(EINVAL);
8030 } else {
8031 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8032 i, track->par->sample_rate);
8033 }
8034 }
8035
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 25 times.
100 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8036
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8037
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
75 track->par->codec_id == AV_CODEC_ID_OPUS) {
8038
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8039 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8040 return AVERROR(EINVAL);
8041 }
8042
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8043 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8044 av_log(s, AV_LOG_ERROR,
8045 "%s in MP4 support is experimental, add "
8046 "'-strict %d' if you want to use it.\n",
8047 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8048 return AVERROR_EXPERIMENTAL;
8049 }
8050 }
8051
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8052 3 track->timescale = st->time_base.den;
8053
8054
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8055 /* 14496-30 requires us to use a single sample per fragment
8056 for TTML, for which we define a per-track flag.
8057
8058 We set the flag in case we are receiving TTML paragraphs
8059 from the input, in other words in case we are not doing
8060 stream copy. */
8061 2 track->squash_fragment_samples_to_one =
8062 2 ff_is_ttml_stream_paragraph_based(track->par);
8063
8064
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8065 track->squash_fragment_samples_to_one) {
8066 av_log(s, AV_LOG_ERROR,
8067 "Fragmentation is not currently supported for "
8068 "TTML in MP4/ISMV (track synchronization between "
8069 "subtitles and other media is not yet implemented)!\n");
8070 return AVERROR_PATCHWELCOME;
8071 }
8072
8073
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->mode != MODE_ISM &&
8074
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8075
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8076 av_log(s, AV_LOG_ERROR,
8077 "ISMV style TTML support with the 'dfxp' tag in "
8078 "non-ISMV formats is not officially supported. Add "
8079 "'-strict unofficial' if you want to use it.\n");
8080 return AVERROR_EXPERIMENTAL;
8081 }
8082 }
8083
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8084 4 track->timescale = st->time_base.den;
8085 } else {
8086 track->timescale = mov->movie_timescale;
8087 }
8088
1/2
✓ Branch 0 taken 287 times.
✗ Branch 1 not taken.
287 if (!track->height)
8089 287 track->height = st->codecpar->height;
8090 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8091 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8092 for video tracks, so if user-set, it isn't overwritten */
8093
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 282 times.
287 if (mov->mode == MODE_ISM &&
8094
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8095
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))) {
8096 5 track->timescale = 10000000;
8097 }
8098
8099 287 avpriv_set_pts_info(st, 64, 1, track->timescale);
8100
8101
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8102 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8103 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8104 track->par->codec_id == AV_CODEC_ID_VVC),
8105 s->flags & AVFMT_FLAG_BITEXACT);
8106 if (ret)
8107 return ret;
8108 }
8109 }
8110
8111 209 enable_tracks(s);
8112 209 return 0;
8113 }
8114
8115 209 static int mov_write_header(AVFormatContext *s)
8116 {
8117 209 AVIOContext *pb = s->pb;
8118 209 MOVMuxContext *mov = s->priv_data;
8119 209 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8120
8121
4/4
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 203 times.
209 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters)
8122 1 nb_tracks++;
8123
8124
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8125 1 hint_track = nb_tracks;
8126
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8127
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8128 2 nb_tracks++;
8129 }
8130 }
8131
8132
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203 times.
209 if (mov->nb_meta_tmcd)
8133 6 tmcd_track = nb_tracks;
8134
8135
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (int i = 0; i < mov->nb_streams; i++) {
8136 267 MOVTrack *track = &mov->tracks[i];
8137 267 AVStream *st = track->st;
8138
8139 /* copy extradata if it exists */
8140
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 150 times.
267 if (st->codecpar->extradata_size) {
8141
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8142 mov_create_dvd_sub_decoder_specific_info(track, st);
8143
15/30
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 117 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 117 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 117 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 117 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 117 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 117 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 117 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 117 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 117 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 117 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 117 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 117 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 117 times.
✗ Branch 29 not taken.
117 else if (!TAG_IS_AVCI(track->tag) && st->codecpar->codec_id != AV_CODEC_ID_DNXHD) {
8144 117 track->vos_len = st->codecpar->extradata_size;
8145 117 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8146
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (!track->vos_data) {
8147 return AVERROR(ENOMEM);
8148 }
8149 117 memcpy(track->vos_data, st->codecpar->extradata, track->vos_len);
8150 117 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8151 }
8152 }
8153
8154
4/4
✓ Branch 0 taken 80 times.
✓ Branch 1 taken 187 times.
✓ Branch 2 taken 66 times.
✓ Branch 3 taken 14 times.
347 if (st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8155 80 av_channel_layout_compare(&track->par->ch_layout,
8156 80 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8157 253 continue;
8158
8159
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 14 times.
47 for (int j = 0; j < mov->nb_streams; j++) {
8160 33 AVStream *stj= mov->tracks[j].st;
8161 33 MOVTrack *trackj= &mov->tracks[j];
8162
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
33 if (j == i)
8163 14 continue;
8164
8165
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8166
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 ||
8167 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8168 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8169 )
8170 4 track->mono_as_fc = -1;
8171
8172
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
30 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8173 11 av_channel_layout_compare(&trackj->par->ch_layout,
8174 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8175
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
8176 )
8177 7 track->mono_as_fc++;
8178
8179
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
30 if (stj->codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
8180 11 av_channel_layout_compare(&trackj->par->ch_layout,
8181 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8182 trackj->language != track->language ||
8183 trackj->tag != track->tag
8184 )
8185 19 continue;
8186 track->multichannel_as_mono++;
8187 }
8188 }
8189
8190
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 17 times.
209 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8191
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
192 if ((ret = mov_write_identification(pb, s)) < 0)
8192 return ret;
8193 }
8194
8195
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->reserved_moov_size){
8196 3 mov->reserved_header_pos = avio_tell(pb);
8197
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8198 avio_skip(pb, mov->reserved_moov_size);
8199 }
8200
8201
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 175 times.
209 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8202 /* If no fragmentation options have been set, set a default. */
8203
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 30 times.
34 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8204 FF_MOV_FLAG_FRAG_CUSTOM |
8205 4 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8206
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
4 !mov->max_fragment_duration && !mov->max_fragment_size)
8207 4 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8208
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
34 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8209 1 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8210
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8211 1 mov->mdat_pos = avio_tell(pb);
8212 }
8213
1/2
✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
175 } else if (mov->mode != MODE_AVIF) {
8214
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 172 times.
175 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8215 3 mov->reserved_header_pos = avio_tell(pb);
8216 175 mov_write_mdat_tag(pb, mov);
8217 }
8218
8219 209 ff_parse_creation_time_metadata(s, &mov->time, 1);
8220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->time)
8221 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8222
8223
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->chapter_track)
8224
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8225 return ret;
8226
8227
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8228
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8229
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8230
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8231 return ret;
8232 2 hint_track++;
8233 }
8234 }
8235 }
8236
8237
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203 times.
209 if (mov->nb_meta_tmcd) {
8238 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8239 "timecode", NULL, 0);
8240 /* Initialize the tmcd tracks */
8241
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8242 8 AVStream *st = mov->tracks[i].st;
8243 8 t = global_tcr;
8244
8245
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8246 AVTimecode tc;
8247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8248 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8249
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8250 continue;
8251
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8252 continue;
8253
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8254 return ret;
8255 6 tmcd_track++;
8256 }
8257 }
8258 }
8259
8260 209 avio_flush(pb);
8261
8262
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_ISML)
8263 mov_write_isml_manifest(pb, mov, s);
8264
8265
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8266
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 17 times.
30 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8267
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8268 return ret;
8269 13 mov->moov_written = 1;
8270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8271 mov->reserved_header_pos = avio_tell(pb);
8272 }
8273
8274 209 return 0;
8275 }
8276
8277 27 static int get_moov_size(AVFormatContext *s)
8278 {
8279 int ret;
8280 AVIOContext *moov_buf;
8281 27 MOVMuxContext *mov = s->priv_data;
8282
8283
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
8284 return ret;
8285
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
8286 return ret;
8287 27 return ffio_close_null_buf(moov_buf);
8288 }
8289
8290 static int get_sidx_size(AVFormatContext *s)
8291 {
8292 int ret;
8293 AVIOContext *buf;
8294 MOVMuxContext *mov = s->priv_data;
8295
8296 if ((ret = ffio_open_null_buf(&buf)) < 0)
8297 return ret;
8298 mov_write_sidx_tags(buf, mov, -1, 0);
8299 return ffio_close_null_buf(buf);
8300 }
8301
8302 /*
8303 * This function gets the moov size if moved to the top of the file: the chunk
8304 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8305 * entries) when the moov is moved to the beginning, so the size of the moov
8306 * would change. It also updates the chunk offset tables.
8307 */
8308 3 static int compute_moov_size(AVFormatContext *s)
8309 {
8310 int i, moov_size, moov_size2;
8311 3 MOVMuxContext *mov = s->priv_data;
8312
8313 3 moov_size = get_moov_size(s);
8314
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8315 return moov_size;
8316
8317
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
8318 8 mov->tracks[i].data_offset += moov_size;
8319
8320 3 moov_size2 = get_moov_size(s);
8321
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
8322 return moov_size2;
8323
8324 /* if the size changed, we just switched from stco to co64 and need to
8325 * update the offsets */
8326
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
8327 for (i = 0; i < mov->nb_tracks; i++)
8328 mov->tracks[i].data_offset += moov_size2 - moov_size;
8329
8330 3 return moov_size2;
8331 }
8332
8333 static int compute_sidx_size(AVFormatContext *s)
8334 {
8335 int i, sidx_size;
8336 MOVMuxContext *mov = s->priv_data;
8337
8338 sidx_size = get_sidx_size(s);
8339 if (sidx_size < 0)
8340 return sidx_size;
8341
8342 for (i = 0; i < mov->nb_tracks; i++)
8343 mov->tracks[i].data_offset += sidx_size;
8344
8345 return sidx_size;
8346 }
8347
8348 3 static int shift_data(AVFormatContext *s)
8349 {
8350 int moov_size;
8351 3 MOVMuxContext *mov = s->priv_data;
8352
8353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
8354 moov_size = compute_sidx_size(s);
8355 else
8356 3 moov_size = compute_moov_size(s);
8357
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8358 return moov_size;
8359
8360 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
8361 }
8362
8363 209 static int mov_write_trailer(AVFormatContext *s)
8364 {
8365 209 MOVMuxContext *mov = s->priv_data;
8366 209 AVIOContext *pb = s->pb;
8367 209 int res = 0;
8368 int i;
8369 int64_t moov_pos;
8370
8371
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 204 times.
209 if (mov->need_rewrite_extradata) {
8372
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
12 for (i = 0; i < mov->nb_streams; i++) {
8373 7 MOVTrack *track = &mov->tracks[i];
8374 7 AVCodecParameters *par = track->par;
8375
8376 7 track->vos_len = par->extradata_size;
8377 7 av_freep(&track->vos_data);
8378 7 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8379
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!track->vos_data)
8380 return AVERROR(ENOMEM);
8381 7 memcpy(track->vos_data, par->extradata, track->vos_len);
8382 7 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8383 }
8384 5 mov->need_rewrite_extradata = 0;
8385 }
8386
8387 /*
8388 * Before actually writing the trailer, make sure that there are no
8389 * dangling subtitles, that need a terminating sample.
8390 */
8391
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 209 times.
485 for (i = 0; i < mov->nb_tracks; i++) {
8392 276 MOVTrack *trk = &mov->tracks[i];
8393
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 275 times.
276 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
8394
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
8395 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
8396 1 trk->last_sample_is_subtitle_end = 1;
8397 }
8398 }
8399
8400 // Check if we have any tracks that require squashing.
8401 // In that case, we'll have to write the packet here.
8402
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 209 times.
209 if ((res = mov_write_squashed_packets(s)) < 0)
8403 return res;
8404
8405 // If there were no chapters when the header was written, but there
8406 // are chapters now, write them in the trailer. This only works
8407 // when we are not doing fragments.
8408
4/4
✓ Branch 0 taken 208 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 174 times.
✓ Branch 3 taken 34 times.
209 if (!mov->chapter_track && !(mov->flags & FF_MOV_FLAG_FRAGMENT)) {
8409
3/4
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 173 times.
174 if (mov->mode & (MODE_MP4|MODE_MOV|MODE_IPOD) && s->nb_chapters) {
8410 mov->chapter_track = mov->nb_tracks++;
8411 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8412 return res;
8413 }
8414 }
8415
8416
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 175 times.
209 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
8417
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
34 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8418
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 175 times.
176 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8419 1 mov_flush_fragment(s, 1);
8420 1 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
8421
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
8422 2 MOVTrack *track = &mov->tracks[i];
8423 2 track->data_offset = 0;
8424 2 av_free(track->cluster);
8425 2 track->cluster = track->cluster_written;
8426 2 track->entry = track->entry_written;
8427 2 track->cluster_written = NULL;
8428 2 track->entry_written = 0;
8429 2 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
8430 }
8431 // Clear the empty_moov flag, as we do want the moov to include
8432 // all the samples at this point.
8433 1 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
8434 }
8435
8436 176 moov_pos = avio_tell(pb);
8437
8438 /* Write size of mdat tag */
8439
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 if (mov->mdat_size + 8 <= UINT32_MAX) {
8440 176 avio_seek(pb, mov->mdat_pos, SEEK_SET);
8441 176 avio_wb32(pb, mov->mdat_size + 8);
8442
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 175 times.
176 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8443 1 ffio_wfourcc(pb, "mdat"); // overwrite the original moov into a mdat
8444 } else {
8445 /* overwrite 'wide' placeholder atom */
8446 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
8447 /* special value: real atom size will be 64 bit value after
8448 * tag field */
8449 avio_wb32(pb, 1);
8450 ffio_wfourcc(pb, "mdat");
8451 avio_wb64(pb, mov->mdat_size + 16);
8452 }
8453
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 176 times.
176 avio_seek(pb, mov->reserved_moov_size > 0 ? mov->reserved_header_pos : moov_pos, SEEK_SET);
8454
8455
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 173 times.
176 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8456 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
8457 3 res = shift_data(s);
8458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
8459 return res;
8460 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8461
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8462 return res;
8463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 } else if (mov->reserved_moov_size > 0) {
8464 int64_t size;
8465 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8466 return res;
8467 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
8468 if (size < 8){
8469 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
8470 return AVERROR(EINVAL);
8471 }
8472 avio_wb32(pb, size);
8473 ffio_wfourcc(pb, "free");
8474 ffio_fill(pb, 0, size - 8);
8475 avio_seek(pb, moov_pos, SEEK_SET);
8476 } else {
8477
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
173 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8478 return res;
8479 }
8480 176 res = 0;
8481 } else {
8482 33 mov_auto_flush_fragment(s, 1);
8483
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++)
8484 63 mov->tracks[i].data_offset = 0;
8485
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8486 int64_t end;
8487 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8488 res = shift_data(s);
8489 if (res < 0)
8490 return res;
8491 end = avio_tell(pb);
8492 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8493 mov_write_sidx_tags(pb, mov, -1, 0);
8494 avio_seek(pb, end, SEEK_SET);
8495 }
8496
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8497 33 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8498 33 res = mov_write_mfra_tag(pb, mov);
8499
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (res < 0)
8500 return res;
8501 }
8502 }
8503
8504 209 return res;
8505 }
8506
8507 232 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8508 const AVPacket *pkt)
8509 {
8510 232 int ret = 1;
8511
8512
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 223 times.
232 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8513
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)
8514 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8515
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
223 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8516 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8517 }
8518
8519 232 return ret;
8520 }
8521
8522 #if CONFIG_AVIF_MUXER
8523 static int avif_write_trailer(AVFormatContext *s)
8524 {
8525 AVIOContext *pb = s->pb;
8526 MOVMuxContext *mov = s->priv_data;
8527 int64_t pos_backup, extent_offsets[2];
8528 uint8_t *buf;
8529 int buf_size, moov_size;
8530
8531 if (mov->moov_written) return 0;
8532
8533 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8534 if (mov->is_animated_avif && mov->nb_streams > 1) {
8535 // For animated avif with alpha channel, we need to write a tref tag
8536 // with type "auxl".
8537 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8538 mov->tracks[1].tref_id = 1;
8539 }
8540 mov_write_identification(pb, s);
8541 mov_write_meta_tag(pb, mov, s);
8542
8543 moov_size = get_moov_size(s);
8544 for (int i = 0; i < mov->nb_tracks; i++)
8545 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8546
8547 if (mov->is_animated_avif) {
8548 int ret;
8549 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8550 return ret;
8551 }
8552
8553 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8554 avio_wb32(pb, buf_size + 8);
8555 ffio_wfourcc(pb, "mdat");
8556
8557 // The offset for the YUV planes is the starting position of mdat.
8558 extent_offsets[0] = avio_tell(pb);
8559 // The offset for alpha plane is YUV offset + YUV size.
8560 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8561
8562 avio_write(pb, buf, buf_size);
8563
8564 // write extent offsets.
8565 pos_backup = avio_tell(pb);
8566 for (int i = 0; i < mov->nb_streams; i++) {
8567 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8568 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8569 return AVERROR_INVALIDDATA;
8570 }
8571 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8572 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8573 }
8574 avio_seek(pb, pos_backup, SEEK_SET);
8575
8576 return 0;
8577 }
8578 #endif
8579
8580 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8581 static const AVCodecTag codec_3gp_tags[] = {
8582 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8583 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8584 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8585 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8586 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8587 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8588 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8589 { AV_CODEC_ID_NONE, 0 },
8590 };
8591 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8592 #endif
8593
8594 static const AVCodecTag codec_mp4_tags[] = {
8595 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8596 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8597 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8598 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8599 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8600 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8601 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8602 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8603 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8604 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8605 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8606 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8607 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8608 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8609 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8610 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8611 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8612 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8613 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8614 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8615 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8616 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
8617 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
8618 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
8619 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
8620 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
8621 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
8622 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
8623 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
8624 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
8625 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
8626 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
8627 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
8628 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
8629 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
8630 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
8631 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
8632 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
8633 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
8634 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
8635
8636 /* ISO/IEC 23003-5 integer formats */
8637 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
8638 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
8639 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
8640 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
8641 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
8642 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
8643 /* ISO/IEC 23003-5 floating-point formats */
8644 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
8645 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
8646 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
8647 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
8648
8649 { AV_CODEC_ID_NONE, 0 },
8650 };
8651 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8652 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
8653 #endif
8654
8655 static const AVCodecTag codec_ism_tags[] = {
8656 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
8657 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
8658 { AV_CODEC_ID_NONE , 0 },
8659 };
8660
8661 static const AVCodecTag codec_ipod_tags[] = {
8662 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8663 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8664 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8665 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
8666 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
8667 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8668 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
8669 { AV_CODEC_ID_NONE, 0 },
8670 };
8671
8672 static const AVCodecTag codec_f4v_tags[] = {
8673 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
8674 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8675 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8676 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
8677 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
8678 { AV_CODEC_ID_NONE, 0 },
8679 };
8680
8681 #if CONFIG_AVIF_MUXER
8682
8683 static const AVOption avif_options[] = {
8684 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
8685 { "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 },
8686 { NULL },
8687 };
8688 static const AVCodecTag codec_avif_tags[] = {
8689 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
8690 { AV_CODEC_ID_NONE, 0 },
8691 };
8692 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
8693
8694 static const AVClass mov_avif_muxer_class = {
8695 .class_name = "avif muxer",
8696 .item_name = av_default_item_name,
8697 .option = avif_options,
8698 .version = LIBAVUTIL_VERSION_INT,
8699 };
8700 #endif
8701
8702 #if CONFIG_MOV_MUXER
8703 const FFOutputFormat ff_mov_muxer = {
8704 .p.name = "mov",
8705 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8706 .p.extensions = "mov",
8707 .priv_data_size = sizeof(MOVMuxContext),
8708 .p.audio_codec = AV_CODEC_ID_AAC,
8709 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8710 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8711 .init = mov_init,
8712 .write_header = mov_write_header,
8713 .write_packet = mov_write_packet,
8714 .write_trailer = mov_write_trailer,
8715 .deinit = mov_free,
8716 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS
8717 #if FF_API_ALLOW_FLUSH
8718 | AVFMT_ALLOW_FLUSH
8719 #endif
8720 ,
8721 .p.codec_tag = (const AVCodecTag* const []){
8722 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
8723 },
8724 .check_bitstream = mov_check_bitstream,
8725 .p.priv_class = &mov_isobmff_muxer_class,
8726 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8727 };
8728 #endif
8729 #if CONFIG_TGP_MUXER
8730 const FFOutputFormat ff_tgp_muxer = {
8731 .p.name = "3gp",
8732 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
8733 .p.extensions = "3gp",
8734 .priv_data_size = sizeof(MOVMuxContext),
8735 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8736 .p.video_codec = AV_CODEC_ID_H263,
8737 .init = mov_init,
8738 .write_header = mov_write_header,
8739 .write_packet = mov_write_packet,
8740 .write_trailer = mov_write_trailer,
8741 .deinit = mov_free,
8742 #if FF_API_ALLOW_FLUSH
8743 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8744 #else
8745 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8746 #endif
8747 .p.codec_tag = codec_3gp_tags_list,
8748 .check_bitstream = mov_check_bitstream,
8749 .p.priv_class = &mov_isobmff_muxer_class,
8750 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8751 };
8752 #endif
8753 #if CONFIG_MP4_MUXER
8754 const FFOutputFormat ff_mp4_muxer = {
8755 .p.name = "mp4",
8756 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
8757 .p.mime_type = "video/mp4",
8758 .p.extensions = "mp4",
8759 .priv_data_size = sizeof(MOVMuxContext),
8760 .p.audio_codec = AV_CODEC_ID_AAC,
8761 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8762 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8763 .init = mov_init,
8764 .write_header = mov_write_header,
8765 .write_packet = mov_write_packet,
8766 .write_trailer = mov_write_trailer,
8767 .deinit = mov_free,
8768 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS
8769 #if FF_API_ALLOW_FLUSH
8770 | AVFMT_ALLOW_FLUSH
8771 #endif
8772 ,
8773 .p.codec_tag = mp4_codec_tags_list,
8774 .check_bitstream = mov_check_bitstream,
8775 .p.priv_class = &mov_isobmff_muxer_class,
8776 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8777 };
8778 #endif
8779 #if CONFIG_PSP_MUXER
8780 const FFOutputFormat ff_psp_muxer = {
8781 .p.name = "psp",
8782 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
8783 .p.extensions = "mp4,psp",
8784 .priv_data_size = sizeof(MOVMuxContext),
8785 .p.audio_codec = AV_CODEC_ID_AAC,
8786 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8787 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8788 .init = mov_init,
8789 .write_header = mov_write_header,
8790 .write_packet = mov_write_packet,
8791 .write_trailer = mov_write_trailer,
8792 .deinit = mov_free,
8793 #if FF_API_ALLOW_FLUSH
8794 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8795 #else
8796 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8797 #endif
8798 .p.codec_tag = mp4_codec_tags_list,
8799 .check_bitstream = mov_check_bitstream,
8800 .p.priv_class = &mov_isobmff_muxer_class,
8801 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8802 };
8803 #endif
8804 #if CONFIG_TG2_MUXER
8805 const FFOutputFormat ff_tg2_muxer = {
8806 .p.name = "3g2",
8807 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
8808 .p.extensions = "3g2",
8809 .priv_data_size = sizeof(MOVMuxContext),
8810 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8811 .p.video_codec = AV_CODEC_ID_H263,
8812 .init = mov_init,
8813 .write_header = mov_write_header,
8814 .write_packet = mov_write_packet,
8815 .write_trailer = mov_write_trailer,
8816 .deinit = mov_free,
8817 #if FF_API_ALLOW_FLUSH
8818 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8819 #else
8820 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8821 #endif
8822 .p.codec_tag = codec_3gp_tags_list,
8823 .check_bitstream = mov_check_bitstream,
8824 .p.priv_class = &mov_isobmff_muxer_class,
8825 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8826 };
8827 #endif
8828 #if CONFIG_IPOD_MUXER
8829 const FFOutputFormat ff_ipod_muxer = {
8830 .p.name = "ipod",
8831 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
8832 .p.mime_type = "video/mp4",
8833 .p.extensions = "m4v,m4a,m4b",
8834 .priv_data_size = sizeof(MOVMuxContext),
8835 .p.audio_codec = AV_CODEC_ID_AAC,
8836 .p.video_codec = AV_CODEC_ID_H264,
8837 .init = mov_init,
8838 .write_header = mov_write_header,
8839 .write_packet = mov_write_packet,
8840 .write_trailer = mov_write_trailer,
8841 .deinit = mov_free,
8842 #if FF_API_ALLOW_FLUSH
8843 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8844 #else
8845 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8846 #endif
8847 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
8848 .check_bitstream = mov_check_bitstream,
8849 .p.priv_class = &mov_isobmff_muxer_class,
8850 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8851 };
8852 #endif
8853 #if CONFIG_ISMV_MUXER
8854 const FFOutputFormat ff_ismv_muxer = {
8855 .p.name = "ismv",
8856 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
8857 .p.mime_type = "video/mp4",
8858 .p.extensions = "ismv,isma",
8859 .priv_data_size = sizeof(MOVMuxContext),
8860 .p.audio_codec = AV_CODEC_ID_AAC,
8861 .p.video_codec = AV_CODEC_ID_H264,
8862 .init = mov_init,
8863 .write_header = mov_write_header,
8864 .write_packet = mov_write_packet,
8865 .write_trailer = mov_write_trailer,
8866 .deinit = mov_free,
8867 #if FF_API_ALLOW_FLUSH
8868 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8869 #else
8870 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8871 #endif
8872 .p.codec_tag = (const AVCodecTag* const []){
8873 codec_mp4_tags, codec_ism_tags, 0 },
8874 .check_bitstream = mov_check_bitstream,
8875 .p.priv_class = &mov_isobmff_muxer_class,
8876 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8877 };
8878 #endif
8879 #if CONFIG_F4V_MUXER
8880 const FFOutputFormat ff_f4v_muxer = {
8881 .p.name = "f4v",
8882 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
8883 .p.mime_type = "application/f4v",
8884 .p.extensions = "f4v",
8885 .priv_data_size = sizeof(MOVMuxContext),
8886 .p.audio_codec = AV_CODEC_ID_AAC,
8887 .p.video_codec = AV_CODEC_ID_H264,
8888 .init = mov_init,
8889 .write_header = mov_write_header,
8890 .write_packet = mov_write_packet,
8891 .write_trailer = mov_write_trailer,
8892 .deinit = mov_free,
8893 #if FF_API_ALLOW_FLUSH
8894 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
8895 #else
8896 .p.flags = AVFMT_GLOBALHEADER,
8897 #endif
8898 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
8899 .check_bitstream = mov_check_bitstream,
8900 .p.priv_class = &mov_isobmff_muxer_class,
8901 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8902 };
8903 #endif
8904 #if CONFIG_AVIF_MUXER
8905 const FFOutputFormat ff_avif_muxer = {
8906 .p.name = "avif",
8907 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
8908 .p.mime_type = "image/avif",
8909 .p.extensions = "avif",
8910 .priv_data_size = sizeof(MOVMuxContext),
8911 .p.video_codec = AV_CODEC_ID_AV1,
8912 .init = mov_init,
8913 .write_header = mov_write_header,
8914 .write_packet = mov_write_packet,
8915 .write_trailer = avif_write_trailer,
8916 .deinit = mov_free,
8917 #if FF_API_ALLOW_FLUSH
8918 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
8919 #else
8920 .p.flags = AVFMT_GLOBALHEADER,
8921 #endif
8922 .p.codec_tag = codec_avif_tags_list,
8923 .p.priv_class = &mov_avif_muxer_class,
8924 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8925 };
8926 #endif
8927