FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2025-04-25 22:50:00
Exec Total Coverage
Lines: 3594 5396 66.6%
Functions: 172 226 76.1%
Branches: 2110 3705 57.0%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <stdint.h>
27 #include <inttypes.h>
28
29 #include "movenc.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
33 #include "riff.h"
34 #include "avio.h"
35 #include "iamf_writer.h"
36 #include "isom.h"
37 #include "av1.h"
38 #include "avc.h"
39 #include "evc.h"
40 #include "libavcodec/ac3_parser_internal.h"
41 #include "libavcodec/dnxhddata.h"
42 #include "libavcodec/flac.h"
43 #include "libavcodec/get_bits.h"
44
45 #include "libavcodec/internal.h"
46 #include "libavcodec/put_bits.h"
47 #include "libavcodec/vc1_common.h"
48 #include "libavcodec/raw.h"
49 #include "internal.h"
50 #include "libavutil/avstring.h"
51 #include "libavutil/channel_layout.h"
52 #include "libavutil/csp.h"
53 #include "libavutil/intfloat.h"
54 #include "libavutil/mathematics.h"
55 #include "libavutil/libm.h"
56 #include "libavutil/mem.h"
57 #include "libavutil/opt.h"
58 #include "libavutil/dict.h"
59 #include "libavutil/pixdesc.h"
60 #include "libavutil/stereo3d.h"
61 #include "libavutil/timecode.h"
62 #include "libavutil/dovi_meta.h"
63 #include "libavutil/uuid.h"
64 #include "hevc.h"
65 #include "rtpenc.h"
66 #include "nal.h"
67 #include "mov_chan.h"
68 #include "movenc_ttml.h"
69 #include "mux.h"
70 #include "rawutils.h"
71 #include "ttmlenc.h"
72 #include "version.h"
73 #include "vpcc.h"
74 #include "vvc.h"
75
76 static const AVOption options[] = {
77 { "brand", "Override major brand", offsetof(MOVMuxContext, major_brand), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
78 { "empty_hdlr_name", "write zero-length name string in hdlr atoms within mdia and minf atoms", offsetof(MOVMuxContext, empty_hdlr_name), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
79 { "encryption_key", "The media encryption key (hex)", offsetof(MOVMuxContext, encryption_key), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
80 { "encryption_kid", "The media encryption key identifier (hex)", offsetof(MOVMuxContext, encryption_kid), AV_OPT_TYPE_BINARY, .flags = AV_OPT_FLAG_ENCODING_PARAM },
81 { "encryption_scheme", "Configures the encryption scheme, allowed values are none, cenc-aes-ctr", offsetof(MOVMuxContext, encryption_scheme_str), AV_OPT_TYPE_STRING, {.str = NULL}, .flags = AV_OPT_FLAG_ENCODING_PARAM },
82 { "frag_duration", "Maximum fragment duration", offsetof(MOVMuxContext, max_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
83 { "frag_interleave", "Interleave samples within fragments (max number of consecutive samples, lower is tighter interleaving, but with more overhead)", offsetof(MOVMuxContext, frag_interleave), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM },
84 { "frag_size", "Maximum fragment size", offsetof(MOVMuxContext, max_fragment_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
85 { "fragment_index", "Fragment number of the next fragment", offsetof(MOVMuxContext, fragments), AV_OPT_TYPE_INT, {.i64 = 1}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
86 { "iods_audio_profile", "iods audio profile atom.", offsetof(MOVMuxContext, iods_audio_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
87 { "iods_video_profile", "iods video profile atom.", offsetof(MOVMuxContext, iods_video_profile), AV_OPT_TYPE_INT, {.i64 = -1}, -1, 255, AV_OPT_FLAG_ENCODING_PARAM},
88 { "ism_lookahead", "Number of lookahead entries for ISM files", offsetof(MOVMuxContext, ism_lookahead), AV_OPT_TYPE_INT, {.i64 = 0}, 0, 255, AV_OPT_FLAG_ENCODING_PARAM},
89 { "movflags", "MOV muxer flags", offsetof(MOVMuxContext, flags), AV_OPT_TYPE_FLAGS, {.i64 = 0}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
90 { "cmaf", "Write CMAF compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_CMAF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
91 { "dash", "Write DASH compatible fragmented MP4", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DASH}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
92 { "default_base_moof", "Set the default-base-is-moof flag in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DEFAULT_BASE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
93 { "delay_moov", "Delay writing the initial moov until the first fragment is cut, or until the first fragment flush", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DELAY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
94 { "disable_chpl", "Disable Nero chapter atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_DISABLE_CHPL}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
95 { "empty_moov", "Make the initial moov atom empty", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_EMPTY_MOOV}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
96 { "faststart", "Run a second pass to put the index (moov atom) at the beginning of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FASTSTART}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
97 { "frag_custom", "Flush fragments on caller requests", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_CUSTOM}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
98 { "frag_discont", "Signal that the next fragment is discontinuous from earlier ones", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_DISCONT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
99 { "frag_every_frame", "Fragment at every frame", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_EVERY_FRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
100 { "frag_keyframe", "Fragment at video keyframes", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_FRAG_KEYFRAME}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
101 { "global_sidx", "Write a global sidx index at the start of the file", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_GLOBAL_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
102 { "isml", "Create a live smooth streaming feed (for pushing to a publishing point)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_ISML}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
103 { "moov_size", "maximum moov size so it can be placed at the begin", offsetof(MOVMuxContext, reserved_moov_size), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = 0 },
104 { "negative_cts_offsets", "Use negative CTS offsets (reducing the need for edit lists)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
105 { "omit_tfhd_offset", "Omit the base data offset in tfhd atoms", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_OMIT_TFHD_OFFSET}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
106 { "prefer_icc", "If writing colr atom prioritise usage of ICC profile if it exists in stream packet side data", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_PREFER_ICC}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
107 { "rtphint", "Add RTP hint tracks", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_RTP_HINT}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
108 { "separate_moof", "Write separate moof/mdat atoms for each track", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SEPARATE_MOOF}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
109 { "skip_sidx", "Skip writing of sidx atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_SIDX}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
110 { "skip_trailer", "Skip writing the mfra/tfra/mfro trailer for fragmented files", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_SKIP_TRAILER}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
111 { "use_metadata_tags", "Use mdta atom for metadata.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_USE_MDTA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
112 { "write_colr", "Write colr atom even if the color info is unspecified (Experimental, may be renamed or changed, do not use from scripts)", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_COLR}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
113 { "write_gama", "Write deprecated gama atom", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_WRITE_GAMA}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
114 { "hybrid_fragmented", "For recoverability, write a fragmented file that is converted to non-fragmented at the end.", 0, AV_OPT_TYPE_CONST, {.i64 = FF_MOV_FLAG_HYBRID_FRAGMENTED}, INT_MIN, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "movflags" },
115 { "min_frag_duration", "Minimum fragment duration", offsetof(MOVMuxContext, min_fragment_duration), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
116 { "mov_gamma", "gamma value for gama atom", offsetof(MOVMuxContext, gamma), AV_OPT_TYPE_FLOAT, {.dbl = 0.0 }, 0.0, 10, AV_OPT_FLAG_ENCODING_PARAM},
117 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
118 FF_RTP_FLAG_OPTS(MOVMuxContext, rtp_flags),
119 { "skip_iods", "Skip writing iods atom.", offsetof(MOVMuxContext, iods_skip), AV_OPT_TYPE_BOOL, {.i64 = 1}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
120 { "use_editlist", "use edit list", offsetof(MOVMuxContext, use_editlist), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
121 { "use_stream_ids_as_track_ids", "use stream ids as track ids", offsetof(MOVMuxContext, use_stream_ids_as_track_ids), AV_OPT_TYPE_BOOL, {.i64 = 0}, 0, 1, AV_OPT_FLAG_ENCODING_PARAM},
122 { "video_track_timescale", "set timescale of all video tracks", offsetof(MOVMuxContext, video_track_timescale), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
123 { "write_btrt", "force or disable writing btrt", offsetof(MOVMuxContext, write_btrt), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
124 { "write_prft", "Write producer reference time box with specified time source", offsetof(MOVMuxContext, write_prft), AV_OPT_TYPE_INT, {.i64 = MOV_PRFT_NONE}, 0, MOV_PRFT_NB-1, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
125 { "pts", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_PTS}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
126 { "wallclock", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = MOV_PRFT_SRC_WALLCLOCK}, 0, 0, AV_OPT_FLAG_ENCODING_PARAM, .unit = "prft"},
127 { "write_tmcd", "force or disable writing tmcd", offsetof(MOVMuxContext, write_tmcd), AV_OPT_TYPE_BOOL, {.i64 = -1}, -1, 1, AV_OPT_FLAG_ENCODING_PARAM},
128 { NULL },
129 };
130
131 static const AVClass mov_isobmff_muxer_class = {
132 .class_name = "mov/mp4/tgp/psp/tg2/ipod/ismv/f4v muxer",
133 .item_name = av_default_item_name,
134 .option = options,
135 .version = LIBAVUTIL_VERSION_INT,
136 };
137
138 static int get_moov_size(AVFormatContext *s);
139 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt);
140
141 24 static int utf8len(const uint8_t *b)
142 {
143 24 int len = 0;
144 int val;
145
2/2
✓ Branch 0 taken 473 times.
✓ Branch 1 taken 24 times.
497 while (*b) {
146
3/8
✓ Branch 0 taken 473 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 473 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 473 times.
473 GET_UTF8(val, *b++, return -1;)
147 473 len++;
148 }
149 24 return len;
150 }
151
152 //FIXME support 64 bit variant with wide placeholders
153 6185 static int64_t update_size(AVIOContext *pb, int64_t pos)
154 {
155 6185 int64_t curpos = avio_tell(pb);
156 6185 avio_seek(pb, pos, SEEK_SET);
157 6185 avio_wb32(pb, curpos - pos); /* rewrite size */
158 6185 avio_seek(pb, curpos, SEEK_SET);
159
160 6185 return curpos - pos;
161 }
162
163 333 static int co64_required(const MOVTrack *track)
164 {
165
3/4
✓ Branch 0 taken 243 times.
✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 243 times.
333 if (track->entry > 0 && track->cluster[track->entry - 1].pos + track->data_offset > UINT32_MAX)
166 return 1;
167 333 return 0;
168 }
169
170 19261 static int is_cover_image(const AVStream *st)
171 {
172 /* Eg. AV_DISPOSITION_ATTACHED_PIC | AV_DISPOSITION_TIMED_THUMBNAILS
173 * is encoded as sparse video track */
174
3/4
✓ Branch 0 taken 19261 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✓ Branch 3 taken 19249 times.
19261 return st && st->disposition == AV_DISPOSITION_ATTACHED_PIC;
175 }
176
177 6 static int rtp_hinting_needed(const AVStream *st)
178 {
179 /* Add hint tracks for each real audio and video stream */
180
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (is_cover_image(st))
181 return 0;
182
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
9 return st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO ||
183
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO;
184 }
185
186 /* Chunk offset atom */
187 333 static int mov_write_stco_tag(AVIOContext *pb, MOVTrack *track)
188 {
189 int i;
190 333 int mode64 = co64_required(track); // use 32 bit size variant if possible
191 333 int64_t pos = avio_tell(pb);
192 333 avio_wb32(pb, 0); /* size */
193
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mode64)
194 ffio_wfourcc(pb, "co64");
195 else
196 333 ffio_wfourcc(pb, "stco");
197 333 avio_wb32(pb, 0); /* version & flags */
198 333 avio_wb32(pb, track->chunkCount); /* entry count */
199
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
200
2/2
✓ Branch 0 taken 10483 times.
✓ Branch 1 taken 3098 times.
13581 if (!track->cluster[i].chunkNum)
201 10483 continue;
202
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3098 times.
3098 if (mode64 == 1)
203 avio_wb64(pb, track->cluster[i].pos + track->data_offset);
204 else
205 3098 avio_wb32(pb, track->cluster[i].pos + track->data_offset);
206 }
207 333 return update_size(pb, pos);
208 }
209
210 /* Sample size atom */
211 333 static int mov_write_stsz_tag(AVIOContext *pb, MOVTrack *track)
212 {
213 333 int equalChunks = 1;
214 333 int i, j, entries = 0, tst = -1, oldtst = -1;
215
216 333 int64_t pos = avio_tell(pb);
217 333 avio_wb32(pb, 0); /* size */
218 333 ffio_wfourcc(pb, "stsz");
219 333 avio_wb32(pb, 0); /* version & flags */
220
221
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
222 13581 tst = track->cluster[i].size / track->cluster[i].entries;
223
4/4
✓ Branch 0 taken 13338 times.
✓ Branch 1 taken 243 times.
✓ Branch 2 taken 8730 times.
✓ Branch 3 taken 4608 times.
13581 if (oldtst != -1 && tst != oldtst)
224 8730 equalChunks = 0;
225 13581 oldtst = tst;
226 13581 entries += track->cluster[i].entries;
227 }
228
4/4
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 109 times.
✓ Branch 3 taken 90 times.
442 if (equalChunks && track->entry) {
229
1/2
✓ Branch 0 taken 109 times.
✗ Branch 1 not taken.
109 int sSize = track->entry ? track->cluster[0].size / track->cluster[0].entries : 0;
230 109 sSize = FFMAX(1, sSize); // adpcm mono case could make sSize == 0
231 109 avio_wb32(pb, sSize); // sample size
232 109 avio_wb32(pb, entries); // sample count
233 } else {
234 224 avio_wb32(pb, 0); // sample size
235 224 avio_wb32(pb, entries); // sample count
236
2/2
✓ Branch 0 taken 9892 times.
✓ Branch 1 taken 224 times.
10116 for (i = 0; i < track->entry; i++) {
237
2/2
✓ Branch 0 taken 9892 times.
✓ Branch 1 taken 9892 times.
19784 for (j = 0; j < track->cluster[i].entries; j++) {
238 9892 avio_wb32(pb, track->cluster[i].size /
239 9892 track->cluster[i].entries);
240 }
241 }
242 }
243 333 return update_size(pb, pos);
244 }
245
246 /* Sample to chunk atom */
247 333 static int mov_write_stsc_tag(AVIOContext *pb, MOVTrack *track)
248 {
249 333 int index = 0, oldval = -1, i;
250 int64_t entryPos, curpos;
251
252 333 int64_t pos = avio_tell(pb);
253 333 avio_wb32(pb, 0); /* size */
254 333 ffio_wfourcc(pb, "stsc");
255 333 avio_wb32(pb, 0); // version & flags
256 333 entryPos = avio_tell(pb);
257 333 avio_wb32(pb, track->chunkCount); // entry count
258
2/2
✓ Branch 0 taken 13581 times.
✓ Branch 1 taken 333 times.
13914 for (i = 0; i < track->entry; i++) {
259
4/4
✓ Branch 0 taken 11299 times.
✓ Branch 1 taken 2282 times.
✓ Branch 2 taken 816 times.
✓ Branch 3 taken 10483 times.
13581 if (oldval != track->cluster[i].samples_in_chunk && track->cluster[i].chunkNum) {
260 816 avio_wb32(pb, track->cluster[i].chunkNum); // first chunk
261 816 avio_wb32(pb, track->cluster[i].samples_in_chunk); // samples per chunk
262 816 avio_wb32(pb, 0x1); // sample description index
263 816 oldval = track->cluster[i].samples_in_chunk;
264 816 index++;
265 }
266 }
267 333 curpos = avio_tell(pb);
268 333 avio_seek(pb, entryPos, SEEK_SET);
269 333 avio_wb32(pb, index); // rewrite size
270 333 avio_seek(pb, curpos, SEEK_SET);
271
272 333 return update_size(pb, pos);
273 }
274
275 /* Sync sample atom */
276 58 static int mov_write_stss_tag(AVIOContext *pb, MOVTrack *track, uint32_t flag)
277 {
278 int64_t curpos, entryPos;
279 58 int i, index = 0;
280 58 int64_t pos = avio_tell(pb);
281 58 avio_wb32(pb, 0); // size
282
1/2
✓ Branch 0 taken 58 times.
✗ Branch 1 not taken.
58 ffio_wfourcc(pb, flag == MOV_SYNC_SAMPLE ? "stss" : "stps");
283 58 avio_wb32(pb, 0); // version & flags
284 58 entryPos = avio_tell(pb);
285 58 avio_wb32(pb, track->entry); // entry count
286
2/2
✓ Branch 0 taken 3209 times.
✓ Branch 1 taken 58 times.
3267 for (i = 0; i < track->entry; i++) {
287
2/2
✓ Branch 0 taken 207 times.
✓ Branch 1 taken 3002 times.
3209 if (track->cluster[i].flags & flag) {
288 207 avio_wb32(pb, i + 1);
289 207 index++;
290 }
291 }
292 58 curpos = avio_tell(pb);
293 58 avio_seek(pb, entryPos, SEEK_SET);
294 58 avio_wb32(pb, index); // rewrite size
295 58 avio_seek(pb, curpos, SEEK_SET);
296 58 return update_size(pb, pos);
297 }
298
299 /* Sample dependency atom */
300 3 static int mov_write_sdtp_tag(AVIOContext *pb, MOVTrack *track)
301 {
302 int i;
303 uint8_t leading, dependent, reference, redundancy;
304 3 int64_t pos = avio_tell(pb);
305 3 avio_wb32(pb, 0); // size
306 3 ffio_wfourcc(pb, "sdtp");
307 3 avio_wb32(pb, 0); // version & flags
308
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 3 times.
16 for (i = 0; i < track->entry; i++) {
309 13 dependent = MOV_SAMPLE_DEPENDENCY_YES;
310 13 leading = reference = redundancy = MOV_SAMPLE_DEPENDENCY_UNKNOWN;
311
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 6 times.
13 if (track->cluster[i].flags & MOV_DISPOSABLE_SAMPLE) {
312 7 reference = MOV_SAMPLE_DEPENDENCY_NO;
313 }
314
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (track->cluster[i].flags & MOV_SYNC_SAMPLE) {
315 3 dependent = MOV_SAMPLE_DEPENDENCY_NO;
316 }
317 13 avio_w8(pb, (leading << 6) | (dependent << 4) |
318 13 (reference << 2) | redundancy);
319 }
320 3 return update_size(pb, pos);
321 }
322
323 #if CONFIG_IAMFENC
324 5 static int mov_write_iacb_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
325 {
326 AVIOContext *dyn_bc;
327 5 int64_t pos = avio_tell(pb);
328 5 uint8_t *dyn_buf = NULL;
329 int dyn_size;
330 5 int ret = avio_open_dyn_buf(&dyn_bc);
331
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
332 return ret;
333
334 5 avio_wb32(pb, 0);
335 5 ffio_wfourcc(pb, "iacb");
336 5 avio_w8(pb, 1); // configurationVersion
337
338 5 ret = ff_iamf_write_descriptors(track->iamf, dyn_bc, s);
339
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
340 return ret;
341
342 5 dyn_size = avio_close_dyn_buf(dyn_bc, &dyn_buf);
343 5 ffio_write_leb(pb, dyn_size);
344 5 avio_write(pb, dyn_buf, dyn_size);
345 5 av_free(dyn_buf);
346
347 5 return update_size(pb, pos);
348 }
349 #endif
350
351 static int mov_write_amr_tag(AVIOContext *pb, MOVTrack *track)
352 {
353 avio_wb32(pb, 0x11); /* size */
354 if (track->mode == MODE_MOV) ffio_wfourcc(pb, "samr");
355 else ffio_wfourcc(pb, "damr");
356 ffio_wfourcc(pb, "FFMP");
357 avio_w8(pb, 0); /* decoder version */
358
359 avio_wb16(pb, 0x81FF); /* Mode set (all modes for AMR_NB) */
360 avio_w8(pb, 0x00); /* Mode change period (no restriction) */
361 avio_w8(pb, 0x01); /* Frames per sample */
362 return 0x11;
363 }
364
365 struct eac3_info {
366 AVPacket *pkt;
367 uint8_t ec3_done;
368 uint8_t num_blocks;
369
370 /* Layout of the EC3SpecificBox */
371 /* maximum bitrate */
372 uint16_t data_rate;
373 int8_t ac3_bit_rate_code;
374 /* number of independent substreams */
375 uint8_t num_ind_sub;
376 struct {
377 /* sample rate code (see ff_ac3_sample_rate_tab) 2 bits */
378 uint8_t fscod;
379 /* bit stream identification 5 bits */
380 uint8_t bsid;
381 /* one bit reserved */
382 /* audio service mixing (not supported yet) 1 bit */
383 /* bit stream mode 3 bits */
384 uint8_t bsmod;
385 /* audio coding mode 3 bits */
386 uint8_t acmod;
387 /* sub woofer on 1 bit */
388 uint8_t lfeon;
389 /* 3 bits reserved */
390 /* number of dependent substreams associated with this substream 4 bits */
391 uint8_t num_dep_sub;
392 /* channel locations of the dependent substream(s), if any, 9 bits */
393 uint16_t chan_loc;
394 /* if there is no dependent substream, then one bit reserved instead */
395 } substream[1]; /* TODO: support 8 independent substreams */
396 };
397
398 5 static int mov_write_ac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
399 {
400 5 struct eac3_info *info = track->eac3_priv;
401 PutBitContext pbc;
402 uint8_t buf[3];
403
404
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (!info || !info->ec3_done) {
405 av_log(s, AV_LOG_ERROR,
406 "Cannot write moov atom before AC3 packets."
407 " Set the delay_moov flag to fix this.\n");
408 return AVERROR(EINVAL);
409 }
410
411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->substream[0].bsid > 8) {
412 av_log(s, AV_LOG_ERROR,
413 "RealAudio AC-3/DolbyNet with bsid %d is not defined by the "
414 "ISOBMFF specification in ETSI TS 102 366!\n",
415 info->substream[0].bsid);
416 return AVERROR(EINVAL);
417 }
418
419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (info->ac3_bit_rate_code < 0) {
420 av_log(s, AV_LOG_ERROR,
421 "No valid AC3 bit rate code for data rate of %d!\n",
422 info->data_rate);
423 return AVERROR(EINVAL);
424 }
425
426 5 avio_wb32(pb, 11);
427 5 ffio_wfourcc(pb, "dac3");
428
429 5 init_put_bits(&pbc, buf, sizeof(buf));
430 5 put_bits(&pbc, 2, info->substream[0].fscod);
431 5 put_bits(&pbc, 5, info->substream[0].bsid);
432 5 put_bits(&pbc, 3, info->substream[0].bsmod);
433 5 put_bits(&pbc, 3, info->substream[0].acmod);
434 5 put_bits(&pbc, 1, info->substream[0].lfeon);
435 5 put_bits(&pbc, 5, info->ac3_bit_rate_code); // bit_rate_code
436 5 put_bits(&pbc, 5, 0); // reserved
437
438 5 flush_put_bits(&pbc);
439 5 avio_write(pb, buf, sizeof(buf));
440
441 5 return 11;
442 }
443
444 1039 static int handle_eac3(MOVMuxContext *mov, AVPacket *pkt, MOVTrack *track)
445 {
446 1039 AC3HeaderInfo *hdr = NULL;
447 struct eac3_info *info;
448 int num_blocks, ret;
449
450
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
1039 if (!track->eac3_priv) {
451
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 5 times.
5 if (!(track->eac3_priv = av_mallocz(sizeof(*info))))
452 return AVERROR(ENOMEM);
453
454 5 ((struct eac3_info *)track->eac3_priv)->ac3_bit_rate_code = -1;
455 }
456 1039 info = track->eac3_priv;
457
458
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1034 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5 times.
1039 if (!info->pkt && !(info->pkt = av_packet_alloc()))
459 return AVERROR(ENOMEM);
460
461
2/2
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1038 times.
1039 if ((ret = avpriv_ac3_parse_header(&hdr, pkt->data, pkt->size)) < 0) {
462
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret == AVERROR(ENOMEM))
463 goto end;
464
465 /* drop the packets until we see a good one */
466
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!track->entry) {
467 1 av_log(mov->fc, AV_LOG_WARNING, "Dropping invalid packet from start of the stream\n");
468 1 ret = 0;
469 } else
470 ret = AVERROR_INVALIDDATA;
471 1 goto end;
472 }
473
474 1038 info->data_rate = FFMAX(info->data_rate, hdr->bit_rate / 1000);
475 1038 info->ac3_bit_rate_code = FFMAX(info->ac3_bit_rate_code,
476 hdr->ac3_bit_rate_code);
477 1038 num_blocks = hdr->num_blocks;
478
479
2/2
✓ Branch 0 taken 1032 times.
✓ Branch 1 taken 6 times.
1038 if (!info->ec3_done) {
480 /* AC-3 substream must be the first one */
481
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
6 if (hdr->bitstream_id <= 10 && hdr->substreamid != 0) {
482 ret = AVERROR(EINVAL);
483 goto end;
484 }
485
486 /* this should always be the case, given that our AC-3 parser
487 * concatenates dependent frames to their independent parent */
488
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (hdr->frame_type == EAC3_FRAME_TYPE_INDEPENDENT ||
489
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 hdr->frame_type == EAC3_FRAME_TYPE_AC3_CONVERT) {
490 /* substream ids must be incremental */
491
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid > info->num_ind_sub + 1) {
492 ret = AVERROR(EINVAL);
493 goto end;
494 }
495
496
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (hdr->substreamid == info->num_ind_sub + 1) {
497 //info->num_ind_sub++;
498 avpriv_request_sample(mov->fc, "Multiple independent substreams");
499 ret = AVERROR_PATCHWELCOME;
500 goto end;
501
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 } else if (hdr->substreamid < info->num_ind_sub ||
502
3/4
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 5 times.
6 hdr->substreamid == 0 && info->substream[0].bsid) {
503 1 info->ec3_done = 1;
504 1 goto concatenate;
505 }
506 } else {
507 if (hdr->substreamid != 0) {
508 avpriv_request_sample(mov->fc, "Multiple non EAC3 independent substreams");
509 ret = AVERROR_PATCHWELCOME;
510 goto end;
511 }
512 }
513
514 /* fill the info needed for the "dec3" atom */
515 5 info->substream[hdr->substreamid].fscod = hdr->sr_code;
516 5 info->substream[hdr->substreamid].bsid = hdr->bitstream_id;
517 5 info->substream[hdr->substreamid].bsmod = hdr->bitstream_mode;
518 5 info->substream[hdr->substreamid].acmod = hdr->channel_mode;
519 5 info->substream[hdr->substreamid].lfeon = hdr->lfe_on;
520
521
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 if (track->par->codec_id == AV_CODEC_ID_AC3) {
522 // with AC-3 we only require the information of a single packet,
523 // so we can finish as soon as the basic values of the bit stream
524 // have been set to the track's informational structure.
525 4 info->ec3_done = 1;
526 4 goto concatenate;
527 }
528
529 /* Parse dependent substream(s), if any */
530
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (pkt->size != hdr->frame_size) {
531 int cumul_size = hdr->frame_size;
532 int parent = hdr->substreamid;
533
534 while (cumul_size != pkt->size) {
535 GetBitContext gbc;
536 int i;
537 ret = avpriv_ac3_parse_header(&hdr, pkt->data + cumul_size, pkt->size - cumul_size);
538 if (ret < 0)
539 goto end;
540 if (hdr->frame_type != EAC3_FRAME_TYPE_DEPENDENT) {
541 ret = AVERROR(EINVAL);
542 goto end;
543 }
544 info->substream[parent].num_dep_sub++;
545 ret /= 8;
546
547 /* header is parsed up to lfeon, but custom channel map may be needed */
548 init_get_bits8(&gbc, pkt->data + cumul_size + ret, pkt->size - cumul_size - ret);
549 /* skip bsid */
550 skip_bits(&gbc, 5);
551 /* skip volume control params */
552 for (i = 0; i < (hdr->channel_mode ? 1 : 2); i++) {
553 skip_bits(&gbc, 5); // skip dialog normalization
554 if (get_bits1(&gbc)) {
555 skip_bits(&gbc, 8); // skip compression gain word
556 }
557 }
558 /* get the dependent stream channel map, if exists */
559 if (get_bits1(&gbc))
560 info->substream[parent].chan_loc |= (get_bits(&gbc, 16) >> 5) & 0x1f;
561 else
562 info->substream[parent].chan_loc |= hdr->channel_mode;
563 cumul_size += hdr->frame_size;
564 }
565 }
566 }
567
568 1033 concatenate:
569
2/4
✓ Branch 0 taken 1038 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1038 times.
✗ Branch 3 not taken.
1038 if (!info->num_blocks && num_blocks == 6) {
570 1038 ret = pkt->size;
571 1038 goto end;
572 }
573 else if (info->num_blocks + num_blocks > 6) {
574 ret = AVERROR_INVALIDDATA;
575 goto end;
576 }
577
578 if (!info->num_blocks) {
579 ret = av_packet_ref(info->pkt, pkt);
580 if (!ret)
581 info->num_blocks = num_blocks;
582 goto end;
583 } else {
584 if ((ret = av_grow_packet(info->pkt, pkt->size)) < 0)
585 goto end;
586 memcpy(info->pkt->data + info->pkt->size - pkt->size, pkt->data, pkt->size);
587 info->num_blocks += num_blocks;
588 info->pkt->duration += pkt->duration;
589 if (info->num_blocks != 6)
590 goto end;
591 av_packet_unref(pkt);
592 av_packet_move_ref(pkt, info->pkt);
593 info->num_blocks = 0;
594 }
595 ret = pkt->size;
596
597 1039 end:
598 1039 av_free(hdr);
599
600 1039 return ret;
601 }
602
603 1 static int mov_write_eac3_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
604 {
605 PutBitContext pbc;
606 uint8_t *buf;
607 struct eac3_info *info;
608 int size, i;
609
610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->eac3_priv) {
611 av_log(s, AV_LOG_ERROR,
612 "Cannot write moov atom before EAC3 packets parsed.\n");
613 return AVERROR(EINVAL);
614 }
615
616 1 info = track->eac3_priv;
617 1 size = 2 + ((34 * (info->num_ind_sub + 1) + 7) >> 3);
618 1 buf = av_malloc(size);
619
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!buf) {
620 return AVERROR(ENOMEM);
621 }
622
623 1 init_put_bits(&pbc, buf, size);
624 1 put_bits(&pbc, 13, info->data_rate);
625 1 put_bits(&pbc, 3, info->num_ind_sub);
626
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i <= info->num_ind_sub; i++) {
627 1 put_bits(&pbc, 2, info->substream[i].fscod);
628 1 put_bits(&pbc, 5, info->substream[i].bsid);
629 1 put_bits(&pbc, 1, 0); /* reserved */
630 1 put_bits(&pbc, 1, 0); /* asvc */
631 1 put_bits(&pbc, 3, info->substream[i].bsmod);
632 1 put_bits(&pbc, 3, info->substream[i].acmod);
633 1 put_bits(&pbc, 1, info->substream[i].lfeon);
634 1 put_bits(&pbc, 5, 0); /* reserved */
635 1 put_bits(&pbc, 4, info->substream[i].num_dep_sub);
636
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (!info->substream[i].num_dep_sub) {
637 1 put_bits(&pbc, 1, 0); /* reserved */
638 } else {
639 put_bits(&pbc, 9, info->substream[i].chan_loc);
640 }
641 }
642 1 flush_put_bits(&pbc);
643 1 size = put_bytes_output(&pbc);
644
645 1 avio_wb32(pb, size + 8);
646 1 ffio_wfourcc(pb, "dec3");
647 1 avio_write(pb, buf, size);
648
649 1 av_free(buf);
650
651 1 return size;
652 }
653
654 /**
655 * This function writes extradata "as is".
656 * Extradata must be formatted like a valid atom (with size and tag).
657 */
658 12 static int mov_write_extradata_tag(AVIOContext *pb, MOVTrack *track)
659 {
660 12 avio_write(pb, track->par->extradata, track->par->extradata_size);
661 12 return track->par->extradata_size;
662 }
663
664 static int mov_write_enda_tag(AVIOContext *pb)
665 {
666 avio_wb32(pb, 10);
667 ffio_wfourcc(pb, "enda");
668 avio_wb16(pb, 1); /* little endian */
669 return 10;
670 }
671
672 2 static int mov_write_enda_tag_be(AVIOContext *pb)
673 {
674 2 avio_wb32(pb, 10);
675 2 ffio_wfourcc(pb, "enda");
676 2 avio_wb16(pb, 0); /* big endian */
677 2 return 10;
678 }
679
680 316 static void put_descr(AVIOContext *pb, int tag, unsigned int size)
681 {
682 316 int i = 3;
683 316 avio_w8(pb, tag);
684
2/2
✓ Branch 0 taken 948 times.
✓ Branch 1 taken 316 times.
1264 for (; i > 0; i--)
685 948 avio_w8(pb, (size >> (7 * i)) | 0x80);
686 316 avio_w8(pb, size & 0x7F);
687 316 }
688
689 210 static unsigned compute_avg_bitrate(MOVTrack *track)
690 {
691 210 uint64_t size = 0;
692 int i;
693
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 173 times.
210 if (!track->track_duration)
694 37 return 0;
695
2/2
✓ Branch 0 taken 8974 times.
✓ Branch 1 taken 173 times.
9147 for (i = 0; i < track->entry; i++)
696 8974 size += track->cluster[i].size;
697 173 return size * 8 * track->timescale / track->track_duration;
698 }
699
700 struct mpeg4_bit_rate_values {
701 uint32_t buffer_size; ///< Size of the decoding buffer for the elementary stream in bytes.
702 uint32_t max_bit_rate; ///< Maximum rate in bits/second over any window of one second.
703 uint32_t avg_bit_rate; ///< Average rate in bits/second over the entire presentation.
704 };
705
706 210 static struct mpeg4_bit_rate_values calculate_mpeg4_bit_rates(MOVTrack *track)
707 {
708 420 const AVPacketSideData *sd = track->st ?
709 209 av_packet_side_data_get(track->st->codecpar->coded_side_data,
710 209 track->st->codecpar->nb_coded_side_data,
711
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 1 times.
210 AV_PKT_DATA_CPB_PROPERTIES) : NULL;
712
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 176 times.
210 AVCPBProperties *props = sd ? (AVCPBProperties *)sd->data : NULL;
713 210 struct mpeg4_bit_rate_values bit_rates = { 0 };
714
715 210 bit_rates.avg_bit_rate = compute_avg_bitrate(track);
716
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 83 times.
210 if (!bit_rates.avg_bit_rate) {
717 // if the average bit rate cannot be calculated at this point, such as
718 // in the case of fragmented MP4, utilize the following values as
719 // fall-back in priority order:
720 //
721 // 1. average bit rate property
722 // 2. bit rate (usually average over the whole clip)
723 // 3. maximum bit rate property
724
725
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 124 times.
✓ Branch 2 taken 3 times.
✗ Branch 3 not taken.
127 if (props && props->avg_bitrate) {
726 3 bit_rates.avg_bit_rate = props->avg_bitrate;
727
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 122 times.
124 } else if (track->par->bit_rate) {
728 2 bit_rates.avg_bit_rate = track->par->bit_rate;
729
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 122 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
122 } else if (props && props->max_bitrate) {
730 bit_rates.avg_bit_rate = props->max_bitrate;
731 }
732 }
733
734 // (FIXME should be max rate in any 1 sec window)
735 210 bit_rates.max_bit_rate = FFMAX(track->par->bit_rate,
736 bit_rates.avg_bit_rate);
737
738 // utilize values from properties if we have them available
739
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 176 times.
210 if (props) {
740 // no avg_bitrate signals that the track is VBR
741
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
34 if (!props->avg_bitrate)
742 bit_rates.avg_bit_rate = props->avg_bitrate;
743 34 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
744 props->max_bitrate);
745 34 bit_rates.buffer_size = props->buffer_size / 8;
746 }
747
748 210 return bit_rates;
749 }
750
751 79 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
752 {
753 79 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
754 79 int64_t pos = avio_tell(pb);
755
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 int decoder_specific_info_len = track->vos_len ? 5 + track->vos_len : 0;
756
757 79 avio_wb32(pb, 0); // size
758 79 ffio_wfourcc(pb, "esds");
759 79 avio_wb32(pb, 0); // Version
760
761 // ES descriptor
762 79 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
763 79 avio_wb16(pb, track->track_id);
764 79 avio_w8(pb, 0x00); // flags (= no flags)
765
766 // DecoderConfig descriptor
767 79 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
768
769 // Object type indication
770
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
771
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 track->par->codec_id == AV_CODEC_ID_MP3) &&
772 track->par->sample_rate > 24000)
773 avio_w8(pb, 0x6B); // 11172-3
774 else
775 79 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
776
777 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
778 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
780 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
781
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 25 times.
79 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
782 54 avio_w8(pb, 0x15); // flags (= Audiostream)
783 else
784 25 avio_w8(pb, 0x11); // flags (= Visualstream)
785
786 79 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
787 79 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
788 79 avio_wb32(pb, bit_rates.avg_bit_rate);
789
790
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if (track->vos_len) {
791 // DecoderSpecific info descriptor
792 79 put_descr(pb, 0x05, track->vos_len);
793 79 avio_write(pb, track->vos_data, track->vos_len);
794 }
795
796 // SL descriptor
797 79 put_descr(pb, 0x06, 1);
798 79 avio_w8(pb, 0x02);
799 79 return update_size(pb, pos);
800 }
801
802 77 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
803 {
804
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 return codec_id == AV_CODEC_ID_PCM_S24LE ||
805
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 codec_id == AV_CODEC_ID_PCM_S32LE ||
806
2/4
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 77 times.
154 codec_id == AV_CODEC_ID_PCM_F32LE ||
807 codec_id == AV_CODEC_ID_PCM_F64LE;
808 }
809
810 77 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
811 {
812
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 4 times.
73 return codec_id == AV_CODEC_ID_PCM_S24BE ||
813
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 codec_id == AV_CODEC_ID_PCM_S32BE ||
814
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 69 times.
150 codec_id == AV_CODEC_ID_PCM_F32BE ||
815 codec_id == AV_CODEC_ID_PCM_F64BE;
816 }
817
818 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
819 {
820 int ret;
821 int64_t pos = avio_tell(pb);
822 avio_wb32(pb, 0);
823 avio_wl32(pb, track->tag); // store it byteswapped
824 track->par->codec_tag = av_bswap16(track->tag >> 16);
825 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
826 return ret;
827 return update_size(pb, pos);
828 }
829
830 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
831 {
832 int ret;
833 int64_t pos = avio_tell(pb);
834 avio_wb32(pb, 0);
835 ffio_wfourcc(pb, "wfex");
836 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
837 return ret;
838 return update_size(pb, pos);
839 }
840
841 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
842 {
843 int64_t pos = avio_tell(pb);
844 avio_wb32(pb, 0);
845 ffio_wfourcc(pb, "dfLa");
846 avio_w8(pb, 0); /* version */
847 avio_wb24(pb, 0); /* flags */
848
849 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
850 if (track->par->extradata_size != FLAC_STREAMINFO_SIZE)
851 return AVERROR_INVALIDDATA;
852
853 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
854 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
855 avio_wb24(pb, track->par->extradata_size); /* Length */
856 avio_write(pb, track->par->extradata, track->par->extradata_size); /* BlockData[Length] */
857
858 return update_size(pb, pos);
859 }
860
861 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
862 {
863 int64_t pos = avio_tell(pb);
864 int channels, channel_map;
865 avio_wb32(pb, 0);
866 ffio_wfourcc(pb, "dOps");
867 avio_w8(pb, 0); /* Version */
868 if (track->par->extradata_size < 19) {
869 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
870 return AVERROR_INVALIDDATA;
871 }
872 /* extradata contains an Ogg OpusHead, other than byte-ordering and
873 OpusHead's preceeding magic/version, OpusSpecificBox is currently
874 identical. */
875 channels = AV_RB8(track->par->extradata + 9);
876 channel_map = AV_RB8(track->par->extradata + 18);
877
878 avio_w8(pb, channels); /* OuputChannelCount */
879 avio_wb16(pb, AV_RL16(track->par->extradata + 10)); /* PreSkip */
880 avio_wb32(pb, AV_RL32(track->par->extradata + 12)); /* InputSampleRate */
881 avio_wb16(pb, AV_RL16(track->par->extradata + 16)); /* OutputGain */
882 avio_w8(pb, channel_map); /* ChannelMappingFamily */
883 /* Write the rest of the header out without byte-swapping. */
884 if (channel_map) {
885 if (track->par->extradata_size < 21 + channels) {
886 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
887 return AVERROR_INVALIDDATA;
888 }
889 avio_write(pb, track->par->extradata + 19, 2 + channels); /* ChannelMappingTable */
890 }
891
892 return update_size(pb, pos);
893 }
894
895 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
896 {
897 int64_t pos = avio_tell(pb);
898 int length;
899 avio_wb32(pb, 0);
900 ffio_wfourcc(pb, "dmlp");
901
902 if (track->vos_len < 20) {
903 av_log(s, AV_LOG_ERROR,
904 "Cannot write moov atom before TrueHD packets."
905 " Set the delay_moov flag to fix this.\n");
906 return AVERROR(EINVAL);
907 }
908
909 length = (AV_RB16(track->vos_data) & 0xFFF) * 2;
910 if (length < 20 || length > track->vos_len)
911 return AVERROR_INVALIDDATA;
912
913 // Only TrueHD is supported
914 if (AV_RB32(track->vos_data + 4) != 0xF8726FBA)
915 return AVERROR_INVALIDDATA;
916
917 avio_wb32(pb, AV_RB32(track->vos_data + 8)); /* format_info */
918 avio_wb16(pb, AV_RB16(track->vos_data + 18) << 1); /* peak_data_rate */
919 avio_wb32(pb, 0); /* reserved */
920
921 return update_size(pb, pos);
922 }
923
924 65 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
925 {
926 65 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
927 65 AVChannelLayout ch_layout = { 0 };
928 int64_t pos;
929 int ambisonic_order, ambi_channels, non_diegetic_channels;
930 int i, ret;
931
932
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 if (!str)
933 65 return 0;
934
935 ret = av_channel_layout_from_string(&ch_layout, str->value);
936 if (ret < 0) {
937 if (ret == AVERROR(EINVAL)) {
938 invalid:
939 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
940 ret = 0;
941 }
942 av_channel_layout_uninit(&ch_layout);
943 return ret;
944 }
945
946 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
947 goto invalid;
948
949 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
950 if (ambisonic_order < 0)
951 goto invalid;
952
953 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
954 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
955 if (non_diegetic_channels &&
956 (non_diegetic_channels != 2 ||
957 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
958 goto invalid;
959
960 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
961
962 pos = avio_tell(pb);
963
964 avio_wb32(pb, 0); // Size
965 ffio_wfourcc(pb, "SA3D");
966 avio_w8(pb, 0); // version
967 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
968 avio_wb32(pb, ambisonic_order); // ambisonic_order
969 avio_w8(pb, 0); // ambisonic_channel_ordering
970 avio_w8(pb, 0); // ambisonic_normalization
971 avio_wb32(pb, ch_layout.nb_channels); // num_channels
972 for (i = 0; i < ambi_channels; i++)
973 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
974 for (; i < ch_layout.nb_channels; i++)
975 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
976
977 av_channel_layout_uninit(&ch_layout);
978
979 return update_size(pb, pos);
980 }
981
982 40 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
983 {
984 uint32_t layout_tag, bitmap, *channel_desc;
985 40 int64_t pos = avio_tell(pb);
986 int num_desc, ret;
987
988
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (track->multichannel_as_mono)
989 return 0;
990
991 40 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
992 &bitmap, &channel_desc);
993
994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0) {
995 if (ret == AVERROR(ENOSYS)) {
996 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
997 "lack of channel information\n");
998 ret = 0;
999 }
1000
1001 return ret;
1002 }
1003
1004
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 3 times.
40 if (layout_tag == MOV_CH_LAYOUT_MONO && track->mono_as_fc > 0) {
1005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1006 1 channel_desc = av_malloc(sizeof(*channel_desc));
1007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1008 return AVERROR(ENOMEM);
1009
1010 1 layout_tag = 0;
1011 1 bitmap = 0;
1012 1 *channel_desc = 3; // channel label "Center"
1013 }
1014
1015
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1016
1017 40 avio_wb32(pb, 0); // Size
1018 40 ffio_wfourcc(pb, "chan"); // Type
1019 40 avio_w8(pb, 0); // Version
1020 40 avio_wb24(pb, 0); // Flags
1021 40 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1022 40 avio_wb32(pb, bitmap); // mChannelBitmap
1023 40 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1024
1025
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 for (int i = 0; i < num_desc; i++) {
1026 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1027 3 avio_wb32(pb, 0); // mChannelFlags
1028 3 avio_wl32(pb, 0); // mCoordinates[0]
1029 3 avio_wl32(pb, 0); // mCoordinates[1]
1030 3 avio_wl32(pb, 0); // mCoordinates[2]
1031 }
1032
1033 40 av_free(channel_desc);
1034
1035 40 return update_size(pb, pos);
1036 }
1037
1038 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1039 {
1040 15 int64_t pos = avio_tell(pb);
1041
1042 15 avio_wb32(pb, 0); /* size */
1043 15 ffio_wfourcc(pb, "wave");
1044
1045
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1046 15 avio_wb32(pb, 12); /* size */
1047 15 ffio_wfourcc(pb, "frma");
1048 15 avio_wl32(pb, track->tag);
1049 }
1050
1051
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1052 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1053 3 avio_wb32(pb, 12); /* size */
1054 3 ffio_wfourcc(pb, "mp4a");
1055 3 avio_wb32(pb, 0);
1056 3 mov_write_esds_tag(pb, track);
1057
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1058 mov_write_enda_tag(pb);
1059
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1060 2 mov_write_enda_tag_be(pb);
1061
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1062 mov_write_amr_tag(pb, track);
1063
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1064 1 mov_write_ac3_tag(s, pb, track);
1065
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1066 mov_write_eac3_tag(s, pb, track);
1067
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1068 track->par->codec_id == AV_CODEC_ID_QDM2) {
1069 9 mov_write_extradata_tag(pb, track);
1070 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1071 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1072 mov_write_ms_tag(s, pb, track);
1073 }
1074
1075 15 avio_wb32(pb, 8); /* size */
1076 15 avio_wb32(pb, 0); /* null tag */
1077
1078 15 return update_size(pb, pos);
1079 }
1080
1081 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1082 {
1083 uint8_t *unescaped;
1084 const uint8_t *start, *next, *end = track->vos_data + track->vos_len;
1085 int unescaped_size, seq_found = 0;
1086 int level = 0, interlace = 0;
1087 int packet_seq = track->vc1_info.packet_seq;
1088 int packet_entry = track->vc1_info.packet_entry;
1089 int slices = track->vc1_info.slices;
1090 PutBitContext pbc;
1091
1092 if (track->start_dts == AV_NOPTS_VALUE) {
1093 /* No packets written yet, vc1_info isn't authoritative yet. */
1094 /* Assume inline sequence and entry headers. */
1095 packet_seq = packet_entry = 1;
1096 av_log(NULL, AV_LOG_WARNING,
1097 "moov atom written before any packets, unable to write correct "
1098 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1099 }
1100
1101 unescaped = av_mallocz(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
1102 if (!unescaped)
1103 return AVERROR(ENOMEM);
1104 start = find_next_marker(track->vos_data, end);
1105 for (next = start; next < end; start = next) {
1106 GetBitContext gb;
1107 int size;
1108 next = find_next_marker(start + 4, end);
1109 size = next - start - 4;
1110 if (size <= 0)
1111 continue;
1112 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1113 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1114 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1115 int profile = get_bits(&gb, 2);
1116 if (profile != PROFILE_ADVANCED) {
1117 av_free(unescaped);
1118 return AVERROR(ENOSYS);
1119 }
1120 seq_found = 1;
1121 level = get_bits(&gb, 3);
1122 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1123 * width, height */
1124 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1125 skip_bits(&gb, 1); /* broadcast */
1126 interlace = get_bits1(&gb);
1127 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1128 }
1129 }
1130 if (!seq_found) {
1131 av_free(unescaped);
1132 return AVERROR(ENOSYS);
1133 }
1134
1135 init_put_bits(&pbc, buf, 7);
1136 /* VC1DecSpecStruc */
1137 put_bits(&pbc, 4, 12); /* profile - advanced */
1138 put_bits(&pbc, 3, level);
1139 put_bits(&pbc, 1, 0); /* reserved */
1140 /* VC1AdvDecSpecStruc */
1141 put_bits(&pbc, 3, level);
1142 put_bits(&pbc, 1, 0); /* cbr */
1143 put_bits(&pbc, 6, 0); /* reserved */
1144 put_bits(&pbc, 1, !interlace); /* no interlace */
1145 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1146 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1147 put_bits(&pbc, 1, !slices); /* no slice code */
1148 put_bits(&pbc, 1, 0); /* no bframe */
1149 put_bits(&pbc, 1, 0); /* reserved */
1150
1151 /* framerate */
1152 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1153 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1154 else
1155 put_bits32(&pbc, 0xffffffff);
1156
1157 flush_put_bits(&pbc);
1158
1159 av_free(unescaped);
1160
1161 return 0;
1162 }
1163
1164 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1165 {
1166 uint8_t buf[7] = { 0 };
1167 int ret;
1168
1169 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1170 return ret;
1171
1172 avio_wb32(pb, track->vos_len + 8 + sizeof(buf));
1173 ffio_wfourcc(pb, "dvc1");
1174 avio_write(pb, buf, sizeof(buf));
1175 avio_write(pb, track->vos_data, track->vos_len);
1176
1177 return 0;
1178 }
1179
1180 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1181 {
1182 4 avio_wb32(pb, track->vos_len + 8);
1183 4 ffio_wfourcc(pb, "glbl");
1184 4 avio_write(pb, track->vos_data, track->vos_len);
1185 4 return 8 + track->vos_len;
1186 }
1187
1188 /**
1189 * Compute flags for 'lpcm' tag.
1190 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1191 */
1192 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1193 {
1194
1/6
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 8 times.
8 switch (codec_id) {
1195 case AV_CODEC_ID_PCM_F32BE:
1196 case AV_CODEC_ID_PCM_F64BE:
1197 return 11;
1198 case AV_CODEC_ID_PCM_F32LE:
1199 case AV_CODEC_ID_PCM_F64LE:
1200 return 9;
1201 case AV_CODEC_ID_PCM_U8:
1202 return 10;
1203 case AV_CODEC_ID_PCM_S16BE:
1204 case AV_CODEC_ID_PCM_S24BE:
1205 case AV_CODEC_ID_PCM_S32BE:
1206 return 14;
1207 case AV_CODEC_ID_PCM_S8:
1208 case AV_CODEC_ID_PCM_S16LE:
1209 case AV_CODEC_ID_PCM_S24LE:
1210 case AV_CODEC_ID_PCM_S32LE:
1211 return 12;
1212 8 default:
1213 8 return 0;
1214 }
1215 }
1216
1217 25209 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1218 {
1219 int64_t next_dts;
1220
1221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 if (cluster_idx >= track->entry)
1222 return 0;
1223
1224
2/2
✓ Branch 0 taken 643 times.
✓ Branch 1 taken 24566 times.
25209 if (cluster_idx + 1 == track->entry)
1225 643 next_dts = track->track_duration + track->start_dts;
1226 else
1227 24566 next_dts = track->cluster[cluster_idx + 1].dts;
1228
1229 25209 next_dts -= track->cluster[cluster_idx].dts;
1230
1231
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 av_assert0(next_dts >= 0);
1232
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 av_assert0(next_dts <= INT_MAX);
1233
1234 25209 return next_dts;
1235 }
1236
1237 4 static int get_samples_per_packet(MOVTrack *track)
1238 {
1239 int i, first_duration;
1240
1241 /* use 1 for raw PCM */
1242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1243 return 1;
1244
1245 /* check to see if duration is constant for all clusters */
1246
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1247 return 0;
1248 4 first_duration = get_cluster_duration(track, 0);
1249
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1250
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1251 4 return 0;
1252 }
1253 return first_duration;
1254 }
1255
1256 131 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1257 {
1258 131 int64_t pos = avio_tell(pb);
1259 131 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1260
3/4
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 50 times.
✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
131 if (!bit_rates.max_bit_rate && !bit_rates.avg_bit_rate &&
1261
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 !bit_rates.buffer_size)
1262 // no useful data to be written, skip
1263 81 return 0;
1264
1265 50 avio_wb32(pb, 0); /* size */
1266 50 ffio_wfourcc(pb, "btrt");
1267
1268 50 avio_wb32(pb, bit_rates.buffer_size);
1269 50 avio_wb32(pb, bit_rates.max_bit_rate);
1270 50 avio_wb32(pb, bit_rates.avg_bit_rate);
1271
1272 50 return update_size(pb, pos);
1273 }
1274
1275 5 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1276 {
1277 5 int64_t pos = avio_tell(pb);
1278 5 int config = 0;
1279 int ret;
1280 5 uint8_t *speaker_pos = NULL;
1281 5 const AVChannelLayout *layout = &track->par->ch_layout;
1282
1283 5 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1284
3/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
5 if (ret || !config) {
1285 4 config = 0;
1286 4 speaker_pos = av_malloc(layout->nb_channels);
1287
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1288 return AVERROR(ENOMEM);
1289 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1290 4 speaker_pos, layout->nb_channels);
1291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1292 char buf[128] = {0};
1293
1294 av_freep(&speaker_pos);
1295 av_channel_layout_describe(layout, buf, sizeof(buf));
1296 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1297 return ret;
1298 }
1299 }
1300
1301 5 avio_wb32(pb, 0); /* size */
1302 5 ffio_wfourcc(pb, "chnl");
1303 5 avio_wb32(pb, 0); /* version & flags */
1304
1305 5 avio_w8(pb, 1); /* stream_structure */
1306 5 avio_w8(pb, config);
1307
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (config) {
1308 1 avio_wb64(pb, 0);
1309 } else {
1310 4 avio_write(pb, speaker_pos, layout->nb_channels);
1311 4 av_freep(&speaker_pos);
1312 }
1313
1314 5 return update_size(pb, pos);
1315 }
1316
1317 7 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1318 {
1319 7 int64_t pos = avio_tell(pb);
1320 int format_flags;
1321 int sample_size;
1322
1323 7 avio_wb32(pb, 0); /* size */
1324 7 ffio_wfourcc(pb, "pcmC");
1325 7 avio_wb32(pb, 0); /* version & flags */
1326
1327 /* 0x01: indicates little-endian format */
1328 20 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1329
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1330
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1331
2/4
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
13 track->par->codec_id == AV_CODEC_ID_PCM_S24LE ||
1332 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1333 7 avio_w8(pb, format_flags);
1334 7 sample_size = track->par->bits_per_raw_sample;
1335
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (!sample_size)
1336 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1337
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 av_assert0(sample_size);
1338 7 avio_w8(pb, sample_size);
1339
1340 7 return update_size(pb, pos);
1341 }
1342
1343 108 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1344 {
1345 108 int64_t pos = avio_tell(pb);
1346 108 int version = 0;
1347 108 uint32_t tag = track->tag;
1348 108 int ret = 0;
1349
1350
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
108 if (track->mode == MODE_MOV) {
1351
3/4
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 36 times.
40 if (track->timescale > UINT16_MAX || !track->par->ch_layout.nb_channels) {
1352
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1353 tag = AV_RL32("lpcm");
1354 4 version = 2;
1355
5/6
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 10 times.
✓ Branch 3 taken 26 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 24 times.
✓ Branch 6 taken 2 times.
62 } else if (track->audio_vbr || mov_pcm_le_gt16(track->par->codec_id) ||
1356 26 mov_pcm_be_gt16(track->par->codec_id) ||
1357
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1358
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1360 12 version = 1;
1361 }
1362 }
1363
1364 108 avio_wb32(pb, 0); /* size */
1365
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (mov->encryption_scheme != MOV_ENC_NONE) {
1366 ffio_wfourcc(pb, "enca");
1367 } else {
1368 108 avio_wl32(pb, tag); // store it byteswapped
1369 }
1370 108 avio_wb32(pb, 0); /* Reserved */
1371 108 avio_wb16(pb, 0); /* Reserved */
1372 108 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1373
1374 /* SoundDescription */
1375 108 avio_wb16(pb, version); /* Version */
1376 108 avio_wb16(pb, 0); /* Revision level */
1377 108 avio_wb32(pb, 0); /* Reserved */
1378
1379
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 104 times.
108 if (version == 2) {
1380 4 avio_wb16(pb, 3);
1381 4 avio_wb16(pb, 16);
1382 4 avio_wb16(pb, 0xfffe);
1383 4 avio_wb16(pb, 0);
1384 4 avio_wb32(pb, 0x00010000);
1385 4 avio_wb32(pb, 72);
1386 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1387 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1388 4 avio_wb32(pb, 0x7F000000);
1389 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1390 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1391 4 avio_wb32(pb, track->sample_size);
1392 4 avio_wb32(pb, get_samples_per_packet(track));
1393 } else {
1394
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 68 times.
104 if (track->mode == MODE_MOV) {
1395 36 avio_wb16(pb, track->par->ch_layout.nb_channels);
1396
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1397
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1398 1 avio_wb16(pb, 8); /* bits per sample */
1399
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1400 avio_wb16(pb, track->par->bits_per_coded_sample);
1401 else
1402 35 avio_wb16(pb, 16);
1403
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1404 } else { /* reserved for mp4/3gp */
1405
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 5 times.
131 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1406 63 0 : track->par->ch_layout.nb_channels);
1407
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 5 times.
68 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1408
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 track->par->codec_id == AV_CODEC_ID_ALAC) {
1409 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1410 } else {
1411 63 avio_wb16(pb, 16);
1412 }
1413 68 avio_wb16(pb, 0);
1414 }
1415
1416 104 avio_wb16(pb, 0); /* packet size (= 0) */
1417
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 99 times.
104 if (track->tag == MKTAG('i','a','m','f'))
1418 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1420 avio_wb16(pb, 48000);
1421
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1422 avio_wb32(pb, track->par->sample_rate);
1423 else
1424
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
198 avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ?
1425 99 track->par->sample_rate : 0);
1426
1427
1/2
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
104 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1428 104 avio_wb16(pb, 0); /* Reserved */
1429 }
1430
1431
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 96 times.
108 if (version == 1) { /* SoundDescription V1 extended info */
1432
3/4
✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 10 times.
24 if (mov_pcm_le_gt16(track->par->codec_id) ||
1433 12 mov_pcm_be_gt16(track->par->codec_id))
1434 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1435 else
1436 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1437 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1438 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1439 12 avio_wb32(pb, 2); /* Bytes per sample */
1440 }
1441
1442
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
108 if (track->mode == MODE_MOV &&
1443
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 (track->par->codec_id == AV_CODEC_ID_AAC ||
1444
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
37 track->par->codec_id == AV_CODEC_ID_AC3 ||
1445
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1446
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1447
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1448
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1449
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1450
2/4
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 27 times.
54 track->par->codec_id == AV_CODEC_ID_QDM2 ||
1451
2/4
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 25 times.
54 (mov_pcm_le_gt16(track->par->codec_id) && version==1) ||
1452
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1453 15 ret = mov_write_wave_tag(s, pb, track);
1454
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 42 times.
93 else if (track->tag == MKTAG('m','p','4','a'))
1455 51 ret = mov_write_esds_tag(pb, track);
1456 #if CONFIG_IAMFENC
1457
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 37 times.
42 else if (track->tag == MKTAG('i','a','m','f'))
1458 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1459 #endif
1460
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1461 ret = mov_write_amr_tag(pb, track);
1462
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 33 times.
37 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1463 4 ret = mov_write_ac3_tag(s, pb, track);
1464
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 32 times.
33 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1465 1 ret = mov_write_eac3_tag(s, pb, track);
1466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1467 ret = mov_write_extradata_tag(pb, track);
1468
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1469 ret = mov_write_wfex_tag(s, pb, track);
1470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1471 ret = mov_write_dfla_tag(pb, track);
1472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1473 ret = mov_write_dops_tag(s, pb, track);
1474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1475 ret = mov_write_dmlp_tag(s, pb, track);
1476
4/4
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 times.
✓ Branch 3 taken 25 times.
32 else if (tag == MOV_MP4_IPCM_TAG || tag == MOV_MP4_FPCM_TAG) {
1477
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (track->par->ch_layout.nb_channels > 1)
1478 5 ret = mov_write_chnl_tag(s, pb, track);
1479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ret < 0)
1480 return ret;
1481 7 ret = mov_write_pcmc_tag(s, pb, track);
1482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->vos_len > 0)
1483 ret = mov_write_glbl_tag(pb, track);
1484
1485
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (ret < 0)
1486 return ret;
1487
1488
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 43 times.
✓ Branch 2 taken 65 times.
✗ Branch 3 not taken.
108 if (track->mode == MODE_MP4 && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1489
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
65 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1490 return ret;
1491 }
1492
1493
3/4
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
✓ Branch 2 taken 40 times.
✗ Branch 3 not taken.
108 if (track->mode == MODE_MOV && track->par->codec_type == AVMEDIA_TYPE_AUDIO
1494
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1495 return ret;
1496 }
1497
1498
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (mov->encryption_scheme != MOV_ENC_NONE
1499 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1500 return ret;
1501 }
1502
1503
3/4
✓ Branch 0 taken 65 times.
✓ Branch 1 taken 43 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 65 times.
173 if (mov->write_btrt &&
1504 65 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1505 return ret;
1506
1507 108 ret = update_size(pb, pos);
1508 108 return ret;
1509 }
1510
1511 static int mov_write_d263_tag(AVIOContext *pb)
1512 {
1513 avio_wb32(pb, 0xf); /* size */
1514 ffio_wfourcc(pb, "d263");
1515 ffio_wfourcc(pb, "FFMP");
1516 avio_w8(pb, 0); /* decoder version */
1517 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1518 avio_w8(pb, 0xa); /* level */
1519 avio_w8(pb, 0); /* profile */
1520 return 0xf;
1521 }
1522
1523 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1524 {
1525 1 int64_t pos = avio_tell(pb);
1526
1527 1 avio_wb32(pb, 0);
1528 1 ffio_wfourcc(pb, "av1C");
1529 1 ff_isom_write_av1c(pb, track->vos_data, track->vos_len, track->mode != MODE_AVIF);
1530 1 return update_size(pb, pos);
1531 }
1532
1533 53 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1534 {
1535 53 int64_t pos = avio_tell(pb);
1536
1537 53 avio_wb32(pb, 0);
1538 53 ffio_wfourcc(pb, "avcC");
1539 53 ff_isom_write_avcc(pb, track->vos_data, track->vos_len);
1540 53 return update_size(pb, pos);
1541 }
1542
1543 /* AVS3 Intelligent Media Coding
1544 * Information Technology - Intelligent Media Coding
1545 * Part 6: Intelligent Media Format
1546 */
1547 static int mov_write_av3c(AVIOContext *pb, const uint8_t *data, int len)
1548 {
1549 if (len < 4)
1550 return AVERROR_INVALIDDATA;
1551
1552 if (data[0] == 1) {
1553 // In Avs3DecoderConfigurationRecord format
1554 avio_write(pb, data, len);
1555 return 0;
1556 }
1557
1558 avio_w8(pb, 1); // version
1559 avio_wb16(pb, len); // sequence_header_length
1560 avio_write(pb, data, len); // sequence_header
1561 avio_w8(pb, 0xFC); // Only support library_dependency_idc = 0
1562
1563 return 0;
1564 }
1565
1566 static int mov_write_av3c_tag(AVIOContext *pb, MOVTrack *track)
1567 {
1568 int64_t pos = avio_tell(pb);
1569 avio_wb32(pb, 0);
1570 ffio_wfourcc(pb, "av3c");
1571 mov_write_av3c(pb, track->vos_data, track->vos_len);
1572 return update_size(pb, pos);
1573 }
1574
1575 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1576 {
1577 int64_t pos = avio_tell(pb);
1578
1579 avio_wb32(pb, 0);
1580 ffio_wfourcc(pb, "vpcC");
1581 ff_isom_write_vpcc(s, pb, track->vos_data, track->vos_len, track->par);
1582 return update_size(pb, pos);
1583 }
1584
1585 3 static int mov_write_hvcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1586 {
1587 3 int64_t pos = avio_tell(pb);
1588
1589 3 avio_wb32(pb, 0);
1590 3 ffio_wfourcc(pb, "hvcC");
1591
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->tag == MKTAG('h','v','c','1'))
1592 1 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 1, s);
1593 else
1594 2 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0, s);
1595 3 return update_size(pb, pos);
1596 }
1597
1598 1 static int mov_write_lhvc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1599 {
1600 1 int64_t pos = avio_tell(pb);
1601 int ret;
1602
1603 1 avio_wb32(pb, 0);
1604 1 ffio_wfourcc(pb, "lhvC");
1605
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1606 1 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 1, s);
1607 else
1608 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 0, s);
1609
1610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1611 avio_seek(pb, pos, SEEK_SET);
1612 return ret;
1613 }
1614
1615 1 return update_size(pb, pos);
1616 }
1617
1618 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1619 {
1620 1 int64_t pos = avio_tell(pb);
1621
1622 1 avio_wb32(pb, 0);
1623 1 ffio_wfourcc(pb, "evcC");
1624
1625
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1626 1 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 1);
1627 else
1628 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 0);
1629
1630 1 return update_size(pb, pos);
1631 }
1632
1633 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1634 {
1635 1 int64_t pos = avio_tell(pb);
1636
1637 1 avio_wb32(pb, 0);
1638 1 ffio_wfourcc(pb, "vvcC");
1639
1640 1 avio_w8 (pb, 0); /* version */
1641 1 avio_wb24(pb, 0); /* flags */
1642
1643
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1644 1 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 1);
1645 else
1646 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 0);
1647 1 return update_size(pb, pos);
1648 }
1649
1650 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1651 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1652 {
1653 int interlaced;
1654 int cid;
1655 23 int display_width = track->par->width;
1656
1657
2/4
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 23 times.
✗ Branch 3 not taken.
23 if (track->vos_data && track->vos_len > 0x29) {
1658
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->vos_data) != 0) {
1659 /* looks like a DNxHD bit stream */
1660 23 interlaced = (track->vos_data[5] & 2);
1661 23 cid = AV_RB32(track->vos_data + 0x28);
1662 } else {
1663 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1664 return 0;
1665 }
1666 } else {
1667 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1668 return 0;
1669 }
1670
1671 23 avio_wb32(pb, 24); /* size */
1672 23 ffio_wfourcc(pb, "ACLR");
1673 23 ffio_wfourcc(pb, "ACLR");
1674 23 ffio_wfourcc(pb, "0001");
1675
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1676 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1677 23 avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */
1678 } else { /* Full range (0-255) */
1679 avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */
1680 }
1681 23 avio_wb32(pb, 0); /* unknown */
1682
1683
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1684 12 avio_wb32(pb, 32);
1685 12 ffio_wfourcc(pb, "ADHR");
1686 12 ffio_wfourcc(pb, "0001");
1687 12 avio_wb32(pb, cid);
1688 12 avio_wb32(pb, 0); /* unknown */
1689 12 avio_wb32(pb, 1); /* unknown */
1690 12 avio_wb32(pb, 0); /* unknown */
1691 12 avio_wb32(pb, 0); /* unknown */
1692 12 return 0;
1693 }
1694
1695 11 avio_wb32(pb, 24); /* size */
1696 11 ffio_wfourcc(pb, "APRG");
1697 11 ffio_wfourcc(pb, "APRG");
1698 11 ffio_wfourcc(pb, "0001");
1699 11 avio_wb32(pb, 1); /* unknown */
1700 11 avio_wb32(pb, 0); /* unknown */
1701
1702 11 avio_wb32(pb, 120); /* size */
1703 11 ffio_wfourcc(pb, "ARES");
1704 11 ffio_wfourcc(pb, "ARES");
1705 11 ffio_wfourcc(pb, "0001");
1706 11 avio_wb32(pb, cid); /* dnxhd cid, some id ? */
1707
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1708 && track->par->sample_aspect_ratio.den > 0)
1709 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1710 11 avio_wb32(pb, display_width);
1711 /* values below are based on samples created with quicktime and avid codecs */
1712
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1713 11 avio_wb32(pb, track->par->height / 2);
1714 11 avio_wb32(pb, 2); /* unknown */
1715 11 avio_wb32(pb, 0); /* unknown */
1716 11 avio_wb32(pb, 4); /* unknown */
1717 } else {
1718 avio_wb32(pb, track->par->height);
1719 avio_wb32(pb, 1); /* unknown */
1720 avio_wb32(pb, 0); /* unknown */
1721 if (track->par->height == 1080)
1722 avio_wb32(pb, 5); /* unknown */
1723 else
1724 avio_wb32(pb, 6); /* unknown */
1725 }
1726 /* padding */
1727 11 ffio_fill(pb, 0, 10 * 8);
1728
1729 11 return 0;
1730 }
1731
1732 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1733 {
1734 avio_wb32(pb, 12);
1735 ffio_wfourcc(pb, "DpxE");
1736 if (track->par->extradata_size >= 12 &&
1737 !memcmp(&track->par->extradata[4], "DpxE", 4)) {
1738 avio_wb32(pb, track->par->extradata[11]);
1739 } else {
1740 avio_wb32(pb, 1);
1741 }
1742 return 0;
1743 }
1744
1745 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1746 {
1747 int tag;
1748
1749
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1750
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','n');
1752 1 else tag = MKTAG('d','v','c',' ');
1753 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1754 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1755 else tag = MKTAG('d','v','p','p');
1756 } else if (track->par->height == 720) { /* HD 720 line */
1757 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1758 else tag = MKTAG('d','v','h','p');
1759 } else if (track->par->height == 1080) { /* HD 1080 line */
1760 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1761 else tag = MKTAG('d','v','h','6');
1762 } else {
1763 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1764 return 0;
1765 }
1766
1767 1 return tag;
1768 }
1769
1770 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1771 {
1772 3 AVRational rational_framerate = st->avg_frame_rate;
1773 3 int rate = 0;
1774
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1775 3 rate = av_q2d(rational_framerate);
1776 3 return rate;
1777 }
1778
1779 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1780 {
1781 1 int tag = track->par->codec_tag;
1782 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1783 1 AVStream *st = track->st;
1784 1 int rate = defined_frame_rate(s, st);
1785
1786
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1787 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1788
1789
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1790
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (track->par->width == 1280 && track->par->height == 720) {
1791 if (!interlaced) {
1792 if (rate == 24) tag = MKTAG('x','d','v','4');
1793 else if (rate == 25) tag = MKTAG('x','d','v','5');
1794 else if (rate == 30) tag = MKTAG('x','d','v','1');
1795 else if (rate == 50) tag = MKTAG('x','d','v','a');
1796 else if (rate == 60) tag = MKTAG('x','d','v','9');
1797 }
1798
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } else if (track->par->width == 1440 && track->par->height == 1080) {
1799 if (!interlaced) {
1800 if (rate == 24) tag = MKTAG('x','d','v','6');
1801 else if (rate == 25) tag = MKTAG('x','d','v','7');
1802 else if (rate == 30) tag = MKTAG('x','d','v','8');
1803 } else {
1804 if (rate == 25) tag = MKTAG('x','d','v','3');
1805 else if (rate == 30) tag = MKTAG('x','d','v','2');
1806 }
1807
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 } else if (track->par->width == 1920 && track->par->height == 1080) {
1808 if (!interlaced) {
1809 if (rate == 24) tag = MKTAG('x','d','v','d');
1810 else if (rate == 25) tag = MKTAG('x','d','v','e');
1811 else if (rate == 30) tag = MKTAG('x','d','v','f');
1812 } else {
1813 if (rate == 25) tag = MKTAG('x','d','v','c');
1814 else if (rate == 30) tag = MKTAG('x','d','v','b');
1815 }
1816 }
1817 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1818 if (track->par->width == 1280 && track->par->height == 720) {
1819 if (!interlaced) {
1820 if (rate == 24) tag = MKTAG('x','d','5','4');
1821 else if (rate == 25) tag = MKTAG('x','d','5','5');
1822 else if (rate == 30) tag = MKTAG('x','d','5','1');
1823 else if (rate == 50) tag = MKTAG('x','d','5','a');
1824 else if (rate == 60) tag = MKTAG('x','d','5','9');
1825 }
1826 } else if (track->par->width == 1920 && track->par->height == 1080) {
1827 if (!interlaced) {
1828 if (rate == 24) tag = MKTAG('x','d','5','d');
1829 else if (rate == 25) tag = MKTAG('x','d','5','e');
1830 else if (rate == 30) tag = MKTAG('x','d','5','f');
1831 } else {
1832 if (rate == 25) tag = MKTAG('x','d','5','c');
1833 else if (rate == 30) tag = MKTAG('x','d','5','b');
1834 }
1835 }
1836 }
1837
1838 1 return tag;
1839 }
1840
1841 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1842 {
1843 2 int tag = track->par->codec_tag;
1844 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1845 2 AVStream *st = track->st;
1846 2 int rate = defined_frame_rate(s, st);
1847
1848
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
1849 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1850
1851
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1852 if (track->par->width == 960 && track->par->height == 720) {
1853 if (!interlaced) {
1854 if (rate == 24) tag = MKTAG('a','i','5','p');
1855 else if (rate == 25) tag = MKTAG('a','i','5','q');
1856 else if (rate == 30) tag = MKTAG('a','i','5','p');
1857 else if (rate == 50) tag = MKTAG('a','i','5','q');
1858 else if (rate == 60) tag = MKTAG('a','i','5','p');
1859 }
1860 } else if (track->par->width == 1440 && track->par->height == 1080) {
1861 if (!interlaced) {
1862 if (rate == 24) tag = MKTAG('a','i','5','3');
1863 else if (rate == 25) tag = MKTAG('a','i','5','2');
1864 else if (rate == 30) tag = MKTAG('a','i','5','3');
1865 } else {
1866 if (rate == 50) tag = MKTAG('a','i','5','5');
1867 else if (rate == 60) tag = MKTAG('a','i','5','6');
1868 }
1869 }
1870
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1871 if (track->par->width == 1280 && track->par->height == 720) {
1872 if (!interlaced) {
1873 if (rate == 24) tag = MKTAG('a','i','1','p');
1874 else if (rate == 25) tag = MKTAG('a','i','1','q');
1875 else if (rate == 30) tag = MKTAG('a','i','1','p');
1876 else if (rate == 50) tag = MKTAG('a','i','1','q');
1877 else if (rate == 60) tag = MKTAG('a','i','1','p');
1878 }
1879 } else if (track->par->width == 1920 && track->par->height == 1080) {
1880 if (!interlaced) {
1881 if (rate == 24) tag = MKTAG('a','i','1','3');
1882 else if (rate == 25) tag = MKTAG('a','i','1','2');
1883 else if (rate == 30) tag = MKTAG('a','i','1','3');
1884 } else {
1885 if (rate == 25) tag = MKTAG('a','i','1','5');
1886 else if (rate == 50) tag = MKTAG('a','i','1','5');
1887 else if (rate == 60) tag = MKTAG('a','i','1','6');
1888 }
1889 } else if ( track->par->width == 4096 && track->par->height == 2160
1890 || track->par->width == 3840 && track->par->height == 2160
1891 || track->par->width == 2048 && track->par->height == 1080) {
1892 tag = MKTAG('a','i','v','x');
1893 }
1894 }
1895
1896 2 return tag;
1897 }
1898
1899 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
1900 {
1901 int tag = track->par->codec_tag;
1902
1903 if (!tag)
1904 tag = MKTAG('e', 'v', 'c', '1');
1905
1906 return tag;
1907 }
1908
1909 static const struct {
1910 enum AVPixelFormat pix_fmt;
1911 uint32_t tag;
1912 unsigned bps;
1913 } mov_pix_fmt_tags[] = {
1914 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
1915 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
1916 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
1917 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
1918 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
1919 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
1920 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
1921 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
1922 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
1923 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
1924 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
1925 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
1926 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
1927 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
1928 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
1929 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
1930 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
1931 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
1932 };
1933
1934 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
1935 {
1936 23 int tag = MKTAG('A','V','d','n');
1937
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
1938
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
1939 12 tag = MKTAG('A','V','d','h');
1940 23 return tag;
1941 }
1942
1943 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
1944 {
1945 17 int tag = track->par->codec_tag;
1946 int i;
1947 enum AVPixelFormat pix_fmt;
1948
1949
2/2
✓ Branch 0 taken 252 times.
✓ Branch 1 taken 12 times.
264 for (i = 0; i < FF_ARRAY_ELEMS(mov_pix_fmt_tags); i++) {
1950
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
1951 17 tag = mov_pix_fmt_tags[i].tag;
1952 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
1953
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
1954 5 break;
1955 }
1956 }
1957
1958 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
1959 17 track->par->bits_per_coded_sample);
1960
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
1961
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
1962 track->par->format != AV_PIX_FMT_GRAY8 &&
1963 track->par->format != AV_PIX_FMT_NONE)
1964 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
1965 av_get_pix_fmt_name(track->par->format));
1966 17 return tag;
1967 }
1968
1969 165 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
1970 {
1971 165 unsigned int tag = track->par->codec_tag;
1972
1973 // "rtp " is used to distinguish internally created RTP-hint tracks
1974 // (with rtp_ctx) from other tracks.
1975
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
165 if (tag == MKTAG('r','t','p',' '))
1976 tag = 0;
1977
3/4
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 129 times.
✓ Branch 3 taken 36 times.
165 if (!tag || (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL &&
1978
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 1 times.
129 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
1979
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 17 times.
128 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
1980
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 track->par->codec_id == AV_CODEC_ID_H263 ||
1981
2/2
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 2 times.
111 track->par->codec_id == AV_CODEC_ID_H264 ||
1982
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 23 times.
109 track->par->codec_id == AV_CODEC_ID_DNXHD ||
1983
4/4
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 18 times.
✓ Branch 3 taken 67 times.
171 track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO ||
1984 85 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
1985
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
1986 1 tag = mov_get_dv_codec_tag(s, track);
1987
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
1988 17 tag = mov_get_rawvideo_codec_tag(s, track);
1989
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
1990 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
1991
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
1992 2 tag = mov_get_h264_codec_tag(s, track);
1993
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
1994 tag = mov_get_evc_codec_tag(s, track);
1995
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
1996 23 tag = mov_get_dnxhd_codec_tag(s, track);
1997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
1998 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
1999 if (!tag) { // if no mac fcc found, try with Microsoft tags
2000 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
2001 if (tag)
2002 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
2003 "the file may be unplayable!\n");
2004 }
2005
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
2006 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
2007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
2008 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
2009 if (ms_tag) {
2010 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
2011 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
2012 "the file may be unplayable!\n");
2013 }
2014 }
2015 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2016 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
2017 }
2018
2019 165 return tag;
2020 }
2021
2022 static const AVCodecTag codec_cover_image_tags[] = {
2023 { AV_CODEC_ID_MJPEG, 0xD },
2024 { AV_CODEC_ID_PNG, 0xE },
2025 { AV_CODEC_ID_BMP, 0x1B },
2026 { AV_CODEC_ID_NONE, 0 },
2027 };
2028
2029 95 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
2030 unsigned int tag, int codec_id)
2031 {
2032 int i;
2033
2034 /**
2035 * Check that tag + id is in the table
2036 */
2037
2/4
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 95 times.
✗ Branch 3 not taken.
95 for (i = 0; tags && tags[i]; i++) {
2038 95 const AVCodecTag *codec_tags = tags[i];
2039
1/2
✓ Branch 0 taken 1298 times.
✗ Branch 1 not taken.
1298 while (codec_tags->id != AV_CODEC_ID_NONE) {
2040
2/2
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 1191 times.
1298 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2041
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 12 times.
107 codec_tags->id == codec_id)
2042 95 return codec_tags->tag;
2043 1203 codec_tags++;
2044 }
2045 }
2046 return 0;
2047 }
2048
2049 262 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2050 {
2051
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 260 times.
262 if (is_cover_image(track->st))
2052 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2053
2054
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 259 times.
260 if (track->mode == MODE_IPOD)
2055
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
2 if (!av_match_ext(s->url, "m4a") &&
2056
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2057 1 !av_match_ext(s->url, "m4b"))
2058 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2059 "Quicktime/Ipod might not play the file\n");
2060
2061
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 95 times.
260 if (track->mode == MODE_MOV) {
2062 165 return mov_get_codec_tag(s, track);
2063 } else
2064 95 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2065 95 track->par->codec_id);
2066 }
2067
2068 /** Write uuid atom.
2069 * Needed to make file play in iPods running newest firmware
2070 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2071 */
2072 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2073 {
2074 avio_wb32(pb, 28);
2075 ffio_wfourcc(pb, "uuid");
2076 avio_wb32(pb, 0x6b6840f2);
2077 avio_wb32(pb, 0x5f244fc5);
2078 avio_wb32(pb, 0xba39a51b);
2079 avio_wb32(pb, 0xcf0323f3);
2080 avio_wb32(pb, 0x0);
2081 return 28;
2082 }
2083
2084 static const uint16_t fiel_data[] = {
2085 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2086 };
2087
2088 95 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2089 {
2090 95 unsigned mov_field_order = 0;
2091
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2092 95 mov_field_order = fiel_data[field_order];
2093 else
2094 return 0;
2095 95 avio_wb32(pb, 10);
2096 95 ffio_wfourcc(pb, "fiel");
2097 95 avio_wb16(pb, mov_field_order);
2098 95 return 10;
2099 }
2100
2101 4 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2102 {
2103 4 MOVMuxContext *mov = s->priv_data;
2104 4 int ret = AVERROR_BUG;
2105 4 int64_t pos = avio_tell(pb);
2106 4 avio_wb32(pb, 0); /* size */
2107 4 avio_wl32(pb, track->tag); // store it byteswapped
2108 4 avio_wb32(pb, 0); /* Reserved */
2109 4 avio_wb16(pb, 0); /* Reserved */
2110 4 avio_wb16(pb, 1); /* Data-reference index */
2111
2112
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2113 mov_write_esds_tag(pb, track);
2114
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2115
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (track->par->codec_tag) {
2116 1 case MOV_ISMV_TTML_TAG:
2117 // ISMV dfxp requires no extradata.
2118 2 break;
2119 1 case MOV_MP4_TTML_TAG:
2120 // As specified in 14496-30, XMLSubtitleSampleEntry
2121 // Namespace
2122 1 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2123 // Empty schema_location
2124 1 avio_w8(pb, 0);
2125 // Empty auxiliary_mime_types
2126 1 avio_w8(pb, 0);
2127 1 break;
2128 default:
2129 av_log(NULL, AV_LOG_ERROR,
2130 "Unknown codec tag '%s' utilized for TTML stream with "
2131 "index %d (track id %d)!\n",
2132 av_fourcc2str(track->par->codec_tag), track->st->index,
2133 track->track_id);
2134 return AVERROR(EINVAL);
2135 }
2136
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->par->extradata_size)
2137 2 avio_write(pb, track->par->extradata, track->par->extradata_size);
2138
2139
2/4
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
8 if (mov->write_btrt &&
2140 4 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2141 return ret;
2142
2143 4 return update_size(pb, pos);
2144 }
2145
2146 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2147 {
2148 int8_t stereo_mode;
2149
2150 if (stereo_3d->flags != 0) {
2151 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2152 return 0;
2153 }
2154
2155 switch (stereo_3d->type) {
2156 case AV_STEREO3D_2D:
2157 stereo_mode = 0;
2158 break;
2159 case AV_STEREO3D_TOPBOTTOM:
2160 stereo_mode = 1;
2161 break;
2162 case AV_STEREO3D_SIDEBYSIDE:
2163 stereo_mode = 2;
2164 break;
2165 default:
2166 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2167 return 0;
2168 }
2169 avio_wb32(pb, 13); /* size */
2170 ffio_wfourcc(pb, "st3d");
2171 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2172 avio_w8(pb, stereo_mode);
2173 return 13;
2174 }
2175
2176 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2177 {
2178 int64_t sv3d_pos, svhd_pos, proj_pos;
2179 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2180
2181 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2182 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2183 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2184 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2185 return 0;
2186 }
2187
2188 sv3d_pos = avio_tell(pb);
2189 avio_wb32(pb, 0); /* size */
2190 ffio_wfourcc(pb, "sv3d");
2191
2192 svhd_pos = avio_tell(pb);
2193 avio_wb32(pb, 0); /* size */
2194 ffio_wfourcc(pb, "svhd");
2195 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2196 avio_put_str(pb, metadata_source);
2197 update_size(pb, svhd_pos);
2198
2199 proj_pos = avio_tell(pb);
2200 avio_wb32(pb, 0); /* size */
2201 ffio_wfourcc(pb, "proj");
2202
2203 avio_wb32(pb, 24); /* size */
2204 ffio_wfourcc(pb, "prhd");
2205 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2206 avio_wb32(pb, spherical_mapping->yaw);
2207 avio_wb32(pb, spherical_mapping->pitch);
2208 avio_wb32(pb, spherical_mapping->roll);
2209
2210 switch (spherical_mapping->projection) {
2211 case AV_SPHERICAL_EQUIRECTANGULAR:
2212 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2213 avio_wb32(pb, 28); /* size */
2214 ffio_wfourcc(pb, "equi");
2215 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2216 avio_wb32(pb, spherical_mapping->bound_top);
2217 avio_wb32(pb, spherical_mapping->bound_bottom);
2218 avio_wb32(pb, spherical_mapping->bound_left);
2219 avio_wb32(pb, spherical_mapping->bound_right);
2220 break;
2221 case AV_SPHERICAL_CUBEMAP:
2222 avio_wb32(pb, 20); /* size */
2223 ffio_wfourcc(pb, "cbmp");
2224 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2225 avio_wb32(pb, 0); /* layout */
2226 avio_wb32(pb, spherical_mapping->padding); /* padding */
2227 break;
2228 }
2229 update_size(pb, proj_pos);
2230
2231 return update_size(pb, sv3d_pos);
2232 }
2233
2234 5 static inline int64_t rescale_rational(AVRational q, int b)
2235 {
2236 5 return av_rescale(q.num, b, q.den);
2237 }
2238
2239 1 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2240 const AVStereo3D *stereo3d)
2241 {
2242
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!stereo3d->horizontal_field_of_view.num)
2243 return;
2244
2245 1 avio_wb32(pb, 12); /* size */
2246 1 ffio_wfourcc(pb, "hfov");
2247 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2248 }
2249
2250 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2251 const AVSphericalMapping *spherical_mapping)
2252 {
2253 1 avio_wb32(pb, 24); /* size */
2254 1 ffio_wfourcc(pb, "proj");
2255 1 avio_wb32(pb, 16); /* size */
2256 1 ffio_wfourcc(pb, "prji");
2257 1 avio_wb32(pb, 0); /* version + flags */
2258
2259
1/5
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
1 switch (spherical_mapping->projection) {
2260 1 case AV_SPHERICAL_RECTILINEAR:
2261 1 ffio_wfourcc(pb, "rect");
2262 1 break;
2263 case AV_SPHERICAL_EQUIRECTANGULAR:
2264 ffio_wfourcc(pb, "equi");
2265 break;
2266 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2267 ffio_wfourcc(pb, "hequ");
2268 break;
2269 case AV_SPHERICAL_FISHEYE:
2270 ffio_wfourcc(pb, "fish");
2271 break;
2272 default:
2273 av_assert0(0);
2274 }
2275 1 }
2276
2277 1 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2278 const AVStereo3D *stereo3d)
2279 {
2280 1 int64_t pos = avio_tell(pb);
2281 1 int view = 0;
2282
2283 1 avio_wb32(pb, 0); /* size */
2284 1 ffio_wfourcc(pb, "eyes");
2285
2286 // stri is mandatory
2287 1 avio_wb32(pb, 13); /* size */
2288 1 ffio_wfourcc(pb, "stri");
2289 1 avio_wb32(pb, 0); /* version + flags */
2290
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo3d->view) {
2291 case AV_STEREO3D_VIEW_LEFT:
2292 view |= 1 << 0;
2293 break;
2294 case AV_STEREO3D_VIEW_RIGHT:
2295 view |= 1 << 1;
2296 break;
2297 1 case AV_STEREO3D_VIEW_PACKED:
2298 1 view |= (1 << 0) | (1 << 1);
2299 1 break;
2300 }
2301 1 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2302 1 avio_w8(pb, view);
2303
2304 // hero is optional
2305
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2306 avio_wb32(pb, 13); /* size */
2307 ffio_wfourcc(pb, "hero");
2308 avio_wb32(pb, 0); /* version + flags */
2309 avio_w8(pb, stereo3d->primary_eye);
2310 }
2311
2312 // it's not clear if cams is mandatory or optional
2313
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->baseline) {
2314 1 avio_wb32(pb, 24); /* size */
2315 1 ffio_wfourcc(pb, "cams");
2316 1 avio_wb32(pb, 16); /* size */
2317 1 ffio_wfourcc(pb, "blin");
2318 1 avio_wb32(pb, 0); /* version + flags */
2319 1 avio_wb32(pb, stereo3d->baseline);
2320 }
2321
2322 // it's not clear if cmfy is mandatory or optional
2323
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->horizontal_disparity_adjustment.num) {
2324 1 avio_wb32(pb, 24); /* size */
2325 1 ffio_wfourcc(pb, "cmfy");
2326 1 avio_wb32(pb, 16); /* size */
2327 1 ffio_wfourcc(pb, "dadj");
2328 1 avio_wb32(pb, 0); /* version + flags */
2329 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2330 }
2331
2332 1 return update_size(pb, pos);
2333 }
2334
2335 1 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2336 const AVStereo3D *stereo3d,
2337 const AVSphericalMapping *spherical_mapping)
2338 {
2339 int64_t pos;
2340
2341
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping &&
2342
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2343 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2344 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2345 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2346 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2347 spherical_mapping->projection);
2348 spherical_mapping = NULL;
2349 }
2350
2351
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 if (stereo3d && (stereo3d->type == AV_STEREO3D_2D ||
2352
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2353
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2354 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2355 !stereo3d->baseline &&
2356 !stereo3d->horizontal_disparity_adjustment.num))) {
2357 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2358 stereo3d = NULL;
2359 }
2360
2361
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!spherical_mapping && !stereo3d)
2362 return 0;
2363
2364 1 pos = avio_tell(pb);
2365 1 avio_wb32(pb, 0); /* size */
2366 1 ffio_wfourcc(pb, "vexu");
2367
2368
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping)
2369 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2370
2371
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d)
2372 1 mov_write_eyes_tag(s, pb, stereo3d);
2373
2374 1 return update_size(pb, pos);
2375 }
2376
2377 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2378 {
2379 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2380
2381 avio_wb32(pb, 32); /* size = 8 + 24 */
2382 if (dovi->dv_profile > 10)
2383 ffio_wfourcc(pb, "dvwC");
2384 else if (dovi->dv_profile > 7)
2385 ffio_wfourcc(pb, "dvvC");
2386 else
2387 ffio_wfourcc(pb, "dvcC");
2388
2389 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2390 avio_write(pb, buf, sizeof(buf));
2391
2392 return 32; /* 8 + 24 */
2393 }
2394
2395 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2396 uint32_t top, uint32_t bottom,
2397 uint32_t left, uint32_t right)
2398 {
2399 5 uint32_t cropped_width = track->par->width - left - right;
2400 5 uint32_t cropped_height = track->height - top - bottom;
2401 AVRational horizOff =
2402 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2403 5 (AVRational) { left, 1 });
2404 AVRational vertOff =
2405 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2406 5 (AVRational) { top, 1 });
2407
2408 5 avio_wb32(pb, 40);
2409 5 ffio_wfourcc(pb, "clap");
2410 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2411 5 avio_wb32(pb, 1); /* apertureWidthD */
2412 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2413 5 avio_wb32(pb, 1); /* apertureHeightD */
2414
2415 5 avio_wb32(pb, -horizOff.num);
2416 5 avio_wb32(pb, horizOff.den);
2417 5 avio_wb32(pb, -vertOff.num);
2418 5 avio_wb32(pb, vertOff.den);
2419
2420 5 return 40;
2421 }
2422
2423 6 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2424 {
2425 AVRational sar;
2426 6 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2427 6 track->par->sample_aspect_ratio.den, INT_MAX);
2428
2429 6 avio_wb32(pb, 16);
2430 6 ffio_wfourcc(pb, "pasp");
2431 6 avio_wb32(pb, sar.num);
2432 6 avio_wb32(pb, sar.den);
2433 6 return 16;
2434 }
2435
2436 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2437 {
2438 uint32_t gama = 0;
2439 if (gamma <= 0.0)
2440 gamma = av_csp_approximate_trc_gamma(track->par->color_trc);
2441 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2442
2443 if (gamma > 1e-6) {
2444 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2445 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2446
2447 av_assert0(track->mode == MODE_MOV);
2448 avio_wb32(pb, 12);
2449 ffio_wfourcc(pb, "gama");
2450 avio_wb32(pb, gama);
2451 return 12;
2452 } else {
2453 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2454 }
2455 return 0;
2456 }
2457
2458 9 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2459 {
2460 9 int64_t pos = avio_tell(pb);
2461
2462 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2463 // Ref (MP4): ISO/IEC 14496-12:2012
2464
2465
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 if (prefer_icc) {
2466 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2467 4 track->st->codecpar->nb_coded_side_data,
2468 AV_PKT_DATA_ICC_PROFILE);
2469
2470
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2471 avio_wb32(pb, 12 + sd->size);
2472 ffio_wfourcc(pb, "colr");
2473 ffio_wfourcc(pb, "prof");
2474 avio_write(pb, sd->data, sd->size);
2475 return 12 + sd->size;
2476 }
2477 else {
2478 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2479 }
2480 }
2481
2482 /* We should only ever be called for MOV, MP4 and AVIF. */
2483
3/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
9 av_assert0(track->mode == MODE_MOV || track->mode == MODE_MP4 ||
2484 track->mode == MODE_AVIF);
2485
2486 9 avio_wb32(pb, 0); /* size */
2487 9 ffio_wfourcc(pb, "colr");
2488
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF)
2489 1 ffio_wfourcc(pb, "nclx");
2490 else
2491 8 ffio_wfourcc(pb, "nclc");
2492 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2493 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2494 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2495 9 avio_wb16(pb, track->par->color_primaries);
2496 9 avio_wb16(pb, track->par->color_trc);
2497 9 avio_wb16(pb, track->par->color_space);
2498
3/4
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 8 times.
9 if (track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2499 1 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2500 1 avio_w8(pb, full_range << 7);
2501 }
2502
2503 9 return update_size(pb, pos);
2504 }
2505
2506 200 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2507 {
2508 const AVPacketSideData *side_data;
2509 const AVContentLightMetadata *content_light_metadata;
2510
2511 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2512 200 track->st->codecpar->nb_coded_side_data,
2513 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2514
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (!side_data) {
2515 200 return 0;
2516 }
2517 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2518
2519 avio_wb32(pb, 12); // size
2520 ffio_wfourcc(pb, "clli");
2521 avio_wb16(pb, content_light_metadata->MaxCLL);
2522 avio_wb16(pb, content_light_metadata->MaxFALL);
2523 return 12;
2524 }
2525
2526 200 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2527 {
2528 200 const int chroma_den = 50000;
2529 200 const int luma_den = 10000;
2530 const AVPacketSideData *side_data;
2531 200 const AVMasteringDisplayMetadata *metadata = NULL;
2532
2533 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2534 200 track->st->codecpar->nb_coded_side_data,
2535 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2536
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if (side_data)
2537 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2538
1/6
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
200 if (!metadata || !metadata->has_primaries || !metadata->has_luminance) {
2539 200 return 0;
2540 }
2541
2542 avio_wb32(pb, 32); // size
2543 ffio_wfourcc(pb, "mdcv");
2544 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2545 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2546 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2547 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2548 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2549 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2550 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2551 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2552 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2553 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2554 return 32;
2555 }
2556
2557 200 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2558 {
2559 200 const int illuminance_den = 10000;
2560 200 const int ambient_den = 50000;
2561 const AVPacketSideData *side_data;
2562 const AVAmbientViewingEnvironment *ambient;
2563
2564
2565 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2566 200 track->st->codecpar->nb_coded_side_data,
2567 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2568
2569
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 1 times.
200 if (!side_data)
2570 199 return 0;
2571
2572 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2573
2/4
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
1 if (!ambient || !ambient->ambient_illuminance.num)
2574 return 0;
2575
2576 1 avio_wb32(pb, 16); // size
2577 1 ffio_wfourcc(pb, "amve");
2578 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2579 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2580 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2581 1 return 16;
2582 }
2583
2584 205 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2585 {
2586 AVDictionaryEntry *encoder;
2587
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2588
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 204 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
204 || (track->par->width == 1440 && track->par->height == 1080)
2589
5/6
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 204 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 191 times.
✓ Branch 4 taken 13 times.
✗ Branch 5 not taken.
410 || (track->par->width == 1920 && track->par->height == 1080);
2590
2591
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 if ((track->mode == MODE_AVIF ||
2592
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
205 track->mode == MODE_MOV ||
2593
4/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 145 times.
✓ Branch 3 taken 55 times.
267 track->mode == MODE_MP4) &&
2594 200 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2595 145 av_strlcpy(compressor_name, encoder->value, 32);
2596
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
60 } else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO && xdcam_res) {
2597 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2598 AVStream *st = track->st;
2599 int rate = defined_frame_rate(NULL, st);
2600 av_strlcatf(compressor_name, len, "XDCAM");
2601 if (track->par->format == AV_PIX_FMT_YUV422P) {
2602 av_strlcatf(compressor_name, len, " HD422");
2603 } else if(track->par->width == 1440) {
2604 av_strlcatf(compressor_name, len, " HD");
2605 } else
2606 av_strlcatf(compressor_name, len, " EX");
2607
2608 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2609
2610 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2611 }
2612 205 }
2613
2614 static int mov_write_ccst_tag(AVIOContext *pb)
2615 {
2616 int64_t pos = avio_tell(pb);
2617 // Write sane defaults:
2618 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2619 // intra_pred_used = 1 : intra prediction may or may not be used.
2620 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2621 // reference images can be used.
2622 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2623 (1 << 6) | /* intra_pred_used */
2624 (15 << 2); /* max_ref_per_pic */
2625 avio_wb32(pb, 0); /* size */
2626 ffio_wfourcc(pb, "ccst");
2627 avio_wb32(pb, 0); /* Version & flags */
2628 avio_w8(pb, ccstValue);
2629 avio_wb24(pb, 0); /* reserved */
2630 return update_size(pb, pos);
2631 }
2632
2633 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2634 {
2635 int64_t pos = avio_tell(pb);
2636 avio_wb32(pb, 0); /* size */
2637 ffio_wfourcc(pb, aux_type);
2638 avio_wb32(pb, 0); /* Version & flags */
2639 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2640 return update_size(pb, pos);
2641 }
2642
2643 205 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2644 {
2645 205 int ret = AVERROR_BUG;
2646 205 int64_t pos = avio_tell(pb);
2647 const AVPacketSideData *sd;
2648 205 char compressor_name[32] = { 0 };
2649 205 int avid = 0;
2650
2651
1/2
✓ Branch 0 taken 17 times.
✗ Branch 1 not taken.
17 int uncompressed_ycbcr = ((track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVY422)
2652
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_YUYV422)
2653
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_VYU444)
2654
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 17 times.
✗ Branch 3 not taken.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_UYVA)
2655
4/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✓ Branch 2 taken 13 times.
✓ Branch 3 taken 4 times.
205 || (track->par->codec_id == AV_CODEC_ID_RAWVIDEO && track->par->format == AV_PIX_FMT_V30XLE)
2656 #if FF_API_V408_CODECID
2657
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V308
2658
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V408
2659
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V410
2660 #endif
2661
3/4
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 188 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 201 times.
410 || track->par->codec_id == AV_CODEC_ID_V210);
2662
2663 205 avio_wb32(pb, 0); /* size */
2664
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->encryption_scheme != MOV_ENC_NONE) {
2665 ffio_wfourcc(pb, "encv");
2666 } else {
2667 205 avio_wl32(pb, track->tag); // store it byteswapped
2668 }
2669 205 avio_wb32(pb, 0); /* Reserved */
2670 205 avio_wb16(pb, 0); /* Reserved */
2671 205 avio_wb16(pb, 1); /* Data-reference index */
2672
2673
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 201 times.
205 if (uncompressed_ycbcr) {
2674 4 avio_wb16(pb, 2); /* Codec stream version */
2675 } else {
2676 201 avio_wb16(pb, 0); /* Codec stream version */
2677 }
2678 205 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2679
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
205 if (track->mode == MODE_MOV) {
2680 138 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2681
3/4
✓ Branch 0 taken 121 times.
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 121 times.
138 if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO || uncompressed_ycbcr) {
2682 17 avio_wb32(pb, 0); /* Temporal Quality */
2683 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2684 } else {
2685 121 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2686 121 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2687 }
2688 } else {
2689 67 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2690 }
2691 205 avio_wb16(pb, track->par->width); /* Video width */
2692 205 avio_wb16(pb, track->height); /* Video height */
2693 205 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2694 205 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2695 205 avio_wb32(pb, 0); /* Data size (= 0) */
2696 205 avio_wb16(pb, 1); /* Frame count (= 1) */
2697
2698 205 find_compressor(compressor_name, 32, track);
2699 205 avio_w8(pb, strlen(compressor_name));
2700 205 avio_write(pb, compressor_name, 31);
2701
2702
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
205 if (track->mode == MODE_MOV &&
2703
2/4
✓ Branch 0 taken 138 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 138 times.
138 (track->par->codec_id == AV_CODEC_ID_V410 || track->par->codec_id == AV_CODEC_ID_V210))
2704 avio_wb16(pb, 0x18);
2705
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 31 times.
✓ Branch 3 taken 107 times.
205 else if (track->mode == MODE_MOV && track->par->bits_per_coded_sample)
2706 31 avio_wb16(pb, track->par->bits_per_coded_sample |
2707
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 28 times.
31 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2708 else
2709 174 avio_wb16(pb, 0x18); /* Reserved */
2710
2711
4/4
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 133 times.
210 if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) {
2712 int pal_size, i;
2713 5 avio_wb16(pb, 0); /* Color table ID */
2714 5 avio_wb32(pb, 0); /* Color table seed */
2715 5 avio_wb16(pb, 0x8000); /* Color table flags */
2716
2/4
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
5 if (track->par->bits_per_coded_sample < 0 || track->par->bits_per_coded_sample > 8)
2717 return AVERROR(EINVAL);
2718 5 pal_size = 1 << track->par->bits_per_coded_sample;
2719 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2720
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2721 1040 uint32_t rgb = track->palette[i];
2722 1040 uint16_t r = (rgb >> 16) & 0xff;
2723 1040 uint16_t g = (rgb >> 8) & 0xff;
2724 1040 uint16_t b = rgb & 0xff;
2725 1040 avio_wb16(pb, 0);
2726 1040 avio_wb16(pb, (r << 8) | r);
2727 1040 avio_wb16(pb, (g << 8) | g);
2728 1040 avio_wb16(pb, (b << 8) | b);
2729 }
2730 } else
2731 200 avio_wb16(pb, 0xffff); /* Reserved */
2732
2733
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 180 times.
205 if (track->tag == MKTAG('m','p','4','v'))
2734 25 mov_write_esds_tag(pb, track);
2735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 else if (track->par->codec_id == AV_CODEC_ID_H263)
2736 mov_write_d263_tag(pb);
2737
2/2
✓ Branch 0 taken 177 times.
✓ Branch 1 taken 3 times.
180 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2738
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 177 times.
177 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2739 3 mov_write_extradata_tag(pb, track);
2740 3 avio_wb32(pb, 0);
2741
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 154 times.
177 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2742 23 mov_write_avid_tag(pb, track);
2743 23 avid = 1;
2744
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 151 times.
154 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2745 3 mov_write_hvcc_tag(mov->fc, pb, track);
2746
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2747 1 ret = mov_write_lhvc_tag(mov->fc, pb, track);
2748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2749 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2750 }
2751
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 150 times.
151 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2752 1 mov_write_vvcc_tag(pb, track);
2753
16/30
✓ Branch 0 taken 53 times.
✓ Branch 1 taken 97 times.
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 53 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 53 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 53 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 53 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 53 times.
✗ Branch 13 not taken.
✓ Branch 14 taken 53 times.
✗ Branch 15 not taken.
✓ Branch 16 taken 53 times.
✗ Branch 17 not taken.
✓ Branch 18 taken 53 times.
✗ Branch 19 not taken.
✓ Branch 20 taken 53 times.
✗ Branch 21 not taken.
✓ Branch 22 taken 53 times.
✗ Branch 23 not taken.
✓ Branch 24 taken 53 times.
✗ Branch 25 not taken.
✓ Branch 26 taken 53 times.
✗ Branch 27 not taken.
✓ Branch 28 taken 53 times.
✗ Branch 29 not taken.
150 else if (track->par->codec_id == AV_CODEC_ID_H264 && !TAG_IS_AVCI(track->tag)) {
2754 53 mov_write_avcc_tag(pb, track);
2755
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (track->mode == MODE_IPOD)
2756 mov_write_uuid_tag_ipod(pb);
2757 }
2758
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 96 times.
97 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2759 1 mov_write_evcc_tag(pb, track);
2760
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2761 mov_write_vpcc_tag(mov->fc, pb, track);
2762
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
96 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2763 1 mov_write_av1c_tag(pb, track);
2764
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
95 } else if (track->par->codec_id == AV_CODEC_ID_VC1 && track->vos_len > 0)
2765 mov_write_dvc1_tag(pb, track);
2766
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2767
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 track->par->codec_id == AV_CODEC_ID_VP6A) {
2768 /* Don't write any potential extradata here - the cropping
2769 * is signalled via the normal width/height fields. */
2770
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2771 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2772 mov_write_dpxe_tag(pb, track);
2773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 } else if (track->par->codec_id == AV_CODEC_ID_AVS3) {
2774 mov_write_av3c_tag(pb, track);
2775
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 91 times.
95 } else if (track->vos_len > 0)
2776 4 mov_write_glbl_tag(pb, track);
2777
2778
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 53 times.
205 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2779
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 25 times.
152 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2780
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 23 times.
127 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2781 104 int field_order = track->par->field_order;
2782
2783
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 9 times.
104 if (field_order != AV_FIELD_UNKNOWN)
2784 95 mov_write_fiel_tag(pb, track, field_order);
2785 }
2786
2787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2788 if (track->mode == MODE_MOV)
2789 mov_write_gama_tag(s, pb, track, mov->gamma);
2790 else
2791 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2792 }
2793
5/6
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 62 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5 times.
405 if (track->mode == MODE_MOV || track->mode == MODE_MP4 || track->mode == MODE_AVIF) {
2794 405 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2795
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 195 times.
✓ Branch 2 taken 5 times.
✗ Branch 3 not taken.
205 track->par->color_trc != AVCOL_TRC_UNSPECIFIED &&
2796
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2797
5/6
✓ Branch 0 taken 195 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 191 times.
✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 191 times.
391 if (has_color_info || mov->flags & FF_MOV_FLAG_WRITE_COLR ||
2798 191 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2799 AV_PKT_DATA_ICC_PROFILE)) {
2800
3/4
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5 times.
9 int prefer_icc = mov->flags & FF_MOV_FLAG_PREFER_ICC || !has_color_info;
2801 9 mov_write_colr_tag(pb, track, prefer_icc);
2802 }
2803
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2804 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2805 }
2806
2807
4/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 5 times.
205 if (track->mode == MODE_MOV || track->mode == MODE_MP4) {
2808 200 mov_write_clli_tag(pb, track);
2809 200 mov_write_mdcv_tag(pb, track);
2810 200 mov_write_amve_tag(pb, track);
2811 }
2812
2813
3/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62 times.
205 if (track->mode == MODE_MP4 && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2814 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2815 track->st->codecpar->nb_coded_side_data,
2816 AV_PKT_DATA_STEREO3D);
2817 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2818 track->st->codecpar->nb_coded_side_data,
2819 AV_PKT_DATA_SPHERICAL);
2820 if (stereo_3d)
2821 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2822 if (spherical_mapping)
2823 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2824 }
2825
2826
4/4
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
✓ Branch 2 taken 62 times.
✓ Branch 3 taken 5 times.
205 if (track->mode == MODE_MOV || (track->mode == MODE_MP4 &&
2827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
2828 138 const AVStereo3D *stereo3d = NULL;
2829 138 const AVSphericalMapping *spherical_mapping = NULL;
2830
2831 138 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2832 138 track->st->codecpar->nb_coded_side_data,
2833 AV_PKT_DATA_STEREO3D);
2834
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (sd)
2835 1 stereo3d = (AVStereo3D *)sd->data;
2836
2837 138 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2838 138 track->st->codecpar->nb_coded_side_data,
2839 AV_PKT_DATA_SPHERICAL);
2840
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (sd)
2841 1 spherical_mapping = (AVSphericalMapping *)sd->data;
2842
2843
3/4
✓ Branch 0 taken 137 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 137 times.
138 if (stereo3d || spherical_mapping)
2844 1 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
2845
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (stereo3d)
2846 1 mov_write_hfov_tag(s, pb, stereo3d);
2847 }
2848
2849
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
205 if (track->mode == MODE_MP4) {
2850 62 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2851 62 track->st->codecpar->nb_coded_side_data,
2852 AV_PKT_DATA_DOVI_CONF);
2853
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
62 if (dovi && mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL) {
2854 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 } else if (dovi) {
2856 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2857 }
2858 }
2859
2860
3/4
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 199 times.
205 if (track->par->sample_aspect_ratio.den && track->par->sample_aspect_ratio.num) {
2861 6 mov_write_pasp_tag(pb, track);
2862 }
2863
2864 205 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2865 205 track->st->codecpar->nb_coded_side_data,
2866 AV_PKT_DATA_FRAME_CROPPING);
2867
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 204 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
206 if (sd && sd->size >= sizeof(uint32_t) * 4) {
2868 1 uint64_t top = AV_RL32(sd->data + 0);
2869 1 uint64_t bottom = AV_RL32(sd->data + 4);
2870 1 uint64_t left = AV_RL32(sd->data + 8);
2871 1 uint64_t right = AV_RL32(sd->data + 12);
2872
2873
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
2874
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
2875 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
2876 return AVERROR(EINVAL);
2877 }
2878
3/8
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
1 if (top || bottom || left || right)
2879 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
2880
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 200 times.
204 } else if (uncompressed_ycbcr)
2881 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
2882
2883
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->encryption_scheme != MOV_ENC_NONE) {
2884 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
2885 }
2886
2887
3/4
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 62 times.
267 if (mov->write_btrt &&
2888 62 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2889 return ret;
2890
2891 /* extra padding for avid stsd */
2892 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
2893
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 182 times.
205 if (avid)
2894 23 avio_wb32(pb, 0);
2895
2896
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (track->mode == MODE_AVIF) {
2897 mov_write_ccst_tag(pb);
2898 if (mov->nb_streams > 0 && track == &mov->tracks[1])
2899 mov_write_aux_tag(pb, "auxi");
2900 }
2901
2902 205 return update_size(pb, pos);
2903 }
2904
2905 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
2906 {
2907 2 int64_t pos = avio_tell(pb);
2908 2 avio_wb32(pb, 0); /* size */
2909 2 ffio_wfourcc(pb, "rtp ");
2910 2 avio_wb32(pb, 0); /* Reserved */
2911 2 avio_wb16(pb, 0); /* Reserved */
2912 2 avio_wb16(pb, 1); /* Data-reference index */
2913
2914 2 avio_wb16(pb, 1); /* Hint track version */
2915 2 avio_wb16(pb, 1); /* Highest compatible version */
2916 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
2917
2918 2 avio_wb32(pb, 12); /* size */
2919 2 ffio_wfourcc(pb, "tims");
2920 2 avio_wb32(pb, track->timescale);
2921
2922 2 return update_size(pb, pos);
2923 }
2924
2925 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
2926 {
2927 2 uint64_t str_size =strlen(reel_name);
2928 2 int64_t pos = avio_tell(pb);
2929
2930
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
2931 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
2932 avio_wb16(pb, 0);
2933 return AVERROR(EINVAL);
2934 }
2935
2936 2 avio_wb32(pb, 0); /* size */
2937 2 ffio_wfourcc(pb, "name"); /* Data format */
2938 2 avio_wb16(pb, str_size); /* string size */
2939 2 avio_wb16(pb, track->language); /* langcode */
2940 2 avio_write(pb, reel_name, str_size); /* reel name */
2941 2 return update_size(pb,pos);
2942 }
2943
2944 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
2945 {
2946 13 int64_t pos = avio_tell(pb);
2947 #if 1
2948 int frame_duration;
2949 int nb_frames;
2950 13 AVDictionaryEntry *t = NULL;
2951
2952
2/4
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
13 if (!track->st->avg_frame_rate.num || !track->st->avg_frame_rate.den) {
2953 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
2954 return AVERROR(EINVAL);
2955 } else {
2956 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
2957
1/2
✓ Branch 0 taken 13 times.
✗ Branch 1 not taken.
13 nb_frames = ROUNDED_DIV(track->st->avg_frame_rate.num, track->st->avg_frame_rate.den);
2958 }
2959
2960
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
2961 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
2962 return AVERROR(EINVAL);
2963 }
2964
2965 13 avio_wb32(pb, 0); /* size */
2966 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
2967 13 avio_wb32(pb, 0); /* Reserved */
2968 13 avio_wb32(pb, 1); /* Data reference index */
2969 13 avio_wb32(pb, 0); /* Flags */
2970 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
2971 13 avio_wb32(pb, track->timescale); /* Timescale */
2972 13 avio_wb32(pb, frame_duration); /* Frame duration */
2973 13 avio_w8(pb, nb_frames); /* Number of frames */
2974 13 avio_w8(pb, 0); /* Reserved */
2975
2976 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
2977
4/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 11 times.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
13 if (t && utf8len(t->value) && track->mode != MODE_MP4)
2978 2 mov_write_source_reference_tag(pb, track, t->value);
2979 else
2980 11 avio_wb16(pb, 0); /* zero size */
2981 #else
2982
2983 avio_wb32(pb, 0); /* size */
2984 ffio_wfourcc(pb, "tmcd"); /* Data format */
2985 avio_wb32(pb, 0); /* Reserved */
2986 avio_wb32(pb, 1); /* Data reference index */
2987 if (track->par->extradata_size)
2988 avio_write(pb, track->par->extradata, track->par->extradata_size);
2989 #endif
2990 13 return update_size(pb, pos);
2991 }
2992
2993 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
2994 {
2995 1 int64_t pos = avio_tell(pb);
2996 1 avio_wb32(pb, 0); /* size */
2997 1 ffio_wfourcc(pb, "gpmd");
2998 1 avio_wb32(pb, 0); /* Reserved */
2999 1 avio_wb16(pb, 0); /* Reserved */
3000 1 avio_wb16(pb, 1); /* Data-reference index */
3001 1 avio_wb32(pb, 0); /* Reserved */
3002 1 return update_size(pb, pos);
3003 }
3004
3005 333 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3006 {
3007 333 int64_t pos = avio_tell(pb);
3008 333 int ret = 0;
3009 333 avio_wb32(pb, 0); /* size */
3010 333 ffio_wfourcc(pb, "stsd");
3011 333 avio_wb32(pb, 0); /* version & flags */
3012 333 avio_wb32(pb, 1); /* entry count */
3013
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3014 205 ret = mov_write_video_tag(s, pb, mov, track);
3015
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3016 108 ret = mov_write_audio_tag(s, pb, mov, track);
3017
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
3018 4 ret = mov_write_subtitle_tag(s, pb, track);
3019
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
3020 2 ret = mov_write_rtp_tag(pb, track);
3021
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
3022 13 ret = mov_write_tmcd_tag(pb, track);
3023
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
3024 1 ret = mov_write_gpmd_tag(pb, track);
3025
3026
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (ret < 0)
3027 return ret;
3028
3029 333 return update_size(pb, pos);
3030 }
3031
3032 9 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3033 {
3034 9 MOVMuxContext *mov = s->priv_data;
3035 MOVCtts *ctts_entries;
3036 9 uint32_t entries = 0;
3037 uint32_t atom_size;
3038 int i;
3039
3040 9 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3041
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ctts_entries)
3042 return AVERROR(ENOMEM);
3043 9 ctts_entries[0].count = 1;
3044 9 ctts_entries[0].offset = track->cluster[0].cts;
3045
2/2
✓ Branch 0 taken 551 times.
✓ Branch 1 taken 9 times.
560 for (i = 1; i < track->entry; i++) {
3046
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 421 times.
551 if (track->cluster[i].cts == ctts_entries[entries].offset) {
3047 130 ctts_entries[entries].count++; /* compress */
3048 } else {
3049 421 entries++;
3050 421 ctts_entries[entries].offset = track->cluster[i].cts;
3051 421 ctts_entries[entries].count = 1;
3052 }
3053 }
3054 9 entries++; /* last one */
3055 9 atom_size = 16 + (entries * 8);
3056 9 avio_wb32(pb, atom_size); /* size */
3057 9 ffio_wfourcc(pb, "ctts");
3058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3059 avio_w8(pb, 1); /* version */
3060 else
3061 9 avio_w8(pb, 0); /* version */
3062 9 avio_wb24(pb, 0); /* flags */
3063 9 avio_wb32(pb, entries); /* entry count */
3064
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 9 times.
439 for (i = 0; i < entries; i++) {
3065 430 avio_wb32(pb, ctts_entries[i].count);
3066 430 avio_wb32(pb, ctts_entries[i].offset);
3067 }
3068 9 av_free(ctts_entries);
3069 9 return atom_size;
3070 }
3071
3072 /* Time to sample atom */
3073 333 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3074 {
3075 333 MOVStts *stts_entries = NULL;
3076 333 uint32_t entries = -1;
3077 uint32_t atom_size;
3078 int i;
3079
3080
4/4
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 75 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO && !track->audio_vbr) {
3081 33 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3082
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!stts_entries)
3083 return AVERROR(ENOMEM);
3084 33 stts_entries[0].count = track->sample_count;
3085 33 stts_entries[0].duration = 1;
3086 33 entries = 1;
3087 } else {
3088
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 90 times.
300 if (track->entry) {
3089 210 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3090
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (!stts_entries)
3091 return AVERROR(ENOMEM);
3092 }
3093
2/2
✓ Branch 0 taken 12206 times.
✓ Branch 1 taken 300 times.
12506 for (i = 0; i < track->entry; i++) {
3094 12206 int duration = get_cluster_duration(track, i);
3095 #if CONFIG_IAMFENC
3096
3/4
✓ Branch 0 taken 50 times.
✓ Branch 1 taken 12156 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 50 times.
12206 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
3097 duration = av_rescale(duration, 48000, track->par->sample_rate);
3098 #endif
3099
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) {
3100 11593 stts_entries[entries].count++; /* compress */
3101 } else {
3102 613 entries++;
3103 613 stts_entries[entries].duration = duration;
3104 613 stts_entries[entries].count = 1;
3105 }
3106 }
3107 300 entries++; /* last one */
3108 }
3109 333 atom_size = 16 + (entries * 8);
3110 333 avio_wb32(pb, atom_size); /* size */
3111 333 ffio_wfourcc(pb, "stts");
3112 333 avio_wb32(pb, 0); /* version & flags */
3113 333 avio_wb32(pb, entries); /* entry count */
3114
2/2
✓ Branch 0 taken 646 times.
✓ Branch 1 taken 333 times.
979 for (i = 0; i < entries; i++) {
3115 646 avio_wb32(pb, stts_entries[i].count);
3116 646 avio_wb32(pb, stts_entries[i].duration);
3117 }
3118 333 av_free(stts_entries);
3119 333 return atom_size;
3120 }
3121
3122 333 static int mov_write_dref_tag(AVIOContext *pb)
3123 {
3124 333 avio_wb32(pb, 28); /* size */
3125 333 ffio_wfourcc(pb, "dref");
3126 333 avio_wb32(pb, 0); /* version & flags */
3127 333 avio_wb32(pb, 1); /* entry count */
3128
3129 333 avio_wb32(pb, 0xc); /* size */
3130 //FIXME add the alis and rsrc atom
3131 333 ffio_wfourcc(pb, "url ");
3132 333 avio_wb32(pb, 1); /* version & flags */
3133
3134 333 return 28;
3135 }
3136
3137 53 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3138 {
3139 struct sgpd_entry {
3140 int count;
3141 int16_t roll_distance;
3142 int group_description_index;
3143 };
3144
3145 53 struct sgpd_entry *sgpd_entries = NULL;
3146 53 int entries = -1;
3147 53 int group = 0;
3148 int i, j;
3149
3150 53 const int OPUS_SEEK_PREROLL_MS = 80;
3151 53 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3152 53 (AVRational){1, 1000},
3153 53 (AVRational){1, 48000});
3154
3155
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 12 times.
53 if (!track->entry)
3156 41 return 0;
3157
3158 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
3160 return AVERROR(ENOMEM);
3161
3162
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);
3163
3164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3165 for (i = 0; i < track->entry; i++) {
3166 int roll_samples_remaining = roll_samples;
3167 int distance = 0;
3168 for (j = i - 1; j >= 0; j--) {
3169 roll_samples_remaining -= get_cluster_duration(track, j);
3170 distance++;
3171 if (roll_samples_remaining <= 0)
3172 break;
3173 }
3174 /* We don't have enough preceeding samples to compute a valid
3175 roll_distance here, so this sample can't be independently
3176 decoded. */
3177 if (roll_samples_remaining > 0)
3178 distance = 0;
3179 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3180 if (distance > 32)
3181 return AVERROR_INVALIDDATA;
3182 if (i && distance == sgpd_entries[entries].roll_distance) {
3183 sgpd_entries[entries].count++;
3184 } else {
3185 entries++;
3186 sgpd_entries[entries].count = 1;
3187 sgpd_entries[entries].roll_distance = distance;
3188 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3189 }
3190 }
3191 } else {
3192 12 entries++;
3193 12 sgpd_entries[entries].count = track->sample_count;
3194 12 sgpd_entries[entries].roll_distance = 1;
3195 12 sgpd_entries[entries].group_description_index = ++group;
3196 }
3197 12 entries++;
3198
3199
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
3200 av_free(sgpd_entries);
3201 return 0;
3202 }
3203
3204 /* Write sgpd tag */
3205 12 avio_wb32(pb, 24 + (group * 2)); /* size */
3206 12 ffio_wfourcc(pb, "sgpd");
3207 12 avio_wb32(pb, 1 << 24); /* fullbox */
3208 12 ffio_wfourcc(pb, "roll");
3209 12 avio_wb32(pb, 2); /* default_length */
3210 12 avio_wb32(pb, group); /* entry_count */
3211
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3212
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
3213 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3214 }
3215 }
3216
3217 /* Write sbgp tag */
3218 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
3219 12 ffio_wfourcc(pb, "sbgp");
3220 12 avio_wb32(pb, 0); /* fullbox */
3221 12 ffio_wfourcc(pb, "roll");
3222 12 avio_wb32(pb, entries); /* entry_count */
3223
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3224 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3225 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3226 }
3227
3228 12 av_free(sgpd_entries);
3229 12 return 0;
3230 }
3231
3232 333 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3233 {
3234 333 int64_t pos = avio_tell(pb);
3235 333 int ret = 0;
3236
3237 333 avio_wb32(pb, 0); /* size */
3238 333 ffio_wfourcc(pb, "stbl");
3239
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3240 return ret;
3241 333 mov_write_stts_tag(pb, track);
3242
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 205 times.
333 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3243
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3244
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3245
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) ||
3246
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 126 times.
128 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3247
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)
3248 58 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3249
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)
3250 3 mov_write_sdtp_tag(pb, track);
3251
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)
3252 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3253
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3254
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) {
3255
3256
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3257 return ret;
3258 }
3259 333 mov_write_stsc_tag(pb, track);
3260 333 mov_write_stsz_tag(pb, track);
3261 333 mov_write_stco_tag(pb, track);
3262
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)) {
3263 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, 0);
3264 }
3265
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) {
3266 53 mov_preroll_write_stbl_atoms(pb, track);
3267 }
3268 333 return update_size(pb, pos);
3269 }
3270
3271 333 static int mov_write_dinf_tag(AVIOContext *pb)
3272 {
3273 333 int64_t pos = avio_tell(pb);
3274 333 avio_wb32(pb, 0); /* size */
3275 333 ffio_wfourcc(pb, "dinf");
3276 333 mov_write_dref_tag(pb);
3277 333 return update_size(pb, pos);
3278 }
3279
3280 6 static int mov_write_nmhd_tag(AVIOContext *pb)
3281 {
3282 6 avio_wb32(pb, 12);
3283 6 ffio_wfourcc(pb, "nmhd");
3284 6 avio_wb32(pb, 0);
3285 6 return 12;
3286 }
3287
3288 1 static int mov_write_sthd_tag(AVIOContext *pb)
3289 {
3290 1 avio_wb32(pb, 12);
3291 1 ffio_wfourcc(pb, "sthd");
3292 1 avio_wb32(pb, 0);
3293 1 return 12;
3294 }
3295
3296 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3297 {
3298 9 int64_t pos = avio_tell(pb);
3299 9 const char *font = "Lucida Grande";
3300 9 avio_wb32(pb, 0); /* size */
3301 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3302 9 avio_wb32(pb, 0); /* version & flags */
3303 9 avio_wb16(pb, 0); /* text font */
3304 9 avio_wb16(pb, 0); /* text face */
3305 9 avio_wb16(pb, 12); /* text size */
3306 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3307 9 avio_wb16(pb, 0x0000); /* text color (red) */
3308 9 avio_wb16(pb, 0x0000); /* text color (green) */
3309 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3310 9 avio_wb16(pb, 0xffff); /* background color (red) */
3311 9 avio_wb16(pb, 0xffff); /* background color (green) */
3312 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3313 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3314 9 avio_write(pb, font, strlen(font)); /* font name */
3315 9 return update_size(pb, pos);
3316 }
3317
3318 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3319 {
3320 11 int64_t pos = avio_tell(pb);
3321 11 avio_wb32(pb, 0); /* size */
3322 11 ffio_wfourcc(pb, "gmhd");
3323 11 avio_wb32(pb, 0x18); /* gmin size */
3324 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3325 11 avio_wb32(pb, 0); /* version & flags */
3326 11 avio_wb16(pb, 0x40); /* graphics mode = */
3327 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3328 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3329 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3330 11 avio_wb16(pb, 0); /* balance */
3331 11 avio_wb16(pb, 0); /* reserved */
3332
3333 /*
3334 * This special text atom is required for
3335 * Apple Quicktime chapters. The contents
3336 * don't appear to be documented, so the
3337 * bytes are copied verbatim.
3338 */
3339
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3340 11 avio_wb32(pb, 0x2C); /* size */
3341 11 ffio_wfourcc(pb, "text");
3342 11 avio_wb16(pb, 0x01);
3343 11 avio_wb32(pb, 0x00);
3344 11 avio_wb32(pb, 0x00);
3345 11 avio_wb32(pb, 0x00);
3346 11 avio_wb32(pb, 0x01);
3347 11 avio_wb32(pb, 0x00);
3348 11 avio_wb32(pb, 0x00);
3349 11 avio_wb32(pb, 0x00);
3350 11 avio_wb32(pb, 0x00004000);
3351 11 avio_wb16(pb, 0x0000);
3352 }
3353
3354
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3355 9 int64_t tmcd_pos = avio_tell(pb);
3356 9 avio_wb32(pb, 0); /* size */
3357 9 ffio_wfourcc(pb, "tmcd");
3358 9 mov_write_tcmi_tag(pb, track);
3359 9 update_size(pb, tmcd_pos);
3360
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3361 1 int64_t gpmd_pos = avio_tell(pb);
3362 1 avio_wb32(pb, 0); /* size */
3363 1 ffio_wfourcc(pb, "gpmd");
3364 1 avio_wb32(pb, 0); /* version */
3365 1 update_size(pb, gpmd_pos);
3366 }
3367 11 return update_size(pb, pos);
3368 }
3369
3370 108 static int mov_write_smhd_tag(AVIOContext *pb)
3371 {
3372 108 avio_wb32(pb, 16); /* size */
3373 108 ffio_wfourcc(pb, "smhd");
3374 108 avio_wb32(pb, 0); /* version & flags */
3375 108 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3376 108 avio_wb16(pb, 0); /* reserved */
3377 108 return 16;
3378 }
3379
3380 205 static int mov_write_vmhd_tag(AVIOContext *pb)
3381 {
3382 205 avio_wb32(pb, 0x14); /* size (always 0x14) */
3383 205 ffio_wfourcc(pb, "vmhd");
3384 205 avio_wb32(pb, 0x01); /* version & flags */
3385 205 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3386 205 return 0x14;
3387 }
3388
3389 218 static int is_clcp_track(MOVTrack *track)
3390 {
3391
1/2
✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
436 return track->tag == MKTAG('c','7','0','8') ||
3392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
218 track->tag == MKTAG('c','6','0','8');
3393 }
3394
3395 520 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3396 {
3397 520 MOVMuxContext *mov = s->priv_data;
3398 520 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3399 520 int64_t pos = avio_tell(pb);
3400 size_t descr_len;
3401
3402 520 hdlr = "dhlr";
3403 520 hdlr_type = "url ";
3404 520 descr = "DataHandler";
3405
3406
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 187 times.
520 if (track) {
3407
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3408
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3409
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (track->mode == MODE_AVIF) {
3410 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3411 descr = "PictureHandler";
3412 } else {
3413 205 hdlr_type = "vide";
3414 205 descr = "VideoHandler";
3415 }
3416
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3417 108 hdlr_type = "soun";
3418 108 descr = "SoundHandler";
3419
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3420
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (is_clcp_track(track)) {
3421 hdlr_type = "clcp";
3422 descr = "ClosedCaptionHandler";
3423 } else {
3424
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (track->tag == MKTAG('t','x','3','g')) {
3425 1 hdlr_type = "sbtl";
3426
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (track->tag == MKTAG('m','p','4','s')) {
3427 hdlr_type = "subp";
3428
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3429 1 hdlr_type = "subt";
3430 } else {
3431 2 hdlr_type = "text";
3432 }
3433 4 descr = "SubtitleHandler";
3434 }
3435
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3436 2 hdlr_type = "hint";
3437 2 descr = "HintHandler";
3438
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3439 13 hdlr_type = "tmcd";
3440 13 descr = "TimeCodeHandler";
3441
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3442 1 hdlr_type = "meta";
3443 1 descr = "GoPro MET"; // GoPro Metadata
3444 } else {
3445 av_log(s, AV_LOG_WARNING,
3446 "Unknown hdlr_type for %s, writing dummy values\n",
3447 av_fourcc2str(track->par->codec_tag));
3448 }
3449
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 3 times.
333 if (track->st) {
3450 // hdlr.name is used by some players to identify the content title
3451 // of the track. So if an alternate handler description is
3452 // specified, use it.
3453 AVDictionaryEntry *t;
3454 330 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3455
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))
3456 21 descr = t->value;
3457 }
3458 }
3459
3460
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 */
3461 descr = "";
3462
3463 520 avio_wb32(pb, 0); /* size */
3464 520 ffio_wfourcc(pb, "hdlr");
3465 520 avio_wb32(pb, 0); /* Version & flags */
3466 520 avio_write(pb, hdlr, 4); /* handler */
3467 520 ffio_wfourcc(pb, hdlr_type); /* handler type */
3468 520 avio_wb32(pb, 0); /* reserved */
3469 520 avio_wb32(pb, 0); /* reserved */
3470 520 avio_wb32(pb, 0); /* reserved */
3471 520 descr_len = strlen(descr);
3472
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)
3473 374 avio_w8(pb, descr_len); /* pascal string */
3474 520 avio_write(pb, descr, descr_len); /* handler description */
3475
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)
3476 146 avio_w8(pb, 0); /* c string */
3477 520 return update_size(pb, pos);
3478 }
3479
3480 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3481 {
3482 int64_t pos = avio_tell(pb);
3483 avio_wb32(pb, 0); /* size */
3484 ffio_wfourcc(pb, "pitm");
3485 avio_wb32(pb, 0); /* Version & flags */
3486 avio_wb16(pb, item_id); /* item_id */
3487 return update_size(pb, pos);
3488 }
3489
3490 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3491 {
3492 int64_t pos = avio_tell(pb);
3493 avio_wb32(pb, 0); /* size */
3494 ffio_wfourcc(pb, "iloc");
3495 avio_wb32(pb, 0); /* Version & flags */
3496 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3497 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3498 avio_wb16(pb, mov->nb_streams); /* item_count */
3499
3500 for (int i = 0; i < mov->nb_streams; i++) {
3501 avio_wb16(pb, i + 1); /* item_id */
3502 avio_wb16(pb, 0); /* data_reference_index */
3503 avio_wb16(pb, 1); /* extent_count */
3504 mov->avif_extent_pos[i] = avio_tell(pb);
3505 avio_wb32(pb, 0); /* extent_offset (written later) */
3506 // For animated AVIF, we simply write the first packet's size.
3507 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3508 }
3509
3510 return update_size(pb, pos);
3511 }
3512
3513 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3514 {
3515 int64_t iinf_pos = avio_tell(pb);
3516 avio_wb32(pb, 0); /* size */
3517 ffio_wfourcc(pb, "iinf");
3518 avio_wb32(pb, 0); /* Version & flags */
3519 avio_wb16(pb, mov->nb_streams); /* entry_count */
3520
3521 for (int i = 0; i < mov->nb_streams; i++) {
3522 int64_t infe_pos = avio_tell(pb);
3523 avio_wb32(pb, 0); /* size */
3524 ffio_wfourcc(pb, "infe");
3525 avio_w8(pb, 0x2); /* Version */
3526 avio_wb24(pb, 0); /* flags */
3527 avio_wb16(pb, i + 1); /* item_id */
3528 avio_wb16(pb, 0); /* item_protection_index */
3529 avio_write(pb, "av01", 4); /* item_type */
3530 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3531 update_size(pb, infe_pos);
3532 }
3533
3534 return update_size(pb, iinf_pos);
3535 }
3536
3537
3538 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3539 {
3540 int64_t auxl_pos;
3541 int64_t iref_pos = avio_tell(pb);
3542 avio_wb32(pb, 0); /* size */
3543 ffio_wfourcc(pb, "iref");
3544 avio_wb32(pb, 0); /* Version & flags */
3545
3546 auxl_pos = avio_tell(pb);
3547 avio_wb32(pb, 0); /* size */
3548 ffio_wfourcc(pb, "auxl");
3549 avio_wb16(pb, 2); /* from_item_ID */
3550 avio_wb16(pb, 1); /* reference_count */
3551 avio_wb16(pb, 1); /* to_item_ID */
3552 update_size(pb, auxl_pos);
3553
3554 return update_size(pb, iref_pos);
3555 }
3556
3557 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3558 int stream_index)
3559 {
3560 int64_t pos = avio_tell(pb);
3561 avio_wb32(pb, 0); /* size */
3562 ffio_wfourcc(pb, "ispe");
3563 avio_wb32(pb, 0); /* Version & flags */
3564 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3565 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3566 return update_size(pb, pos);
3567 }
3568
3569 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3570 int stream_index)
3571 {
3572 int64_t pos = avio_tell(pb);
3573 const AVPixFmtDescriptor *pixdesc =
3574 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3575 avio_wb32(pb, 0); /* size */
3576 ffio_wfourcc(pb, "pixi");
3577 avio_wb32(pb, 0); /* Version & flags */
3578 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3579 for (int i = 0; i < pixdesc->nb_components; ++i) {
3580 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3581 }
3582 return update_size(pb, pos);
3583 }
3584
3585 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3586 {
3587 int64_t pos = avio_tell(pb);
3588 avio_wb32(pb, 0); /* size */
3589 ffio_wfourcc(pb, "ipco");
3590 for (int i = 0; i < mov->nb_streams; i++) {
3591 mov_write_ispe_tag(pb, mov, s, i);
3592 mov_write_pixi_tag(pb, mov, s, i);
3593 mov_write_av1c_tag(pb, &mov->tracks[i]);
3594 if (!i)
3595 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3596 else
3597 mov_write_aux_tag(pb, "auxC");
3598 }
3599 return update_size(pb, pos);
3600 }
3601
3602 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3603 {
3604 int64_t pos = avio_tell(pb);
3605 avio_wb32(pb, 0); /* size */
3606 ffio_wfourcc(pb, "ipma");
3607 avio_wb32(pb, 0); /* Version & flags */
3608 avio_wb32(pb, mov->nb_streams); /* entry_count */
3609
3610 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3611 avio_wb16(pb, i + 1); /* item_ID */
3612 avio_w8(pb, 4); /* association_count */
3613
3614 // ispe association.
3615 avio_w8(pb, index++); /* essential and property_index */
3616 // pixi association.
3617 avio_w8(pb, index++); /* essential and property_index */
3618 // av1C association.
3619 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3620 // colr/auxC association.
3621 avio_w8(pb, index++); /* essential and property_index */
3622 }
3623 return update_size(pb, pos);
3624 }
3625
3626 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3627 {
3628 int64_t pos = avio_tell(pb);
3629 avio_wb32(pb, 0); /* size */
3630 ffio_wfourcc(pb, "iprp");
3631 mov_write_ipco_tag(pb, mov, s);
3632 mov_write_ipma_tag(pb, mov, s);
3633 return update_size(pb, pos);
3634 }
3635
3636 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3637 {
3638 /* This atom must be present, but leaving the values at zero
3639 * seems harmless. */
3640 2 avio_wb32(pb, 28); /* size */
3641 2 ffio_wfourcc(pb, "hmhd");
3642 2 avio_wb32(pb, 0); /* version, flags */
3643 2 avio_wb16(pb, 0); /* maxPDUsize */
3644 2 avio_wb16(pb, 0); /* avgPDUsize */
3645 2 avio_wb32(pb, 0); /* maxbitrate */
3646 2 avio_wb32(pb, 0); /* avgbitrate */
3647 2 avio_wb32(pb, 0); /* reserved */
3648 2 return 28;
3649 }
3650
3651 333 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3652 {
3653 333 int64_t pos = avio_tell(pb);
3654 int ret;
3655
3656 333 avio_wb32(pb, 0); /* size */
3657 333 ffio_wfourcc(pb, "minf");
3658
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3659 205 mov_write_vmhd_tag(pb);
3660
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3661 108 mov_write_smhd_tag(pb);
3662
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3663
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)) {
3664 1 mov_write_gmhd_tag(pb, track);
3665
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3666 1 mov_write_sthd_tag(pb);
3667 } else {
3668 2 mov_write_nmhd_tag(pb);
3669 }
3670
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3671 2 mov_write_hmhd_tag(pb);
3672
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3673
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3674 4 mov_write_nmhd_tag(pb);
3675 else
3676 9 mov_write_gmhd_tag(pb, track);
3677
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3678 1 mov_write_gmhd_tag(pb, track);
3679 }
3680
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 */
3681 187 mov_write_hdlr_tag(s, pb, NULL);
3682 333 mov_write_dinf_tag(pb);
3683
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3684 return ret;
3685 333 return update_size(pb, pos);
3686 }
3687
3688 1294 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3689 int64_t *start, int64_t *end)
3690 {
3691
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) {
3692 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3693 // another track's duration, while the end_pts may be left at zero.
3694 // Calculate the pts duration for that track instead.
3695 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end);
3696 38 *start = av_rescale(*start, track->timescale,
3697 38 mov->tracks[track->src_track].timescale);
3698 38 *end = av_rescale(*end, track->timescale,
3699 38 mov->tracks[track->src_track].timescale);
3700 38 return;
3701 }
3702
2/2
✓ Branch 0 taken 1198 times.
✓ Branch 1 taken 58 times.
1256 if (track->end_pts != AV_NOPTS_VALUE &&
3703
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 track->start_dts != AV_NOPTS_VALUE &&
3704
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 track->start_cts != AV_NOPTS_VALUE) {
3705 1198 *start = track->start_dts + track->start_cts;
3706 1198 *end = track->end_pts;
3707 1198 return;
3708 }
3709 58 *start = 0;
3710 58 *end = track->track_duration;
3711 }
3712
3713 616 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3714 {
3715 int64_t start, end;
3716 616 get_pts_range(mov, track, &start, &end);
3717 616 return end - start;
3718 }
3719
3720 // Calculate the actual duration of the track, after edits.
3721 // If it starts with a pts < 0, that is removed by the edit list.
3722 // If it starts with a pts > 0, the edit list adds a delay before that.
3723 // Thus, with edit lists enabled, the post-edit output of the file is
3724 // starting with pts=0.
3725 640 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3726 {
3727 int64_t start, end;
3728 640 get_pts_range(mov, track, &start, &end);
3729
2/2
✓ Branch 0 taken 572 times.
✓ Branch 1 taken 68 times.
640 if (mov->use_editlist != 0)
3730 572 start = 0;
3731 640 return end - start;
3732 }
3733
3734 903 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3735 {
3736
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)
3737 14 return 1;
3738
2/2
✓ Branch 0 taken 885 times.
✓ Branch 1 taken 4 times.
889 if (duration < INT32_MAX)
3739 885 return 0;
3740 4 return 1;
3741 }
3742
3743 333 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3744 MOVTrack *track)
3745 {
3746 333 int64_t duration = calc_samples_pts_duration(mov, track);
3747 333 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3748
3749
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
333 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3750 333 ffio_wfourcc(pb, "mdhd");
3751 333 avio_w8(pb, version);
3752 333 avio_wb24(pb, 0); /* flags */
3753
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
333 if (version == 1) {
3754 11 avio_wb64(pb, track->time);
3755 11 avio_wb64(pb, track->time);
3756 } else {
3757 322 avio_wb32(pb, track->time); /* creation time */
3758 322 avio_wb32(pb, track->time); /* modification time */
3759 }
3760 333 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3761
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)
3762
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3763
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 243 times.
326 else if (!track->entry)
3764
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 79 times.
83 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3765 else
3766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3767 333 avio_wb16(pb, track->language); /* language */
3768 333 avio_wb16(pb, 0); /* reserved (quality) */
3769
3770
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) {
3771 av_log(NULL, AV_LOG_ERROR,
3772 "FATAL error, file duration too long for timebase, this file will not be\n"
3773 "playable with QuickTime. Choose a different timebase with "
3774 "-video_track_timescale or a different container format\n");
3775 }
3776
3777 333 return 32;
3778 }
3779
3780 333 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3781 MOVMuxContext *mov, MOVTrack *track)
3782 {
3783 333 int64_t pos = avio_tell(pb);
3784 int ret;
3785
3786 333 avio_wb32(pb, 0); /* size */
3787 333 ffio_wfourcc(pb, "mdia");
3788 333 mov_write_mdhd_tag(pb, mov, track);
3789 333 mov_write_hdlr_tag(s, pb, track);
3790
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3791 return ret;
3792 333 return update_size(pb, pos);
3793 }
3794
3795 /* transformation matrix
3796 |a b u|
3797 |c d v|
3798 |tx ty w| */
3799 569 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3800 int16_t d, int16_t tx, int16_t ty)
3801 {
3802 569 avio_wb32(pb, a << 16); /* 16.16 format */
3803 569 avio_wb32(pb, b << 16); /* 16.16 format */
3804 569 avio_wb32(pb, 0); /* u in 2.30 format */
3805 569 avio_wb32(pb, c << 16); /* 16.16 format */
3806 569 avio_wb32(pb, d << 16); /* 16.16 format */
3807 569 avio_wb32(pb, 0); /* v in 2.30 format */
3808 569 avio_wb32(pb, tx << 16); /* 16.16 format */
3809 569 avio_wb32(pb, ty << 16); /* 16.16 format */
3810 569 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3811 569 }
3812
3813 333 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3814 MOVTrack *track, AVStream *st)
3815 {
3816 666 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3817 333 mov->movie_timescale, track->timescale,
3818 AV_ROUND_UP);
3819 int version;
3820 333 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3821 333 int group = 0;
3822
3823 333 uint32_t *display_matrix = NULL;
3824 int i;
3825
3826
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mov->mode == MODE_AVIF)
3827 if (!mov->avif_loop_count)
3828 duration = INT64_MAX;
3829 else
3830 duration *= mov->avif_loop_count;
3831
3832
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 13 times.
333 if (st) {
3833 const AVPacketSideData *sd;
3834
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (mov->per_stream_grouping)
3835 group = st->index;
3836 else
3837 320 group = st->codecpar->codec_type;
3838
3839 320 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3840 320 st->codecpar->nb_coded_side_data,
3841 AV_PKT_DATA_DISPLAYMATRIX);
3842
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))
3843 1 display_matrix = (uint32_t *)sd->data;
3844 }
3845
3846
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 25 times.
333 if (track->flags & MOV_TRACK_ENABLED)
3847 308 flags |= MOV_TKHD_FLAG_ENABLED;
3848
3849 333 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3850
3851
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 326 times.
333 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
3852 333 ffio_wfourcc(pb, "tkhd");
3853 333 avio_w8(pb, version);
3854 333 avio_wb24(pb, flags);
3855
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 326 times.
333 if (version == 1) {
3856 7 avio_wb64(pb, track->time);
3857 7 avio_wb64(pb, track->time);
3858 } else {
3859 326 avio_wb32(pb, track->time); /* creation time */
3860 326 avio_wb32(pb, track->time); /* modification time */
3861 }
3862 333 avio_wb32(pb, track->track_id); /* track-id */
3863 333 avio_wb32(pb, 0); /* reserved */
3864
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)
3865
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3866
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 243 times.
326 else if (!track->entry)
3867
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3868 else
3869
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
3870
3871 333 avio_wb32(pb, 0); /* reserved */
3872 333 avio_wb32(pb, 0); /* reserved */
3873 333 avio_wb16(pb, 0); /* layer */
3874 333 avio_wb16(pb, group); /* alternate group) */
3875 /* Volume, only for audio */
3876
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3877 108 avio_wb16(pb, 0x0100);
3878 else
3879 225 avio_wb16(pb, 0);
3880 333 avio_wb16(pb, 0); /* reserved */
3881
3882 /* Matrix structure */
3883
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 332 times.
333 if (display_matrix) {
3884
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
3885 9 avio_wb32(pb, display_matrix[i]);
3886 } else {
3887 332 write_matrix(pb, 1, 0, 0, 1, 0, 0);
3888 }
3889 /* Track width and height, for visual only */
3890
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 ||
3891
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 112 times.
323 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
3892 int64_t track_width_1616;
3893
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) {
3894 138 track_width_1616 = track->par->width * 0x10000ULL;
3895 } else {
3896 70 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
3897 70 track->par->width * 0x10000LL,
3898 70 st->sample_aspect_ratio.den);
3899
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 68 times.
70 if (!track_width_1616 ||
3900
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 ||
3901 track_width_1616 > UINT32_MAX)
3902 68 track_width_1616 = track->par->width * 0x10000ULL;
3903 }
3904
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (track_width_1616 > UINT32_MAX) {
3905 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
3906 track_width_1616 = 0;
3907 }
3908 208 avio_wb32(pb, track_width_1616);
3909
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (track->height > 0xFFFF) {
3910 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
3911 avio_wb32(pb, 0);
3912 } else
3913 208 avio_wb32(pb, track->height * 0x10000U);
3914 } else {
3915 125 avio_wb32(pb, 0);
3916 125 avio_wb32(pb, 0);
3917 }
3918 333 return 0x5c;
3919 }
3920
3921 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
3922 {
3923 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
3924 1 track->par->sample_aspect_ratio.den);
3925
3926 1 int64_t pos = avio_tell(pb);
3927
3928 1 avio_wb32(pb, 0); /* size */
3929 1 ffio_wfourcc(pb, "tapt");
3930
3931 1 avio_wb32(pb, 20);
3932 1 ffio_wfourcc(pb, "clef");
3933 1 avio_wb32(pb, 0);
3934 1 avio_wb32(pb, width << 16);
3935 1 avio_wb32(pb, track->par->height << 16);
3936
3937 1 avio_wb32(pb, 20);
3938 1 ffio_wfourcc(pb, "prof");
3939 1 avio_wb32(pb, 0);
3940 1 avio_wb32(pb, width << 16);
3941 1 avio_wb32(pb, track->par->height << 16);
3942
3943 1 avio_wb32(pb, 20);
3944 1 ffio_wfourcc(pb, "enof");
3945 1 avio_wb32(pb, 0);
3946 1 avio_wb32(pb, track->par->width << 16);
3947 1 avio_wb32(pb, track->par->height << 16);
3948
3949 1 return update_size(pb, pos);
3950 }
3951
3952 // This box is written in the following cases:
3953 // * Seems important for the psp playback. Without it the movie seems to hang.
3954 // * Used for specifying the looping behavior of animated AVIF (as specified
3955 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
3956 283 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
3957 MOVTrack *track)
3958 {
3959 566 int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track),
3960 283 mov->movie_timescale, track->timescale,
3961 AV_ROUND_UP);
3962 283 int version = duration < INT32_MAX ? 0 : 1;
3963 int entry_size, entry_count, size;
3964 283 int64_t delay, start_ct = track->start_cts;
3965 283 int64_t start_dts = track->start_dts;
3966 283 int flags = 0;
3967
3968
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 54 times.
283 if (track->entry) {
3969
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) {
3970
3971 av_log(mov->fc, AV_LOG_DEBUG,
3972 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
3973 track->cluster[0].dts, track->cluster[0].cts,
3974 start_dts, start_ct, track->track_id);
3975 start_dts = track->cluster[0].dts;
3976 start_ct = track->cluster[0].cts;
3977 }
3978 }
3979
3980 283 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
3981 283 track->timescale, AV_ROUND_DOWN);
3982
3983
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (mov->mode == MODE_AVIF) {
3984 delay = 0;
3985 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
3986 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
3987 // list is not repeated, while (flags & 1) equal to 1 specifies that the
3988 // edit list is repeated.
3989 flags = mov->avif_loop_count != 1;
3990 start_ct = 0;
3991 }
3992
3993 283 version |= delay < INT32_MAX ? 0 : 1;
3994
3995
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 entry_size = (version == 1) ? 20 : 12;
3996
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 entry_count = 1 + (delay > 0);
3997 283 size = 24 + entry_count * entry_size;
3998
3999 /* write the atom data */
4000 283 avio_wb32(pb, size);
4001 283 ffio_wfourcc(pb, "edts");
4002 283 avio_wb32(pb, size - 8);
4003 283 ffio_wfourcc(pb, "elst");
4004 283 avio_w8(pb, version);
4005 283 avio_wb24(pb, flags); /* flags */
4006
4007 283 avio_wb32(pb, entry_count);
4008
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 if (delay > 0) { /* add an empty edit to delay presentation */
4009 /* In the positive delay case, the delay includes the cts
4010 * offset, and the second edit list entry below trims out
4011 * the same amount from the actual content. This makes sure
4012 * that the offset last sample is included in the edit
4013 * list duration as well. */
4014
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
4015 avio_wb64(pb, delay);
4016 avio_wb64(pb, -1);
4017 } else {
4018 2 avio_wb32(pb, delay);
4019 2 avio_wb32(pb, -1);
4020 }
4021 2 avio_wb32(pb, 0x00010000);
4022
1/2
✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
281 } else if (mov->mode != MODE_AVIF) {
4023 /* Avoid accidentally ending up with start_ct = -1 which has got a
4024 * special meaning. Normally start_ct should end up positive or zero
4025 * here, but use FFMIN in case dts is a small positive integer
4026 * rounded to 0 when represented in movie timescale units. */
4027
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);
4028 281 start_ct = -FFMIN(start_dts, 0);
4029
4030 #if CONFIG_IAMFENC
4031
3/4
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 276 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5 times.
281 if (track->iamf && track->par->codec_id == AV_CODEC_ID_OPUS)
4032 start_ct = av_rescale(start_ct, 48000, track->par->sample_rate);
4033 #endif
4034 /* Note, this delay is calculated from the pts of the first sample,
4035 * ensuring that we don't reduce the duration for cases with
4036 * dts<0 pts=0. */
4037 281 duration += delay;
4038 }
4039
4040 /* For fragmented files, we don't know the full length yet. Setting
4041 * duration to 0 allows us to only specify the offset, including
4042 * the rest of the content (from all future fragments) without specifying
4043 * an explicit duration. */
4044
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 225 times.
283 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
4045 58 duration = 0;
4046
4047 /* duration */
4048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (version == 1) {
4049 avio_wb64(pb, duration);
4050 avio_wb64(pb, start_ct);
4051 } else {
4052 283 avio_wb32(pb, duration);
4053 283 avio_wb32(pb, start_ct);
4054 }
4055 283 avio_wb32(pb, 0x00010000);
4056 283 return size;
4057 }
4058
4059 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4060 {
4061 14 avio_wb32(pb, 20); // size
4062 14 ffio_wfourcc(pb, "tref");
4063 14 avio_wb32(pb, 12); // size (subatom)
4064 14 avio_wl32(pb, track->tref_tag);
4065 14 avio_wb32(pb, track->tref_id);
4066 14 return 20;
4067 }
4068
4069 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4070 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4071 {
4072 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4073 2 ffio_wfourcc(pb, "uuid");
4074 2 ffio_wfourcc(pb, "USMT");
4075 2 avio_wb32(pb, 0x21d24fce);
4076 2 avio_wb32(pb, 0xbb88695c);
4077 2 avio_wb32(pb, 0xfac9c740);
4078 2 avio_wb32(pb, 0x1c); // another size here!
4079 2 ffio_wfourcc(pb, "MTDT");
4080 2 avio_wb32(pb, 0x00010012);
4081 2 avio_wb32(pb, 0x0a);
4082 2 avio_wb32(pb, 0x55c40000);
4083 2 avio_wb32(pb, 0x1);
4084 2 avio_wb32(pb, 0x0);
4085 2 return 0x34;
4086 }
4087
4088 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4089 {
4090 2 AVFormatContext *ctx = track->rtp_ctx;
4091 2 char buf[1000] = "";
4092 int len;
4093
4094 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
4095 NULL, NULL, 0, 0, ctx);
4096 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4097 2 len = strlen(buf);
4098
4099 2 avio_wb32(pb, len + 24);
4100 2 ffio_wfourcc(pb, "udta");
4101 2 avio_wb32(pb, len + 16);
4102 2 ffio_wfourcc(pb, "hnti");
4103 2 avio_wb32(pb, len + 8);
4104 2 ffio_wfourcc(pb, "sdp ");
4105 2 avio_write(pb, buf, len);
4106 2 return len + 24;
4107 }
4108
4109 312 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4110 const char *tag, const char *str)
4111 {
4112 312 int64_t pos = avio_tell(pb);
4113 312 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4114
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))
4115 311 return 0;
4116
4117 1 avio_wb32(pb, 0); /* size */
4118 1 ffio_wfourcc(pb, tag); /* type */
4119 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4120 1 return update_size(pb, pos);
4121 }
4122
4123 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4124 const char *value)
4125 {
4126 2 int64_t pos = avio_tell(pb);
4127
4128 /* Box|FullBox basics */
4129 2 avio_wb32(pb, 0); /* size placeholder */
4130 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4131 2 avio_w8(pb, 0); /* version = 0 */
4132 2 avio_wb24(pb, 0); /* flags = 0 */
4133
4134 /* Required null-terminated scheme URI */
4135 2 avio_write(pb, (const unsigned char *)scheme_uri,
4136 2 strlen(scheme_uri));
4137 2 avio_w8(pb, 0);
4138
4139 /* Optional value string */
4140
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])
4141 2 avio_write(pb, (const unsigned char *)value,
4142 2 strlen(value));
4143
4144 2 avio_w8(pb, 0);
4145
4146 2 return update_size(pb, pos);
4147 }
4148
4149 131 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4150 {
4151 131 int ret = AVERROR_BUG;
4152
4153
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++) {
4154 131 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4155
4156
2/2
✓ Branch 0 taken 655 times.
✓ Branch 1 taken 131 times.
786 for (int j = 0; map.value_maps[j].disposition; j++) {
4157 655 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4158
2/2
✓ Branch 0 taken 653 times.
✓ Branch 1 taken 2 times.
655 if (!(st->disposition & value_map.disposition))
4159 653 continue;
4160
4161
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)
4162 return ret;
4163 }
4164 }
4165
4166 131 return 0;
4167 }
4168
4169 333 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4170 AVStream *st)
4171 {
4172 AVIOContext *pb_buf;
4173 int ret, size;
4174 uint8_t *buf;
4175
4176
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 320 times.
333 if (!st)
4177 13 return 0;
4178
4179 320 ret = avio_open_dyn_buf(&pb_buf);
4180
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (ret < 0)
4181 return ret;
4182
4183
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 8 times.
320 if (mov->mode & (MODE_MP4|MODE_MOV))
4184 312 mov_write_track_metadata(pb_buf, st, "name", "title");
4185
4186
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 189 times.
320 if (mov->mode & MODE_MP4) {
4187
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
131 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4188 return ret;
4189 }
4190
4191
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 317 times.
320 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4192 3 avio_wb32(pb, size + 8);
4193 3 ffio_wfourcc(pb, "udta");
4194 3 avio_write(pb, buf, size);
4195 }
4196 320 ffio_free_dyn_buf(&pb_buf);
4197
4198 320 return 0;
4199 }
4200
4201 333 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4202 MOVTrack *track, AVStream *st)
4203 {
4204 333 int64_t pos = avio_tell(pb);
4205 333 int entry_backup = track->entry;
4206 333 int chunk_backup = track->chunkCount;
4207 int ret;
4208
4209 /* If we want to have an empty moov, but some samples already have been
4210 * buffered (delay_moov), pretend that no samples have been written yet. */
4211
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 243 times.
333 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4212 90 track->chunkCount = track->entry = 0;
4213
4214 333 avio_wb32(pb, 0); /* size */
4215 333 ffio_wfourcc(pb, "trak");
4216 333 mov_write_tkhd_tag(pb, mov, track, st);
4217
4218 av_assert2(mov->use_editlist >= 0);
4219
4220
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 26 times.
333 if (track->start_dts != AV_NOPTS_VALUE) {
4221
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 24 times.
307 if (mov->use_editlist)
4222 283 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4223
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))
4224 av_log(mov->fc, AV_LOG_WARNING,
4225 "Not writing any edit list even though one would have been required\n");
4226 }
4227
4228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mov->is_animated_avif)
4229 mov_write_edts_tag(pb, mov, track);
4230
4231
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 319 times.
333 if (track->tref_tag)
4232 14 mov_write_tref_tag(pb, track);
4233
4234
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4235 return ret;
4236
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
333 if (track->mode == MODE_PSP)
4237 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4238
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
333 if (track->tag == MKTAG('r','t','p',' '))
4239 2 mov_write_udta_sdp(pb, track);
4240
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 if (track->mode == MODE_MOV) {
4241
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 49 times.
187 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4242 138 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4243
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) {
4244 1 mov_write_tapt_tag(pb, track);
4245 }
4246 }
4247
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) {
4248 mov_write_tapt_tag(pb, track);
4249 }
4250 }
4251 333 mov_write_track_udta_tag(pb, mov, st);
4252 333 track->entry = entry_backup;
4253 333 track->chunkCount = chunk_backup;
4254 333 return update_size(pb, pos);
4255 }
4256
4257 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4258 {
4259 int i, has_audio = 0, has_video = 0;
4260 int64_t pos = avio_tell(pb);
4261 int audio_profile = mov->iods_audio_profile;
4262 int video_profile = mov->iods_video_profile;
4263 for (i = 0; i < mov->nb_tracks; i++) {
4264 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4265 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4266 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4267 }
4268 }
4269 if (audio_profile < 0)
4270 audio_profile = 0xFF - has_audio;
4271 if (video_profile < 0)
4272 video_profile = 0xFF - has_video;
4273 avio_wb32(pb, 0x0); /* size */
4274 ffio_wfourcc(pb, "iods");
4275 avio_wb32(pb, 0); /* version & flags */
4276 put_descr(pb, 0x10, 7);
4277 avio_wb16(pb, 0x004f);
4278 avio_w8(pb, 0xff);
4279 avio_w8(pb, 0xff);
4280 avio_w8(pb, audio_profile);
4281 avio_w8(pb, video_profile);
4282 avio_w8(pb, 0xff);
4283 return update_size(pb, pos);
4284 }
4285
4286 108 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4287 {
4288 108 avio_wb32(pb, 0x20); /* size */
4289 108 ffio_wfourcc(pb, "trex");
4290 108 avio_wb32(pb, 0); /* version & flags */
4291 108 avio_wb32(pb, track->track_id); /* track ID */
4292 108 avio_wb32(pb, 1); /* default sample description index */
4293 108 avio_wb32(pb, 0); /* default sample duration */
4294 108 avio_wb32(pb, 0); /* default sample size */
4295 108 avio_wb32(pb, 0); /* default sample flags */
4296 108 return 0;
4297 }
4298
4299 56 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4300 {
4301 56 int64_t pos = avio_tell(pb);
4302 int i;
4303 56 avio_wb32(pb, 0x0); /* size */
4304 56 ffio_wfourcc(pb, "mvex");
4305
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 56 times.
164 for (i = 0; i < mov->nb_tracks; i++)
4306 108 mov_write_trex_tag(pb, &mov->tracks[i]);
4307 56 return update_size(pb, pos);
4308 }
4309
4310 237 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4311 {
4312 237 int max_track_id = 1, i;
4313 237 int64_t max_track_len = 0;
4314 int version;
4315 int timescale;
4316
4317
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
4318
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) {
4319 614 int64_t max_track_len_temp = av_rescale_rnd(
4320 307 calc_pts_duration(mov, &mov->tracks[i]),
4321 307 mov->movie_timescale,
4322 307 mov->tracks[i].timescale,
4323 AV_ROUND_UP);
4324
2/2
✓ Branch 0 taken 238 times.
✓ Branch 1 taken 69 times.
307 if (max_track_len < max_track_len_temp)
4325 238 max_track_len = max_track_len_temp;
4326
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 224 times.
307 if (max_track_id < mov->tracks[i].track_id)
4327 83 max_track_id = mov->tracks[i].track_id;
4328 }
4329 }
4330 /* If using delay_moov, make sure the output is the same as if no
4331 * samples had been written yet. */
4332
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 190 times.
237 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4333 47 max_track_len = 0;
4334 47 max_track_id = 1;
4335 }
4336
4337 237 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4339
4340 237 ffio_wfourcc(pb, "mvhd");
4341 237 avio_w8(pb, version);
4342 237 avio_wb24(pb, 0); /* flags */
4343
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (version == 1) {
4344 avio_wb64(pb, mov->time);
4345 avio_wb64(pb, mov->time);
4346 } else {
4347 237 avio_wb32(pb, mov->time); /* creation time */
4348 237 avio_wb32(pb, mov->time); /* modification time */
4349 }
4350
4351 237 timescale = mov->movie_timescale;
4352
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)
4353 timescale = mov->tracks[0].timescale;
4354
4355 237 avio_wb32(pb, timescale);
4356
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 */
4357
4358 237 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4359 237 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4360 237 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4361
4362 /* Matrix structure */
4363 237 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4364
4365 237 avio_wb32(pb, 0); /* reserved (preview time) */
4366 237 avio_wb32(pb, 0); /* reserved (preview duration) */
4367 237 avio_wb32(pb, 0); /* reserved (poster time) */
4368 237 avio_wb32(pb, 0); /* reserved (selection time) */
4369 237 avio_wb32(pb, 0); /* reserved (selection duration) */
4370 237 avio_wb32(pb, 0); /* reserved (current time) */
4371 237 avio_wb32(pb, max_track_id + 1); /* Next track id */
4372 237 return 0x6c;
4373 }
4374
4375 82 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4376 AVFormatContext *s)
4377 {
4378 82 avio_wb32(pb, 33); /* size */
4379 82 ffio_wfourcc(pb, "hdlr");
4380 82 avio_wb32(pb, 0);
4381 82 avio_wb32(pb, 0);
4382 82 ffio_wfourcc(pb, "mdir");
4383 82 ffio_wfourcc(pb, "appl");
4384 82 avio_wb32(pb, 0);
4385 82 avio_wb32(pb, 0);
4386 82 avio_w8(pb, 0);
4387 82 return 33;
4388 }
4389
4390 /* helper function to write a data tag with the specified string as data */
4391 54 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4392 {
4393 54 size_t data_len = strlen(data);
4394
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 34 times.
54 if (long_style) {
4395 20 int size = 16 + data_len;
4396 20 avio_wb32(pb, size); /* size */
4397 20 ffio_wfourcc(pb, "data");
4398 20 avio_wb32(pb, 1);
4399 20 avio_wb32(pb, 0);
4400 20 avio_write(pb, data, data_len);
4401 20 return size;
4402 } else {
4403 34 avio_wb16(pb, data_len); /* string length */
4404
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4405 26 lang = ff_mov_iso639_to_lang("und", 1);
4406 34 avio_wb16(pb, lang);
4407 34 avio_write(pb, data, data_len);
4408 34 return data_len + 4;
4409 }
4410 }
4411
4412 54 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4413 const char *value, int lang, int long_style)
4414 {
4415 54 int size = 0;
4416
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]) {
4417 54 int64_t pos = avio_tell(pb);
4418 54 avio_wb32(pb, 0); /* size */
4419 54 ffio_wfourcc(pb, name);
4420 54 mov_write_string_data_tag(pb, value, lang, long_style);
4421 54 size = update_size(pb, pos);
4422 }
4423 54 return size;
4424 }
4425
4426 3714 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4427 const char *tag, int *lang)
4428 {
4429 int l, len, len2;
4430 3714 AVDictionaryEntry *t, *t2 = NULL;
4431 char tag2[16];
4432
4433 3714 *lang = 0;
4434
4435
2/2
✓ Branch 1 taken 3662 times.
✓ Branch 2 taken 52 times.
3714 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4436 3662 return NULL;
4437
4438 52 len = strlen(t->key);
4439 52 snprintf(tag2, sizeof(tag2), "%s-", tag);
4440
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))) {
4441 8 len2 = strlen(t2->key);
4442
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)
4443
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4444 8 *lang = l;
4445 8 return t;
4446 }
4447 }
4448 44 return t;
4449 }
4450
4451 3632 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4452 const char *name, const char *tag,
4453 int long_style)
4454 {
4455 int lang;
4456 3632 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4457
2/2
✓ Branch 0 taken 3580 times.
✓ Branch 1 taken 52 times.
3632 if (!t)
4458 3580 return 0;
4459 52 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4460 }
4461
4462 /* iTunes bpm number */
4463 82 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4464 {
4465 82 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4466
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 int size = 0, tmpo = t ? atoi(t->value) : 0;
4467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (tmpo) {
4468 size = 26;
4469 avio_wb32(pb, size);
4470 ffio_wfourcc(pb, "tmpo");
4471 avio_wb32(pb, size-8); /* size */
4472 ffio_wfourcc(pb, "data");
4473 avio_wb32(pb, 0x15); //type specifier
4474 avio_wb32(pb, 0);
4475 avio_wb16(pb, tmpo); // data
4476 }
4477 82 return size;
4478 }
4479
4480 /* 3GPP TS 26.244 */
4481 82 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4482 {
4483 int lang;
4484 82 int64_t pos = avio_tell(pb);
4485 double latitude, longitude, altitude;
4486 int32_t latitude_fix, longitude_fix, altitude_fix;
4487 82 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4488 82 const char *ptr, *place = "";
4489 char *end;
4490 static const char *astronomical_body = "earth";
4491
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 if (!t)
4492 82 return 0;
4493
4494 ptr = t->value;
4495 latitude = strtod(ptr, &end);
4496 if (end == ptr) {
4497 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4498 return 0;
4499 }
4500 ptr = end;
4501 longitude = strtod(ptr, &end);
4502 if (end == ptr) {
4503 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4504 return 0;
4505 }
4506 ptr = end;
4507 altitude = strtod(ptr, &end);
4508 /* If no altitude was present, the default 0 should be fine */
4509 if (*end == '/')
4510 place = end + 1;
4511
4512 latitude_fix = (int32_t) ((1 << 16) * latitude);
4513 longitude_fix = (int32_t) ((1 << 16) * longitude);
4514 altitude_fix = (int32_t) ((1 << 16) * altitude);
4515
4516 avio_wb32(pb, 0); /* size */
4517 ffio_wfourcc(pb, "loci"); /* type */
4518 avio_wb32(pb, 0); /* version + flags */
4519 avio_wb16(pb, lang);
4520 avio_write(pb, place, strlen(place) + 1);
4521 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4522 avio_wb32(pb, longitude_fix);
4523 avio_wb32(pb, latitude_fix);
4524 avio_wb32(pb, altitude_fix);
4525 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4526 avio_w8(pb, 0); /* additional notes, null terminated string */
4527
4528 return update_size(pb, pos);
4529 }
4530
4531 /* iTunes track or disc number */
4532 164 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4533 AVFormatContext *s, int disc)
4534 {
4535
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 82 times.
164 AVDictionaryEntry *t = av_dict_get(s->metadata,
4536 disc ? "disc" : "track",
4537 NULL, 0);
4538
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 162 times.
164 int size = 0, track = t ? atoi(t->value) : 0;
4539
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 162 times.
164 if (track) {
4540 2 int tracks = 0;
4541 2 char *slash = strchr(t->value, '/');
4542
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4543 2 tracks = atoi(slash + 1);
4544 2 avio_wb32(pb, 32); /* size */
4545
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4546 2 avio_wb32(pb, 24); /* size */
4547 2 ffio_wfourcc(pb, "data");
4548 2 avio_wb32(pb, 0); // 8 bytes empty
4549 2 avio_wb32(pb, 0);
4550 2 avio_wb16(pb, 0); // empty
4551 2 avio_wb16(pb, track); // track / disc number
4552 2 avio_wb16(pb, tracks); // total track / disc number
4553 2 avio_wb16(pb, 0); // empty
4554 2 size = 32;
4555 }
4556 164 return size;
4557 }
4558
4559 492 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4560 const char *name, const char *tag,
4561 int len)
4562 {
4563 492 AVDictionaryEntry *t = NULL;
4564 uint8_t num;
4565 492 int size = 24 + len;
4566
4567
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)
4568 return -1;
4569
4570
2/2
✓ Branch 1 taken 490 times.
✓ Branch 2 taken 2 times.
492 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4571 490 return 0;
4572 2 num = atoi(t->value);
4573
4574 2 avio_wb32(pb, size);
4575 2 ffio_wfourcc(pb, name);
4576 2 avio_wb32(pb, size - 8);
4577 2 ffio_wfourcc(pb, "data");
4578 2 avio_wb32(pb, 0x15);
4579 2 avio_wb32(pb, 0);
4580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4581 2 else avio_w8 (pb, num);
4582
4583 2 return size;
4584 }
4585
4586 82 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4587 {
4588 82 MOVMuxContext *mov = s->priv_data;
4589 82 int64_t pos = 0;
4590
4591
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 82 times.
221 for (int i = 0; i < mov->nb_streams; i++) {
4592 139 MOVTrack *trk = &mov->tracks[i];
4593
4594
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)
4595 137 continue;
4596
4597
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4598 1 pos = avio_tell(pb);
4599 1 avio_wb32(pb, 0);
4600 1 ffio_wfourcc(pb, "covr");
4601 }
4602 2 avio_wb32(pb, 16 + trk->cover_image->size);
4603 2 ffio_wfourcc(pb, "data");
4604 2 avio_wb32(pb, trk->tag);
4605 2 avio_wb32(pb , 0);
4606 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4607 }
4608
4609
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 81 times.
82 return pos ? update_size(pb, pos) : 0;
4610 }
4611
4612 /* iTunes meta data list */
4613 82 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4614 AVFormatContext *s)
4615 {
4616 82 int64_t pos = avio_tell(pb);
4617 82 avio_wb32(pb, 0); /* size */
4618 82 ffio_wfourcc(pb, "ilst");
4619 82 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4620 82 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4621 82 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4622 82 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4623 82 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4624 82 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4625
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4626
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 80 times.
82 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4627 2 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4628 }
4629 82 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4630 82 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4631 82 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4632 82 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4633 82 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4634 82 mov_write_string_metadata(s, pb, "desc", "description",1);
4635 82 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4636 82 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4637 82 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4638 82 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4639 82 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4640 82 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4641 82 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4642 82 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4643 82 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4644 82 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4645 82 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4646 82 mov_write_covr(pb, s);
4647 82 mov_write_trkn_tag(pb, mov, s, 0); // track number
4648 82 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4649 82 mov_write_tmpo_tag(pb, s);
4650 82 return update_size(pb, pos);
4651 }
4652
4653 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4654 AVFormatContext *s)
4655 {
4656 avio_wb32(pb, 33); /* size */
4657 ffio_wfourcc(pb, "hdlr");
4658 avio_wb32(pb, 0);
4659 avio_wb32(pb, 0);
4660 ffio_wfourcc(pb, "mdta");
4661 avio_wb32(pb, 0);
4662 avio_wb32(pb, 0);
4663 avio_wb32(pb, 0);
4664 avio_w8(pb, 0);
4665 return 33;
4666 }
4667
4668 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4669 AVFormatContext *s)
4670 {
4671 const AVDictionaryEntry *t = NULL;
4672 int64_t pos = avio_tell(pb);
4673 int64_t curpos, entry_pos;
4674 int count = 0;
4675
4676 avio_wb32(pb, 0); /* size */
4677 ffio_wfourcc(pb, "keys");
4678 avio_wb32(pb, 0);
4679 entry_pos = avio_tell(pb);
4680 avio_wb32(pb, 0); /* entry count */
4681
4682 while (t = av_dict_iterate(s->metadata, t)) {
4683 size_t key_len = strlen(t->key);
4684 avio_wb32(pb, key_len + 8);
4685 ffio_wfourcc(pb, "mdta");
4686 avio_write(pb, t->key, key_len);
4687 count += 1;
4688 }
4689 curpos = avio_tell(pb);
4690 avio_seek(pb, entry_pos, SEEK_SET);
4691 avio_wb32(pb, count); // rewrite entry count
4692 avio_seek(pb, curpos, SEEK_SET);
4693
4694 return update_size(pb, pos);
4695 }
4696
4697 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4698 AVFormatContext *s)
4699 {
4700 const AVDictionaryEntry *t = NULL;
4701 int64_t pos = avio_tell(pb);
4702 int count = 1; /* keys are 1-index based */
4703
4704 avio_wb32(pb, 0); /* size */
4705 ffio_wfourcc(pb, "ilst");
4706
4707 while (t = av_dict_iterate(s->metadata, t)) {
4708 int64_t entry_pos = avio_tell(pb);
4709 avio_wb32(pb, 0); /* size */
4710 avio_wb32(pb, count); /* key */
4711 mov_write_string_data_tag(pb, t->value, 0, 1);
4712 update_size(pb, entry_pos);
4713 count += 1;
4714 }
4715 return update_size(pb, pos);
4716 }
4717
4718 /* meta data tags */
4719 82 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4720 AVFormatContext *s)
4721 {
4722 82 int size = 0;
4723 82 int64_t pos = avio_tell(pb);
4724 82 avio_wb32(pb, 0); /* size */
4725 82 ffio_wfourcc(pb, "meta");
4726 82 avio_wb32(pb, 0);
4727
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4728 mov_write_mdta_hdlr_tag(pb, mov, s);
4729 mov_write_mdta_keys_tag(pb, mov, s);
4730 mov_write_mdta_ilst_tag(pb, mov, s);
4731
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (mov->mode == MODE_AVIF) {
4732 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4733 // We always write the primary item id as 1 since only one track is
4734 // supported for AVIF.
4735 mov_write_pitm_tag(pb, 1);
4736 mov_write_iloc_tag(pb, mov, s);
4737 mov_write_iinf_tag(pb, mov, s);
4738 if (mov->nb_streams > 1)
4739 mov_write_iref_tag(pb, mov, s);
4740 mov_write_iprp_tag(pb, mov, s);
4741 } else {
4742 /* iTunes metadata tag */
4743 82 mov_write_itunes_hdlr_tag(pb, mov, s);
4744 82 mov_write_ilst_tag(pb, mov, s);
4745 }
4746 82 size = update_size(pb, pos);
4747 82 return size;
4748 }
4749
4750 154 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4751 const char *name, const char *key)
4752 {
4753 int len;
4754 AVDictionaryEntry *t;
4755
4756
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4757 154 return 0;
4758
4759 len = strlen(t->value);
4760 if (len > 0) {
4761 int size = len + 8;
4762 avio_wb32(pb, size);
4763 ffio_wfourcc(pb, name);
4764 avio_write(pb, t->value, len);
4765 return size;
4766 }
4767 return 0;
4768 }
4769
4770 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4771 {
4772 int val;
4773 while (*b) {
4774 GET_UTF8(val, *b++, return -1;)
4775 avio_wb16(pb, val);
4776 }
4777 avio_wb16(pb, 0x00);
4778 return 0;
4779 }
4780
4781 static uint16_t language_code(const char *str)
4782 {
4783 return (((str[0] - 0x60) & 0x1F) << 10) +
4784 (((str[1] - 0x60) & 0x1F) << 5) +
4785 (( str[2] - 0x60) & 0x1F);
4786 }
4787
4788 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4789 const char *tag, const char *str)
4790 {
4791 int64_t pos = avio_tell(pb);
4792 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4793 if (!t || !utf8len(t->value))
4794 return 0;
4795 avio_wb32(pb, 0); /* size */
4796 ffio_wfourcc(pb, tag); /* type */
4797 avio_wb32(pb, 0); /* version + flags */
4798 if (!strcmp(tag, "yrrc"))
4799 avio_wb16(pb, atoi(t->value));
4800 else {
4801 avio_wb16(pb, language_code("eng")); /* language */
4802 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4803 if (!strcmp(tag, "albm") &&
4804 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4805 avio_w8(pb, atoi(t->value));
4806 }
4807 return update_size(pb, pos);
4808 }
4809
4810 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4811 {
4812 1 int64_t pos = avio_tell(pb);
4813 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4814
4815 1 avio_wb32(pb, 0); // size
4816 1 ffio_wfourcc(pb, "chpl");
4817 1 avio_wb32(pb, 0x01000000); // version + flags
4818 1 avio_wb32(pb, 0); // unknown
4819 1 avio_w8(pb, nb_chapters);
4820
4821
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4822 4 AVChapter *c = s->chapters[i];
4823 AVDictionaryEntry *t;
4824 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4825
4826
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4827
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4828 4 avio_w8(pb, len);
4829 4 avio_write(pb, t->value, len);
4830 } else
4831 avio_w8(pb, 0);
4832 }
4833 1 return update_size(pb, pos);
4834 }
4835
4836 236 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4837 AVFormatContext *s)
4838 {
4839 AVIOContext *pb_buf;
4840 int ret, size;
4841 uint8_t *buf;
4842
4843 236 ret = avio_open_dyn_buf(&pb_buf);
4844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (ret < 0)
4845 return ret;
4846
4847
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (mov->mode & MODE_3GP) {
4848 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
4849 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
4850 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
4851 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
4852 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
4853 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
4854 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
4855 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
4856 mov_write_loci_tag(s, pb_buf);
4857
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
4858 154 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
4859 154 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
4860 154 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
4861 154 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
4862 154 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
4863 154 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
4864 // currently ignored by mov.c
4865 154 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
4866 // add support for libquicktime, this atom is also actually read by mov.c
4867 154 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
4868 154 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
4869 154 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
4870 154 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
4871 154 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
4872 154 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
4873 154 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
4874 154 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
4875 } else {
4876 /* iTunes meta data */
4877 82 mov_write_meta_tag(pb_buf, mov, s);
4878 82 mov_write_loci_tag(s, pb_buf);
4879 }
4880
4881
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))
4882 1 mov_write_chpl_tag(pb_buf, s);
4883
4884
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 126 times.
236 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4885 110 avio_wb32(pb, size + 8);
4886 110 ffio_wfourcc(pb, "udta");
4887 110 avio_write(pb, buf, size);
4888 }
4889 236 ffio_free_dyn_buf(&pb_buf);
4890
4891 236 return 0;
4892 }
4893
4894 static void mov_write_psp_udta_tag(AVIOContext *pb,
4895 const char *str, const char *lang, int type)
4896 {
4897 int len = utf8len(str) + 1;
4898 if (len <= 0)
4899 return;
4900 avio_wb16(pb, len * 2 + 10); /* size */
4901 avio_wb32(pb, type); /* type */
4902 avio_wb16(pb, language_code(lang)); /* language */
4903 avio_wb16(pb, 0x01); /* ? */
4904 ascii_to_wc(pb, str);
4905 }
4906
4907 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
4908 {
4909 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
4910 int64_t pos, pos2;
4911
4912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
4913 pos = avio_tell(pb);
4914 avio_wb32(pb, 0); /* size placeholder*/
4915 ffio_wfourcc(pb, "uuid");
4916 ffio_wfourcc(pb, "USMT");
4917 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
4918 avio_wb32(pb, 0xbb88695c);
4919 avio_wb32(pb, 0xfac9c740);
4920
4921 pos2 = avio_tell(pb);
4922 avio_wb32(pb, 0); /* size placeholder*/
4923 ffio_wfourcc(pb, "MTDT");
4924 avio_wb16(pb, 4);
4925
4926 // ?
4927 avio_wb16(pb, 0x0C); /* size */
4928 avio_wb32(pb, 0x0B); /* type */
4929 avio_wb16(pb, language_code("und")); /* language */
4930 avio_wb16(pb, 0x0); /* ? */
4931 avio_wb16(pb, 0x021C); /* data */
4932
4933 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4934 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
4935 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
4936 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
4937
4938 update_size(pb, pos2);
4939 return update_size(pb, pos);
4940 }
4941
4942 1 return 0;
4943 }
4944
4945 322 static int mov_write_pssh_tag(AVIOContext *pb, AVStream *st)
4946 {
4947 AVEncryptionInitInfo *info;
4948 322 const AVPacketSideData *sd = av_packet_side_data_get(st->codecpar->coded_side_data,
4949 322 st->codecpar->nb_coded_side_data,
4950 AV_PKT_DATA_ENCRYPTION_INIT_INFO);
4951
1/2
✓ Branch 0 taken 322 times.
✗ Branch 1 not taken.
322 if (!sd)
4952 322 return 0;
4953
4954 info = av_encryption_init_info_get_side_data(sd->data, sd->size);
4955 for (AVEncryptionInitInfo *copy = info; copy; copy = copy->next) {
4956 int64_t pos;
4957
4958 if (!copy->data_size && !copy->num_key_ids)
4959 continue;
4960
4961 pos = avio_tell(pb);
4962 avio_wb32(pb, 0); /* size placeholder */
4963 ffio_wfourcc(pb, "pssh");
4964 avio_w8(pb, 1); /* version */
4965 avio_wb24(pb, 0);
4966 for (int i = 0; i < copy->system_id_size; i++)
4967 avio_w8(pb, copy->system_id[i]);
4968 avio_wb32(pb, copy->num_key_ids);
4969 for (int i = 0; i < copy->num_key_ids; i++)
4970 for (int j = 0; j < copy->key_id_size; j++)
4971 avio_w8(pb, copy->key_ids[i][j]);
4972 avio_wb32(pb, copy->data_size);
4973 avio_write(pb, copy->data, copy->data_size);
4974 update_size(pb, pos);
4975 }
4976
4977 av_encryption_init_info_free(info);
4978
4979 return 0;
4980 }
4981
4982 307 static void build_chunks(MOVTrack *trk)
4983 {
4984 int i;
4985 307 MOVIentry *chunk = &trk->cluster[0];
4986 307 uint64_t chunkSize = chunk->size;
4987 307 chunk->chunkNum = 1;
4988
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 252 times.
307 if (trk->chunkCount)
4989 55 return;
4990 252 trk->chunkCount = 1;
4991
2/2
✓ Branch 0 taken 14753 times.
✓ Branch 1 taken 252 times.
15005 for (i = 1; i<trk->entry; i++){
4992
2/2
✓ Branch 0 taken 12852 times.
✓ Branch 1 taken 1901 times.
14753 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
4993
2/2
✓ Branch 0 taken 12207 times.
✓ Branch 1 taken 645 times.
12852 chunkSize + trk->cluster[i].size < (1<<20)){
4994 12207 chunkSize += trk->cluster[i].size;
4995 12207 chunk->samples_in_chunk += trk->cluster[i].entries;
4996 } else {
4997 2546 trk->cluster[i].chunkNum = chunk->chunkNum+1;
4998 2546 chunk=&trk->cluster[i];
4999 2546 chunkSize = chunk->size;
5000 2546 trk->chunkCount++;
5001 }
5002 }
5003 }
5004
5005 /**
5006 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
5007 * the stream ids are used as track ids.
5008 *
5009 * This assumes mov->tracks and s->streams are in the same order and
5010 * there are no gaps in either of them (so mov->tracks[n] refers to
5011 * s->streams[n]).
5012 *
5013 * As an exception, there can be more entries in
5014 * s->streams than in mov->tracks, in which case new track ids are
5015 * generated (starting after the largest found stream id).
5016 */
5017 237 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
5018 {
5019 int i;
5020
5021
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 209 times.
237 if (mov->track_ids_ok)
5022 28 return 0;
5023
5024
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->use_stream_ids_as_track_ids) {
5025 1 int next_generated_track_id = 0;
5026
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
5027 2 AVStream *st = mov->tracks[i].st;
5028
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
5029 2 next_generated_track_id = st->id;
5030 }
5031
5032
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
5033
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))
5034 continue;
5035
5036
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;
5037 }
5038 } else {
5039 208 int last_track_id = 0;
5040
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 208 times.
482 for (i = 0; i < mov->nb_tracks; i++) {
5041
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))
5042 2 continue;
5043
5044 272 last_track_id =
5045 272 mov->tracks[i].track_id = (mov->tracks[i].st
5046 269 ? FFMAX(mov->tracks[i].st->index, last_track_id)
5047
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 3 times.
272 : FFMAX(i, last_track_id)) + 1;
5048 }
5049 }
5050
5051 209 mov->track_ids_ok = 1;
5052
5053 209 return 0;
5054 }
5055
5056 237 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
5057 AVFormatContext *s)
5058 {
5059 int i;
5060 237 int64_t pos = avio_tell(pb);
5061 237 avio_wb32(pb, 0); /* size placeholder*/
5062 237 ffio_wfourcc(pb, "moov");
5063
5064 237 mov_setup_track_ids(mov, s);
5065
5066
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5067
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))
5068 2 continue;
5069
5070 333 mov->tracks[i].time = mov->time;
5071
5072
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 26 times.
333 if (mov->tracks[i].entry)
5073 307 build_chunks(&mov->tracks[i]);
5074 }
5075
5076
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
237 if (mov->chapter_track)
5077
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
5078 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
5079 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
5080 }
5081
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5082 335 MOVTrack *track = &mov->tracks[i];
5083
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 333 times.
335 if (track->tag == MKTAG('r','t','p',' ')) {
5084 2 track->tref_tag = MKTAG('h','i','n','t');
5085 2 track->tref_id = mov->tracks[track->src_track].track_id;
5086
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
333 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5087 108 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5088 108 track->st->codecpar->nb_coded_side_data,
5089 AV_PKT_DATA_FALLBACK_TRACK );
5090
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)) {
5091 int *fallback = (int *)sd->data;
5092 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5093 track->tref_tag = MKTAG('f','a','l','l');
5094 track->tref_id = mov->tracks[*fallback].track_id;
5095 }
5096 }
5097 }
5098 }
5099
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5100
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 322 times.
335 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
5101 13 int src_trk = mov->tracks[i].src_track;
5102 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
5103 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
5104 //src_trk may have a different timescale than the tmcd track
5105 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5106 13 mov->tracks[i].timescale,
5107 13 mov->tracks[src_trk].timescale);
5108 }
5109 }
5110
5111 237 mov_write_mvhd_tag(pb, mov);
5112
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)
5113 mov_write_iods_tag(pb, mov);
5114
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5115
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 ||
5116
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5117
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);
5118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (ret < 0)
5119 return ret;
5120 }
5121 }
5122
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 181 times.
237 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5123 56 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5124
5125
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
237 if (mov->mode == MODE_PSP)
5126 1 mov_write_uuidusmt_tag(pb, s);
5127
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 else if (mov->mode != MODE_AVIF)
5128 236 mov_write_udta_tag(pb, mov, s);
5129
2/2
✓ Branch 0 taken 322 times.
✓ Branch 1 taken 237 times.
559 for (i = 0; i < mov->nb_streams; i++)
5130 322 mov_write_pssh_tag(pb, mov->tracks[i].st);
5131
5132 237 return update_size(pb, pos);
5133 }
5134
5135 static void param_write_int(AVIOContext *pb, const char *name, int value)
5136 {
5137 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5138 }
5139
5140 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5141 {
5142 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5143 }
5144
5145 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5146 {
5147 char buf[150];
5148 len = FFMIN(sizeof(buf) / 2 - 1, len);
5149 ff_data_to_hex(buf, value, len, 0);
5150 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5151 }
5152
5153 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5154 {
5155 int64_t pos = avio_tell(pb);
5156 int i;
5157
5158 static const AVUUID uuid = {
5159 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5160 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5161 };
5162
5163 avio_wb32(pb, 0);
5164 ffio_wfourcc(pb, "uuid");
5165 avio_write(pb, uuid, AV_UUID_LEN);
5166 avio_wb32(pb, 0);
5167
5168 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5169 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5170 avio_printf(pb, "<head>\n");
5171 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5172 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5173 LIBAVFORMAT_IDENT);
5174 avio_printf(pb, "</head>\n");
5175 avio_printf(pb, "<body>\n");
5176 avio_printf(pb, "<switch>\n");
5177
5178 mov_setup_track_ids(mov, s);
5179
5180 for (i = 0; i < mov->nb_tracks; i++) {
5181 MOVTrack *track = &mov->tracks[i];
5182 struct mpeg4_bit_rate_values bit_rates =
5183 calculate_mpeg4_bit_rates(track);
5184 const char *type;
5185 int track_id = track->track_id;
5186 char track_name_buf[32] = { 0 };
5187
5188 AVStream *st = track->st;
5189 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5190
5191 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5192 type = "video";
5193 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5194 type = "audio";
5195 } else {
5196 continue;
5197 }
5198
5199 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5200 bit_rates.avg_bit_rate);
5201 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5202 param_write_int(pb, "trackID", track_id);
5203 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5204
5205 /* Build track name piece by piece: */
5206 /* 1. track type */
5207 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5208 /* 2. track language, if available */
5209 if (lang)
5210 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5211 "_%s", lang->value);
5212 /* 3. special type suffix */
5213 /* "_cc" = closed captions, "_ad" = audio_description */
5214 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5215 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5216 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5217 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5218
5219 param_write_string(pb, "trackName", track_name_buf);
5220
5221 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5222 if (track->par->codec_id == AV_CODEC_ID_H264) {
5223 uint8_t *ptr;
5224 int size = track->par->extradata_size;
5225 if (!ff_avc_write_annexb_extradata(track->par->extradata, &ptr,
5226 &size)) {
5227 param_write_hex(pb, "CodecPrivateData",
5228 ptr ? ptr : track->par->extradata,
5229 size);
5230 av_free(ptr);
5231 }
5232 param_write_string(pb, "FourCC", "H264");
5233 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5234 param_write_string(pb, "FourCC", "WVC1");
5235 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5236 track->par->extradata_size);
5237 }
5238 param_write_int(pb, "MaxWidth", track->par->width);
5239 param_write_int(pb, "MaxHeight", track->par->height);
5240 param_write_int(pb, "DisplayWidth", track->par->width);
5241 param_write_int(pb, "DisplayHeight", track->par->height);
5242 } else {
5243 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5244 switch (track->par->profile) {
5245 case AV_PROFILE_AAC_HE_V2:
5246 param_write_string(pb, "FourCC", "AACP");
5247 break;
5248 case AV_PROFILE_AAC_HE:
5249 param_write_string(pb, "FourCC", "AACH");
5250 break;
5251 default:
5252 param_write_string(pb, "FourCC", "AACL");
5253 }
5254 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5255 param_write_string(pb, "FourCC", "WMAP");
5256 }
5257 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5258 track->par->extradata_size);
5259 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5260 track->par->codec_id));
5261 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5262 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5263 0 : track->par->sample_rate);
5264 param_write_int(pb, "BitsPerSample", 16);
5265 param_write_int(pb, "PacketSize", track->par->block_align ?
5266 track->par->block_align : 4);
5267 }
5268 avio_printf(pb, "</%s>\n", type);
5269 }
5270 avio_printf(pb, "</switch>\n");
5271 avio_printf(pb, "</body>\n");
5272 avio_printf(pb, "</smil>\n");
5273
5274 return update_size(pb, pos);
5275 }
5276
5277 142 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5278 {
5279 142 avio_wb32(pb, 16);
5280 142 ffio_wfourcc(pb, "mfhd");
5281 142 avio_wb32(pb, 0);
5282 142 avio_wb32(pb, mov->fragments);
5283 142 return 0;
5284 }
5285
5286 10742 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5287 {
5288
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 :
5289 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5290 }
5291
5292 234 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5293 MOVTrack *track, int64_t moof_offset)
5294 {
5295 234 int64_t pos = avio_tell(pb);
5296 234 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5297 MOV_TFHD_BASE_DATA_OFFSET;
5298
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (!track->entry) {
5299 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5300 } else {
5301 234 flags |= MOV_TFHD_DEFAULT_FLAGS;
5302 }
5303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5304 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5305
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 156 times.
234 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5306 78 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5307 78 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5308 }
5309 /* CMAF requires all values to be explicit in tfhd atoms */
5310
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 226 times.
234 if (mov->flags & FF_MOV_FLAG_CMAF)
5311 8 flags |= MOV_TFHD_STSD_ID;
5312
5313 /* Don't set a default sample size, the silverlight player refuses
5314 * to play files with that set. Don't set a default sample duration,
5315 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5316 * file format says it MUST NOT be set. */
5317
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (track->mode == MODE_ISM)
5318 30 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5319 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5320
5321 234 avio_wb32(pb, 0); /* size placeholder */
5322 234 ffio_wfourcc(pb, "tfhd");
5323 234 avio_w8(pb, 0); /* version */
5324 234 avio_wb24(pb, flags);
5325
5326 234 avio_wb32(pb, track->track_id); /* track-id */
5327
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 108 times.
234 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5328 126 avio_wb64(pb, moof_offset);
5329
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 226 times.
234 if (flags & MOV_TFHD_STSD_ID) {
5330 8 avio_wb32(pb, 1);
5331 }
5332
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5333 204 track->default_duration = get_cluster_duration(track, 0);
5334 204 avio_wb32(pb, track->default_duration);
5335 }
5336
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5337
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 track->default_size = track->entry ? track->cluster[0].size : 1;
5338 204 avio_wb32(pb, track->default_size);
5339 } else
5340 30 track->default_size = -1;
5341
5342
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5343 /* Set the default flags based on the second sample, if available.
5344 * If the first sample is different, that can be signaled via a separate field. */
5345
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 10 times.
234 if (track->entry > 1)
5346 224 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5347 else
5348 10 track->default_sample_flags =
5349 10 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5350
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) :
5351 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5352 234 avio_wb32(pb, track->default_sample_flags);
5353 }
5354
5355 234 return update_size(pb, pos);
5356 }
5357
5358 234 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5359 MOVTrack *track, int moof_size,
5360 int first, int end)
5361 {
5362 234 int64_t pos = avio_tell(pb);
5363 234 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5364 int i;
5365
5366
2/2
✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 234 times.
10278 for (i = first; i < end; i++) {
5367
2/2
✓ Branch 1 taken 618 times.
✓ Branch 2 taken 9426 times.
10044 if (get_cluster_duration(track, i) != track->default_duration)
5368 618 flags |= MOV_TRUN_SAMPLE_DURATION;
5369
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 9544 times.
10044 if (track->cluster[i].size != track->default_size)
5370 500 flags |= MOV_TRUN_SAMPLE_SIZE;
5371
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)
5372 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5373 }
5374
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 &&
5375
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 116 times.
226 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5376 110 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5377
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 166 times.
234 if (track->flags & MOV_TRACK_CTTS)
5378 68 flags |= MOV_TRUN_SAMPLE_CTS;
5379
5380 234 avio_wb32(pb, 0); /* size placeholder */
5381 234 ffio_wfourcc(pb, "trun");
5382
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 180 times.
234 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5383 54 avio_w8(pb, 1); /* version */
5384 else
5385 180 avio_w8(pb, 0); /* version */
5386 234 avio_wb24(pb, flags);
5387
5388 234 avio_wb32(pb, end - first); /* sample count */
5389
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5390 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5391 !mov->first_trun)
5392 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5393 else
5394 234 avio_wb32(pb, moof_size + 8 + track->data_offset +
5395 234 track->cluster[first].pos); /* data offset */
5396
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 124 times.
234 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5397 110 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5398
5399
2/2
✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 234 times.
10278 for (i = first; i < end; i++) {
5400
2/2
✓ Branch 0 taken 722 times.
✓ Branch 1 taken 9322 times.
10044 if (flags & MOV_TRUN_SAMPLE_DURATION)
5401 722 avio_wb32(pb, get_cluster_duration(track, i));
5402
2/2
✓ Branch 0 taken 1064 times.
✓ Branch 1 taken 8980 times.
10044 if (flags & MOV_TRUN_SAMPLE_SIZE)
5403 1064 avio_wb32(pb, track->cluster[i].size);
5404
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 9672 times.
10044 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5405 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5406
2/2
✓ Branch 0 taken 1980 times.
✓ Branch 1 taken 8064 times.
10044 if (flags & MOV_TRUN_SAMPLE_CTS)
5407 1980 avio_wb32(pb, track->cluster[i].cts);
5408 }
5409
5410 234 mov->first_trun = 0;
5411 234 return update_size(pb, pos);
5412 }
5413
5414 30 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5415 {
5416 30 int64_t pos = avio_tell(pb);
5417 static const uint8_t uuid[] = {
5418 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5419 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5420 };
5421
5422 30 avio_wb32(pb, 0); /* size placeholder */
5423 30 ffio_wfourcc(pb, "uuid");
5424 30 avio_write(pb, uuid, AV_UUID_LEN);
5425 30 avio_w8(pb, 1);
5426 30 avio_wb24(pb, 0);
5427 30 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5428 30 avio_wb64(pb, track->end_pts -
5429 30 (track->cluster[0].dts + track->cluster[0].cts));
5430
5431 30 return update_size(pb, pos);
5432 }
5433
5434 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5435 MOVTrack *track, int entry)
5436 {
5437 int n = track->nb_frag_info - 1 - entry, i;
5438 int size = 8 + 16 + 4 + 1 + 16*n;
5439 static const uint8_t uuid[] = {
5440 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5441 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5442 };
5443
5444 if (entry < 0)
5445 return 0;
5446
5447 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5448 avio_wb32(pb, size);
5449 ffio_wfourcc(pb, "uuid");
5450 avio_write(pb, uuid, AV_UUID_LEN);
5451 avio_w8(pb, 1);
5452 avio_wb24(pb, 0);
5453 avio_w8(pb, n);
5454 for (i = 0; i < n; i++) {
5455 int index = entry + 1 + i;
5456 avio_wb64(pb, track->frag_info[index].time);
5457 avio_wb64(pb, track->frag_info[index].duration);
5458 }
5459 if (n < mov->ism_lookahead) {
5460 int free_size = 16 * (mov->ism_lookahead - n);
5461 avio_wb32(pb, free_size);
5462 ffio_wfourcc(pb, "free");
5463 ffio_fill(pb, 0, free_size - 8);
5464 }
5465
5466 return 0;
5467 }
5468
5469 117 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5470 MOVTrack *track)
5471 {
5472 117 int64_t pos = avio_tell(pb);
5473 int i;
5474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 for (i = 0; i < mov->ism_lookahead; i++) {
5475 /* Update the tfrf tag for the last ism_lookahead fragments,
5476 * nb_frag_info - 1 is the next fragment to be written. */
5477 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5478 }
5479 117 avio_seek(pb, pos, SEEK_SET);
5480 117 return 0;
5481 }
5482
5483 71 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5484 int size)
5485 {
5486 int i;
5487
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 71 times.
204 for (i = 0; i < mov->nb_tracks; i++) {
5488 133 MOVTrack *track = &mov->tracks[i];
5489 MOVFragmentInfo *info;
5490
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)
5491 16 continue;
5492 117 track->nb_frag_info++;
5493
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 54 times.
117 if (track->nb_frag_info >= track->frag_info_capacity) {
5494 63 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5495
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
63 if (av_reallocp_array(&track->frag_info,
5496 new_capacity,
5497 sizeof(*track->frag_info)))
5498 return AVERROR(ENOMEM);
5499 63 track->frag_info_capacity = new_capacity;
5500 }
5501 117 info = &track->frag_info[track->nb_frag_info - 1];
5502 117 info->offset = avio_tell(pb);
5503 117 info->size = size;
5504 // Try to recreate the original pts for the first packet
5505 // from the fields we have stored
5506 117 info->time = track->cluster[0].dts + track->cluster[0].cts;
5507 117 info->duration = track->end_pts -
5508 117 (track->cluster[0].dts + track->cluster[0].cts);
5509 // If the pts is less than zero, we will have trimmed
5510 // away parts of the media track using an edit list,
5511 // and the corresponding start presentation time is zero.
5512
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 109 times.
117 if (info->time < 0) {
5513 8 info->duration += info->time;
5514 8 info->time = 0;
5515 }
5516 117 info->tfrf_offset = 0;
5517 117 mov_write_tfrf_tags(pb, mov, track);
5518 }
5519 71 return 0;
5520 }
5521
5522 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5523 {
5524 int i;
5525 for (i = 0; i < mov->nb_tracks; i++) {
5526 MOVTrack *track = &mov->tracks[i];
5527 if ((tracks >= 0 && i != tracks) || !track->entry)
5528 continue;
5529 if (track->nb_frag_info > max) {
5530 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5531 track->nb_frag_info = max;
5532 }
5533 }
5534 }
5535
5536 204 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5537 {
5538 204 int64_t pos = avio_tell(pb);
5539
5540 204 avio_wb32(pb, 0); /* size */
5541 204 ffio_wfourcc(pb, "tfdt");
5542 204 avio_w8(pb, 1); /* version */
5543 204 avio_wb24(pb, 0);
5544 204 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5545 204 return update_size(pb, pos);
5546 }
5547
5548 234 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5549 MOVTrack *track, int64_t moof_offset,
5550 int moof_size)
5551 {
5552 234 int64_t pos = avio_tell(pb);
5553 234 int i, start = 0;
5554 234 avio_wb32(pb, 0); /* size placeholder */
5555 234 ffio_wfourcc(pb, "traf");
5556
5557 234 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5558
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (mov->mode != MODE_ISM)
5559 204 mov_write_tfdt_tag(pb, track);
5560
2/2
✓ Branch 0 taken 9810 times.
✓ Branch 1 taken 234 times.
10044 for (i = 1; i < track->entry; i++) {
5561
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) {
5562 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5563 start = i;
5564 }
5565 }
5566 234 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5567
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (mov->mode == MODE_ISM) {
5568 30 mov_write_tfxd_tag(pb, track);
5569
5570
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (mov->ism_lookahead) {
5571 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5572
5573 if (track->nb_frag_info > 0) {
5574 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5575 if (!info->tfrf_offset)
5576 info->tfrf_offset = avio_tell(pb);
5577 }
5578 avio_wb32(pb, 8 + size);
5579 ffio_wfourcc(pb, "free");
5580 ffio_fill(pb, 0, size);
5581 }
5582 }
5583
5584
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))
5585 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb, moof_offset);
5586
5587 234 return update_size(pb, pos);
5588 }
5589
5590 142 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5591 int tracks, int moof_size)
5592 {
5593 142 int64_t pos = avio_tell(pb);
5594 int i;
5595
5596 142 avio_wb32(pb, 0); /* size placeholder */
5597 142 ffio_wfourcc(pb, "moof");
5598 142 mov->first_trun = 1;
5599
5600 142 mov_write_mfhd_tag(pb, mov);
5601
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 142 times.
408 for (i = 0; i < mov->nb_tracks; i++) {
5602 266 MOVTrack *track = &mov->tracks[i];
5603
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)
5604 24 continue;
5605
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 234 times.
242 if (!track->entry)
5606 8 continue;
5607
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))
5608 mov_write_pssh_tag(pb, track->st);
5609 234 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5610 }
5611
5612 142 return update_size(pb, pos);
5613 }
5614
5615 70 static int mov_write_sidx_tag(AVIOContext *pb,
5616 MOVTrack *track, int ref_size, int total_sidx_size)
5617 {
5618 70 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5619 int64_t presentation_time, duration, offset;
5620 unsigned starts_with_SAP;
5621 int i, entries;
5622
5623
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 if (track->entry) {
5624 70 entries = 1;
5625 70 presentation_time = track->cluster[0].dts + track->cluster[0].cts -
5626 70 track->start_dts - track->start_cts;
5627 70 duration = track->end_pts -
5628 70 (track->cluster[0].dts + track->cluster[0].cts);
5629 70 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5630
5631 // pts<0 should be cut away using edts
5632
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (presentation_time < 0) {
5633 duration += presentation_time;
5634 presentation_time = 0;
5635 }
5636 } else {
5637 entries = track->nb_frag_info;
5638 if (entries <= 0)
5639 return 0;
5640 presentation_time = track->frag_info[0].time;
5641 /* presentation_time <= 0 is handled by mov_add_tfra_entries() */
5642 if (presentation_time > 0)
5643 presentation_time -= track->start_dts + track->start_cts;
5644 }
5645
5646 70 avio_wb32(pb, 0); /* size */
5647 70 ffio_wfourcc(pb, "sidx");
5648 70 avio_w8(pb, 1); /* version */
5649 70 avio_wb24(pb, 0);
5650 70 avio_wb32(pb, track->track_id); /* reference_ID */
5651 70 avio_wb32(pb, track->timescale); /* timescale */
5652 70 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5653 70 offset_pos = avio_tell(pb);
5654 70 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5655 70 avio_wb16(pb, 0); /* reserved */
5656
5657 70 avio_wb16(pb, entries); /* reference_count */
5658
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 70 times.
140 for (i = 0; i < entries; i++) {
5659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (!track->entry) {
5660 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5661 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5662 }
5663 duration = track->frag_info[i].duration;
5664 ref_size = track->frag_info[i].size;
5665 starts_with_SAP = 1;
5666 }
5667 70 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5668 70 avio_wb32(pb, duration); /* subsegment_duration */
5669 70 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5670 }
5671
5672 70 end_pos = avio_tell(pb);
5673 70 offset = pos + total_sidx_size - end_pos;
5674 70 avio_seek(pb, offset_pos, SEEK_SET);
5675 70 avio_wb64(pb, offset);
5676 70 avio_seek(pb, end_pos, SEEK_SET);
5677 70 return update_size(pb, pos);
5678 }
5679
5680 20 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5681 int tracks, int ref_size)
5682 {
5683 int i, round, ret;
5684 AVIOContext *avio_buf;
5685 20 int total_size = 0;
5686
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (round = 0; round < 2; round++) {
5687 // First run one round to calculate the total size of all
5688 // sidx atoms.
5689 // This would be much simpler if we'd only write one sidx
5690 // atom, for the first track in the moof.
5691
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0) {
5692
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5693 return ret;
5694 } else {
5695 20 avio_buf = pb;
5696 }
5697
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 40 times.
110 for (i = 0; i < mov->nb_tracks; i++) {
5698 70 MOVTrack *track = &mov->tracks[i];
5699
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)
5700 continue;
5701 // When writing a sidx for the full file, entry is 0, but
5702 // we want to include all tracks. ref_size is 0 in this case,
5703 // since we read it from frag_info instead.
5704
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)
5705 continue;
5706 70 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5707 total_size);
5708 }
5709
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0)
5710 20 total_size = ffio_close_null_buf(avio_buf);
5711 }
5712 20 return 0;
5713 }
5714
5715 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5716 {
5717 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5718 MOVTrack *first_track;
5719 int flags = 24;
5720
5721 /* PRFT should be associated with at most one track. So, choosing only the
5722 * first track. */
5723 if (tracks > 0)
5724 return 0;
5725 first_track = &(mov->tracks[0]);
5726
5727 if (!first_track->entry) {
5728 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5729 return 0;
5730 }
5731
5732 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5733 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5734 return 0;
5735 }
5736
5737 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5738 if (first_track->cluster[0].prft.wallclock) {
5739 /* Round the NTP time to whole milliseconds. */
5740 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5741 NTP_OFFSET_US);
5742 flags = first_track->cluster[0].prft.flags;
5743 } else
5744 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5745 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5746 pts_us = av_rescale_q(first_track->cluster[0].pts,
5747 first_track->st->time_base, AV_TIME_BASE_Q);
5748 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5749 } else {
5750 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5751 mov->write_prft);
5752 return 0;
5753 }
5754
5755 avio_wb32(pb, 0); // Size place holder
5756 ffio_wfourcc(pb, "prft"); // Type
5757 avio_w8(pb, 1); // Version
5758 avio_wb24(pb, flags); // Flags
5759 avio_wb32(pb, first_track->track_id); // reference track ID
5760 avio_wb64(pb, ntp_ts); // NTP time stamp
5761 avio_wb64(pb, first_track->cluster[0].pts); //media time
5762 return update_size(pb, pos);
5763 }
5764
5765 71 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5766 int64_t mdat_size)
5767 {
5768 AVIOContext *avio_buf;
5769 int ret, moof_size;
5770
5771
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
71 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5772 return ret;
5773 71 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5774 71 moof_size = ffio_close_null_buf(avio_buf);
5775
5776
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 51 times.
71 if (mov->flags & FF_MOV_FLAG_DASH &&
5777
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5778 20 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5779
5780
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)
5781 mov_write_prft_tag(pb, mov, tracks);
5782
5783
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5785 mov->ism_lookahead) {
5786
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)
5787 return ret;
5788
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5790 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5791 }
5792 }
5793
5794 71 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5795 }
5796
5797 61 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5798 {
5799 61 int64_t pos = avio_tell(pb);
5800 int i;
5801
5802 61 avio_wb32(pb, 0); /* size placeholder */
5803 61 ffio_wfourcc(pb, "tfra");
5804 61 avio_w8(pb, 1); /* version */
5805 61 avio_wb24(pb, 0);
5806
5807 61 avio_wb32(pb, track->track_id);
5808 61 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5809 61 avio_wb32(pb, track->nb_frag_info);
5810
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 61 times.
175 for (i = 0; i < track->nb_frag_info; i++) {
5811 114 avio_wb64(pb, track->frag_info[i].time);
5812 114 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5813 114 avio_w8(pb, 1); /* traf number */
5814 114 avio_w8(pb, 1); /* trun number */
5815 114 avio_w8(pb, 1); /* sample number */
5816 }
5817
5818 61 return update_size(pb, pos);
5819 }
5820
5821 33 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5822 {
5823 AVIOContext *mfra_pb;
5824 int i, ret, sz;
5825 uint8_t *buf;
5826
5827 33 ret = avio_open_dyn_buf(&mfra_pb);
5828
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret < 0)
5829 return ret;
5830
5831 33 avio_wb32(mfra_pb, 0); /* size placeholder */
5832 33 ffio_wfourcc(mfra_pb, "mfra");
5833 /* An empty mfra atom is enough to indicate to the publishing point that
5834 * the stream has ended. */
5835
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_ISML)
5836 goto done_mfra;
5837
5838
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++) {
5839 63 MOVTrack *track = &mov->tracks[i];
5840
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2 times.
63 if (track->nb_frag_info)
5841 61 mov_write_tfra_tag(mfra_pb, track);
5842 }
5843
5844 33 avio_wb32(mfra_pb, 16);
5845 33 ffio_wfourcc(mfra_pb, "mfro");
5846 33 avio_wb32(mfra_pb, 0); /* version + flags */
5847 33 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
5848
5849 33 done_mfra:
5850
5851 33 sz = update_size(mfra_pb, 0);
5852 33 ret = avio_get_dyn_buf(mfra_pb, &buf);
5853 33 avio_write(pb, buf, ret);
5854 33 ffio_free_dyn_buf(&mfra_pb);
5855
5856 33 return sz;
5857 }
5858
5859 175 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
5860 {
5861 175 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
5862
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 30 times.
175 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
5863
5864 175 mov->mdat_pos = avio_tell(pb);
5865 175 avio_wb32(pb, 0); /* size placeholder*/
5866 175 ffio_wfourcc(pb, "mdat");
5867 175 return 0;
5868 }
5869
5870 418 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
5871 int has_h264, int has_video, int write_minor)
5872 {
5873 418 MOVMuxContext *mov = s->priv_data;
5874 418 int minor = 0x200;
5875
5876
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)
5877 ffio_wfourcc(pb, mov->major_brand);
5878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 else if (mov->mode == MODE_3GP) {
5879 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
5880 minor = has_h264 ? 0x100 : 0x200;
5881
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 } else if (mov->mode == MODE_AVIF) {
5882 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
5883 minor = 0;
5884
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 } else if (mov->mode & MODE_3G2) {
5885 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
5886 minor = has_h264 ? 0x20000 : 0x10000;
5887
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 416 times.
418 } else if (mov->mode == MODE_PSP)
5888 2 ffio_wfourcc(pb, "MSNV");
5889
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 &&
5890
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 52 times.
58 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5891 6 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
5892
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)
5893 22 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
5894
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)
5895 ffio_wfourcc(pb, "iso4");
5896
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 302 times.
388 else if (mov->mode == MODE_MP4)
5897 86 ffio_wfourcc(pb, "isom");
5898
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 300 times.
302 else if (mov->mode == MODE_IPOD)
5899
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
5900
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 292 times.
300 else if (mov->mode == MODE_ISM)
5901 8 ffio_wfourcc(pb, "isml");
5902
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 else if (mov->mode == MODE_F4V)
5903 ffio_wfourcc(pb, "f4v ");
5904 else
5905 292 ffio_wfourcc(pb, "qt ");
5906
5907
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 209 times.
418 if (write_minor)
5908 209 avio_wb32(pb, minor);
5909 418 }
5910
5911 209 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
5912 {
5913 209 MOVMuxContext *mov = s->priv_data;
5914 209 int64_t pos = avio_tell(pb);
5915 209 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
5916 209 int has_iamf = 0;
5917
5918 #if CONFIG_IAMFENC
5919
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 204 times.
209 for (int i = 0; i < s->nb_stream_groups; i++) {
5920 5 const AVStreamGroup *stg = s->stream_groups[i];
5921
5922
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
5923 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
5924 5 has_iamf = 1;
5925 5 break;
5926 }
5927 }
5928 #endif
5929
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (int i = 0; i < mov->nb_streams; i++) {
5930 267 AVStream *st = mov->tracks[i].st;
5931
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 265 times.
267 if (is_cover_image(st))
5932 2 continue;
5933
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 87 times.
265 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5934 178 has_video = 1;
5935
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 231 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
5936 34 has_h264 = 1;
5937
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 264 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
5938 1 has_av1 = 1;
5939
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 4 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
5940
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 1 times.
261 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
5941
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 ||
5942 260 av_packet_side_data_get(st->codecpar->coded_side_data,
5943 260 st->codecpar->nb_coded_side_data,
5944 AV_PKT_DATA_DOVI_CONF))
5945 5 has_dolby = 1;
5946
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
5947 has_id3 = 1;
5948 }
5949
5950 209 avio_wb32(pb, 0); /* size */
5951 209 ffio_wfourcc(pb, "ftyp");
5952
5953 // Write major brand
5954 209 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
5955 // Write the major brand as the first compatible brand as well
5956 209 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
5957
5958 // Write compatible brands, ensuring that we don't write the major brand as a
5959 // compatible brand a second time.
5960
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (mov->mode == MODE_ISM) {
5961 4 ffio_wfourcc(pb, "piff");
5962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 } else if (mov->mode == MODE_AVIF) {
5963 const AVPixFmtDescriptor *pix_fmt_desc =
5964 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
5965 const int depth = pix_fmt_desc->comp[0].depth;
5966 if (mov->is_animated_avif) {
5967 // For animated AVIF, major brand is "avis". Add "avif" as a
5968 // compatible brand.
5969 ffio_wfourcc(pb, "avif");
5970 ffio_wfourcc(pb, "msf1");
5971 ffio_wfourcc(pb, "iso8");
5972 }
5973 ffio_wfourcc(pb, "mif1");
5974 ffio_wfourcc(pb, "miaf");
5975 if (depth == 8 || depth == 10) {
5976 // MA1B and MA1A brands are based on AV1 profile. Short hand for
5977 // computing that is based on chroma subsampling type. 420 chroma
5978 // subsampling is MA1B. 444 chroma subsampling is MA1A.
5979 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
5980 // 444 chroma subsampling.
5981 ffio_wfourcc(pb, "MA1A");
5982 } else {
5983 // 420 chroma subsampling.
5984 ffio_wfourcc(pb, "MA1B");
5985 }
5986 }
5987
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 146 times.
205 } else if (mov->mode != MODE_MOV) {
5988 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
5989 // brand, if not already the major brand. This is compatible with users that
5990 // don't understand tfdt.
5991
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 2 times.
59 if (mov->mode == MODE_MP4) {
5992
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
57 if (mov->flags & FF_MOV_FLAG_CMAF)
5993 1 ffio_wfourcc(pb, "cmfc");
5994
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))
5995 26 ffio_wfourcc(pb, "iso6");
5996
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
57 if (has_av1)
5997 1 ffio_wfourcc(pb, "av01");
5998
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 54 times.
57 if (has_dolby)
5999 3 ffio_wfourcc(pb, "dby1");
6000
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 52 times.
57 if (has_iamf)
6001 5 ffio_wfourcc(pb, "iamf");
6002 } else {
6003
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
6004 ffio_wfourcc(pb, "iso6");
6005
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
6006 ffio_wfourcc(pb, "iso5");
6007
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
6008 ffio_wfourcc(pb, "iso4");
6009 }
6010 // Brands prior to iso5 can't be signaled when using default-base-is-moof
6011
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 12 times.
59 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
6012 // write isom for mp4 only if it it's not the major brand already.
6013
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)
6014 4 ffio_wfourcc(pb, "isom");
6015 47 ffio_wfourcc(pb, "iso2");
6016
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 27 times.
47 if (has_h264)
6017 20 ffio_wfourcc(pb, "avc1");
6018 }
6019 }
6020
6021
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 152 times.
209 if (mov->mode == MODE_MP4)
6022 57 ffio_wfourcc(pb, "mp41");
6023
6024
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)
6025 ffio_wfourcc(pb, "dash");
6026
6027
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (has_id3)
6028 ffio_wfourcc(pb, "aid3");
6029
6030 209 return update_size(pb, pos);
6031 }
6032
6033 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
6034 {
6035 1 AVStream *video_st = s->streams[0];
6036 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
6037 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
6038 1 int audio_rate = audio_par->sample_rate;
6039 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
6040
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 :
6041 0;
6042 1 int audio_kbitrate = audio_par->bit_rate / 1000;
6043 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
6044
6045
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) {
6046 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
6047 return AVERROR(EINVAL);
6048 }
6049
6050 1 avio_wb32(pb, 0x94); /* size */
6051 1 ffio_wfourcc(pb, "uuid");
6052 1 ffio_wfourcc(pb, "PROF");
6053
6054 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
6055 1 avio_wb32(pb, 0xbb88695c);
6056 1 avio_wb32(pb, 0xfac9c740);
6057
6058 1 avio_wb32(pb, 0x0); /* ? */
6059 1 avio_wb32(pb, 0x3); /* 3 sections ? */
6060
6061 1 avio_wb32(pb, 0x14); /* size */
6062 1 ffio_wfourcc(pb, "FPRF");
6063 1 avio_wb32(pb, 0x0); /* ? */
6064 1 avio_wb32(pb, 0x0); /* ? */
6065 1 avio_wb32(pb, 0x0); /* ? */
6066
6067 1 avio_wb32(pb, 0x2c); /* size */
6068 1 ffio_wfourcc(pb, "APRF"); /* audio */
6069 1 avio_wb32(pb, 0x0);
6070 1 avio_wb32(pb, 0x2); /* TrackID */
6071 1 ffio_wfourcc(pb, "mp4a");
6072 1 avio_wb32(pb, 0x20f);
6073 1 avio_wb32(pb, 0x0);
6074 1 avio_wb32(pb, audio_kbitrate);
6075 1 avio_wb32(pb, audio_kbitrate);
6076 1 avio_wb32(pb, audio_rate);
6077 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
6078
6079 1 avio_wb32(pb, 0x34); /* size */
6080 1 ffio_wfourcc(pb, "VPRF"); /* video */
6081 1 avio_wb32(pb, 0x0);
6082 1 avio_wb32(pb, 0x1); /* TrackID */
6083
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
6084 1 ffio_wfourcc(pb, "avc1");
6085 1 avio_wb16(pb, 0x014D);
6086 1 avio_wb16(pb, 0x0015);
6087 } else {
6088 ffio_wfourcc(pb, "mp4v");
6089 avio_wb16(pb, 0x0000);
6090 avio_wb16(pb, 0x0103);
6091 }
6092 1 avio_wb32(pb, 0x0);
6093 1 avio_wb32(pb, video_kbitrate);
6094 1 avio_wb32(pb, video_kbitrate);
6095 1 avio_wb32(pb, frame_rate);
6096 1 avio_wb32(pb, frame_rate);
6097 1 avio_wb16(pb, video_par->width);
6098 1 avio_wb16(pb, video_par->height);
6099 1 avio_wb32(pb, 0x010001); /* ? */
6100
6101 1 return 0;
6102 }
6103
6104 209 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6105 {
6106 209 MOVMuxContext *mov = s->priv_data;
6107 int i;
6108
6109 209 mov_write_ftyp_tag(pb,s);
6110
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->mode == MODE_PSP) {
6111 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6112
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6113 2 AVStream *st = mov->tracks[i].st;
6114
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6115 continue;
6116
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6117 1 video_streams_nb++;
6118
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6119 1 audio_streams_nb++;
6120 else
6121 other_streams_nb++;
6122 }
6123
6124
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) {
6125 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6126 return AVERROR(EINVAL);
6127 }
6128 1 return mov_write_uuidprof_tag(pb, s);
6129 }
6130 208 return 0;
6131 }
6132
6133 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6134 {
6135 8 uint32_t c = -1;
6136 8 int i, closed_gop = 0;
6137
6138
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6139 368 c = (c << 8) + pkt->data[i];
6140
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6141 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6142
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6143 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6144
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
6145 8 *flags = MOV_SYNC_SAMPLE;
6146 else
6147 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6148 8 break;
6149 }
6150 }
6151 8 return 0;
6152 }
6153
6154 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6155 {
6156 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6157 int seq = 0, entry = 0;
6158 int key = pkt->flags & AV_PKT_FLAG_KEY;
6159 start = find_next_marker(pkt->data, end);
6160 for (next = start; next < end; start = next) {
6161 next = find_next_marker(start + 4, end);
6162 switch (AV_RB32(start)) {
6163 case VC1_CODE_SEQHDR:
6164 seq = 1;
6165 break;
6166 case VC1_CODE_ENTRYPOINT:
6167 entry = 1;
6168 break;
6169 case VC1_CODE_SLICE:
6170 trk->vc1_info.slices = 1;
6171 break;
6172 }
6173 }
6174 if (!trk->entry && trk->vc1_info.first_packet_seen)
6175 trk->vc1_info.first_frag_written = 1;
6176 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6177 /* First packet in first fragment */
6178 trk->vc1_info.first_packet_seq = seq;
6179 trk->vc1_info.first_packet_entry = entry;
6180 trk->vc1_info.first_packet_seen = 1;
6181 } else if ((seq && !trk->vc1_info.packet_seq) ||
6182 (entry && !trk->vc1_info.packet_entry)) {
6183 int i;
6184 for (i = 0; i < trk->entry; i++)
6185 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6186 trk->has_keyframes = 0;
6187 if (seq)
6188 trk->vc1_info.packet_seq = 1;
6189 if (entry)
6190 trk->vc1_info.packet_entry = 1;
6191 if (!trk->vc1_info.first_frag_written) {
6192 /* First fragment */
6193 if ((!seq || trk->vc1_info.first_packet_seq) &&
6194 (!entry || trk->vc1_info.first_packet_entry)) {
6195 /* First packet had the same headers as this one, readd the
6196 * sync sample flag. */
6197 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6198 trk->has_keyframes = 1;
6199 }
6200 }
6201 }
6202 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6203 key = seq && entry;
6204 else if (trk->vc1_info.packet_seq)
6205 key = seq;
6206 else if (trk->vc1_info.packet_entry)
6207 key = entry;
6208 if (key) {
6209 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6210 trk->has_keyframes++;
6211 }
6212 }
6213
6214 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6215 {
6216 int length;
6217
6218 if (pkt->size < 8)
6219 return;
6220
6221 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6222 if (length < 8 || length > pkt->size)
6223 return;
6224
6225 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6226 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6227 trk->has_keyframes++;
6228 }
6229
6230 return;
6231 }
6232
6233 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6234 {
6235 MOVMuxContext *mov = s->priv_data;
6236 int ret, buf_size;
6237 uint8_t *buf;
6238 int i, offset;
6239
6240 if (!track->mdat_buf)
6241 return 0;
6242 if (!mov->mdat_buf) {
6243 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6244 return ret;
6245 }
6246 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6247
6248 offset = avio_tell(mov->mdat_buf);
6249 avio_write(mov->mdat_buf, buf, buf_size);
6250 ffio_free_dyn_buf(&track->mdat_buf);
6251
6252 for (i = track->entries_flushed; i < track->entry; i++)
6253 track->cluster[i].pos += offset;
6254 track->entries_flushed = track->entry;
6255 return 0;
6256 }
6257
6258 2 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6259 {
6260 2 MOVMuxContext *mov = s->priv_data;
6261 2 AVPacket *squashed_packet = mov->pkt;
6262 2 int ret = AVERROR_BUG;
6263
6264
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 switch (track->st->codecpar->codec_id) {
6265 2 case AV_CODEC_ID_TTML: {
6266 2 int had_packets = !!track->squashed_packet_queue.head;
6267
6268
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) {
6269 goto finish_squash;
6270 }
6271
6272 // We have generated a padding packet (no actual input packets in
6273 // queue) and its duration is zero. Skipping writing it.
6274
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) {
6275 goto finish_squash;
6276 }
6277
6278 2 track->end_reliable = 1;
6279 2 break;
6280 }
6281 default:
6282 ret = AVERROR(EINVAL);
6283 goto finish_squash;
6284 }
6285
6286 2 squashed_packet->stream_index = track->st->index;
6287
6288 2 ret = mov_write_single_packet(s, squashed_packet);
6289
6290 2 finish_squash:
6291 2 av_packet_unref(squashed_packet);
6292
6293 2 return ret;
6294 }
6295
6296 315 static int mov_write_squashed_packets(AVFormatContext *s)
6297 {
6298 315 MOVMuxContext *mov = s->priv_data;
6299
6300
2/2
✓ Branch 0 taken 459 times.
✓ Branch 1 taken 315 times.
774 for (int i = 0; i < mov->nb_streams; i++) {
6301 459 MOVTrack *track = &mov->tracks[i];
6302 459 int ret = AVERROR_BUG;
6303
6304
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) {
6305
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6306 av_log(s, AV_LOG_ERROR,
6307 "Failed to write squashed packet for %s stream with "
6308 "index %d and track id %d. Error: %s\n",
6309 avcodec_get_name(track->st->codecpar->codec_id),
6310 track->st->index, track->track_id,
6311 av_err2str(ret));
6312 return ret;
6313 }
6314 }
6315 }
6316
6317 315 return 0;
6318 }
6319
6320 129 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6321 int64_t ref_pos)
6322 {
6323 int i;
6324
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 125 times.
129 if (!track->entry)
6325 4 return 0;
6326
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 120 times.
125 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6327
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 5 times.
41 for (i = 0; i < track->entry; i++)
6328 36 track->cluster[i].pos += ref_pos + track->data_offset;
6329
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)) {
6330 // First flush. If this was a case of not using empty moov, reset chunking.
6331
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (i = 0; i < track->entry; i++) {
6332 18 track->cluster[i].chunkNum = 0;
6333 18 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6334 }
6335 }
6336
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (av_reallocp_array(&track->cluster_written,
6337 5 track->entry_written + track->entry,
6338 sizeof(*track->cluster)))
6339 return AVERROR(ENOMEM);
6340 5 memcpy(&track->cluster_written[track->entry_written],
6341 5 track->cluster, track->entry * sizeof(*track->cluster));
6342 5 track->entry_written += track->entry;
6343 }
6344 125 track->entry = 0;
6345 125 track->entries_flushed = 0;
6346 125 track->end_reliable = 0;
6347 125 return 0;
6348 }
6349
6350 106 static int mov_flush_fragment(AVFormatContext *s, int force)
6351 {
6352 106 MOVMuxContext *mov = s->priv_data;
6353 106 int i, first_track = -1;
6354 106 int64_t mdat_size = 0, mdat_start = 0;
6355 int ret;
6356 106 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6357
6358
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
106 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6359 return 0;
6360
6361 // Check if we have any tracks that require squashing.
6362 // In that case, we'll have to write the packet here.
6363
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 106 times.
106 if ((ret = mov_write_squashed_packets(s)) < 0)
6364 return ret;
6365
6366 // Try to fill in the duration of the last packet in each stream
6367 // from queued packets in the interleave queues. If the flushing
6368 // of fragments was triggered automatically by an AVPacket, we
6369 // already have reliable info for the end of that track, but other
6370 // tracks may need to be filled in.
6371
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 106 times.
298 for (i = 0; i < mov->nb_streams; i++) {
6372 192 MOVTrack *track = &mov->tracks[i];
6373
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 38 times.
192 if (!track->end_reliable) {
6374 154 const AVPacket *pkt = ff_interleaved_peek(s, i);
6375
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 148 times.
154 if (pkt) {
6376 int64_t offset, dts, pts;
6377 6 ff_get_muxer_ts_offset(s, i, &offset);
6378 6 pts = pkt->pts + offset;
6379 6 dts = pkt->dts + offset;
6380
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6381 dts += track->dts_shift;
6382 6 track->track_duration = dts - track->start_dts;
6383
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6384 6 track->end_pts = pts;
6385 else
6386 track->end_pts = dts;
6387 }
6388 }
6389 }
6390
6391
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 106 times.
304 for (i = 0; i < mov->nb_tracks; i++) {
6392 198 MOVTrack *track = &mov->tracks[i];
6393
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 153 times.
198 if (track->entry <= 1)
6394 45 continue;
6395 // Sample durations are calculated as the diff of dts values,
6396 // but for the last sample in a fragment, we don't know the dts
6397 // of the first sample in the next fragment, so we have to rely
6398 // on what was set as duration in the AVPacket. Not all callers
6399 // set this though, so we might want to replace it with an
6400 // estimate if it currently is zero.
6401
2/2
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 2 times.
153 if (get_cluster_duration(track, track->entry - 1) != 0)
6402 151 continue;
6403 // Use the duration (i.e. dts diff) of the second last sample for
6404 // the last one. This is a wild guess (and fatal if it turns out
6405 // to be too long), but probably the best we can do - having a zero
6406 // duration is bad as well.
6407 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6408 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6409
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6410 2 av_log(s, AV_LOG_WARNING,
6411 "Estimating the duration of the last packet in a "
6412 "fragment, consider setting the duration field in "
6413 "AVPacket instead.\n");
6414 2 mov->missing_duration_warned = 1;
6415 }
6416 }
6417
6418
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 83 times.
106 if (!mov->moov_written) {
6419 23 int64_t pos = avio_tell(s->pb);
6420 uint8_t *buf;
6421 int buf_size, moov_size;
6422
6423
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 19 times.
64 for (i = 0; i < mov->nb_tracks; i++)
6424
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))
6425 4 break;
6426 /* Don't write the initial moov unless all tracks have data */
6427
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)
6428 2 return 0;
6429
6430 21 moov_size = get_moov_size(s);
6431
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 21 times.
62 for (i = 0; i < mov->nb_tracks; i++)
6432 41 mov->tracks[i].data_offset = pos + moov_size + 8;
6433
6434 21 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6435
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6436 17 mov_write_identification(s->pb, s);
6437
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6438 return ret;
6439
6440
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6441
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6442 mov->reserved_header_pos = avio_tell(s->pb);
6443 17 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6444 17 mov->moov_written = 1;
6445 17 return 0;
6446 }
6447
6448 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6449 4 avio_wb32(s->pb, buf_size + 8);
6450 4 ffio_wfourcc(s->pb, "mdat");
6451 4 avio_write(s->pb, buf, buf_size);
6452 4 ffio_free_dyn_buf(&mov->mdat_buf);
6453
6454
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6455 mov->reserved_header_pos = avio_tell(s->pb);
6456
6457 4 mov->moov_written = 1;
6458 4 mov->mdat_size = 0;
6459
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (i = 0; i < mov->nb_tracks; i++)
6460 8 mov_finish_fragment(mov, &mov->tracks[i], 0);
6461 4 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6462 4 return 0;
6463 }
6464
6465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 if (mov->frag_interleave) {
6466 for (i = 0; i < mov->nb_tracks; i++) {
6467 MOVTrack *track = &mov->tracks[i];
6468 int ret;
6469 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6470 return ret;
6471 }
6472
6473 if (!mov->mdat_buf)
6474 return 0;
6475 mdat_size = avio_tell(mov->mdat_buf);
6476 }
6477
6478
2/2
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 83 times.
236 for (i = 0; i < mov->nb_tracks; i++) {
6479 153 MOVTrack *track = &mov->tracks[i];
6480
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)
6481 19 track->data_offset = 0;
6482 else
6483 134 track->data_offset = mdat_size;
6484
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 80 times.
153 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6485 73 has_video = 1;
6486
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if (first_video_track) {
6487
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 12 times.
73 if (track->entry)
6488 61 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6489 73 first_video_track = 0;
6490 }
6491 }
6492
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 117 times.
153 if (!track->entry)
6493 36 continue;
6494
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 if (track->mdat_buf)
6495 117 mdat_size += avio_tell(track->mdat_buf);
6496
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 50 times.
117 if (first_track < 0)
6497 67 first_track = i;
6498 }
6499
6500
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 67 times.
83 if (!mdat_size)
6501 16 return 0;
6502
6503
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 3 times.
67 avio_write_marker(s->pb,
6504 67 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6505
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);
6506
6507
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 67 times.
192 for (i = 0; i < mov->nb_tracks; i++) {
6508 125 MOVTrack *track = &mov->tracks[i];
6509 125 int buf_size, write_moof = 1, moof_tracks = -1;
6510 uint8_t *buf;
6511
6512
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 106 times.
125 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6513
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
19 if (!track->entry)
6514 8 continue;
6515 15 mdat_size = avio_tell(track->mdat_buf);
6516 15 moof_tracks = i;
6517 } else {
6518 106 write_moof = i == first_track;
6519 }
6520
6521
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 50 times.
121 if (write_moof) {
6522 71 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6523
6524 71 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6525 71 mov->fragments++;
6526
6527 71 avio_wb32(s->pb, mdat_size + 8);
6528 71 ffio_wfourcc(s->pb, "mdat");
6529 71 mdat_start = avio_tell(s->pb);
6530 }
6531
6532 121 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6533
1/2
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
121 if (!mov->frag_interleave) {
6534
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 117 times.
121 if (!track->mdat_buf)
6535 4 continue;
6536 117 buf_size = avio_close_dyn_buf(track->mdat_buf, &buf);
6537 117 track->mdat_buf = NULL;
6538 } else {
6539 if (!mov->mdat_buf)
6540 continue;
6541 buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf);
6542 mov->mdat_buf = NULL;
6543 }
6544
6545 117 avio_write(s->pb, buf, buf_size);
6546 117 av_free(buf);
6547 }
6548
6549 67 mov->mdat_size = 0;
6550
6551 67 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6552 67 return 0;
6553 }
6554
6555 61 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6556 {
6557 61 MOVMuxContext *mov = s->priv_data;
6558 61 int had_moov = mov->moov_written;
6559 61 int ret = mov_flush_fragment(s, force);
6560
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if (ret < 0)
6561 return ret;
6562 // If using delay_moov, the first flush only wrote the moov,
6563 // not the actual moof+mdat pair, thus flush once again.
6564
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)
6565 9 ret = mov_flush_fragment(s, force);
6566 61 return ret;
6567 }
6568
6569 36163 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6570 {
6571 int64_t ref;
6572 uint64_t duration;
6573
6574
2/2
✓ Branch 0 taken 35525 times.
✓ Branch 1 taken 638 times.
36163 if (trk->entry) {
6575 35525 ref = trk->cluster[trk->entry - 1].dts;
6576
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 524 times.
638 } else if ( trk->start_dts != AV_NOPTS_VALUE
6577
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 8 times.
114 && !trk->frag_discont) {
6578 106 ref = trk->start_dts + trk->track_duration;
6579 } else
6580 532 ref = pkt->dts; // Skip tests for the first packet
6581
6582
2/2
✓ Branch 0 taken 1655 times.
✓ Branch 1 taken 34508 times.
36163 if (trk->dts_shift != AV_NOPTS_VALUE) {
6583 /* With negative CTS offsets we have set an offset to the DTS,
6584 * reverse this for the check. */
6585 1655 ref -= trk->dts_shift;
6586 }
6587
6588 36163 duration = pkt->dts - ref;
6589
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) {
6590 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" in stream %d is out of range\n",
6591 duration, pkt->dts, pkt->stream_index);
6592
6593 pkt->dts = ref + 1;
6594 pkt->pts = AV_NOPTS_VALUE;
6595 }
6596
6597
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) {
6598 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" in stream %d is invalid\n", pkt->duration, pkt->stream_index);
6599 return AVERROR(EINVAL);
6600 }
6601 36163 return 0;
6602 }
6603
6604 18100 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6605 {
6606 18100 MOVMuxContext *mov = s->priv_data;
6607 18100 AVIOContext *pb = s->pb;
6608 MOVTrack *trk;
6609 AVCodecParameters *par;
6610 AVProducerReferenceTime *prft;
6611 18100 unsigned int samples_in_chunk = 0;
6612 18100 int size = pkt->size, ret = 0, offset = 0;
6613 size_t prft_size;
6614 18100 uint8_t *reformatted_data = NULL;
6615
6616
2/2
✓ Branch 0 taken 18054 times.
✓ Branch 1 taken 46 times.
18100 if (pkt->stream_index < s->nb_streams)
6617 18054 trk = s->streams[pkt->stream_index]->priv_data;
6618 else // Timecode or chapter
6619 46 trk = &mov->tracks[pkt->stream_index];
6620 18100 par = trk->par;
6621
6622 18100 ret = check_pkt(s, trk, pkt);
6623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (ret < 0)
6624 return ret;
6625
6626
2/2
✓ Branch 0 taken 17498 times.
✓ Branch 1 taken 602 times.
18100 if (pkt->pts != AV_NOPTS_VALUE &&
6627
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)) {
6628 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
6629 return AVERROR_PATCHWELCOME;
6630 }
6631
6632
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) {
6633 int ret;
6634
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) {
6635
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) {
6636 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6637 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6638 return ret;
6639 }
6640 }
6641
6642
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 4905 times.
5022 if (!trk->mdat_buf) {
6643
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
117 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6644 return ret;
6645 }
6646 5022 pb = trk->mdat_buf;
6647 } else {
6648
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
6649
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6650 return ret;
6651 }
6652 238 pb = mov->mdat_buf;
6653 }
6654 }
6655
6656
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6657 /* We must find out how many AMR blocks there are in one packet */
6658 static const uint16_t packed_size[16] =
6659 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6660 int len = 0;
6661
6662 while (len < size && samples_in_chunk < 100) {
6663 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6664 samples_in_chunk++;
6665 }
6666 if (samples_in_chunk > 1) {
6667 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6668 return -1;
6669 }
6670
1/2
✓ Branch 0 taken 18100 times.
✗ Branch 1 not taken.
18100 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6672 samples_in_chunk = trk->par->frame_size;
6673
2/2
✓ Branch 0 taken 1297 times.
✓ Branch 1 taken 16803 times.
18100 } else if (trk->sample_size)
6674 1297 samples_in_chunk = size / trk->sample_size;
6675 else
6676 16803 samples_in_chunk = 1;
6677
6678
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (samples_in_chunk < 1) {
6679 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6680 return AVERROR_PATCHWELCOME;
6681 }
6682
6683 /* copy extradata if it exists */
6684
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 &&
6685
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) &&
6686
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6687 2 trk->vos_len = par->extradata_size;
6688 2 trk->vos_data = av_malloc(trk->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
6689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->vos_data) {
6690 ret = AVERROR(ENOMEM);
6691 goto err;
6692 }
6693 2 memcpy(trk->vos_data, par->extradata, trk->vos_len);
6694 2 memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6695 }
6696
6697
2/2
✓ Branch 0 taken 17985 times.
✓ Branch 1 taken 115 times.
18100 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6698
2/2
✓ Branch 0 taken 15397 times.
✓ Branch 1 taken 2588 times.
17985 par->codec_id == AV_CODEC_ID_H264 ||
6699
2/2
✓ Branch 0 taken 15242 times.
✓ Branch 1 taken 155 times.
15397 par->codec_id == AV_CODEC_ID_HEVC ||
6700
2/2
✓ Branch 0 taken 15232 times.
✓ Branch 1 taken 10 times.
15242 par->codec_id == AV_CODEC_ID_VVC ||
6701
1/2
✓ Branch 0 taken 15232 times.
✗ Branch 1 not taken.
15232 par->codec_id == AV_CODEC_ID_VP9 ||
6702
2/2
✓ Branch 0 taken 14932 times.
✓ Branch 1 taken 300 times.
15232 par->codec_id == AV_CODEC_ID_EVC ||
6703
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 &&
6704
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)) {
6705 /* copy frame to create needed atoms */
6706 24 trk->vos_len = size;
6707 24 trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6708
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->vos_data) {
6709 ret = AVERROR(ENOMEM);
6710 goto err;
6711 }
6712 24 memcpy(trk->vos_data, pkt->data, size);
6713 24 memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6714 }
6715
6716
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 &&
6717
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5540 times.
5540 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6718 if (!trk->st->nb_frames) {
6719 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6720 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6721 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6722 return -1;
6723 }
6724 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6725 }
6726
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)) {
6727 /* from x264 or from bytestream H.264 */
6728 /* NAL reformatting needed */
6729
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) {
6730 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
6731 &size);
6732 if (ret < 0)
6733 return ret;
6734 avio_write(pb, reformatted_data, size);
6735 } else {
6736
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 if (trk->cenc.aes_ctr) {
6737 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6738 if (size < 0) {
6739 ret = size;
6740 goto err;
6741 }
6742 } else {
6743 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
6744 }
6745 }
6746
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 &&
6747
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)) {
6748 /* extradata is Annex B, assume the bitstream is too and convert it */
6749 144 int filter_ps = (trk->tag == MKTAG('h','v','c','1'));
6750
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) {
6751 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6752 &size, filter_ps, NULL);
6753 if (ret < 0)
6754 return ret;
6755 avio_write(pb, reformatted_data, size);
6756 } else {
6757
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
144 if (trk->cenc.aes_ctr) {
6758 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6759 if (size < 0) {
6760 ret = size;
6761 goto err;
6762 }
6763 } else {
6764 144 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, filter_ps, NULL);
6765 }
6766 }
6767
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 &&
6768
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)) {
6769 /* extradata is Annex B, assume the bitstream is too and convert it */
6770
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) {
6771 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6772 &size, 0, NULL);
6773 if (ret < 0)
6774 return ret;
6775 avio_write(pb, reformatted_data, size);
6776 } else {
6777 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6778 }
6779
3/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 17444 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
17448 } else if (par->codec_id == AV_CODEC_ID_AV1 && !trk->cenc.aes_ctr) {
6780
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) {
6781 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
6782 &size, &offset);
6783 if (ret < 0)
6784 return ret;
6785 avio_write(pb, reformatted_data, size);
6786 } else {
6787 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
6788
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]) {
6789 mov->avif_extent_length[pkt->stream_index] = size;
6790 }
6791 }
6792
6793
2/2
✓ Branch 0 taken 17057 times.
✓ Branch 1 taken 387 times.
17444 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
6794
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 16405 times.
17057 par->codec_id == AV_CODEC_ID_EAC3) {
6795 1039 size = handle_eac3(mov, pkt, trk);
6796
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
6797 return size;
6798
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
6799 1 goto end;
6800 1038 avio_write(pb, pkt->data, size);
6801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16405 times.
16405 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
6802 size = 8;
6803
6804 for (int i = 0; i < pkt->size; i += 3) {
6805 if (pkt->data[i] == 0xFC) {
6806 size += 2;
6807 }
6808 }
6809 avio_wb32(pb, size);
6810 ffio_wfourcc(pb, "cdat");
6811 for (int i = 0; i < pkt->size; i += 3) {
6812 if (pkt->data[i] == 0xFC) {
6813 avio_w8(pb, pkt->data[i + 1]);
6814 avio_w8(pb, pkt->data[i + 2]);
6815 }
6816 }
6817 } else {
6818
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16405 times.
16405 if (trk->cenc.aes_ctr) {
6819 if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 4) {
6820 int nal_size_length = (par->extradata[4] & 0x3) + 1;
6821 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6822 } else if(par->codec_id == AV_CODEC_ID_HEVC && par->extradata_size > 21) {
6823 int nal_size_length = (par->extradata[21] & 0x3) + 1;
6824 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6825 } else if(par->codec_id == AV_CODEC_ID_VVC) {
6826 ret = AVERROR_PATCHWELCOME;
6827 } else if(par->codec_id == AV_CODEC_ID_AV1) {
6828 av_assert0(size == pkt->size);
6829 ret = ff_mov_cenc_av1_write_obus(s, &trk->cenc, pb, pkt);
6830 if (ret > 0) {
6831 size = ret;
6832 ret = 0;
6833 }
6834 } else {
6835 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
6836 }
6837
6838 if (ret) {
6839 goto err;
6840 }
6841 } else {
6842 16405 avio_write(pb, pkt->data, size);
6843 }
6844 }
6845
6846
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 17826 times.
18099 if (trk->entry >= trk->cluster_capacity) {
6847 273 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
6848 273 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
6849
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273 times.
273 if (!cluster) {
6850 ret = AVERROR(ENOMEM);
6851 goto err;
6852 }
6853 273 trk->cluster = cluster;
6854 273 trk->cluster_capacity = new_capacity;
6855 }
6856
6857 18099 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6858 18099 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
6859 18099 trk->cluster[trk->entry].chunkNum = 0;
6860 18099 trk->cluster[trk->entry].size = size;
6861 18099 trk->cluster[trk->entry].entries = samples_in_chunk;
6862 18099 trk->cluster[trk->entry].dts = pkt->dts;
6863 18099 trk->cluster[trk->entry].pts = pkt->pts;
6864
2/2
✓ Branch 0 taken 18097 times.
✓ Branch 1 taken 2 times.
18099 if (!trk->squash_fragment_samples_to_one &&
6865
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) {
6866
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 4 times.
75 if (!trk->frag_discont) {
6867 /* First packet of a new fragment. We already wrote the duration
6868 * of the last packet of the previous fragment based on track_duration,
6869 * which might not exactly match our dts. Therefore adjust the dts
6870 * of this packet to be what the previous packets duration implies. */
6871 71 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
6872 /* We also may have written the pts and the corresponding duration
6873 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
6874 * the next fragment. This means the cts of the first sample must
6875 * be the same in all fragments, unless end_pts was updated by
6876 * the packet causing the fragment to be written. */
6877
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 57 times.
71 if ((mov->flags & FF_MOV_FLAG_DASH &&
6878
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
6879
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 47 times.
57 mov->mode == MODE_ISM)
6880 24 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
6881 } else {
6882 /* New fragment, but discontinuous from previous fragments.
6883 * Pretend the duration sum of the earlier fragments is
6884 * pkt->dts - trk->start_dts. */
6885 4 trk->end_pts = AV_NOPTS_VALUE;
6886 4 trk->frag_discont = 0;
6887 }
6888 }
6889
6890
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 &&
6891
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 11 times.
30 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
6892 /* Not using edit lists and shifting the first track to start from zero.
6893 * If the other streams start from a later timestamp, we won't be able
6894 * to signal the difference in starting time without an edit list.
6895 * Thus move the timestamp for this first sample to 0, increasing
6896 * its duration instead. */
6897 19 trk->cluster[trk->entry].dts = trk->start_dts = 0;
6898 }
6899
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 17859 times.
18099 if (trk->start_dts == AV_NOPTS_VALUE) {
6900 240 trk->start_dts = pkt->dts;
6901
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 234 times.
240 if (trk->frag_discont) {
6902
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
6903 /* Pretend the whole stream started at pts=0, with earlier fragments
6904 * already written. If the stream started at pts=0, the duration sum
6905 * of earlier fragments would have been pkt->pts. */
6906 4 trk->start_dts = pkt->dts - pkt->pts;
6907 } else {
6908 /* Pretend the whole stream started at dts=0, with earlier fragments
6909 * already written, with a duration summing up to pkt->dts. */
6910 2 trk->start_dts = 0;
6911 }
6912 6 trk->frag_discont = 0;
6913
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)
6914 2 av_log(s, AV_LOG_WARNING,
6915 "Track %d starts with a nonzero dts %"PRId64", while the moov "
6916 "already has been written. Set the delay_moov flag to handle "
6917 "this case.\n",
6918 pkt->stream_index, pkt->dts);
6919 }
6920 18099 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
6921 18099 trk->last_sample_is_subtitle_end = 0;
6922
6923
2/2
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 17497 times.
18099 if (pkt->pts == AV_NOPTS_VALUE) {
6924 602 av_log(s, AV_LOG_WARNING, "pts has no value\n");
6925 602 pkt->pts = pkt->dts;
6926 }
6927
2/2
✓ Branch 0 taken 1018 times.
✓ Branch 1 taken 17081 times.
18099 if (pkt->dts != pkt->pts)
6928 1018 trk->flags |= MOV_TRACK_CTTS;
6929 18099 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
6930 18099 trk->cluster[trk->entry].flags = 0;
6931
2/2
✓ Branch 0 taken 259 times.
✓ Branch 1 taken 17840 times.
18099 if (trk->start_cts == AV_NOPTS_VALUE)
6932 259 trk->start_cts = pkt->pts - pkt->dts;
6933
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 17836 times.
18099 if (trk->end_pts == AV_NOPTS_VALUE)
6934 263 trk->end_pts = trk->cluster[trk->entry].dts +
6935 263 trk->cluster[trk->entry].cts + pkt->duration;
6936 else
6937 17836 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
6938 trk->cluster[trk->entry].cts +
6939 pkt->duration);
6940
6941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
18099 if (par->codec_id == AV_CODEC_ID_VC1) {
6942 mov_parse_vc1_frame(pkt, trk);
6943
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
18099 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
6944 mov_parse_truehd_frame(pkt, trk);
6945
2/2
✓ Branch 0 taken 13459 times.
✓ Branch 1 taken 4640 times.
18099 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
6946
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 &&
6947
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
6948 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
6949
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
6950 trk->flags |= MOV_TRACK_STPS;
6951 } else {
6952 13451 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
6953 }
6954
1/2
✓ Branch 0 taken 13459 times.
✗ Branch 1 not taken.
13459 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
6955 13459 trk->has_keyframes++;
6956 }
6957
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18092 times.
18099 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
6958 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
6959 7 trk->has_disposable++;
6960 }
6961
6962 18099 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
6963
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))
6964 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
6965 else
6966 18099 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
6967
6968 18099 trk->entry++;
6969 18099 trk->sample_count += samples_in_chunk;
6970 18099 mov->mdat_size += size;
6971
6972
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)
6973 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
6974
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
6975 : NULL, size);
6976
6977 18100 end:
6978 18100 err:
6979
6980
1/2
✓ Branch 0 taken 18100 times.
✗ Branch 1 not taken.
18100 if (pkt->data != reformatted_data)
6981 18100 av_free(reformatted_data);
6982 18100 return ret;
6983 }
6984
6985 18063 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
6986 {
6987 18063 MOVMuxContext *mov = s->priv_data;
6988 18063 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
6989 18063 AVCodecParameters *par = trk->par;
6990 18063 int64_t frag_duration = 0;
6991 18063 int size = pkt->size;
6992
6993 18063 int ret = check_pkt(s, trk, pkt);
6994
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18063 times.
18063 if (ret < 0)
6995 return ret;
6996
6997
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18058 times.
18063 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
6998
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
6999 10 mov->tracks[i].frag_discont = 1;
7000 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
7001 }
7002
7003
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 17253 times.
18063 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
7004
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 799 times.
810 if (trk->dts_shift == AV_NOPTS_VALUE)
7005 11 trk->dts_shift = pkt->pts - pkt->dts;
7006 810 pkt->dts += trk->dts_shift;
7007 }
7008
7009
1/2
✓ Branch 0 taken 18063 times.
✗ Branch 1 not taken.
18063 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
7010
2/2
✓ Branch 0 taken 12521 times.
✓ Branch 1 taken 5542 times.
18063 trk->par->codec_id == AV_CODEC_ID_AAC ||
7011
2/2
✓ Branch 0 taken 12517 times.
✓ Branch 1 taken 4 times.
12521 trk->par->codec_id == AV_CODEC_ID_AV1 ||
7012
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12462 times.
12517 trk->par->codec_id == AV_CODEC_ID_FLAC) {
7013 size_t side_size;
7014 5601 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
7015
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))) {
7016 6 void *newextra = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
7017
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
7018 return AVERROR(ENOMEM);
7019 6 av_free(par->extradata);
7020 6 par->extradata = newextra;
7021 6 memcpy(par->extradata, side, side_size);
7022 6 par->extradata_size = side_size;
7023
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (!pkt->size) // Flush packet
7024 5 mov->need_rewrite_extradata = 1;
7025 }
7026 }
7027
7028
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18054 times.
18063 if (!pkt->size) {
7029
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) {
7030 4 trk->start_dts = pkt->dts;
7031
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
7032 4 trk->start_cts = pkt->pts - pkt->dts;
7033 else
7034 trk->start_cts = 0;
7035 }
7036
7037 9 return 0; /* Discard 0 sized packets */
7038 }
7039
7040
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)
7041 17731 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
7042 17731 s->streams[pkt->stream_index]->time_base,
7043 17731 AV_TIME_BASE_Q);
7044
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 17881 times.
18054 if ((mov->max_fragment_duration &&
7045
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 3 times.
173 frag_duration >= mov->max_fragment_duration) ||
7046
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) ||
7047
2/2
✓ Branch 0 taken 3673 times.
✓ Branch 1 taken 14378 times.
18051 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
7048
2/2
✓ Branch 0 taken 1125 times.
✓ Branch 1 taken 2548 times.
3673 par->codec_type == AVMEDIA_TYPE_VIDEO &&
7049
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) ||
7050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18026 times.
18026 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
7051
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (frag_duration >= mov->min_fragment_duration) {
7052
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (trk->entry) {
7053 // Set the duration of this track to line up with the next
7054 // sample in this track. This avoids relying on AVPacket
7055 // duration, but only helps for this particular track, not
7056 // for the other ones that are flushed at the same time.
7057 //
7058 // If we have trk->entry == 0, no fragment will be written
7059 // for this track, and we can't adjust the track end here.
7060 28 trk->track_duration = pkt->dts - trk->start_dts;
7061
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (pkt->pts != AV_NOPTS_VALUE)
7062 28 trk->end_pts = pkt->pts;
7063 else
7064 trk->end_pts = pkt->dts;
7065 28 trk->end_reliable = 1;
7066 }
7067 28 mov_auto_flush_fragment(s, 0);
7068 }
7069 }
7070
7071 18054 return ff_mov_write_packet(s, pkt);
7072 }
7073
7074 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
7075 int stream_index,
7076 int64_t dts) {
7077 3 MOVMuxContext *mov = s->priv_data;
7078 3 AVPacket *end = mov->pkt;
7079 3 uint8_t data[2] = {0};
7080 int ret;
7081
7082 3 end->size = sizeof(data);
7083 3 end->data = data;
7084 3 end->pts = dts;
7085 3 end->dts = dts;
7086 3 end->duration = 0;
7087 3 end->stream_index = stream_index;
7088
7089 3 ret = mov_write_single_packet(s, end);
7090 3 av_packet_unref(end);
7091
7092 3 return ret;
7093 }
7094
7095 #if CONFIG_IAMFENC
7096 275 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
7097 {
7098 uint8_t *data;
7099 int ret;
7100
7101
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 220 times.
275 if (pkt->stream_index == trk->first_iamf_idx) {
7102 55 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7103
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (ret < 0)
7104 return ret;
7105 }
7106
7107 275 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7108 275 s->streams[pkt->stream_index]->id, pkt);
7109
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 if (ret < 0)
7110 return ret;
7111
7112
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (pkt->stream_index != trk->last_iamf_idx)
7113 220 return AVERROR(EAGAIN);
7114
7115 55 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7116 55 trk->iamf_buf = NULL;
7117
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
55 if (!ret) {
7118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7119 // Either all or none of the packets for a single
7120 // IA Sample may be empty.
7121 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7122 "stream #%d\n", pkt->stream_index);
7123 ret = AVERROR_INVALIDDATA;
7124 }
7125 5 av_free(data);
7126 5 return ret;
7127 }
7128
7129 50 av_buffer_unref(&pkt->buf);
7130 50 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7131
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!pkt->buf) {
7132 av_free(data);
7133 return AVERROR(ENOMEM);
7134 }
7135 50 pkt->data = data;
7136 50 pkt->size = ret;
7137 50 pkt->stream_index = trk->first_iamf_idx;
7138
7139 50 return avio_open_dyn_buf(&trk->iamf_buf);
7140 }
7141 #endif
7142
7143 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7144 {
7145 2 int64_t pos = avio_tell(pb);
7146 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7147 2 const char *value = "";
7148
7149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7150
7151 2 avio_write_marker(pb,
7152 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7153 AVIO_DATA_MARKER_BOUNDARY_POINT);
7154
7155 2 avio_wb32(pb, 0); /* size */
7156 2 ffio_wfourcc(pb, "emsg");
7157 2 avio_w8(pb, 1); /* version */
7158 2 avio_wb24(pb, 0);
7159 2 avio_wb32(pb, st->time_base.den); /* timescale */
7160 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7161 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7162 2 avio_wb32(pb, 0); /* id */
7163 /* null terminated UTF8 strings */
7164 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7165 2 avio_write(pb, value, strlen(value) + 1);
7166 2 avio_write(pb, pkt->data, pkt->size);
7167
7168 2 return update_size(pb, pos);
7169 }
7170
7171 18391 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7172 {
7173 18391 MOVMuxContext *mov = s->priv_data;
7174 MOVTrack *trk;
7175
7176
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 18356 times.
18391 if (!pkt) {
7177 35 mov_flush_fragment(s, 1);
7178 35 return 1;
7179 }
7180
7181
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) {
7182 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7183 2 return 0;
7184 }
7185
7186 18354 trk = s->streams[pkt->stream_index]->priv_data;
7187
7188 #if CONFIG_IAMFENC
7189
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 18079 times.
18354 if (trk->iamf) {
7190 275 int ret = mov_build_iamf_packet(s, trk, pkt);
7191
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (ret < 0) {
7192
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (ret == AVERROR(EAGAIN))
7193 220 return 0;
7194 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7195 "for stream #%d\n", trk->st->index);
7196 return ret;
7197 }
7198 }
7199 #endif
7200
7201
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18132 times.
18134 if (is_cover_image(trk->st)) {
7202 int ret;
7203
7204
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7205 if (trk->st->nb_frames == 1)
7206 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7207 " ignoring.\n", pkt->stream_index);
7208 return 0;
7209 }
7210
7211
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7212 return ret;
7213
7214 2 return 0;
7215 } else {
7216 int i;
7217
7218
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18123 times.
18132 if (!pkt->size)
7219 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7220
7221 /*
7222 * Subtitles require special handling.
7223 *
7224 * 1) For full complaince, every track must have a sample at
7225 * dts == 0, which is rarely true for subtitles. So, as soon
7226 * as we see any packet with dts > 0, write an empty subtitle
7227 * at dts == 0 for any subtitle track with no samples in it.
7228 *
7229 * 2) For each subtitle track, check if the current packet's
7230 * dts is past the duration of the last subtitle sample. If
7231 * so, we now need to write an end sample for that subtitle.
7232 *
7233 * This must be done conditionally to allow for subtitles that
7234 * immediately replace each other, in which case an end sample
7235 * is not needed, and is, in fact, actively harmful.
7236 *
7237 * 3) See mov_write_trailer for how the final end sample is
7238 * handled.
7239 */
7240
2/2
✓ Branch 0 taken 32861 times.
✓ Branch 1 taken 18123 times.
50984 for (i = 0; i < mov->nb_tracks; i++) {
7241 32861 MOVTrack *trk = &mov->tracks[i];
7242 int ret;
7243
7244
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 32858 times.
32861 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7245
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7246
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)) {
7247 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7248
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7249 2 trk->last_sample_is_subtitle_end = 1;
7250 }
7251 }
7252
7253
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 18049 times.
18123 if (trk->squash_fragment_samples_to_one) {
7254 /*
7255 * If the track has to have its samples squashed into one sample,
7256 * we just take it into the track's queue.
7257 * This will then be utilized as the samples get written in either
7258 * mov_flush_fragment or when the mux is finalized in
7259 * mov_write_trailer.
7260 */
7261 74 int ret = AVERROR_BUG;
7262
7263
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (pkt->pts == AV_NOPTS_VALUE) {
7264 av_log(s, AV_LOG_ERROR,
7265 "Packets without a valid presentation timestamp are "
7266 "not supported with packet squashing!\n");
7267 return AVERROR(EINVAL);
7268 }
7269
7270 /* The following will reset pkt and is only allowed to be used
7271 * because we return immediately. afterwards. */
7272
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
7273 pkt, NULL, 0)) < 0) {
7274 return ret;
7275 }
7276
7277 74 return 0;
7278 }
7279
7280
7281
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) {
7282 3702 AVPacket *opkt = pkt;
7283 int reshuffle_ret, ret;
7284
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3677 times.
3702 if (trk->is_unaligned_qt_rgb) {
7285
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;
7286 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7287 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7289 return reshuffle_ret;
7290 } else
7291 3677 reshuffle_ret = 0;
7292
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) {
7293 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7294
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7295 goto fail;
7296
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7297 5 trk->pal_done++;
7298
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 2872 times.
3697 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7299
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7300
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7301 ret = av_packet_make_writable(pkt);
7302 if (ret < 0)
7303 goto fail;
7304 for (i = 0; i < pkt->size; i++)
7305 pkt->data[i] = ~pkt->data[i];
7306 }
7307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3702 times.
3702 if (reshuffle_ret) {
7308 ret = mov_write_single_packet(s, pkt);
7309 fail:
7310 if (reshuffle_ret)
7311 av_packet_free(&pkt);
7312 return ret;
7313 }
7314 }
7315
7316 18049 return mov_write_single_packet(s, pkt);
7317 }
7318 }
7319
7320 // QuickTime chapters involve an additional text track with the chapter names
7321 // as samples, and a tref pointing from the other tracks to the chapter one.
7322 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7323 {
7324 static const uint8_t stub_header[] = {
7325 // TextSampleEntry
7326 0x00, 0x00, 0x00, 0x01, // displayFlags
7327 0x00, 0x00, // horizontal + vertical justification
7328 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7329 // BoxRecord
7330 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7331 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7332 // StyleRecord
7333 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7334 0x00, 0x01, // fontID
7335 0x00, 0x00, // fontStyleFlags + fontSize
7336 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7337 // FontTableBox
7338 0x00, 0x00, 0x00, 0x0D, // box size
7339 'f', 't', 'a', 'b', // box atom name
7340 0x00, 0x01, // entry count
7341 // FontRecord
7342 0x00, 0x01, // font ID
7343 0x00, // font name length
7344 };
7345 1 MOVMuxContext *mov = s->priv_data;
7346 1 MOVTrack *track = &mov->tracks[tracknum];
7347 1 AVPacket *pkt = mov->pkt;
7348 int i, len;
7349 int ret;
7350
7351 1 track->mode = mov->mode;
7352 1 track->tag = MKTAG('t','e','x','t');
7353 1 track->timescale = mov->movie_timescale;
7354 1 track->par = avcodec_parameters_alloc();
7355
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7356 return AVERROR(ENOMEM);
7357 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7358 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7359
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7360 return ret;
7361 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7362
7363 1 pkt->stream_index = tracknum;
7364 1 pkt->flags = AV_PKT_FLAG_KEY;
7365
7366
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7367 4 AVChapter *c = s->chapters[i];
7368 AVDictionaryEntry *t;
7369
7370 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7371 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7372 4 pkt->duration = end - pkt->dts;
7373
7374
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7375 static const char encd[12] = {
7376 0x00, 0x00, 0x00, 0x0C,
7377 'e', 'n', 'c', 'd',
7378 0x00, 0x00, 0x01, 0x00 };
7379 4 len = strlen(t->value);
7380 4 pkt->size = len + 2 + 12;
7381 4 pkt->data = av_malloc(pkt->size);
7382
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7383 av_packet_unref(pkt);
7384 return AVERROR(ENOMEM);
7385 }
7386 4 AV_WB16(pkt->data, len);
7387 4 memcpy(pkt->data + 2, t->value, len);
7388 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7389 4 ff_mov_write_packet(s, pkt);
7390 4 av_freep(&pkt->data);
7391 }
7392 }
7393
7394 1 av_packet_unref(mov->pkt);
7395
7396 1 return 0;
7397 }
7398
7399
7400 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7401 {
7402 int ret;
7403
7404 /* compute the frame number */
7405 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7406 13 return ret;
7407 }
7408
7409 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7410 {
7411 6 MOVMuxContext *mov = s->priv_data;
7412 6 MOVTrack *track = &mov->tracks[index];
7413 6 AVStream *src_st = mov->tracks[src_index].st;
7414 uint8_t data[4];
7415 6 AVPacket *pkt = mov->pkt;
7416 6 AVRational rate = src_st->avg_frame_rate;
7417 int ret;
7418
7419 /* tmcd track based on video stream */
7420 6 track->mode = mov->mode;
7421 6 track->tag = MKTAG('t','m','c','d');
7422 6 track->src_track = src_index;
7423 6 track->timescale = mov->tracks[src_index].timescale;
7424
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7425 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7426
7427 /* set st to src_st for metadata access*/
7428 6 track->st = src_st;
7429
7430 /* encode context: tmcd data stream */
7431 6 track->par = avcodec_parameters_alloc();
7432
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7433 return AVERROR(ENOMEM);
7434 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7435 6 track->par->codec_tag = track->tag;
7436 6 track->st->avg_frame_rate = rate;
7437
7438 /* the tmcd track just contains one packet with the frame number */
7439 6 pkt->data = data;
7440 6 pkt->stream_index = index;
7441 6 pkt->flags = AV_PKT_FLAG_KEY;
7442 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
7443 6 pkt->size = 4;
7444 6 AV_WB32(pkt->data, tc.start);
7445 6 ret = ff_mov_write_packet(s, pkt);
7446 6 av_packet_unref(pkt);
7447 6 return ret;
7448 }
7449
7450 /*
7451 * st->disposition controls the "enabled" flag in the tkhd tag.
7452 * QuickTime will not play a track if it is not enabled. So make sure
7453 * that one track of each type (audio, video, subtitle) is enabled.
7454 *
7455 * Subtitles are special. For audio and video, setting "enabled" also
7456 * makes the track "default" (i.e. it is rendered when played). For
7457 * subtitles, an "enabled" subtitle is not rendered by default, but
7458 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7459 * empty!
7460 */
7461 209 static void enable_tracks(AVFormatContext *s)
7462 {
7463 209 MOVMuxContext *mov = s->priv_data;
7464 int i;
7465 int enabled[AVMEDIA_TYPE_NB];
7466 int first[AVMEDIA_TYPE_NB];
7467
7468
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 209 times.
1254 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7469 1045 enabled[i] = 0;
7470 1045 first[i] = -1;
7471 }
7472
7473
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (i = 0; i < mov->nb_streams; i++) {
7474 267 AVStream *st = mov->tracks[i].st;
7475
7476
1/2
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
267 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7477
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 ||
7478 267 is_cover_image(st))
7479 2 continue;
7480
7481
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 14 times.
265 if (first[st->codecpar->codec_type] < 0)
7482 251 first[st->codecpar->codec_type] = i;
7483
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 236 times.
265 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7484 29 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7485 29 enabled[st->codecpar->codec_type]++;
7486 }
7487 }
7488
7489
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 209 times.
1254 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7490
2/2
✓ Branch 0 taken 627 times.
✓ Branch 1 taken 418 times.
1045 switch (i) {
7491 627 case AVMEDIA_TYPE_VIDEO:
7492 case AVMEDIA_TYPE_AUDIO:
7493 case AVMEDIA_TYPE_SUBTITLE:
7494
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 627 times.
627 if (enabled[i] > 1)
7495 mov->per_stream_grouping = 1;
7496
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)
7497 224 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7498 627 break;
7499 }
7500 }
7501 209 }
7502
7503 209 static void mov_free(AVFormatContext *s)
7504 {
7505 209 MOVMuxContext *mov = s->priv_data;
7506
7507
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (int i = 0; i < s->nb_streams; i++)
7508 288 s->streams[i]->priv_data = NULL;
7509
7510
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!mov->tracks)
7511 return;
7512
7513
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->chapter_track) {
7514 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7515 }
7516
7517
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 209 times.
485 for (int i = 0; i < mov->nb_tracks; i++) {
7518 276 MOVTrack *const track = &mov->tracks[i];
7519
7520
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 274 times.
276 if (track->tag == MKTAG('r','t','p',' '))
7521 2 ff_mov_close_hinting(track);
7522
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)
7523 6 av_freep(&track->par);
7524 276 av_freep(&track->cluster);
7525 276 av_freep(&track->cluster_written);
7526 276 av_freep(&track->frag_info);
7527 276 av_packet_free(&track->cover_image);
7528
7529
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 271 times.
276 if (track->eac3_priv) {
7530 5 struct eac3_info *info = track->eac3_priv;
7531 5 av_packet_free(&info->pkt);
7532 5 av_freep(&track->eac3_priv);
7533 }
7534
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 133 times.
276 if (track->vos_len)
7535 143 av_freep(&track->vos_data);
7536
7537 276 ff_mov_cenc_free(&track->cenc);
7538 276 ffio_free_dyn_buf(&track->mdat_buf);
7539
7540 #if CONFIG_IAMFENC
7541 276 ffio_free_dyn_buf(&track->iamf_buf);
7542
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 271 times.
276 if (track->iamf)
7543 5 ff_iamf_uninit_context(track->iamf);
7544 276 av_freep(&track->iamf);
7545 #endif
7546
7547 276 avpriv_packet_list_free(&track->squashed_packet_queue);
7548 }
7549
7550 209 av_freep(&mov->tracks);
7551 209 ffio_free_dyn_buf(&mov->mdat_buf);
7552 }
7553
7554 static uint32_t rgb_to_yuv(uint32_t rgb)
7555 {
7556 uint8_t r, g, b;
7557 int y, cb, cr;
7558
7559 r = (rgb >> 16) & 0xFF;
7560 g = (rgb >> 8) & 0xFF;
7561 b = (rgb ) & 0xFF;
7562
7563 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7564 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7565 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7566
7567 return (y << 16) | (cr << 8) | cb;
7568 }
7569
7570 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7571 AVStream *st)
7572 {
7573 int i, width = 720, height = 480;
7574 int have_palette = 0, have_size = 0;
7575 uint32_t palette[16];
7576 char *cur = st->codecpar->extradata;
7577
7578 while (cur && *cur) {
7579 if (strncmp("palette:", cur, 8) == 0) {
7580 int i, count;
7581 count = sscanf(cur + 8,
7582 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7583 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7584 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7585 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7586 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7587 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7588 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7589 &palette[12], &palette[13], &palette[14], &palette[15]);
7590
7591 for (i = 0; i < count; i++) {
7592 palette[i] = rgb_to_yuv(palette[i]);
7593 }
7594 have_palette = 1;
7595 } else if (!strncmp("size:", cur, 5)) {
7596 sscanf(cur + 5, "%dx%d", &width, &height);
7597 have_size = 1;
7598 }
7599 if (have_palette && have_size)
7600 break;
7601 cur += strcspn(cur, "\n\r");
7602 cur += strspn(cur, "\n\r");
7603 }
7604 if (have_palette) {
7605 track->vos_data = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7606 if (!track->vos_data)
7607 return AVERROR(ENOMEM);
7608 for (i = 0; i < 16; i++) {
7609 AV_WB32(track->vos_data + i * 4, palette[i]);
7610 }
7611 memset(track->vos_data + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7612 track->vos_len = 16 * 4;
7613 }
7614 st->codecpar->width = width;
7615 st->codecpar->height = track->height = height;
7616
7617 return 0;
7618 }
7619
7620 #if CONFIG_IAMFENC
7621 209 static int mov_init_iamf_track(AVFormatContext *s)
7622 {
7623 209 MOVMuxContext *mov = s->priv_data;
7624 MOVTrack *track;
7625 IAMFContext *iamf;
7626 209 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
7627 209 int nb_audio_elements = 0, nb_mix_presentations = 0;
7628 int ret;
7629
7630
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209 times.
219 for (int i = 0; i < s->nb_stream_groups; i++) {
7631 10 const AVStreamGroup *stg = s->stream_groups[i];
7632
7633
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7634 5 nb_audio_elements++;
7635
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7636 5 nb_mix_presentations++;
7637 }
7638
7639
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)
7640 204 return 0;
7641
7642
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) {
7643 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7644 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7645 return AVERROR(EINVAL);
7646 }
7647
7648 5 iamf = av_mallocz(sizeof(*iamf));
7649
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
7650 return AVERROR(ENOMEM);
7651
7652
7653
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7654 10 const AVStreamGroup *stg = s->stream_groups[i];
7655
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
7656 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7657
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7658 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
7659 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
7660 }
7661
7662 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
7663 5 break;
7664 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7665 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
7666 5 break;
7667 default:
7668 av_assert0(0);
7669 }
7670
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
7671 return ret;
7672 }
7673
7674 5 track = &mov->tracks[first_iamf_idx];
7675 5 track->iamf = iamf;
7676 5 track->first_iamf_idx = first_iamf_idx;
7677 5 track->last_iamf_idx = last_iamf_idx;
7678 5 track->tag = MKTAG('i','a','m','f');
7679
7680
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7681 10 AVStreamGroup *stg = s->stream_groups[i];
7682
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7683 5 continue;
7684
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
7685 25 stg->streams[j]->priv_data = track;
7686 }
7687
7688 5 ret = avio_open_dyn_buf(&track->iamf_buf);
7689
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7690 return ret;
7691
7692 5 return 0;
7693 }
7694 #endif
7695
7696 209 static int mov_init(AVFormatContext *s)
7697 {
7698 209 MOVMuxContext *mov = s->priv_data;
7699 209 int has_iamf = 0;
7700 int i, ret;
7701
7702 209 mov->fc = s;
7703 209 mov->pkt = ffformatcontext(s)->pkt;
7704
7705 /* Default mode == MP4 */
7706 209 mov->mode = MODE_MP4;
7707
7708 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7711
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 63 times.
209 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7712
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 62 times.
63 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7713
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7714
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 57 times.
61 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7715
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7716
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7717 #undef IS_MODE
7718
7719
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
209 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7720 17 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7721
7722
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->mode == MODE_AVIF)
7723 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7724
7725 /* Set the FRAGMENT flag if any of the fragmentation methods are
7726 * enabled. */
7727
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 ||
7728
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 179 times.
208 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7729 FF_MOV_FLAG_FRAG_KEYFRAME |
7730 FF_MOV_FLAG_FRAG_CUSTOM |
7731 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7732 30 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7733
7734 /* Set other implicit flags immediately */
7735
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
7736 1 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7737
7738
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (mov->mode == MODE_ISM)
7739 4 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
7740 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7741
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 198 times.
209 if (mov->flags & FF_MOV_FLAG_DASH)
7742 11 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7743 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
7744
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_CMAF)
7745 1 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7746 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7747
7748
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) {
7749 29 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7750 29 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
7751 }
7752
7753
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) {
7754 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
7755 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
7756 }
7757
7758
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7759 3 mov->reserved_moov_size = -1;
7760 }
7761
7762
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 7 times.
209 if (mov->use_editlist < 0) {
7763 202 mov->use_editlist = 1;
7764
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 175 times.
202 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7765
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 15 times.
27 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7766 // If we can avoid needing an edit list by shifting the
7767 // tracks, prefer that over (trying to) write edit lists
7768 // in fragmented output.
7769
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
7770
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
7771 11 mov->use_editlist = 0;
7772 }
7773 }
7774
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7775
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)
7776 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7777
7778
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 &&
7779
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
7780 10 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
7781
7782 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7783 * if the latter is set that's enough and omit_tfhd_offset doesn't
7784 * add anything extra on top of that. */
7785
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
7786 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
7787 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
7788
7789
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->frag_interleave &&
7790 mov->flags & (FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF)) {
7791 av_log(s, AV_LOG_ERROR,
7792 "Sample interleaving in fragments is mutually exclusive with "
7793 "omit_tfhd_offset and separate_moof\n");
7794 return AVERROR(EINVAL);
7795 }
7796
7797 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
7798 * is enabled, we don't support non-seekable output at all. */
7799
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 181 times.
209 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
7800
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 ||
7801
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 mov->mode == MODE_AVIF)) {
7802 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
7803 return AVERROR(EINVAL);
7804 }
7805
7806 /* AVIF output must have at most two video streams (one for YUV and one for
7807 * alpha). */
7808
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->mode == MODE_AVIF) {
7809 if (s->nb_streams > 2) {
7810 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
7811 return AVERROR(EINVAL);
7812 }
7813 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
7814 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
7815 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
7816 return AVERROR(EINVAL);
7817 }
7818 if (s->nb_streams > 1) {
7819 const AVPixFmtDescriptor *pixdesc =
7820 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
7821 if (pixdesc->nb_components != 1) {
7822 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
7823 return AVERROR(EINVAL);
7824 }
7825 }
7826 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
7827 }
7828
7829 #if CONFIG_IAMFENC
7830
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209 times.
219 for (i = 0; i < s->nb_stream_groups; i++) {
7831 10 AVStreamGroup *stg = s->stream_groups[i];
7832
7833
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7834 5 continue;
7835
7836
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7837 25 AVStream *st = stg->streams[j];
7838
7839
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
7840 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
7841 "IAMF Audio Element\n", j);
7842 return AVERROR(EINVAL);
7843 }
7844 25 st->priv_data = st;
7845 }
7846 5 has_iamf = 1;
7847
7848
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
7849 5 mov->nb_tracks++;
7850 }
7851 #endif
7852
7853
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (i = 0; i < s->nb_streams; i++) {
7854 288 AVStream *st = s->streams[i];
7855
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 263 times.
288 if (st->priv_data)
7856 25 continue;
7857 // Don't produce a track in the output file for timed ID3 streams.
7858
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 262 times.
263 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7859 // Leave priv_data set to NULL for these AVStreams that don't
7860 // have a corresponding track.
7861 1 continue;
7862 }
7863 262 st->priv_data = st;
7864 262 mov->nb_tracks++;
7865 }
7866
7867 209 mov->nb_streams = mov->nb_tracks;
7868
7869
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)
7870 1 mov->chapter_track = mov->nb_tracks++;
7871
7872
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
7873
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
7874
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
7875 2 mov->nb_tracks++;
7876 }
7877
7878
1/2
✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
209 if (mov->write_btrt < 0) {
7879 209 mov->write_btrt = mov->mode == MODE_MP4;
7880 }
7881
7882
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)
7883
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 || mov->write_tmcd == 1) {
7884 206 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
7885 NULL, 0);
7886
7887 /* +1 tmcd track for each video stream with a timecode */
7888
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 206 times.
489 for (i = 0; i < s->nb_streams; i++) {
7889 283 AVStream *st = s->streams[i];
7890 283 AVDictionaryEntry *t = global_tcr;
7891
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 &&
7892
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 171 times.
171 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
7893 AVTimecode tc;
7894 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
7895
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
7896 7 mov->nb_meta_tmcd++;
7897 }
7898 }
7899
7900 /* check if there is already a tmcd track to remux */
7901
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 199 times.
206 if (mov->nb_meta_tmcd) {
7902
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
7903 13 AVStream *st = s->streams[i];
7904
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
7905 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
7906 "so timecode metadata are now ignored\n");
7907 3 mov->nb_meta_tmcd = 0;
7908 }
7909 }
7910 }
7911
7912 206 mov->nb_tracks += mov->nb_meta_tmcd;
7913 }
7914
7915 // Reserve an extra stream for chapters for the case where chapters
7916 // are written in the trailer
7917 209 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
7918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!mov->tracks)
7919 return AVERROR(ENOMEM);
7920
7921
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) {
7922 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
7923 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
7924
7925 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
7926 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
7927 mov->encryption_key_len, AES_CTR_KEY_SIZE);
7928 return AVERROR(EINVAL);
7929 }
7930
7931 if (mov->encryption_kid_len != CENC_KID_SIZE) {
7932 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
7933 mov->encryption_kid_len, CENC_KID_SIZE);
7934 return AVERROR(EINVAL);
7935 }
7936 } else {
7937 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
7938 mov->encryption_scheme_str);
7939 return AVERROR(EINVAL);
7940 }
7941 }
7942
7943 #if CONFIG_IAMFENC
7944 209 ret = mov_init_iamf_track(s);
7945
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (ret < 0)
7946 return ret;
7947 #endif
7948
7949
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (int j = 0, i = 0; j < s->nb_streams; j++) {
7950 288 AVStream *st = s->streams[j];
7951
7952
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 262 times.
288 if (st != st->priv_data) {
7953
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
7954 5 i += has_iamf--;
7955 26 continue;
7956 }
7957 262 st->priv_data = &mov->tracks[i++];
7958 }
7959
7960
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (i = 0; i < s->nb_streams; i++) {
7961 288 AVStream *st= s->streams[i];
7962 288 MOVTrack *track = st->priv_data;
7963 288 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
7964
7965
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 287 times.
288 if (!track)
7966 1 continue;
7967
7968
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 20 times.
287 if (!track->st) {
7969 267 track->st = st;
7970 267 track->par = st->codecpar;
7971 }
7972
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);
7973
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 132 times.
287 if (track->language < 0)
7974 155 track->language = 32767; // Unspecified Macintosh language code
7975 287 track->mode = mov->mode;
7976
2/2
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 25 times.
287 if (!track->tag)
7977 262 track->tag = mov_find_codec_tag(s, track);
7978
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (!track->tag) {
7979 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
7980 "codec not currently supported in container\n",
7981 avcodec_get_name(st->codecpar->codec_id), i);
7982 return AVERROR(EINVAL);
7983 }
7984 /* If hinting of this track is enabled by a later hint track,
7985 * this is updated. */
7986 287 track->hint_track = -1;
7987 287 track->start_dts = AV_NOPTS_VALUE;
7988 287 track->start_cts = AV_NOPTS_VALUE;
7989 287 track->end_pts = AV_NOPTS_VALUE;
7990 287 track->dts_shift = AV_NOPTS_VALUE;
7991
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 107 times.
287 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
7992
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') ||
7993
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') ||
7994
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')) {
7995 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
7996 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
7997 return AVERROR(EINVAL);
7998 }
7999 track->height = track->tag >> 24 == 'n' ? 486 : 576;
8000 }
8001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 if (mov->video_track_timescale) {
8002 track->timescale = mov->video_track_timescale;
8003 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
8004 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
8005 } else {
8006 180 track->timescale = st->time_base.den;
8007
2/2
✓ Branch 0 taken 1467 times.
✓ Branch 1 taken 180 times.
1647 while(track->timescale < 10000)
8008 1467 track->timescale *= 2;
8009 }
8010
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) {
8011 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
8012 return AVERROR(EINVAL);
8013 }
8014
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)
8015 2 av_log(s, AV_LOG_WARNING,
8016 "WARNING codec timebase is very high. If duration is too long,\n"
8017 "file may not be playable by quicktime. Specify a shorter timebase\n"
8018 "or choose different container.\n");
8019
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 50 times.
180 if (track->mode == MODE_MOV &&
8020
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 113 times.
130 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
8021
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
8022 1 enum AVPixelFormat pix_fmt = track->par->format;
8023
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)
8024 pix_fmt = AV_PIX_FMT_MONOWHITE;
8025 1 track->is_unaligned_qt_rgb =
8026 pix_fmt == AV_PIX_FMT_RGB24 ||
8027 pix_fmt == AV_PIX_FMT_BGR24 ||
8028 pix_fmt == AV_PIX_FMT_PAL8 ||
8029 pix_fmt == AV_PIX_FMT_GRAY8 ||
8030
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 ||
8031 pix_fmt == AV_PIX_FMT_MONOBLACK;
8032 }
8033
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) {
8034 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8035 return AVERROR(EINVAL);
8036
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 179 times.
180 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
8037
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) {
8038 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
8039 return AVERROR(EINVAL);
8040
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
8041 /* altref frames handling is not defined in the spec as of version v1.0,
8042 * so just forbid muxing VP8 streams altogether until a new version does */
8043 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
8044 return AVERROR_PATCHWELCOME;
8045 }
8046
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 178 times.
180 if (is_cover_image(st)) {
8047 2 track->cover_image = av_packet_alloc();
8048
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
8049 return AVERROR(ENOMEM);
8050 }
8051
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 7 times.
107 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
8052 100 track->timescale = st->codecpar->sample_rate;
8053
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)) {
8054 6 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
8055 6 track->audio_vbr = 1;
8056
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
8057
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
8058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
8059 if (!st->codecpar->block_align) {
8060 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
8061 return AVERROR(EINVAL);
8062 }
8063 track->sample_size = st->codecpar->block_align;
8064
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 25 times.
94 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
8065 69 track->audio_vbr = 1;
8066 }else{
8067 25 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
8068 25 st->codecpar->ch_layout.nb_channels;
8069 }
8070
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
8071
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
8072 track->audio_vbr = 1;
8073 }
8074
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 32 times.
100 if (track->mode != MODE_MOV &&
8075
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) {
8076 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
8077 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
8078 i, track->par->sample_rate);
8079 return AVERROR(EINVAL);
8080 } else {
8081 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
8082 i, track->par->sample_rate);
8083 }
8084 }
8085
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 25 times.
100 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
8086
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
8087
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
75 track->par->codec_id == AV_CODEC_ID_OPUS) {
8088
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
8089 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
8090 return AVERROR(EINVAL);
8091 }
8092
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8093 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8094 av_log(s, AV_LOG_ERROR,
8095 "%s in MP4 support is experimental, add "
8096 "'-strict %d' if you want to use it.\n",
8097 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8098 return AVERROR_EXPERIMENTAL;
8099 }
8100 }
8101
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8102 3 track->timescale = st->time_base.den;
8103
8104
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8105 /* 14496-30 requires us to use a single sample per fragment
8106 for TTML, for which we define a per-track flag.
8107
8108 We set the flag in case we are receiving TTML paragraphs
8109 from the input, in other words in case we are not doing
8110 stream copy. */
8111 2 track->squash_fragment_samples_to_one =
8112 2 ff_is_ttml_stream_paragraph_based(track->par);
8113
8114
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8115 track->squash_fragment_samples_to_one) {
8116 av_log(s, AV_LOG_ERROR,
8117 "Fragmentation is not currently supported for "
8118 "TTML in MP4/ISMV (track synchronization between "
8119 "subtitles and other media is not yet implemented)!\n");
8120 return AVERROR_PATCHWELCOME;
8121 }
8122
8123
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->mode != MODE_ISM &&
8124
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8125
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8126 av_log(s, AV_LOG_ERROR,
8127 "ISMV style TTML support with the 'dfxp' tag in "
8128 "non-ISMV formats is not officially supported. Add "
8129 "'-strict unofficial' if you want to use it.\n");
8130 return AVERROR_EXPERIMENTAL;
8131 }
8132 }
8133
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8134 4 track->timescale = st->time_base.den;
8135 } else {
8136 track->timescale = mov->movie_timescale;
8137 }
8138
1/2
✓ Branch 0 taken 287 times.
✗ Branch 1 not taken.
287 if (!track->height)
8139 287 track->height = st->codecpar->height;
8140 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8141 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8142 for video tracks, so if user-set, it isn't overwritten */
8143
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 282 times.
287 if (mov->mode == MODE_ISM &&
8144
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8145
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))) {
8146 5 track->timescale = 10000000;
8147 }
8148
8149 287 avpriv_set_pts_info(st, 64, 1, track->timescale);
8150
8151
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8152 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8153 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8154 track->par->codec_id == AV_CODEC_ID_VVC || track->par->codec_id == AV_CODEC_ID_AV1),
8155 track->par->codec_id, s->flags & AVFMT_FLAG_BITEXACT);
8156 if (ret)
8157 return ret;
8158 }
8159 }
8160
8161 209 enable_tracks(s);
8162 209 return 0;
8163 }
8164
8165 209 static int mov_write_header(AVFormatContext *s)
8166 {
8167 209 AVIOContext *pb = s->pb;
8168 209 MOVMuxContext *mov = s->priv_data;
8169 209 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8170
8171
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)
8172 1 nb_tracks++;
8173
8174
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8175 1 hint_track = nb_tracks;
8176
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8177
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8178 2 nb_tracks++;
8179 }
8180 }
8181
8182
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203 times.
209 if (mov->nb_meta_tmcd)
8183 6 tmcd_track = nb_tracks;
8184
8185
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (int i = 0; i < mov->nb_streams; i++) {
8186 267 MOVTrack *track = &mov->tracks[i];
8187 267 AVStream *st = track->st;
8188
8189 /* copy extradata if it exists */
8190
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 150 times.
267 if (st->codecpar->extradata_size) {
8191
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8192 mov_create_dvd_sub_decoder_specific_info(track, st);
8193
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) {
8194 117 track->vos_len = st->codecpar->extradata_size;
8195 117 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8196
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (!track->vos_data) {
8197 return AVERROR(ENOMEM);
8198 }
8199 117 memcpy(track->vos_data, st->codecpar->extradata, track->vos_len);
8200 117 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8201 }
8202 }
8203
8204
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 ||
8205 80 av_channel_layout_compare(&track->par->ch_layout,
8206 80 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8207 253 continue;
8208
8209
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 14 times.
47 for (int j = 0; j < mov->nb_streams; j++) {
8210 33 AVStream *stj= mov->tracks[j].st;
8211 33 MOVTrack *trackj= &mov->tracks[j];
8212
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
33 if (j == i)
8213 14 continue;
8214
8215
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8216
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 ||
8217 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8218 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8219 )
8220 4 track->mono_as_fc = -1;
8221
8222
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 &&
8223 11 av_channel_layout_compare(&trackj->par->ch_layout,
8224 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8225
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
8226 )
8227 7 track->mono_as_fc++;
8228
8229
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 ||
8230 11 av_channel_layout_compare(&trackj->par->ch_layout,
8231 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8232 trackj->language != track->language ||
8233 trackj->tag != track->tag
8234 )
8235 19 continue;
8236 track->multichannel_as_mono++;
8237 }
8238 }
8239
8240
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 17 times.
209 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8241
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
192 if ((ret = mov_write_identification(pb, s)) < 0)
8242 return ret;
8243 }
8244
8245
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->reserved_moov_size){
8246 3 mov->reserved_header_pos = avio_tell(pb);
8247
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8248 avio_skip(pb, mov->reserved_moov_size);
8249 }
8250
8251
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 175 times.
209 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8252 /* If no fragmentation options have been set, set a default. */
8253
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 30 times.
34 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8254 FF_MOV_FLAG_FRAG_CUSTOM |
8255 4 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8256
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)
8257 4 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8258
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
34 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8259 1 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8260
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8261 1 mov->mdat_pos = avio_tell(pb);
8262 }
8263
1/2
✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
175 } else if (mov->mode != MODE_AVIF) {
8264
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 172 times.
175 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8265 3 mov->reserved_header_pos = avio_tell(pb);
8266 175 mov_write_mdat_tag(pb, mov);
8267 }
8268
8269 209 ff_parse_creation_time_metadata(s, &mov->time, 1);
8270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->time)
8271 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8272
8273
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->chapter_track)
8274
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8275 return ret;
8276
8277
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8278
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8279
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8280
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8281 return ret;
8282 2 hint_track++;
8283 }
8284 }
8285 }
8286
8287
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203 times.
209 if (mov->nb_meta_tmcd) {
8288 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8289 "timecode", NULL, 0);
8290 /* Initialize the tmcd tracks */
8291
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8292 8 AVStream *st = mov->tracks[i].st;
8293 8 t = global_tcr;
8294
8295
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8296 AVTimecode tc;
8297
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8298 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8299
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8300 continue;
8301
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8302 continue;
8303
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8304 return ret;
8305 6 tmcd_track++;
8306 }
8307 }
8308 }
8309
8310 209 avio_flush(pb);
8311
8312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_ISML)
8313 mov_write_isml_manifest(pb, mov, s);
8314
8315
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8316
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 17 times.
30 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8317
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8318 return ret;
8319 13 mov->moov_written = 1;
8320
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8321 mov->reserved_header_pos = avio_tell(pb);
8322 }
8323
8324 209 return 0;
8325 }
8326
8327 27 static int get_moov_size(AVFormatContext *s)
8328 {
8329 int ret;
8330 AVIOContext *moov_buf;
8331 27 MOVMuxContext *mov = s->priv_data;
8332
8333
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
8334 return ret;
8335
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
8336 return ret;
8337 27 return ffio_close_null_buf(moov_buf);
8338 }
8339
8340 static int get_sidx_size(AVFormatContext *s)
8341 {
8342 int ret;
8343 AVIOContext *buf;
8344 MOVMuxContext *mov = s->priv_data;
8345
8346 if ((ret = ffio_open_null_buf(&buf)) < 0)
8347 return ret;
8348 mov_write_sidx_tags(buf, mov, -1, 0);
8349 return ffio_close_null_buf(buf);
8350 }
8351
8352 /*
8353 * This function gets the moov size if moved to the top of the file: the chunk
8354 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8355 * entries) when the moov is moved to the beginning, so the size of the moov
8356 * would change. It also updates the chunk offset tables.
8357 */
8358 3 static int compute_moov_size(AVFormatContext *s)
8359 {
8360 int i, moov_size, moov_size2;
8361 3 MOVMuxContext *mov = s->priv_data;
8362
8363 3 moov_size = get_moov_size(s);
8364
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8365 return moov_size;
8366
8367
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
8368 8 mov->tracks[i].data_offset += moov_size;
8369
8370 3 moov_size2 = get_moov_size(s);
8371
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
8372 return moov_size2;
8373
8374 /* if the size changed, we just switched from stco to co64 and need to
8375 * update the offsets */
8376
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
8377 for (i = 0; i < mov->nb_tracks; i++)
8378 mov->tracks[i].data_offset += moov_size2 - moov_size;
8379
8380 3 return moov_size2;
8381 }
8382
8383 static int compute_sidx_size(AVFormatContext *s)
8384 {
8385 int i, sidx_size;
8386 MOVMuxContext *mov = s->priv_data;
8387
8388 sidx_size = get_sidx_size(s);
8389 if (sidx_size < 0)
8390 return sidx_size;
8391
8392 for (i = 0; i < mov->nb_tracks; i++)
8393 mov->tracks[i].data_offset += sidx_size;
8394
8395 return sidx_size;
8396 }
8397
8398 3 static int shift_data(AVFormatContext *s)
8399 {
8400 int moov_size;
8401 3 MOVMuxContext *mov = s->priv_data;
8402
8403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
8404 moov_size = compute_sidx_size(s);
8405 else
8406 3 moov_size = compute_moov_size(s);
8407
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8408 return moov_size;
8409
8410 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
8411 }
8412
8413 209 static int mov_write_trailer(AVFormatContext *s)
8414 {
8415 209 MOVMuxContext *mov = s->priv_data;
8416 209 AVIOContext *pb = s->pb;
8417 209 int res = 0;
8418 int i;
8419 int64_t moov_pos;
8420
8421
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 204 times.
209 if (mov->need_rewrite_extradata) {
8422
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
12 for (i = 0; i < mov->nb_streams; i++) {
8423 7 MOVTrack *track = &mov->tracks[i];
8424 7 AVCodecParameters *par = track->par;
8425
8426 7 track->vos_len = par->extradata_size;
8427 7 av_freep(&track->vos_data);
8428 7 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8429
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!track->vos_data)
8430 return AVERROR(ENOMEM);
8431 7 memcpy(track->vos_data, par->extradata, track->vos_len);
8432 7 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8433 }
8434 5 mov->need_rewrite_extradata = 0;
8435 }
8436
8437 /*
8438 * Before actually writing the trailer, make sure that there are no
8439 * dangling subtitles, that need a terminating sample.
8440 */
8441
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 209 times.
485 for (i = 0; i < mov->nb_tracks; i++) {
8442 276 MOVTrack *trk = &mov->tracks[i];
8443
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 275 times.
276 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
8444
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
8445 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
8446 1 trk->last_sample_is_subtitle_end = 1;
8447 }
8448 }
8449
8450 // Check if we have any tracks that require squashing.
8451 // In that case, we'll have to write the packet here.
8452
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 209 times.
209 if ((res = mov_write_squashed_packets(s)) < 0)
8453 return res;
8454
8455 // If there were no chapters when the header was written, but there
8456 // are chapters now, write them in the trailer. This only works
8457 // when we are not doing fragments.
8458
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)) {
8459
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) {
8460 mov->chapter_track = mov->nb_tracks++;
8461 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8462 return res;
8463 }
8464 }
8465
8466
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 175 times.
209 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
8467
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
34 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8468
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 175 times.
176 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8469 1 mov_flush_fragment(s, 1);
8470 1 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
8471
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
8472 2 MOVTrack *track = &mov->tracks[i];
8473 2 track->data_offset = 0;
8474 2 av_free(track->cluster);
8475 2 track->cluster = track->cluster_written;
8476 2 track->entry = track->entry_written;
8477 2 track->cluster_written = NULL;
8478 2 track->entry_written = 0;
8479 2 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
8480 }
8481 // Clear the empty_moov flag, as we do want the moov to include
8482 // all the samples at this point.
8483 1 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
8484 }
8485
8486 176 moov_pos = avio_tell(pb);
8487
8488 /* Write size of mdat tag */
8489
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 if (mov->mdat_size + 8 <= UINT32_MAX) {
8490 176 avio_seek(pb, mov->mdat_pos, SEEK_SET);
8491 176 avio_wb32(pb, mov->mdat_size + 8);
8492
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 175 times.
176 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8493 1 ffio_wfourcc(pb, "mdat"); // overwrite the original moov into a mdat
8494 } else {
8495 /* overwrite 'wide' placeholder atom */
8496 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
8497 /* special value: real atom size will be 64 bit value after
8498 * tag field */
8499 avio_wb32(pb, 1);
8500 ffio_wfourcc(pb, "mdat");
8501 avio_wb64(pb, mov->mdat_size + 16);
8502 }
8503
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);
8504
8505
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 173 times.
176 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8506 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
8507 3 res = shift_data(s);
8508
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
8509 return res;
8510 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8511
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8512 return res;
8513
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 } else if (mov->reserved_moov_size > 0) {
8514 int64_t size;
8515 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8516 return res;
8517 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
8518 if (size < 8){
8519 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
8520 return AVERROR(EINVAL);
8521 }
8522 avio_wb32(pb, size);
8523 ffio_wfourcc(pb, "free");
8524 ffio_fill(pb, 0, size - 8);
8525 avio_seek(pb, moov_pos, SEEK_SET);
8526 } else {
8527
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
173 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8528 return res;
8529 }
8530 176 res = 0;
8531 } else {
8532 33 mov_auto_flush_fragment(s, 1);
8533
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++)
8534 63 mov->tracks[i].data_offset = 0;
8535
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8536 int64_t end;
8537 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8538 res = shift_data(s);
8539 if (res < 0)
8540 return res;
8541 end = avio_tell(pb);
8542 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8543 mov_write_sidx_tags(pb, mov, -1, 0);
8544 avio_seek(pb, end, SEEK_SET);
8545 }
8546
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8547 33 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8548 33 res = mov_write_mfra_tag(pb, mov);
8549
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (res < 0)
8550 return res;
8551 }
8552 }
8553
8554 209 return res;
8555 }
8556
8557 232 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8558 const AVPacket *pkt)
8559 {
8560 232 int ret = 1;
8561
8562
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 223 times.
232 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8563
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)
8564 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
223 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8566 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8567 }
8568
8569 232 return ret;
8570 }
8571
8572 #if CONFIG_AVIF_MUXER
8573 static int avif_write_trailer(AVFormatContext *s)
8574 {
8575 AVIOContext *pb = s->pb;
8576 MOVMuxContext *mov = s->priv_data;
8577 int64_t pos_backup, extent_offsets[2];
8578 uint8_t *buf;
8579 int buf_size, moov_size;
8580
8581 if (mov->moov_written) return 0;
8582
8583 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8584 if (mov->is_animated_avif && mov->nb_streams > 1) {
8585 // For animated avif with alpha channel, we need to write a tref tag
8586 // with type "auxl".
8587 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8588 mov->tracks[1].tref_id = 1;
8589 }
8590 mov_write_identification(pb, s);
8591 mov_write_meta_tag(pb, mov, s);
8592
8593 moov_size = get_moov_size(s);
8594 for (int i = 0; i < mov->nb_tracks; i++)
8595 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8596
8597 if (mov->is_animated_avif) {
8598 int ret;
8599 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8600 return ret;
8601 }
8602
8603 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8604 avio_wb32(pb, buf_size + 8);
8605 ffio_wfourcc(pb, "mdat");
8606
8607 // The offset for the YUV planes is the starting position of mdat.
8608 extent_offsets[0] = avio_tell(pb);
8609 // The offset for alpha plane is YUV offset + YUV size.
8610 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8611
8612 avio_write(pb, buf, buf_size);
8613
8614 // write extent offsets.
8615 pos_backup = avio_tell(pb);
8616 for (int i = 0; i < mov->nb_streams; i++) {
8617 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8618 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8619 return AVERROR_INVALIDDATA;
8620 }
8621 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8622 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8623 }
8624 avio_seek(pb, pos_backup, SEEK_SET);
8625
8626 return 0;
8627 }
8628 #endif
8629
8630 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8631 static const AVCodecTag codec_3gp_tags[] = {
8632 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8633 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8634 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8635 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8636 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8637 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8638 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8639 { AV_CODEC_ID_NONE, 0 },
8640 };
8641 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8642 #endif
8643
8644 static const AVCodecTag codec_mp4_tags[] = {
8645 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8646 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8647 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8648 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8649 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8650 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8651 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8652 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8653 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8654 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8655 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8656 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8657 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8658 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8659 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8660 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8661 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8662 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8663 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8664 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8665 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8666 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
8667 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
8668 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
8669 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
8670 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
8671 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
8672 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
8673 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
8674 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
8675 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
8676 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
8677 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
8678 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
8679 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
8680 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
8681 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
8682 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
8683 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
8684 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
8685
8686 /* ISO/IEC 23003-5 integer formats */
8687 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
8688 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
8689 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
8690 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
8691 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
8692 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
8693 /* ISO/IEC 23003-5 floating-point formats */
8694 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
8695 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
8696 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
8697 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
8698
8699 { AV_CODEC_ID_AVS3, MKTAG('a', 'v', 's', '3') },
8700
8701 { AV_CODEC_ID_NONE, 0 },
8702 };
8703 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8704 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
8705 #endif
8706
8707 static const AVCodecTag codec_ism_tags[] = {
8708 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
8709 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
8710 { AV_CODEC_ID_NONE , 0 },
8711 };
8712
8713 static const AVCodecTag codec_ipod_tags[] = {
8714 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8715 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8716 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8717 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
8718 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
8719 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8720 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
8721 { AV_CODEC_ID_NONE, 0 },
8722 };
8723
8724 static const AVCodecTag codec_f4v_tags[] = {
8725 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
8726 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8727 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8728 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
8729 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
8730 { AV_CODEC_ID_NONE, 0 },
8731 };
8732
8733 #if CONFIG_AVIF_MUXER
8734
8735 static const AVOption avif_options[] = {
8736 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
8737 { "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 },
8738 { NULL },
8739 };
8740 static const AVCodecTag codec_avif_tags[] = {
8741 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
8742 { AV_CODEC_ID_NONE, 0 },
8743 };
8744 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
8745
8746 static const AVClass mov_avif_muxer_class = {
8747 .class_name = "avif muxer",
8748 .item_name = av_default_item_name,
8749 .option = avif_options,
8750 .version = LIBAVUTIL_VERSION_INT,
8751 };
8752 #endif
8753
8754 #if CONFIG_MOV_MUXER
8755 const FFOutputFormat ff_mov_muxer = {
8756 .p.name = "mov",
8757 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8758 .p.extensions = "mov",
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 .p.codec_tag = (const AVCodecTag* const []){
8770 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
8771 },
8772 .check_bitstream = mov_check_bitstream,
8773 .p.priv_class = &mov_isobmff_muxer_class,
8774 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8775 };
8776 #endif
8777 #if CONFIG_TGP_MUXER
8778 const FFOutputFormat ff_tgp_muxer = {
8779 .p.name = "3gp",
8780 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
8781 .p.extensions = "3gp",
8782 .priv_data_size = sizeof(MOVMuxContext),
8783 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8784 .p.video_codec = AV_CODEC_ID_H263,
8785 .init = mov_init,
8786 .write_header = mov_write_header,
8787 .write_packet = mov_write_packet,
8788 .write_trailer = mov_write_trailer,
8789 .deinit = mov_free,
8790 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8791 .p.codec_tag = codec_3gp_tags_list,
8792 .check_bitstream = mov_check_bitstream,
8793 .p.priv_class = &mov_isobmff_muxer_class,
8794 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8795 };
8796 #endif
8797 #if CONFIG_MP4_MUXER
8798 const FFOutputFormat ff_mp4_muxer = {
8799 .p.name = "mp4",
8800 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
8801 .p.mime_type = "video/mp4",
8802 .p.extensions = "mp4",
8803 .priv_data_size = sizeof(MOVMuxContext),
8804 .p.audio_codec = AV_CODEC_ID_AAC,
8805 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8806 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8807 .init = mov_init,
8808 .write_header = mov_write_header,
8809 .write_packet = mov_write_packet,
8810 .write_trailer = mov_write_trailer,
8811 .deinit = mov_free,
8812 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS,
8813 .p.codec_tag = mp4_codec_tags_list,
8814 .check_bitstream = mov_check_bitstream,
8815 .p.priv_class = &mov_isobmff_muxer_class,
8816 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8817 };
8818 #endif
8819 #if CONFIG_PSP_MUXER
8820 const FFOutputFormat ff_psp_muxer = {
8821 .p.name = "psp",
8822 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
8823 .p.extensions = "mp4,psp",
8824 .priv_data_size = sizeof(MOVMuxContext),
8825 .p.audio_codec = AV_CODEC_ID_AAC,
8826 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8827 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8828 .init = mov_init,
8829 .write_header = mov_write_header,
8830 .write_packet = mov_write_packet,
8831 .write_trailer = mov_write_trailer,
8832 .deinit = mov_free,
8833 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8834 .p.codec_tag = mp4_codec_tags_list,
8835 .check_bitstream = mov_check_bitstream,
8836 .p.priv_class = &mov_isobmff_muxer_class,
8837 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8838 };
8839 #endif
8840 #if CONFIG_TG2_MUXER
8841 const FFOutputFormat ff_tg2_muxer = {
8842 .p.name = "3g2",
8843 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
8844 .p.extensions = "3g2",
8845 .priv_data_size = sizeof(MOVMuxContext),
8846 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8847 .p.video_codec = AV_CODEC_ID_H263,
8848 .init = mov_init,
8849 .write_header = mov_write_header,
8850 .write_packet = mov_write_packet,
8851 .write_trailer = mov_write_trailer,
8852 .deinit = mov_free,
8853 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8854 .p.codec_tag = codec_3gp_tags_list,
8855 .check_bitstream = mov_check_bitstream,
8856 .p.priv_class = &mov_isobmff_muxer_class,
8857 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8858 };
8859 #endif
8860 #if CONFIG_IPOD_MUXER
8861 const FFOutputFormat ff_ipod_muxer = {
8862 .p.name = "ipod",
8863 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
8864 .p.mime_type = "video/mp4",
8865 .p.extensions = "m4v,m4a,m4b",
8866 .priv_data_size = sizeof(MOVMuxContext),
8867 .p.audio_codec = AV_CODEC_ID_AAC,
8868 .p.video_codec = AV_CODEC_ID_H264,
8869 .init = mov_init,
8870 .write_header = mov_write_header,
8871 .write_packet = mov_write_packet,
8872 .write_trailer = mov_write_trailer,
8873 .deinit = mov_free,
8874 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8875 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
8876 .check_bitstream = mov_check_bitstream,
8877 .p.priv_class = &mov_isobmff_muxer_class,
8878 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8879 };
8880 #endif
8881 #if CONFIG_ISMV_MUXER
8882 const FFOutputFormat ff_ismv_muxer = {
8883 .p.name = "ismv",
8884 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
8885 .p.mime_type = "video/mp4",
8886 .p.extensions = "ismv,isma",
8887 .priv_data_size = sizeof(MOVMuxContext),
8888 .p.audio_codec = AV_CODEC_ID_AAC,
8889 .p.video_codec = AV_CODEC_ID_H264,
8890 .init = mov_init,
8891 .write_header = mov_write_header,
8892 .write_packet = mov_write_packet,
8893 .write_trailer = mov_write_trailer,
8894 .deinit = mov_free,
8895 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8896 .p.codec_tag = (const AVCodecTag* const []){
8897 codec_mp4_tags, codec_ism_tags, 0 },
8898 .check_bitstream = mov_check_bitstream,
8899 .p.priv_class = &mov_isobmff_muxer_class,
8900 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8901 };
8902 #endif
8903 #if CONFIG_F4V_MUXER
8904 const FFOutputFormat ff_f4v_muxer = {
8905 .p.name = "f4v",
8906 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
8907 .p.mime_type = "application/f4v",
8908 .p.extensions = "f4v",
8909 .priv_data_size = sizeof(MOVMuxContext),
8910 .p.audio_codec = AV_CODEC_ID_AAC,
8911 .p.video_codec = AV_CODEC_ID_H264,
8912 .init = mov_init,
8913 .write_header = mov_write_header,
8914 .write_packet = mov_write_packet,
8915 .write_trailer = mov_write_trailer,
8916 .deinit = mov_free,
8917 .p.flags = AVFMT_GLOBALHEADER,
8918 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
8919 .check_bitstream = mov_check_bitstream,
8920 .p.priv_class = &mov_isobmff_muxer_class,
8921 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8922 };
8923 #endif
8924 #if CONFIG_AVIF_MUXER
8925 const FFOutputFormat ff_avif_muxer = {
8926 .p.name = "avif",
8927 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
8928 .p.mime_type = "image/avif",
8929 .p.extensions = "avif",
8930 .priv_data_size = sizeof(MOVMuxContext),
8931 .p.video_codec = AV_CODEC_ID_AV1,
8932 .init = mov_init,
8933 .write_header = mov_write_header,
8934 .write_packet = mov_write_packet,
8935 .write_trailer = avif_write_trailer,
8936 .deinit = mov_free,
8937 .p.flags = AVFMT_GLOBALHEADER,
8938 .p.codec_tag = codec_avif_tags_list,
8939 .p.priv_class = &mov_avif_muxer_class,
8940 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8941 };
8942 #endif
8943