FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavformat/movenc.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 3582 5337 67.1%
Functions: 171 223 76.7%
Branches: 2098 3655 57.4%

Line Branch Exec Source
1 /*
2 * MOV, 3GP, MP4 muxer
3 * Copyright (c) 2003 Thomas Raivio
4 * Copyright (c) 2004 Gildas Bazin <gbazin at videolan dot org>
5 * Copyright (c) 2009 Baptiste Coudurier <baptiste dot coudurier at gmail dot com>
6 *
7 * This file is part of FFmpeg.
8 *
9 * FFmpeg is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 * FFmpeg is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with FFmpeg; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
22 */
23
24 #include "config_components.h"
25
26 #include <stdint.h>
27 #include <inttypes.h>
28
29 #include "movenc.h"
30 #include "avformat.h"
31 #include "avio_internal.h"
32 #include "dovi_isom.h"
33 #include "riff.h"
34 #include "avio.h"
35 #include "iamf_writer.h"
36 #include "isom.h"
37 #include "av1.h"
38 #include "avc.h"
39 #include "evc.h"
40 #include "libavcodec/ac3_parser_internal.h"
41 #include "libavcodec/dnxhddata.h"
42 #include "libavcodec/flac.h"
43 #include "libavcodec/get_bits.h"
44
45 #include "libavcodec/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 34 bit_rates.max_bit_rate = FFMAX(bit_rates.max_bit_rate,
741 props->max_bitrate);
742 34 bit_rates.buffer_size = props->buffer_size / 8;
743 }
744
745 210 return bit_rates;
746 }
747
748 79 static int mov_write_esds_tag(AVIOContext *pb, MOVTrack *track) // Basic
749 {
750 79 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
751 79 int64_t pos = avio_tell(pb);
752
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;
753
754 79 avio_wb32(pb, 0); // size
755 79 ffio_wfourcc(pb, "esds");
756 79 avio_wb32(pb, 0); // Version
757
758 // ES descriptor
759 79 put_descr(pb, 0x03, 3 + 5+13 + decoder_specific_info_len + 5+1);
760 79 avio_wb16(pb, track->track_id);
761 79 avio_w8(pb, 0x00); // flags (= no flags)
762
763 // DecoderConfig descriptor
764 79 put_descr(pb, 0x04, 13 + decoder_specific_info_len);
765
766 // Object type indication
767
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if ((track->par->codec_id == AV_CODEC_ID_MP2 ||
768
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 track->par->codec_id == AV_CODEC_ID_MP3) &&
769 track->par->sample_rate > 24000)
770 avio_w8(pb, 0x6B); // 11172-3
771 else
772 79 avio_w8(pb, ff_codec_get_tag(ff_mp4_obj_type, track->par->codec_id));
773
774 // the following fields is made of 6 bits to identify the streamtype (4 for video, 5 for audio)
775 // plus 1 bit to indicate upstream and 1 bit set to 1 (reserved)
776
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 79 times.
79 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
777 avio_w8(pb, (0x38 << 2) | 1); // flags (= NeroSubpicStream)
778
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 25 times.
79 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
779 54 avio_w8(pb, 0x15); // flags (= Audiostream)
780 else
781 25 avio_w8(pb, 0x11); // flags (= Visualstream)
782
783 79 avio_wb24(pb, bit_rates.buffer_size); // Buffersize DB
784 79 avio_wb32(pb, bit_rates.max_bit_rate); // maxbitrate
785 79 avio_wb32(pb, bit_rates.avg_bit_rate);
786
787
1/2
✓ Branch 0 taken 79 times.
✗ Branch 1 not taken.
79 if (track->vos_len) {
788 // DecoderSpecific info descriptor
789 79 put_descr(pb, 0x05, track->vos_len);
790 79 avio_write(pb, track->vos_data, track->vos_len);
791 }
792
793 // SL descriptor
794 79 put_descr(pb, 0x06, 1);
795 79 avio_w8(pb, 0x02);
796 79 return update_size(pb, pos);
797 }
798
799 77 static int mov_pcm_le_gt16(enum AVCodecID codec_id)
800 {
801
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 return codec_id == AV_CODEC_ID_PCM_S24LE ||
802
1/2
✓ Branch 0 taken 77 times.
✗ Branch 1 not taken.
77 codec_id == AV_CODEC_ID_PCM_S32LE ||
803
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 ||
804 codec_id == AV_CODEC_ID_PCM_F64LE;
805 }
806
807 77 static int mov_pcm_be_gt16(enum AVCodecID codec_id)
808 {
809
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 4 times.
73 return codec_id == AV_CODEC_ID_PCM_S24BE ||
810
1/2
✓ Branch 0 taken 69 times.
✗ Branch 1 not taken.
69 codec_id == AV_CODEC_ID_PCM_S32BE ||
811
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 ||
812 codec_id == AV_CODEC_ID_PCM_F64BE;
813 }
814
815 static int mov_write_ms_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
816 {
817 int ret;
818 int64_t pos = avio_tell(pb);
819 avio_wb32(pb, 0);
820 avio_wl32(pb, track->tag); // store it byteswapped
821 track->par->codec_tag = av_bswap16(track->tag >> 16);
822 if ((ret = ff_put_wav_header(s, pb, track->par, 0)) < 0)
823 return ret;
824 return update_size(pb, pos);
825 }
826
827 static int mov_write_wfex_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
828 {
829 int ret;
830 int64_t pos = avio_tell(pb);
831 avio_wb32(pb, 0);
832 ffio_wfourcc(pb, "wfex");
833 if ((ret = ff_put_wav_header(s, pb, track->st->codecpar, FF_PUT_WAV_HEADER_FORCE_WAVEFORMATEX)) < 0)
834 return ret;
835 return update_size(pb, pos);
836 }
837
838 static int mov_write_dfla_tag(AVIOContext *pb, MOVTrack *track)
839 {
840 int64_t pos = avio_tell(pb);
841 avio_wb32(pb, 0);
842 ffio_wfourcc(pb, "dfLa");
843 avio_w8(pb, 0); /* version */
844 avio_wb24(pb, 0); /* flags */
845
846 /* Expect the encoder to pass a METADATA_BLOCK_TYPE_STREAMINFO. */
847 if (track->par->extradata_size != FLAC_STREAMINFO_SIZE)
848 return AVERROR_INVALIDDATA;
849
850 /* TODO: Write other METADATA_BLOCK_TYPEs if the encoder makes them available. */
851 avio_w8(pb, 1 << 7 | FLAC_METADATA_TYPE_STREAMINFO); /* LastMetadataBlockFlag << 7 | BlockType */
852 avio_wb24(pb, track->par->extradata_size); /* Length */
853 avio_write(pb, track->par->extradata, track->par->extradata_size); /* BlockData[Length] */
854
855 return update_size(pb, pos);
856 }
857
858 static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
859 {
860 int64_t pos = avio_tell(pb);
861 int channels, channel_map;
862 avio_wb32(pb, 0);
863 ffio_wfourcc(pb, "dOps");
864 avio_w8(pb, 0); /* Version */
865 if (track->par->extradata_size < 19) {
866 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
867 return AVERROR_INVALIDDATA;
868 }
869 /* extradata contains an Ogg OpusHead, other than byte-ordering and
870 OpusHead's preceeding magic/version, OpusSpecificBox is currently
871 identical. */
872 channels = AV_RB8(track->par->extradata + 9);
873 channel_map = AV_RB8(track->par->extradata + 18);
874
875 avio_w8(pb, channels); /* OuputChannelCount */
876 avio_wb16(pb, AV_RL16(track->par->extradata + 10)); /* PreSkip */
877 avio_wb32(pb, AV_RL32(track->par->extradata + 12)); /* InputSampleRate */
878 avio_wb16(pb, AV_RL16(track->par->extradata + 16)); /* OutputGain */
879 avio_w8(pb, channel_map); /* ChannelMappingFamily */
880 /* Write the rest of the header out without byte-swapping. */
881 if (channel_map) {
882 if (track->par->extradata_size < 21 + channels) {
883 av_log(s, AV_LOG_ERROR, "invalid extradata size\n");
884 return AVERROR_INVALIDDATA;
885 }
886 avio_write(pb, track->par->extradata + 19, 2 + channels); /* ChannelMappingTable */
887 }
888
889 return update_size(pb, pos);
890 }
891
892 static int mov_write_dmlp_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
893 {
894 int64_t pos = avio_tell(pb);
895 int length;
896 avio_wb32(pb, 0);
897 ffio_wfourcc(pb, "dmlp");
898
899 if (track->vos_len < 20) {
900 av_log(s, AV_LOG_ERROR,
901 "Cannot write moov atom before TrueHD packets."
902 " Set the delay_moov flag to fix this.\n");
903 return AVERROR(EINVAL);
904 }
905
906 length = (AV_RB16(track->vos_data) & 0xFFF) * 2;
907 if (length < 20 || length > track->vos_len)
908 return AVERROR_INVALIDDATA;
909
910 // Only TrueHD is supported
911 if (AV_RB32(track->vos_data + 4) != 0xF8726FBA)
912 return AVERROR_INVALIDDATA;
913
914 avio_wb32(pb, AV_RB32(track->vos_data + 8)); /* format_info */
915 avio_wb16(pb, AV_RB16(track->vos_data + 18) << 1); /* peak_data_rate */
916 avio_wb32(pb, 0); /* reserved */
917
918 return update_size(pb, pos);
919 }
920
921 65 static int mov_write_SA3D_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
922 {
923 65 const AVDictionaryEntry *str = av_dict_get(track->st->metadata, "SA3D", NULL, 0);
924 65 AVChannelLayout ch_layout = { 0 };
925 int64_t pos;
926 int ambisonic_order, ambi_channels, non_diegetic_channels;
927 int i, ret;
928
929
1/2
✓ Branch 0 taken 65 times.
✗ Branch 1 not taken.
65 if (!str)
930 65 return 0;
931
932 ret = av_channel_layout_from_string(&ch_layout, str->value);
933 if (ret < 0) {
934 if (ret == AVERROR(EINVAL)) {
935 invalid:
936 av_log(s, AV_LOG_ERROR, "Invalid SA3D layout: \"%s\"\n", str->value);
937 ret = 0;
938 }
939 av_channel_layout_uninit(&ch_layout);
940 return ret;
941 }
942
943 if (track->st->codecpar->ch_layout.nb_channels != ch_layout.nb_channels)
944 goto invalid;
945
946 ambisonic_order = av_channel_layout_ambisonic_order(&ch_layout);
947 if (ambisonic_order < 0)
948 goto invalid;
949
950 ambi_channels = (ambisonic_order + 1LL) * (ambisonic_order + 1LL);
951 non_diegetic_channels = ch_layout.nb_channels - ambi_channels;
952 if (non_diegetic_channels &&
953 (non_diegetic_channels != 2 ||
954 av_channel_layout_subset(&ch_layout, AV_CH_LAYOUT_STEREO) != AV_CH_LAYOUT_STEREO))
955 goto invalid;
956
957 av_log(s, AV_LOG_VERBOSE, "Inserting SA3D box with layout: \"%s\"\n", str->value);
958
959 pos = avio_tell(pb);
960
961 avio_wb32(pb, 0); // Size
962 ffio_wfourcc(pb, "SA3D");
963 avio_w8(pb, 0); // version
964 avio_w8(pb, (!!non_diegetic_channels) << 7); // head_locked_stereo and ambisonic_type
965 avio_wb32(pb, ambisonic_order); // ambisonic_order
966 avio_w8(pb, 0); // ambisonic_channel_ordering
967 avio_w8(pb, 0); // ambisonic_normalization
968 avio_wb32(pb, ch_layout.nb_channels); // num_channels
969 for (i = 0; i < ambi_channels; i++)
970 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) - AV_CHAN_AMBISONIC_BASE);
971 for (; i < ch_layout.nb_channels; i++)
972 avio_wb32(pb, av_channel_layout_channel_from_index(&ch_layout, i) + ambi_channels);
973
974 av_channel_layout_uninit(&ch_layout);
975
976 return update_size(pb, pos);
977 }
978
979 40 static int mov_write_chan_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
980 {
981 uint32_t layout_tag, bitmap, *channel_desc;
982 40 int64_t pos = avio_tell(pb);
983 int num_desc, ret;
984
985
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (track->multichannel_as_mono)
986 return 0;
987
988 40 ret = ff_mov_get_channel_layout_tag(track->par, &layout_tag,
989 &bitmap, &channel_desc);
990
991
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 40 times.
40 if (ret < 0) {
992 if (ret == AVERROR(ENOSYS)) {
993 av_log(s, AV_LOG_WARNING, "not writing 'chan' tag due to "
994 "lack of channel information\n");
995 ret = 0;
996 }
997
998 return ret;
999 }
1000
1001
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) {
1002
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 av_assert0(!channel_desc);
1003 1 channel_desc = av_malloc(sizeof(*channel_desc));
1004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!channel_desc)
1005 return AVERROR(ENOMEM);
1006
1007 1 layout_tag = 0;
1008 1 bitmap = 0;
1009 1 *channel_desc = 3; // channel label "Center"
1010 }
1011
1012
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 37 times.
40 num_desc = layout_tag ? 0 : track->par->ch_layout.nb_channels;
1013
1014 40 avio_wb32(pb, 0); // Size
1015 40 ffio_wfourcc(pb, "chan"); // Type
1016 40 avio_w8(pb, 0); // Version
1017 40 avio_wb24(pb, 0); // Flags
1018 40 avio_wb32(pb, layout_tag); // mChannelLayoutTag
1019 40 avio_wb32(pb, bitmap); // mChannelBitmap
1020 40 avio_wb32(pb, num_desc); // mNumberChannelDescriptions
1021
1022
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 40 times.
43 for (int i = 0; i < num_desc; i++) {
1023 3 avio_wb32(pb, channel_desc[i]); // mChannelLabel
1024 3 avio_wb32(pb, 0); // mChannelFlags
1025 3 avio_wl32(pb, 0); // mCoordinates[0]
1026 3 avio_wl32(pb, 0); // mCoordinates[1]
1027 3 avio_wl32(pb, 0); // mCoordinates[2]
1028 }
1029
1030 40 av_free(channel_desc);
1031
1032 40 return update_size(pb, pos);
1033 }
1034
1035 15 static int mov_write_wave_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1036 {
1037 15 int64_t pos = avio_tell(pb);
1038
1039 15 avio_wb32(pb, 0); /* size */
1040 15 ffio_wfourcc(pb, "wave");
1041
1042
1/2
✓ Branch 0 taken 15 times.
✗ Branch 1 not taken.
15 if (track->par->codec_id != AV_CODEC_ID_QDM2) {
1043 15 avio_wb32(pb, 12); /* size */
1044 15 ffio_wfourcc(pb, "frma");
1045 15 avio_wl32(pb, track->tag);
1046 }
1047
1048
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 12 times.
15 if (track->par->codec_id == AV_CODEC_ID_AAC) {
1049 /* useless atom needed by mplayer, ipod, not needed by quicktime */
1050 3 avio_wb32(pb, 12); /* size */
1051 3 ffio_wfourcc(pb, "mp4a");
1052 3 avio_wb32(pb, 0);
1053 3 mov_write_esds_tag(pb, track);
1054
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
12 } else if (mov_pcm_le_gt16(track->par->codec_id)) {
1055 mov_write_enda_tag(pb);
1056
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 10 times.
12 } else if (mov_pcm_be_gt16(track->par->codec_id)) {
1057 2 mov_write_enda_tag_be(pb);
1058
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AMR_NB) {
1059 mov_write_amr_tag(pb, track);
1060
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 9 times.
10 } else if (track->par->codec_id == AV_CODEC_ID_AC3) {
1061 1 mov_write_ac3_tag(s, pb, track);
1062
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_EAC3) {
1063 mov_write_eac3_tag(s, pb, track);
1064
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 } else if (track->par->codec_id == AV_CODEC_ID_ALAC ||
1065 track->par->codec_id == AV_CODEC_ID_QDM2) {
1066 9 mov_write_extradata_tag(pb, track);
1067 } else if (track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1068 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
1069 mov_write_ms_tag(s, pb, track);
1070 }
1071
1072 15 avio_wb32(pb, 8); /* size */
1073 15 avio_wb32(pb, 0); /* null tag */
1074
1075 15 return update_size(pb, pos);
1076 }
1077
1078 static int mov_write_dvc1_structs(MOVTrack *track, uint8_t *buf)
1079 {
1080 uint8_t *unescaped;
1081 const uint8_t *start, *next, *end = track->vos_data + track->vos_len;
1082 int unescaped_size, seq_found = 0;
1083 int level = 0, interlace = 0;
1084 int packet_seq = track->vc1_info.packet_seq;
1085 int packet_entry = track->vc1_info.packet_entry;
1086 int slices = track->vc1_info.slices;
1087 PutBitContext pbc;
1088
1089 if (track->start_dts == AV_NOPTS_VALUE) {
1090 /* No packets written yet, vc1_info isn't authoritative yet. */
1091 /* Assume inline sequence and entry headers. */
1092 packet_seq = packet_entry = 1;
1093 av_log(NULL, AV_LOG_WARNING,
1094 "moov atom written before any packets, unable to write correct "
1095 "dvc1 atom. Set the delay_moov flag to fix this.\n");
1096 }
1097
1098 unescaped = av_mallocz(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
1099 if (!unescaped)
1100 return AVERROR(ENOMEM);
1101 start = find_next_marker(track->vos_data, end);
1102 for (next = start; next < end; start = next) {
1103 GetBitContext gb;
1104 int size;
1105 next = find_next_marker(start + 4, end);
1106 size = next - start - 4;
1107 if (size <= 0)
1108 continue;
1109 unescaped_size = vc1_unescape_buffer(start + 4, size, unescaped);
1110 init_get_bits(&gb, unescaped, 8 * unescaped_size);
1111 if (AV_RB32(start) == VC1_CODE_SEQHDR) {
1112 int profile = get_bits(&gb, 2);
1113 if (profile != PROFILE_ADVANCED) {
1114 av_free(unescaped);
1115 return AVERROR(ENOSYS);
1116 }
1117 seq_found = 1;
1118 level = get_bits(&gb, 3);
1119 /* chromaformat, frmrtq_postproc, bitrtq_postproc, postprocflag,
1120 * width, height */
1121 skip_bits_long(&gb, 2 + 3 + 5 + 1 + 2*12);
1122 skip_bits(&gb, 1); /* broadcast */
1123 interlace = get_bits1(&gb);
1124 skip_bits(&gb, 4); /* tfcntrflag, finterpflag, reserved, psf */
1125 }
1126 }
1127 if (!seq_found) {
1128 av_free(unescaped);
1129 return AVERROR(ENOSYS);
1130 }
1131
1132 init_put_bits(&pbc, buf, 7);
1133 /* VC1DecSpecStruc */
1134 put_bits(&pbc, 4, 12); /* profile - advanced */
1135 put_bits(&pbc, 3, level);
1136 put_bits(&pbc, 1, 0); /* reserved */
1137 /* VC1AdvDecSpecStruc */
1138 put_bits(&pbc, 3, level);
1139 put_bits(&pbc, 1, 0); /* cbr */
1140 put_bits(&pbc, 6, 0); /* reserved */
1141 put_bits(&pbc, 1, !interlace); /* no interlace */
1142 put_bits(&pbc, 1, !packet_seq); /* no multiple seq */
1143 put_bits(&pbc, 1, !packet_entry); /* no multiple entry */
1144 put_bits(&pbc, 1, !slices); /* no slice code */
1145 put_bits(&pbc, 1, 0); /* no bframe */
1146 put_bits(&pbc, 1, 0); /* reserved */
1147
1148 /* framerate */
1149 if (track->st->avg_frame_rate.num > 0 && track->st->avg_frame_rate.den > 0)
1150 put_bits32(&pbc, track->st->avg_frame_rate.num / track->st->avg_frame_rate.den);
1151 else
1152 put_bits32(&pbc, 0xffffffff);
1153
1154 flush_put_bits(&pbc);
1155
1156 av_free(unescaped);
1157
1158 return 0;
1159 }
1160
1161 static int mov_write_dvc1_tag(AVIOContext *pb, MOVTrack *track)
1162 {
1163 uint8_t buf[7] = { 0 };
1164 int ret;
1165
1166 if ((ret = mov_write_dvc1_structs(track, buf)) < 0)
1167 return ret;
1168
1169 avio_wb32(pb, track->vos_len + 8 + sizeof(buf));
1170 ffio_wfourcc(pb, "dvc1");
1171 avio_write(pb, buf, sizeof(buf));
1172 avio_write(pb, track->vos_data, track->vos_len);
1173
1174 return 0;
1175 }
1176
1177 4 static int mov_write_glbl_tag(AVIOContext *pb, MOVTrack *track)
1178 {
1179 4 avio_wb32(pb, track->vos_len + 8);
1180 4 ffio_wfourcc(pb, "glbl");
1181 4 avio_write(pb, track->vos_data, track->vos_len);
1182 4 return 8 + track->vos_len;
1183 }
1184
1185 /**
1186 * Compute flags for 'lpcm' tag.
1187 * See CoreAudioTypes and AudioStreamBasicDescription at Apple.
1188 */
1189 8 static int mov_get_lpcm_flags(enum AVCodecID codec_id)
1190 {
1191
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) {
1192 case AV_CODEC_ID_PCM_F32BE:
1193 case AV_CODEC_ID_PCM_F64BE:
1194 return 11;
1195 case AV_CODEC_ID_PCM_F32LE:
1196 case AV_CODEC_ID_PCM_F64LE:
1197 return 9;
1198 case AV_CODEC_ID_PCM_U8:
1199 return 10;
1200 case AV_CODEC_ID_PCM_S16BE:
1201 case AV_CODEC_ID_PCM_S24BE:
1202 case AV_CODEC_ID_PCM_S32BE:
1203 return 14;
1204 case AV_CODEC_ID_PCM_S8:
1205 case AV_CODEC_ID_PCM_S16LE:
1206 case AV_CODEC_ID_PCM_S24LE:
1207 case AV_CODEC_ID_PCM_S32LE:
1208 return 12;
1209 8 default:
1210 8 return 0;
1211 }
1212 }
1213
1214 25209 static int get_cluster_duration(MOVTrack *track, int cluster_idx)
1215 {
1216 int64_t next_dts;
1217
1218
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 if (cluster_idx >= track->entry)
1219 return 0;
1220
1221
2/2
✓ Branch 0 taken 643 times.
✓ Branch 1 taken 24566 times.
25209 if (cluster_idx + 1 == track->entry)
1222 643 next_dts = track->track_duration + track->start_dts;
1223 else
1224 24566 next_dts = track->cluster[cluster_idx + 1].dts;
1225
1226 25209 next_dts -= track->cluster[cluster_idx].dts;
1227
1228
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 av_assert0(next_dts >= 0);
1229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25209 times.
25209 av_assert0(next_dts <= INT_MAX);
1230
1231 25209 return next_dts;
1232 }
1233
1234 4 static int get_samples_per_packet(MOVTrack *track)
1235 {
1236 int i, first_duration;
1237
1238 /* use 1 for raw PCM */
1239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->audio_vbr)
1240 return 1;
1241
1242 /* check to see if duration is constant for all clusters */
1243
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!track->entry)
1244 return 0;
1245 4 first_duration = get_cluster_duration(track, 0);
1246
1/2
✓ Branch 0 taken 1872 times.
✗ Branch 1 not taken.
1872 for (i = 1; i < track->entry; i++) {
1247
2/2
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1868 times.
1872 if (get_cluster_duration(track, i) != first_duration)
1248 4 return 0;
1249 }
1250 return first_duration;
1251 }
1252
1253 131 static int mov_write_btrt_tag(AVIOContext *pb, MOVTrack *track)
1254 {
1255 131 int64_t pos = avio_tell(pb);
1256 131 struct mpeg4_bit_rate_values bit_rates = calculate_mpeg4_bit_rates(track);
1257
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 &&
1258
1/2
✓ Branch 0 taken 81 times.
✗ Branch 1 not taken.
81 !bit_rates.buffer_size)
1259 // no useful data to be written, skip
1260 81 return 0;
1261
1262 50 avio_wb32(pb, 0); /* size */
1263 50 ffio_wfourcc(pb, "btrt");
1264
1265 50 avio_wb32(pb, bit_rates.buffer_size);
1266 50 avio_wb32(pb, bit_rates.max_bit_rate);
1267 50 avio_wb32(pb, bit_rates.avg_bit_rate);
1268
1269 50 return update_size(pb, pos);
1270 }
1271
1272 5 static int mov_write_chnl_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1273 {
1274 5 int64_t pos = avio_tell(pb);
1275 5 int config = 0;
1276 int ret;
1277 5 uint8_t *speaker_pos = NULL;
1278 5 const AVChannelLayout *layout = &track->par->ch_layout;
1279
1280 5 ret = ff_mov_get_channel_config_from_layout(layout, &config);
1281
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) {
1282 4 config = 0;
1283 4 speaker_pos = av_malloc(layout->nb_channels);
1284
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!speaker_pos)
1285 return AVERROR(ENOMEM);
1286 4 ret = ff_mov_get_channel_positions_from_layout(layout,
1287 4 speaker_pos, layout->nb_channels);
1288
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (ret) {
1289 char buf[128] = {0};
1290
1291 av_freep(&speaker_pos);
1292 av_channel_layout_describe(layout, buf, sizeof(buf));
1293 av_log(s, AV_LOG_ERROR, "unsupported channel layout %s\n", buf);
1294 return ret;
1295 }
1296 }
1297
1298 5 avio_wb32(pb, 0); /* size */
1299 5 ffio_wfourcc(pb, "chnl");
1300 5 avio_wb32(pb, 0); /* version & flags */
1301
1302 5 avio_w8(pb, 1); /* stream_structure */
1303 5 avio_w8(pb, config);
1304
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 4 times.
5 if (config) {
1305 1 avio_wb64(pb, 0);
1306 } else {
1307 4 avio_write(pb, speaker_pos, layout->nb_channels);
1308 4 av_freep(&speaker_pos);
1309 }
1310
1311 5 return update_size(pb, pos);
1312 }
1313
1314 7 static int mov_write_pcmc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1315 {
1316 7 int64_t pos = avio_tell(pb);
1317 int format_flags;
1318 int sample_size;
1319
1320 7 avio_wb32(pb, 0); /* size */
1321 7 ffio_wfourcc(pb, "pcmC");
1322 7 avio_wb32(pb, 0); /* version & flags */
1323
1324 /* 0x01: indicates little-endian format */
1325 20 format_flags = (track->par->codec_id == AV_CODEC_ID_PCM_F32LE ||
1326
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 track->par->codec_id == AV_CODEC_ID_PCM_F64LE ||
1327
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 track->par->codec_id == AV_CODEC_ID_PCM_S16LE ||
1328
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 ||
1329 track->par->codec_id == AV_CODEC_ID_PCM_S32LE);
1330 7 avio_w8(pb, format_flags);
1331 7 sample_size = track->par->bits_per_raw_sample;
1332
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
7 if (!sample_size)
1333 1 sample_size = av_get_exact_bits_per_sample(track->par->codec_id);
1334
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 av_assert0(sample_size);
1335 7 avio_w8(pb, sample_size);
1336
1337 7 return update_size(pb, pos);
1338 }
1339
1340 108 static int mov_write_audio_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
1341 {
1342 108 int64_t pos = avio_tell(pb);
1343 108 int version = 0;
1344 108 uint32_t tag = track->tag;
1345 108 int ret = 0;
1346
1347
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
108 if (track->mode == MODE_MOV) {
1348
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) {
1349
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (mov_get_lpcm_flags(track->par->codec_id))
1350 tag = AV_RL32("lpcm");
1351 4 version = 2;
1352
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) ||
1353 26 mov_pcm_be_gt16(track->par->codec_id) ||
1354
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1355
1/2
✓ Branch 0 taken 24 times.
✗ Branch 1 not taken.
24 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1356
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 track->par->codec_id == AV_CODEC_ID_QDM2) {
1357 12 version = 1;
1358 }
1359 }
1360
1361 108 avio_wb32(pb, 0); /* size */
1362
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (mov->encryption_scheme != MOV_ENC_NONE) {
1363 ffio_wfourcc(pb, "enca");
1364 } else {
1365 108 avio_wl32(pb, tag); // store it byteswapped
1366 }
1367 108 avio_wb32(pb, 0); /* Reserved */
1368 108 avio_wb16(pb, 0); /* Reserved */
1369 108 avio_wb16(pb, 1); /* Data-reference index, XXX == 1 */
1370
1371 /* SoundDescription */
1372 108 avio_wb16(pb, version); /* Version */
1373 108 avio_wb16(pb, 0); /* Revision level */
1374 108 avio_wb32(pb, 0); /* Reserved */
1375
1376
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 104 times.
108 if (version == 2) {
1377 4 avio_wb16(pb, 3);
1378 4 avio_wb16(pb, 16);
1379 4 avio_wb16(pb, 0xfffe);
1380 4 avio_wb16(pb, 0);
1381 4 avio_wb32(pb, 0x00010000);
1382 4 avio_wb32(pb, 72);
1383 4 avio_wb64(pb, av_double2int(track->par->sample_rate));
1384 4 avio_wb32(pb, track->par->ch_layout.nb_channels);
1385 4 avio_wb32(pb, 0x7F000000);
1386 4 avio_wb32(pb, av_get_bits_per_sample(track->par->codec_id));
1387 4 avio_wb32(pb, mov_get_lpcm_flags(track->par->codec_id));
1388 4 avio_wb32(pb, track->sample_size);
1389 4 avio_wb32(pb, get_samples_per_packet(track));
1390 } else {
1391
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 68 times.
104 if (track->mode == MODE_MOV) {
1392 36 avio_wb16(pb, track->par->ch_layout.nb_channels);
1393
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 if (track->par->codec_id == AV_CODEC_ID_PCM_U8 ||
1394
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 35 times.
36 track->par->codec_id == AV_CODEC_ID_PCM_S8)
1395 1 avio_wb16(pb, 8); /* bits per sample */
1396
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 35 times.
35 else if (track->par->codec_id == AV_CODEC_ID_ADPCM_G726)
1397 avio_wb16(pb, track->par->bits_per_coded_sample);
1398 else
1399 35 avio_wb16(pb, 16);
1400
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 26 times.
36 avio_wb16(pb, track->audio_vbr ? -2 : 0); /* compression ID */
1401 } else { /* reserved for mp4/3gp */
1402
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 5 times.
131 avio_wb16(pb, track->tag == MKTAG('i', 'a', 'm', 'f') ?
1403 63 0 : track->par->ch_layout.nb_channels);
1404
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 5 times.
68 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
1405
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 63 times.
63 track->par->codec_id == AV_CODEC_ID_ALAC) {
1406 5 avio_wb16(pb, track->par->bits_per_raw_sample);
1407 } else {
1408 63 avio_wb16(pb, 16);
1409 }
1410 68 avio_wb16(pb, 0);
1411 }
1412
1413 104 avio_wb16(pb, 0); /* packet size (= 0) */
1414
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 99 times.
104 if (track->tag == MKTAG('i','a','m','f'))
1415 5 avio_wb16(pb, 0); /* samplerate must be 0 for IAMF */
1416
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1417 avio_wb16(pb, 48000);
1418
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 99 times.
99 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1419 avio_wb32(pb, track->par->sample_rate);
1420 else
1421
1/2
✓ Branch 0 taken 99 times.
✗ Branch 1 not taken.
198 avio_wb16(pb, track->par->sample_rate <= UINT16_MAX ?
1422 99 track->par->sample_rate : 0);
1423
1424
1/2
✓ Branch 0 taken 104 times.
✗ Branch 1 not taken.
104 if (track->par->codec_id != AV_CODEC_ID_TRUEHD)
1425 104 avio_wb16(pb, 0); /* Reserved */
1426 }
1427
1428
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 96 times.
108 if (version == 1) { /* SoundDescription V1 extended info */
1429
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) ||
1430 12 mov_pcm_be_gt16(track->par->codec_id))
1431 2 avio_wb32(pb, 1); /* must be 1 for uncompressed formats */
1432 else
1433 10 avio_wb32(pb, track->par->frame_size); /* Samples per packet */
1434 12 avio_wb32(pb, track->sample_size / track->par->ch_layout.nb_channels); /* Bytes per packet */
1435 12 avio_wb32(pb, track->sample_size); /* Bytes per frame */
1436 12 avio_wb32(pb, 2); /* Bytes per sample */
1437 }
1438
1439
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 68 times.
108 if (track->mode == MODE_MOV &&
1440
2/2
✓ Branch 0 taken 37 times.
✓ Branch 1 taken 3 times.
40 (track->par->codec_id == AV_CODEC_ID_AAC ||
1441
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 1 times.
37 track->par->codec_id == AV_CODEC_ID_AC3 ||
1442
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_EAC3 ||
1443
1/2
✓ Branch 0 taken 36 times.
✗ Branch 1 not taken.
36 track->par->codec_id == AV_CODEC_ID_AMR_NB ||
1444
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 9 times.
36 track->par->codec_id == AV_CODEC_ID_ALAC ||
1445
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_MS ||
1446
1/2
✓ Branch 0 taken 27 times.
✗ Branch 1 not taken.
27 track->par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
1447
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 ||
1448
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) ||
1449
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
29 (mov_pcm_be_gt16(track->par->codec_id) && version==1)))
1450 15 ret = mov_write_wave_tag(s, pb, track);
1451
2/2
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 42 times.
93 else if (track->tag == MKTAG('m','p','4','a'))
1452 51 ret = mov_write_esds_tag(pb, track);
1453 #if CONFIG_IAMFENC
1454
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 37 times.
42 else if (track->tag == MKTAG('i','a','m','f'))
1455 5 ret = mov_write_iacb_tag(mov->fc, pb, track);
1456 #endif
1457
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
37 else if (track->par->codec_id == AV_CODEC_ID_AMR_NB)
1458 ret = mov_write_amr_tag(pb, track);
1459
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 33 times.
37 else if (track->par->codec_id == AV_CODEC_ID_AC3)
1460 4 ret = mov_write_ac3_tag(s, pb, track);
1461
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 32 times.
33 else if (track->par->codec_id == AV_CODEC_ID_EAC3)
1462 1 ret = mov_write_eac3_tag(s, pb, track);
1463
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_ALAC)
1464 ret = mov_write_extradata_tag(pb, track);
1465
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_WMAPRO)
1466 ret = mov_write_wfex_tag(s, pb, track);
1467
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_FLAC)
1468 ret = mov_write_dfla_tag(pb, track);
1469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_OPUS)
1470 ret = mov_write_dops_tag(s, pb, track);
1471
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
32 else if (track->par->codec_id == AV_CODEC_ID_TRUEHD)
1472 ret = mov_write_dmlp_tag(s, pb, track);
1473
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) {
1474
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
7 if (track->par->ch_layout.nb_channels > 1)
1475 5 ret = mov_write_chnl_tag(s, pb, track);
1476
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (ret < 0)
1477 return ret;
1478 7 ret = mov_write_pcmc_tag(s, pb, track);
1479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 } else if (track->vos_len > 0)
1480 ret = mov_write_glbl_tag(pb, track);
1481
1482
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (ret < 0)
1483 return ret;
1484
1485
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
1486
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 65 times.
65 && ((ret = mov_write_SA3D_tag(s, pb, track)) < 0)) {
1487 return ret;
1488 }
1489
1490
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
1491
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 40 times.
40 && ((ret = mov_write_chan_tag(s, pb, track)) < 0)) {
1492 return ret;
1493 }
1494
1495
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 108 times.
108 if (mov->encryption_scheme != MOV_ENC_NONE
1496 && ((ret = ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid)) < 0)) {
1497 return ret;
1498 }
1499
1500
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 &&
1501 65 ((ret = mov_write_btrt_tag(pb, track)) < 0))
1502 return ret;
1503
1504 108 ret = update_size(pb, pos);
1505 108 return ret;
1506 }
1507
1508 static int mov_write_d263_tag(AVIOContext *pb)
1509 {
1510 avio_wb32(pb, 0xf); /* size */
1511 ffio_wfourcc(pb, "d263");
1512 ffio_wfourcc(pb, "FFMP");
1513 avio_w8(pb, 0); /* decoder version */
1514 /* FIXME use AVCodecContext level/profile, when encoder will set values */
1515 avio_w8(pb, 0xa); /* level */
1516 avio_w8(pb, 0); /* profile */
1517 return 0xf;
1518 }
1519
1520 1 static int mov_write_av1c_tag(AVIOContext *pb, MOVTrack *track)
1521 {
1522 1 int64_t pos = avio_tell(pb);
1523
1524 1 avio_wb32(pb, 0);
1525 1 ffio_wfourcc(pb, "av1C");
1526 1 ff_isom_write_av1c(pb, track->vos_data, track->vos_len, track->mode != MODE_AVIF);
1527 1 return update_size(pb, pos);
1528 }
1529
1530 53 static int mov_write_avcc_tag(AVIOContext *pb, MOVTrack *track)
1531 {
1532 53 int64_t pos = avio_tell(pb);
1533
1534 53 avio_wb32(pb, 0);
1535 53 ffio_wfourcc(pb, "avcC");
1536 53 ff_isom_write_avcc(pb, track->vos_data, track->vos_len);
1537 53 return update_size(pb, pos);
1538 }
1539
1540 static int mov_write_vpcc_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
1541 {
1542 int64_t pos = avio_tell(pb);
1543
1544 avio_wb32(pb, 0);
1545 ffio_wfourcc(pb, "vpcC");
1546 ff_isom_write_vpcc(s, pb, track->vos_data, track->vos_len, track->par);
1547 return update_size(pb, pos);
1548 }
1549
1550 3 static int mov_write_hvcc_tag(AVIOContext *pb, MOVTrack *track)
1551 {
1552 3 int64_t pos = avio_tell(pb);
1553
1554 3 avio_wb32(pb, 0);
1555 3 ffio_wfourcc(pb, "hvcC");
1556
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->tag == MKTAG('h','v','c','1'))
1557 1 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 1);
1558 else
1559 2 ff_isom_write_hvcc(pb, track->vos_data, track->vos_len, 0);
1560 3 return update_size(pb, pos);
1561 }
1562
1563 1 static int mov_write_lhvc_tag(AVIOContext *pb, MOVTrack *track)
1564 {
1565 1 int64_t pos = avio_tell(pb);
1566 int ret;
1567
1568 1 avio_wb32(pb, 0);
1569 1 ffio_wfourcc(pb, "lhvC");
1570
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('h','v','c','1'))
1571 1 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 1);
1572 else
1573 ret = ff_isom_write_lhvc(pb, track->vos_data, track->vos_len, 0);
1574
1575
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0) {
1576 avio_seek(pb, pos, SEEK_SET);
1577 return ret;
1578 }
1579
1580 1 return update_size(pb, pos);
1581 }
1582
1583 1 static int mov_write_evcc_tag(AVIOContext *pb, MOVTrack *track)
1584 {
1585 1 int64_t pos = avio_tell(pb);
1586
1587 1 avio_wb32(pb, 0);
1588 1 ffio_wfourcc(pb, "evcC");
1589
1590
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('e','v','c','1'))
1591 1 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 1);
1592 else
1593 ff_isom_write_evcc(pb, track->vos_data, track->vos_len, 0);
1594
1595 1 return update_size(pb, pos);
1596 }
1597
1598 1 static int mov_write_vvcc_tag(AVIOContext *pb, MOVTrack *track)
1599 {
1600 1 int64_t pos = avio_tell(pb);
1601
1602 1 avio_wb32(pb, 0);
1603 1 ffio_wfourcc(pb, "vvcC");
1604
1605 1 avio_w8 (pb, 0); /* version */
1606 1 avio_wb24(pb, 0); /* flags */
1607
1608
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->tag == MKTAG('v','v','c','1'))
1609 1 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 1);
1610 else
1611 ff_isom_write_vvcc(pb, track->vos_data, track->vos_len, 0);
1612 1 return update_size(pb, pos);
1613 }
1614
1615 /* also used by all avid codecs (dv, imx, meridien) and their variants */
1616 23 static int mov_write_avid_tag(AVIOContext *pb, MOVTrack *track)
1617 {
1618 int interlaced;
1619 int cid;
1620 23 int display_width = track->par->width;
1621
1622
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) {
1623
1/2
✓ Branch 1 taken 23 times.
✗ Branch 2 not taken.
46 if (ff_dnxhd_parse_header_prefix(track->vos_data) != 0) {
1624 /* looks like a DNxHD bit stream */
1625 23 interlaced = (track->vos_data[5] & 2);
1626 23 cid = AV_RB32(track->vos_data + 0x28);
1627 } else {
1628 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream in vos_data\n");
1629 return 0;
1630 }
1631 } else {
1632 av_log(NULL, AV_LOG_WARNING, "Could not locate DNxHD bit stream, vos_data too small\n");
1633 return 0;
1634 }
1635
1636 23 avio_wb32(pb, 24); /* size */
1637 23 ffio_wfourcc(pb, "ACLR");
1638 23 ffio_wfourcc(pb, "ACLR");
1639 23 ffio_wfourcc(pb, "0001");
1640
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
23 if (track->par->color_range == AVCOL_RANGE_MPEG || /* Legal range (16-235) */
1641 track->par->color_range == AVCOL_RANGE_UNSPECIFIED) {
1642 23 avio_wb32(pb, 1); /* Corresponds to 709 in official encoder */
1643 } else { /* Full range (0-255) */
1644 avio_wb32(pb, 2); /* Corresponds to RGB in official encoder */
1645 }
1646 23 avio_wb32(pb, 0); /* unknown */
1647
1648
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 if (track->tag == MKTAG('A','V','d','h')) {
1649 12 avio_wb32(pb, 32);
1650 12 ffio_wfourcc(pb, "ADHR");
1651 12 ffio_wfourcc(pb, "0001");
1652 12 avio_wb32(pb, cid);
1653 12 avio_wb32(pb, 0); /* unknown */
1654 12 avio_wb32(pb, 1); /* unknown */
1655 12 avio_wb32(pb, 0); /* unknown */
1656 12 avio_wb32(pb, 0); /* unknown */
1657 12 return 0;
1658 }
1659
1660 11 avio_wb32(pb, 24); /* size */
1661 11 ffio_wfourcc(pb, "APRG");
1662 11 ffio_wfourcc(pb, "APRG");
1663 11 ffio_wfourcc(pb, "0001");
1664 11 avio_wb32(pb, 1); /* unknown */
1665 11 avio_wb32(pb, 0); /* unknown */
1666
1667 11 avio_wb32(pb, 120); /* size */
1668 11 ffio_wfourcc(pb, "ARES");
1669 11 ffio_wfourcc(pb, "ARES");
1670 11 ffio_wfourcc(pb, "0001");
1671 11 avio_wb32(pb, cid); /* dnxhd cid, some id ? */
1672
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11 times.
11 if ( track->par->sample_aspect_ratio.num > 0
1673 && track->par->sample_aspect_ratio.den > 0)
1674 display_width = display_width * track->par->sample_aspect_ratio.num / track->par->sample_aspect_ratio.den;
1675 11 avio_wb32(pb, display_width);
1676 /* values below are based on samples created with quicktime and avid codecs */
1677
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (interlaced) {
1678 11 avio_wb32(pb, track->par->height / 2);
1679 11 avio_wb32(pb, 2); /* unknown */
1680 11 avio_wb32(pb, 0); /* unknown */
1681 11 avio_wb32(pb, 4); /* unknown */
1682 } else {
1683 avio_wb32(pb, track->par->height);
1684 avio_wb32(pb, 1); /* unknown */
1685 avio_wb32(pb, 0); /* unknown */
1686 if (track->par->height == 1080)
1687 avio_wb32(pb, 5); /* unknown */
1688 else
1689 avio_wb32(pb, 6); /* unknown */
1690 }
1691 /* padding */
1692 11 ffio_fill(pb, 0, 10 * 8);
1693
1694 11 return 0;
1695 }
1696
1697 static int mov_write_dpxe_tag(AVIOContext *pb, MOVTrack *track)
1698 {
1699 avio_wb32(pb, 12);
1700 ffio_wfourcc(pb, "DpxE");
1701 if (track->par->extradata_size >= 12 &&
1702 !memcmp(&track->par->extradata[4], "DpxE", 4)) {
1703 avio_wb32(pb, track->par->extradata[11]);
1704 } else {
1705 avio_wb32(pb, 1);
1706 }
1707 return 0;
1708 }
1709
1710 1 static int mov_get_dv_codec_tag(AVFormatContext *s, MOVTrack *track)
1711 {
1712 int tag;
1713
1714
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->width == 720) { /* SD */
1715
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->height == 480) { /* NTSC */
1716
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');
1717 1 else tag = MKTAG('d','v','c',' ');
1718 }else if (track->par->format == AV_PIX_FMT_YUV422P) tag = MKTAG('d','v','5','p');
1719 else if (track->par->format == AV_PIX_FMT_YUV420P) tag = MKTAG('d','v','c','p');
1720 else tag = MKTAG('d','v','p','p');
1721 } else if (track->par->height == 720) { /* HD 720 line */
1722 if (track->st->time_base.den == 50) tag = MKTAG('d','v','h','q');
1723 else tag = MKTAG('d','v','h','p');
1724 } else if (track->par->height == 1080) { /* HD 1080 line */
1725 if (track->st->time_base.den == 25) tag = MKTAG('d','v','h','5');
1726 else tag = MKTAG('d','v','h','6');
1727 } else {
1728 av_log(s, AV_LOG_ERROR, "unsupported height for dv codec\n");
1729 return 0;
1730 }
1731
1732 1 return tag;
1733 }
1734
1735 3 static int defined_frame_rate(AVFormatContext *s, AVStream *st)
1736 {
1737 3 AVRational rational_framerate = st->avg_frame_rate;
1738 3 int rate = 0;
1739
1/2
✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
3 if (rational_framerate.den != 0)
1740 3 rate = av_q2d(rational_framerate);
1741 3 return rate;
1742 }
1743
1744 1 static int mov_get_mpeg2_xdcam_codec_tag(AVFormatContext *s, MOVTrack *track)
1745 {
1746 1 int tag = track->par->codec_tag;
1747 1 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1748 1 AVStream *st = track->st;
1749 1 int rate = defined_frame_rate(s, st);
1750
1751
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!tag)
1752 tag = MKTAG('m', '2', 'v', '1'); //fallback tag
1753
1754
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (track->par->format == AV_PIX_FMT_YUV420P) {
1755
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) {
1756 if (!interlaced) {
1757 if (rate == 24) tag = MKTAG('x','d','v','4');
1758 else if (rate == 25) tag = MKTAG('x','d','v','5');
1759 else if (rate == 30) tag = MKTAG('x','d','v','1');
1760 else if (rate == 50) tag = MKTAG('x','d','v','a');
1761 else if (rate == 60) tag = MKTAG('x','d','v','9');
1762 }
1763
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) {
1764 if (!interlaced) {
1765 if (rate == 24) tag = MKTAG('x','d','v','6');
1766 else if (rate == 25) tag = MKTAG('x','d','v','7');
1767 else if (rate == 30) tag = MKTAG('x','d','v','8');
1768 } else {
1769 if (rate == 25) tag = MKTAG('x','d','v','3');
1770 else if (rate == 30) tag = MKTAG('x','d','v','2');
1771 }
1772
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) {
1773 if (!interlaced) {
1774 if (rate == 24) tag = MKTAG('x','d','v','d');
1775 else if (rate == 25) tag = MKTAG('x','d','v','e');
1776 else if (rate == 30) tag = MKTAG('x','d','v','f');
1777 } else {
1778 if (rate == 25) tag = MKTAG('x','d','v','c');
1779 else if (rate == 30) tag = MKTAG('x','d','v','b');
1780 }
1781 }
1782 } else if (track->par->format == AV_PIX_FMT_YUV422P) {
1783 if (track->par->width == 1280 && track->par->height == 720) {
1784 if (!interlaced) {
1785 if (rate == 24) tag = MKTAG('x','d','5','4');
1786 else if (rate == 25) tag = MKTAG('x','d','5','5');
1787 else if (rate == 30) tag = MKTAG('x','d','5','1');
1788 else if (rate == 50) tag = MKTAG('x','d','5','a');
1789 else if (rate == 60) tag = MKTAG('x','d','5','9');
1790 }
1791 } else if (track->par->width == 1920 && track->par->height == 1080) {
1792 if (!interlaced) {
1793 if (rate == 24) tag = MKTAG('x','d','5','d');
1794 else if (rate == 25) tag = MKTAG('x','d','5','e');
1795 else if (rate == 30) tag = MKTAG('x','d','5','f');
1796 } else {
1797 if (rate == 25) tag = MKTAG('x','d','5','c');
1798 else if (rate == 30) tag = MKTAG('x','d','5','b');
1799 }
1800 }
1801 }
1802
1803 1 return tag;
1804 }
1805
1806 2 static int mov_get_h264_codec_tag(AVFormatContext *s, MOVTrack *track)
1807 {
1808 2 int tag = track->par->codec_tag;
1809 2 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
1810 2 AVStream *st = track->st;
1811 2 int rate = defined_frame_rate(s, st);
1812
1813
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!tag)
1814 tag = MKTAG('a', 'v', 'c', 'i'); //fallback tag
1815
1816
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (track->par->format == AV_PIX_FMT_YUV420P10) {
1817 if (track->par->width == 960 && track->par->height == 720) {
1818 if (!interlaced) {
1819 if (rate == 24) tag = MKTAG('a','i','5','p');
1820 else if (rate == 25) tag = MKTAG('a','i','5','q');
1821 else if (rate == 30) tag = MKTAG('a','i','5','p');
1822 else if (rate == 50) tag = MKTAG('a','i','5','q');
1823 else if (rate == 60) tag = MKTAG('a','i','5','p');
1824 }
1825 } else if (track->par->width == 1440 && track->par->height == 1080) {
1826 if (!interlaced) {
1827 if (rate == 24) tag = MKTAG('a','i','5','3');
1828 else if (rate == 25) tag = MKTAG('a','i','5','2');
1829 else if (rate == 30) tag = MKTAG('a','i','5','3');
1830 } else {
1831 if (rate == 50) tag = MKTAG('a','i','5','5');
1832 else if (rate == 60) tag = MKTAG('a','i','5','6');
1833 }
1834 }
1835
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 } else if (track->par->format == AV_PIX_FMT_YUV422P10) {
1836 if (track->par->width == 1280 && track->par->height == 720) {
1837 if (!interlaced) {
1838 if (rate == 24) tag = MKTAG('a','i','1','p');
1839 else if (rate == 25) tag = MKTAG('a','i','1','q');
1840 else if (rate == 30) tag = MKTAG('a','i','1','p');
1841 else if (rate == 50) tag = MKTAG('a','i','1','q');
1842 else if (rate == 60) tag = MKTAG('a','i','1','p');
1843 }
1844 } else if (track->par->width == 1920 && track->par->height == 1080) {
1845 if (!interlaced) {
1846 if (rate == 24) tag = MKTAG('a','i','1','3');
1847 else if (rate == 25) tag = MKTAG('a','i','1','2');
1848 else if (rate == 30) tag = MKTAG('a','i','1','3');
1849 } else {
1850 if (rate == 25) tag = MKTAG('a','i','1','5');
1851 else if (rate == 50) tag = MKTAG('a','i','1','5');
1852 else if (rate == 60) tag = MKTAG('a','i','1','6');
1853 }
1854 } else if ( track->par->width == 4096 && track->par->height == 2160
1855 || track->par->width == 3840 && track->par->height == 2160
1856 || track->par->width == 2048 && track->par->height == 1080) {
1857 tag = MKTAG('a','i','v','x');
1858 }
1859 }
1860
1861 2 return tag;
1862 }
1863
1864 static int mov_get_evc_codec_tag(AVFormatContext *s, MOVTrack *track)
1865 {
1866 int tag = track->par->codec_tag;
1867
1868 if (!tag)
1869 tag = MKTAG('e', 'v', 'c', '1');
1870
1871 return tag;
1872 }
1873
1874 static const struct {
1875 enum AVPixelFormat pix_fmt;
1876 uint32_t tag;
1877 unsigned bps;
1878 } mov_pix_fmt_tags[] = {
1879 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','2'), 0 },
1880 { AV_PIX_FMT_YUYV422, MKTAG('y','u','v','s'), 0 },
1881 { AV_PIX_FMT_UYVY422, MKTAG('2','v','u','y'), 0 },
1882 { AV_PIX_FMT_VYU444, MKTAG('v','3','0','8'), 0 },
1883 { AV_PIX_FMT_UYVA, MKTAG('v','4','0','8'), 0 },
1884 { AV_PIX_FMT_V30XLE, MKTAG('v','4','1','0'), 0 },
1885 { AV_PIX_FMT_RGB555BE,MKTAG('r','a','w',' '), 16 },
1886 { AV_PIX_FMT_RGB555LE,MKTAG('L','5','5','5'), 16 },
1887 { AV_PIX_FMT_RGB565LE,MKTAG('L','5','6','5'), 16 },
1888 { AV_PIX_FMT_RGB565BE,MKTAG('B','5','6','5'), 16 },
1889 { AV_PIX_FMT_GRAY16BE,MKTAG('b','1','6','g'), 16 },
1890 { AV_PIX_FMT_RGB24, MKTAG('r','a','w',' '), 24 },
1891 { AV_PIX_FMT_BGR24, MKTAG('2','4','B','G'), 24 },
1892 { AV_PIX_FMT_ARGB, MKTAG('r','a','w',' '), 32 },
1893 { AV_PIX_FMT_BGRA, MKTAG('B','G','R','A'), 32 },
1894 { AV_PIX_FMT_RGBA, MKTAG('R','G','B','A'), 32 },
1895 { AV_PIX_FMT_ABGR, MKTAG('A','B','G','R'), 32 },
1896 { AV_PIX_FMT_RGB48BE, MKTAG('b','4','8','r'), 48 },
1897 };
1898
1899 23 static int mov_get_dnxhd_codec_tag(AVFormatContext *s, MOVTrack *track)
1900 {
1901 23 int tag = MKTAG('A','V','d','n');
1902
1/2
✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
23 if (track->par->profile != AV_PROFILE_UNKNOWN &&
1903
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
23 track->par->profile != AV_PROFILE_DNXHD)
1904 12 tag = MKTAG('A','V','d','h');
1905 23 return tag;
1906 }
1907
1908 17 static int mov_get_rawvideo_codec_tag(AVFormatContext *s, MOVTrack *track)
1909 {
1910 17 int tag = track->par->codec_tag;
1911 int i;
1912 enum AVPixelFormat pix_fmt;
1913
1914
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++) {
1915
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 235 times.
252 if (track->par->format == mov_pix_fmt_tags[i].pix_fmt) {
1916 17 tag = mov_pix_fmt_tags[i].tag;
1917 17 track->par->bits_per_coded_sample = mov_pix_fmt_tags[i].bps;
1918
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 12 times.
17 if (track->par->codec_tag == mov_pix_fmt_tags[i].tag)
1919 5 break;
1920 }
1921 }
1922
1923 17 pix_fmt = avpriv_pix_fmt_find(PIX_FMT_LIST_MOV,
1924 17 track->par->bits_per_coded_sample);
1925
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 if (tag == MKTAG('r','a','w',' ') &&
1926
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 track->par->format != pix_fmt &&
1927 track->par->format != AV_PIX_FMT_GRAY8 &&
1928 track->par->format != AV_PIX_FMT_NONE)
1929 av_log(s, AV_LOG_ERROR, "%s rawvideo cannot be written to mov, output file will be unreadable\n",
1930 av_get_pix_fmt_name(track->par->format));
1931 17 return tag;
1932 }
1933
1934 165 static unsigned int mov_get_codec_tag(AVFormatContext *s, MOVTrack *track)
1935 {
1936 165 unsigned int tag = track->par->codec_tag;
1937
1938 // "rtp " is used to distinguish internally created RTP-hint tracks
1939 // (with rtp_ctx) from other tracks.
1940
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 165 times.
165 if (tag == MKTAG('r','t','p',' '))
1941 tag = 0;
1942
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 &&
1943
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 1 times.
129 (track->par->codec_id == AV_CODEC_ID_DVVIDEO ||
1944
2/2
✓ Branch 0 taken 111 times.
✓ Branch 1 taken 17 times.
128 track->par->codec_id == AV_CODEC_ID_RAWVIDEO ||
1945
1/2
✓ Branch 0 taken 111 times.
✗ Branch 1 not taken.
111 track->par->codec_id == AV_CODEC_ID_H263 ||
1946
2/2
✓ Branch 0 taken 109 times.
✓ Branch 1 taken 2 times.
111 track->par->codec_id == AV_CODEC_ID_H264 ||
1947
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 23 times.
109 track->par->codec_id == AV_CODEC_ID_DNXHD ||
1948
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 ||
1949 85 av_get_bits_per_sample(track->par->codec_id)))) { // pcm audio
1950
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 if (track->par->codec_id == AV_CODEC_ID_DVVIDEO)
1951 1 tag = mov_get_dv_codec_tag(s, track);
1952
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 44 times.
61 else if (track->par->codec_id == AV_CODEC_ID_RAWVIDEO)
1953 17 tag = mov_get_rawvideo_codec_tag(s, track);
1954
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 43 times.
44 else if (track->par->codec_id == AV_CODEC_ID_MPEG2VIDEO)
1955 1 tag = mov_get_mpeg2_xdcam_codec_tag(s, track);
1956
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 41 times.
43 else if (track->par->codec_id == AV_CODEC_ID_H264)
1957 2 tag = mov_get_h264_codec_tag(s, track);
1958
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 41 times.
41 else if (track->par->codec_id == AV_CODEC_ID_EVC)
1959 tag = mov_get_evc_codec_tag(s, track);
1960
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 18 times.
41 else if (track->par->codec_id == AV_CODEC_ID_DNXHD)
1961 23 tag = mov_get_dnxhd_codec_tag(s, track);
1962
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 else if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
1963 tag = ff_codec_get_tag(ff_codec_movvideo_tags, track->par->codec_id);
1964 if (!tag) { // if no mac fcc found, try with Microsoft tags
1965 tag = ff_codec_get_tag(ff_codec_bmp_tags, track->par->codec_id);
1966 if (tag)
1967 av_log(s, AV_LOG_WARNING, "Using MS style video codec tag, "
1968 "the file may be unplayable!\n");
1969 }
1970
1/2
✓ Branch 0 taken 18 times.
✗ Branch 1 not taken.
18 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
1971 18 tag = ff_codec_get_tag(ff_codec_movaudio_tags, track->par->codec_id);
1972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18 times.
18 if (!tag) { // if no mac fcc found, try with Microsoft tags
1973 int ms_tag = ff_codec_get_tag(ff_codec_wav_tags, track->par->codec_id);
1974 if (ms_tag) {
1975 tag = MKTAG('m', 's', ((ms_tag >> 8) & 0xff), (ms_tag & 0xff));
1976 av_log(s, AV_LOG_WARNING, "Using MS style audio codec tag, "
1977 "the file may be unplayable!\n");
1978 }
1979 }
1980 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
1981 tag = ff_codec_get_tag(ff_codec_movsubtitle_tags, track->par->codec_id);
1982 }
1983
1984 165 return tag;
1985 }
1986
1987 static const AVCodecTag codec_cover_image_tags[] = {
1988 { AV_CODEC_ID_MJPEG, 0xD },
1989 { AV_CODEC_ID_PNG, 0xE },
1990 { AV_CODEC_ID_BMP, 0x1B },
1991 { AV_CODEC_ID_NONE, 0 },
1992 };
1993
1994 95 static unsigned int validate_codec_tag(const AVCodecTag *const *tags,
1995 unsigned int tag, int codec_id)
1996 {
1997 int i;
1998
1999 /**
2000 * Check that tag + id is in the table
2001 */
2002
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++) {
2003 95 const AVCodecTag *codec_tags = tags[i];
2004
1/2
✓ Branch 0 taken 1298 times.
✗ Branch 1 not taken.
1298 while (codec_tags->id != AV_CODEC_ID_NONE) {
2005
2/2
✓ Branch 2 taken 107 times.
✓ Branch 3 taken 1191 times.
1298 if (ff_toupper4(codec_tags->tag) == ff_toupper4(tag) &&
2006
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 12 times.
107 codec_tags->id == codec_id)
2007 95 return codec_tags->tag;
2008 1203 codec_tags++;
2009 }
2010 }
2011 return 0;
2012 }
2013
2014 262 static unsigned int mov_find_codec_tag(AVFormatContext *s, MOVTrack *track)
2015 {
2016
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 260 times.
262 if (is_cover_image(track->st))
2017 2 return ff_codec_get_tag(codec_cover_image_tags, track->par->codec_id);
2018
2019
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 259 times.
260 if (track->mode == MODE_IPOD)
2020
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") &&
2021
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 !av_match_ext(s->url, "m4v") &&
2022 1 !av_match_ext(s->url, "m4b"))
2023 1 av_log(s, AV_LOG_WARNING, "Warning, extension is not .m4a nor .m4v "
2024 "Quicktime/Ipod might not play the file\n");
2025
2026
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 95 times.
260 if (track->mode == MODE_MOV) {
2027 165 return mov_get_codec_tag(s, track);
2028 } else
2029 95 return validate_codec_tag(s->oformat->codec_tag, track->par->codec_tag,
2030 95 track->par->codec_id);
2031 }
2032
2033 /** Write uuid atom.
2034 * Needed to make file play in iPods running newest firmware
2035 * goes after avcC atom in moov.trak.mdia.minf.stbl.stsd.avc1
2036 */
2037 static int mov_write_uuid_tag_ipod(AVIOContext *pb)
2038 {
2039 avio_wb32(pb, 28);
2040 ffio_wfourcc(pb, "uuid");
2041 avio_wb32(pb, 0x6b6840f2);
2042 avio_wb32(pb, 0x5f244fc5);
2043 avio_wb32(pb, 0xba39a51b);
2044 avio_wb32(pb, 0xcf0323f3);
2045 avio_wb32(pb, 0x0);
2046 return 28;
2047 }
2048
2049 static const uint16_t fiel_data[] = {
2050 0x0000, 0x0100, 0x0201, 0x0206, 0x0209, 0x020e
2051 };
2052
2053 95 static int mov_write_fiel_tag(AVIOContext *pb, MOVTrack *track, int field_order)
2054 {
2055 95 unsigned mov_field_order = 0;
2056
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 if (field_order < FF_ARRAY_ELEMS(fiel_data))
2057 95 mov_field_order = fiel_data[field_order];
2058 else
2059 return 0;
2060 95 avio_wb32(pb, 10);
2061 95 ffio_wfourcc(pb, "fiel");
2062 95 avio_wb16(pb, mov_field_order);
2063 95 return 10;
2064 }
2065
2066 4 static int mov_write_subtitle_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2067 {
2068 4 MOVMuxContext *mov = s->priv_data;
2069 4 int ret = AVERROR_BUG;
2070 4 int64_t pos = avio_tell(pb);
2071 4 avio_wb32(pb, 0); /* size */
2072 4 avio_wl32(pb, track->tag); // store it byteswapped
2073 4 avio_wb32(pb, 0); /* Reserved */
2074 4 avio_wb16(pb, 0); /* Reserved */
2075 4 avio_wb16(pb, 1); /* Data-reference index */
2076
2077
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (track->par->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
2078 mov_write_esds_tag(pb, track);
2079
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2 times.
4 else if (track->par->codec_id == AV_CODEC_ID_TTML) {
2080
2/3
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
2 switch (track->par->codec_tag) {
2081 1 case MOV_ISMV_TTML_TAG:
2082 // ISMV dfxp requires no extradata.
2083 2 break;
2084 1 case MOV_MP4_TTML_TAG:
2085 // As specified in 14496-30, XMLSubtitleSampleEntry
2086 // Namespace
2087 1 avio_put_str(pb, "http://www.w3.org/ns/ttml");
2088 // Empty schema_location
2089 1 avio_w8(pb, 0);
2090 // Empty auxiliary_mime_types
2091 1 avio_w8(pb, 0);
2092 1 break;
2093 default:
2094 av_log(NULL, AV_LOG_ERROR,
2095 "Unknown codec tag '%s' utilized for TTML stream with "
2096 "index %d (track id %d)!\n",
2097 av_fourcc2str(track->par->codec_tag), track->st->index,
2098 track->track_id);
2099 return AVERROR(EINVAL);
2100 }
2101
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 } else if (track->par->extradata_size)
2102 2 avio_write(pb, track->par->extradata, track->par->extradata_size);
2103
2104
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 &&
2105 4 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2106 return ret;
2107
2108 4 return update_size(pb, pos);
2109 }
2110
2111 static int mov_write_st3d_tag(AVFormatContext *s, AVIOContext *pb, AVStereo3D *stereo_3d)
2112 {
2113 int8_t stereo_mode;
2114
2115 if (stereo_3d->flags != 0) {
2116 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d flags %x. st3d not written.\n", stereo_3d->flags);
2117 return 0;
2118 }
2119
2120 switch (stereo_3d->type) {
2121 case AV_STEREO3D_2D:
2122 stereo_mode = 0;
2123 break;
2124 case AV_STEREO3D_TOPBOTTOM:
2125 stereo_mode = 1;
2126 break;
2127 case AV_STEREO3D_SIDEBYSIDE:
2128 stereo_mode = 2;
2129 break;
2130 default:
2131 av_log(s, AV_LOG_WARNING, "Unsupported stereo_3d type %s. st3d not written.\n", av_stereo3d_type_name(stereo_3d->type));
2132 return 0;
2133 }
2134 avio_wb32(pb, 13); /* size */
2135 ffio_wfourcc(pb, "st3d");
2136 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2137 avio_w8(pb, stereo_mode);
2138 return 13;
2139 }
2140
2141 static int mov_write_sv3d_tag(AVFormatContext *s, AVIOContext *pb, AVSphericalMapping *spherical_mapping)
2142 {
2143 int64_t sv3d_pos, svhd_pos, proj_pos;
2144 const char* metadata_source = s->flags & AVFMT_FLAG_BITEXACT ? "Lavf" : LIBAVFORMAT_IDENT;
2145
2146 if (spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2147 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR_TILE &&
2148 spherical_mapping->projection != AV_SPHERICAL_CUBEMAP) {
2149 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. sv3d not written.\n", spherical_mapping->projection);
2150 return 0;
2151 }
2152
2153 sv3d_pos = avio_tell(pb);
2154 avio_wb32(pb, 0); /* size */
2155 ffio_wfourcc(pb, "sv3d");
2156
2157 svhd_pos = avio_tell(pb);
2158 avio_wb32(pb, 0); /* size */
2159 ffio_wfourcc(pb, "svhd");
2160 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2161 avio_put_str(pb, metadata_source);
2162 update_size(pb, svhd_pos);
2163
2164 proj_pos = avio_tell(pb);
2165 avio_wb32(pb, 0); /* size */
2166 ffio_wfourcc(pb, "proj");
2167
2168 avio_wb32(pb, 24); /* size */
2169 ffio_wfourcc(pb, "prhd");
2170 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2171 avio_wb32(pb, spherical_mapping->yaw);
2172 avio_wb32(pb, spherical_mapping->pitch);
2173 avio_wb32(pb, spherical_mapping->roll);
2174
2175 switch (spherical_mapping->projection) {
2176 case AV_SPHERICAL_EQUIRECTANGULAR:
2177 case AV_SPHERICAL_EQUIRECTANGULAR_TILE:
2178 avio_wb32(pb, 28); /* size */
2179 ffio_wfourcc(pb, "equi");
2180 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2181 avio_wb32(pb, spherical_mapping->bound_top);
2182 avio_wb32(pb, spherical_mapping->bound_bottom);
2183 avio_wb32(pb, spherical_mapping->bound_left);
2184 avio_wb32(pb, spherical_mapping->bound_right);
2185 break;
2186 case AV_SPHERICAL_CUBEMAP:
2187 avio_wb32(pb, 20); /* size */
2188 ffio_wfourcc(pb, "cbmp");
2189 avio_wb32(pb, 0); /* version = 0 & flags = 0 */
2190 avio_wb32(pb, 0); /* layout */
2191 avio_wb32(pb, spherical_mapping->padding); /* padding */
2192 break;
2193 }
2194 update_size(pb, proj_pos);
2195
2196 return update_size(pb, sv3d_pos);
2197 }
2198
2199 5 static inline int64_t rescale_rational(AVRational q, int b)
2200 {
2201 5 return av_rescale(q.num, b, q.den);
2202 }
2203
2204 1 static void mov_write_hfov_tag(AVFormatContext *s, AVIOContext *pb,
2205 const AVStereo3D *stereo3d)
2206 {
2207
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!stereo3d->horizontal_field_of_view.num)
2208 return;
2209
2210 1 avio_wb32(pb, 12); /* size */
2211 1 ffio_wfourcc(pb, "hfov");
2212 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_field_of_view, 1000));
2213 }
2214
2215 1 static void mov_write_vexu_proj_tag(AVFormatContext *s, AVIOContext *pb,
2216 const AVSphericalMapping *spherical_mapping)
2217 {
2218 1 avio_wb32(pb, 24); /* size */
2219 1 ffio_wfourcc(pb, "proj");
2220 1 avio_wb32(pb, 16); /* size */
2221 1 ffio_wfourcc(pb, "prji");
2222 1 avio_wb32(pb, 0); /* version + flags */
2223
2224
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) {
2225 1 case AV_SPHERICAL_RECTILINEAR:
2226 1 ffio_wfourcc(pb, "rect");
2227 1 break;
2228 case AV_SPHERICAL_EQUIRECTANGULAR:
2229 ffio_wfourcc(pb, "equi");
2230 break;
2231 case AV_SPHERICAL_HALF_EQUIRECTANGULAR:
2232 ffio_wfourcc(pb, "hequ");
2233 break;
2234 case AV_SPHERICAL_FISHEYE:
2235 ffio_wfourcc(pb, "fish");
2236 break;
2237 default:
2238 av_assert0(0);
2239 }
2240 1 }
2241
2242 1 static int mov_write_eyes_tag(AVFormatContext *s, AVIOContext *pb,
2243 const AVStereo3D *stereo3d)
2244 {
2245 1 int64_t pos = avio_tell(pb);
2246 1 int view = 0;
2247
2248 1 avio_wb32(pb, 0); /* size */
2249 1 ffio_wfourcc(pb, "eyes");
2250
2251 // stri is mandatory
2252 1 avio_wb32(pb, 13); /* size */
2253 1 ffio_wfourcc(pb, "stri");
2254 1 avio_wb32(pb, 0); /* version + flags */
2255
1/4
✗ Branch 0 not taken.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
1 switch (stereo3d->view) {
2256 case AV_STEREO3D_VIEW_LEFT:
2257 view |= 1 << 0;
2258 break;
2259 case AV_STEREO3D_VIEW_RIGHT:
2260 view |= 1 << 1;
2261 break;
2262 1 case AV_STEREO3D_VIEW_PACKED:
2263 1 view |= (1 << 0) | (1 << 1);
2264 1 break;
2265 }
2266 1 view |= !!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) << 3;
2267 1 avio_w8(pb, view);
2268
2269 // hero is optional
2270
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (stereo3d->primary_eye != AV_PRIMARY_EYE_NONE) {
2271 avio_wb32(pb, 13); /* size */
2272 ffio_wfourcc(pb, "hero");
2273 avio_wb32(pb, 0); /* version + flags */
2274 avio_w8(pb, stereo3d->primary_eye);
2275 }
2276
2277 // it's not clear if cams is mandatory or optional
2278
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->baseline) {
2279 1 avio_wb32(pb, 24); /* size */
2280 1 ffio_wfourcc(pb, "cams");
2281 1 avio_wb32(pb, 16); /* size */
2282 1 ffio_wfourcc(pb, "blin");
2283 1 avio_wb32(pb, 0); /* version + flags */
2284 1 avio_wb32(pb, stereo3d->baseline);
2285 }
2286
2287 // it's not clear if cmfy is mandatory or optional
2288
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d->horizontal_disparity_adjustment.num) {
2289 1 avio_wb32(pb, 24); /* size */
2290 1 ffio_wfourcc(pb, "cmfy");
2291 1 avio_wb32(pb, 16); /* size */
2292 1 ffio_wfourcc(pb, "dadj");
2293 1 avio_wb32(pb, 0); /* version + flags */
2294 1 avio_wb32(pb, rescale_rational(stereo3d->horizontal_disparity_adjustment, 10000));
2295 }
2296
2297 1 return update_size(pb, pos);
2298 }
2299
2300 1 static int mov_write_vexu_tag(AVFormatContext *s, AVIOContext *pb,
2301 const AVStereo3D *stereo3d,
2302 const AVSphericalMapping *spherical_mapping)
2303 {
2304 int64_t pos;
2305
2306
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping &&
2307
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 spherical_mapping->projection != AV_SPHERICAL_RECTILINEAR &&
2308 spherical_mapping->projection != AV_SPHERICAL_EQUIRECTANGULAR &&
2309 spherical_mapping->projection != AV_SPHERICAL_HALF_EQUIRECTANGULAR &&
2310 spherical_mapping->projection != AV_SPHERICAL_FISHEYE) {
2311 av_log(s, AV_LOG_WARNING, "Unsupported projection %d. proj not written.\n",
2312 spherical_mapping->projection);
2313 spherical_mapping = NULL;
2314 }
2315
2316
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 ||
2317
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 (!(stereo3d->flags & AV_STEREO3D_FLAG_INVERT) &&
2318
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 stereo3d->view == AV_STEREO3D_VIEW_UNSPEC &&
2319 stereo3d->primary_eye == AV_PRIMARY_EYE_NONE &&
2320 !stereo3d->baseline &&
2321 !stereo3d->horizontal_disparity_adjustment.num))) {
2322 av_log(s, AV_LOG_WARNING, "Unsupported stereo 3d metadata. eyes not written.\n");
2323 stereo3d = NULL;
2324 }
2325
2326
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
1 if (!spherical_mapping && !stereo3d)
2327 return 0;
2328
2329 1 pos = avio_tell(pb);
2330 1 avio_wb32(pb, 0); /* size */
2331 1 ffio_wfourcc(pb, "vexu");
2332
2333
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (spherical_mapping)
2334 1 mov_write_vexu_proj_tag(s, pb, spherical_mapping);
2335
2336
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (stereo3d)
2337 1 mov_write_eyes_tag(s, pb, stereo3d);
2338
2339 1 return update_size(pb, pos);
2340 }
2341
2342 static int mov_write_dvcc_dvvc_tag(AVFormatContext *s, AVIOContext *pb, AVDOVIDecoderConfigurationRecord *dovi)
2343 {
2344 uint8_t buf[ISOM_DVCC_DVVC_SIZE];
2345
2346 avio_wb32(pb, 32); /* size = 8 + 24 */
2347 if (dovi->dv_profile > 10)
2348 ffio_wfourcc(pb, "dvwC");
2349 else if (dovi->dv_profile > 7)
2350 ffio_wfourcc(pb, "dvvC");
2351 else
2352 ffio_wfourcc(pb, "dvcC");
2353
2354 ff_isom_put_dvcc_dvvc(s, buf, dovi);
2355 avio_write(pb, buf, sizeof(buf));
2356
2357 return 32; /* 8 + 24 */
2358 }
2359
2360 5 static int mov_write_clap_tag(AVIOContext *pb, MOVTrack *track,
2361 uint32_t top, uint32_t bottom,
2362 uint32_t left, uint32_t right)
2363 {
2364 5 uint32_t cropped_width = track->par->width - left - right;
2365 5 uint32_t cropped_height = track->height - top - bottom;
2366 AVRational horizOff =
2367 5 av_sub_q((AVRational) { track->par->width - cropped_width, 2 },
2368 5 (AVRational) { left, 1 });
2369 AVRational vertOff =
2370 5 av_sub_q((AVRational) { track->height - cropped_height, 2 },
2371 5 (AVRational) { top, 1 });
2372
2373 5 avio_wb32(pb, 40);
2374 5 ffio_wfourcc(pb, "clap");
2375 5 avio_wb32(pb, cropped_width); /* apertureWidthN */
2376 5 avio_wb32(pb, 1); /* apertureWidthD */
2377 5 avio_wb32(pb, cropped_height); /* apertureHeightN */
2378 5 avio_wb32(pb, 1); /* apertureHeightD */
2379
2380 5 avio_wb32(pb, -horizOff.num);
2381 5 avio_wb32(pb, horizOff.den);
2382 5 avio_wb32(pb, -vertOff.num);
2383 5 avio_wb32(pb, vertOff.den);
2384
2385 5 return 40;
2386 }
2387
2388 6 static int mov_write_pasp_tag(AVIOContext *pb, MOVTrack *track)
2389 {
2390 AVRational sar;
2391 6 av_reduce(&sar.num, &sar.den, track->par->sample_aspect_ratio.num,
2392 6 track->par->sample_aspect_ratio.den, INT_MAX);
2393
2394 6 avio_wb32(pb, 16);
2395 6 ffio_wfourcc(pb, "pasp");
2396 6 avio_wb32(pb, sar.num);
2397 6 avio_wb32(pb, sar.den);
2398 6 return 16;
2399 }
2400
2401 static int mov_write_gama_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track, double gamma)
2402 {
2403 uint32_t gama = 0;
2404 if (gamma <= 0.0)
2405 gamma = av_csp_approximate_trc_gamma(track->par->color_trc);
2406 av_log(s, AV_LOG_DEBUG, "gamma value %g\n", gamma);
2407
2408 if (gamma > 1e-6) {
2409 gama = (uint32_t)lrint((double)(1<<16) * gamma);
2410 av_log(s, AV_LOG_DEBUG, "writing gama value %"PRId32"\n", gama);
2411
2412 av_assert0(track->mode == MODE_MOV);
2413 avio_wb32(pb, 12);
2414 ffio_wfourcc(pb, "gama");
2415 avio_wb32(pb, gama);
2416 return 12;
2417 } else {
2418 av_log(s, AV_LOG_WARNING, "gamma value unknown, unable to write gama atom\n");
2419 }
2420 return 0;
2421 }
2422
2423 9 static int mov_write_colr_tag(AVIOContext *pb, MOVTrack *track, int prefer_icc)
2424 {
2425 9 int64_t pos = avio_tell(pb);
2426
2427 // Ref (MOV): https://developer.apple.com/library/mac/technotes/tn2162/_index.html#//apple_ref/doc/uid/DTS40013070-CH1-TNTAG9
2428 // Ref (MP4): ISO/IEC 14496-12:2012
2429
2430
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 5 times.
9 if (prefer_icc) {
2431 4 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2432 4 track->st->codecpar->nb_coded_side_data,
2433 AV_PKT_DATA_ICC_PROFILE);
2434
2435
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (sd) {
2436 avio_wb32(pb, 12 + sd->size);
2437 ffio_wfourcc(pb, "colr");
2438 ffio_wfourcc(pb, "prof");
2439 avio_write(pb, sd->data, sd->size);
2440 return 12 + sd->size;
2441 }
2442 else {
2443 4 av_log(NULL, AV_LOG_INFO, "no ICC profile found, will write nclx/nclc colour info instead\n");
2444 }
2445 }
2446
2447 /* We should only ever be called for MOV, MP4 and AVIF. */
2448
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 ||
2449 track->mode == MODE_AVIF);
2450
2451 9 avio_wb32(pb, 0); /* size */
2452 9 ffio_wfourcc(pb, "colr");
2453
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)
2454 1 ffio_wfourcc(pb, "nclx");
2455 else
2456 8 ffio_wfourcc(pb, "nclc");
2457 // Do not try to guess the color info if it is AVCOL_PRI_UNSPECIFIED.
2458 // e.g., Dolby Vision for Apple devices should be set to AVCOL_PRI_UNSPECIFIED. See
2459 // https://developer.apple.com/av-foundation/High-Dynamic-Range-Metadata-for-Apple-Devices.pdf
2460 9 avio_wb16(pb, track->par->color_primaries);
2461 9 avio_wb16(pb, track->par->color_trc);
2462 9 avio_wb16(pb, track->par->color_space);
2463
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) {
2464 1 int full_range = track->par->color_range == AVCOL_RANGE_JPEG;
2465 1 avio_w8(pb, full_range << 7);
2466 }
2467
2468 9 return update_size(pb, pos);
2469 }
2470
2471 200 static int mov_write_clli_tag(AVIOContext *pb, MOVTrack *track)
2472 {
2473 const AVPacketSideData *side_data;
2474 const AVContentLightMetadata *content_light_metadata;
2475
2476 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2477 200 track->st->codecpar->nb_coded_side_data,
2478 AV_PKT_DATA_CONTENT_LIGHT_LEVEL);
2479
1/2
✓ Branch 0 taken 200 times.
✗ Branch 1 not taken.
200 if (!side_data) {
2480 200 return 0;
2481 }
2482 content_light_metadata = (const AVContentLightMetadata*)side_data->data;
2483
2484 avio_wb32(pb, 12); // size
2485 ffio_wfourcc(pb, "clli");
2486 avio_wb16(pb, content_light_metadata->MaxCLL);
2487 avio_wb16(pb, content_light_metadata->MaxFALL);
2488 return 12;
2489 }
2490
2491 200 static int mov_write_mdcv_tag(AVIOContext *pb, MOVTrack *track)
2492 {
2493 200 const int chroma_den = 50000;
2494 200 const int luma_den = 10000;
2495 const AVPacketSideData *side_data;
2496 200 const AVMasteringDisplayMetadata *metadata = NULL;
2497
2498 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2499 200 track->st->codecpar->nb_coded_side_data,
2500 AV_PKT_DATA_MASTERING_DISPLAY_METADATA);
2501
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 200 times.
200 if (side_data)
2502 metadata = (const AVMasteringDisplayMetadata*)side_data->data;
2503
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) {
2504 200 return 0;
2505 }
2506
2507 avio_wb32(pb, 32); // size
2508 ffio_wfourcc(pb, "mdcv");
2509 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][0], chroma_den));
2510 avio_wb16(pb, rescale_rational(metadata->display_primaries[1][1], chroma_den));
2511 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][0], chroma_den));
2512 avio_wb16(pb, rescale_rational(metadata->display_primaries[2][1], chroma_den));
2513 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][0], chroma_den));
2514 avio_wb16(pb, rescale_rational(metadata->display_primaries[0][1], chroma_den));
2515 avio_wb16(pb, rescale_rational(metadata->white_point[0], chroma_den));
2516 avio_wb16(pb, rescale_rational(metadata->white_point[1], chroma_den));
2517 avio_wb32(pb, rescale_rational(metadata->max_luminance, luma_den));
2518 avio_wb32(pb, rescale_rational(metadata->min_luminance, luma_den));
2519 return 32;
2520 }
2521
2522 200 static int mov_write_amve_tag(AVIOContext *pb, MOVTrack *track)
2523 {
2524 200 const int illuminance_den = 10000;
2525 200 const int ambient_den = 50000;
2526 const AVPacketSideData *side_data;
2527 const AVAmbientViewingEnvironment *ambient;
2528
2529
2530 200 side_data = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2531 200 track->st->codecpar->nb_coded_side_data,
2532 AV_PKT_DATA_AMBIENT_VIEWING_ENVIRONMENT);
2533
2534
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 1 times.
200 if (!side_data)
2535 199 return 0;
2536
2537 1 ambient = (const AVAmbientViewingEnvironment*)side_data->data;
2538
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)
2539 return 0;
2540
2541 1 avio_wb32(pb, 16); // size
2542 1 ffio_wfourcc(pb, "amve");
2543 1 avio_wb32(pb, rescale_rational(ambient->ambient_illuminance, illuminance_den));
2544 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_x, ambient_den));
2545 1 avio_wb16(pb, rescale_rational(ambient->ambient_light_y, ambient_den));
2546 1 return 16;
2547 }
2548
2549 205 static void find_compressor(char * compressor_name, int len, MOVTrack *track)
2550 {
2551 AVDictionaryEntry *encoder;
2552
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 int xdcam_res = (track->par->width == 1280 && track->par->height == 720)
2553
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)
2554
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);
2555
2556
1/2
✓ Branch 0 taken 205 times.
✗ Branch 1 not taken.
205 if ((track->mode == MODE_AVIF ||
2557
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 138 times.
205 track->mode == MODE_MOV ||
2558
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) &&
2559 200 (encoder = av_dict_get(track->st->metadata, "encoder", NULL, 0))) {
2560 145 av_strlcpy(compressor_name, encoder->value, 32);
2561
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) {
2562 int interlaced = track->par->field_order > AV_FIELD_PROGRESSIVE;
2563 AVStream *st = track->st;
2564 int rate = defined_frame_rate(NULL, st);
2565 av_strlcatf(compressor_name, len, "XDCAM");
2566 if (track->par->format == AV_PIX_FMT_YUV422P) {
2567 av_strlcatf(compressor_name, len, " HD422");
2568 } else if(track->par->width == 1440) {
2569 av_strlcatf(compressor_name, len, " HD");
2570 } else
2571 av_strlcatf(compressor_name, len, " EX");
2572
2573 av_strlcatf(compressor_name, len, " %d%c", track->par->height, interlaced ? 'i' : 'p');
2574
2575 av_strlcatf(compressor_name, len, "%d", rate * (interlaced + 1));
2576 }
2577 205 }
2578
2579 static int mov_write_ccst_tag(AVIOContext *pb)
2580 {
2581 int64_t pos = avio_tell(pb);
2582 // Write sane defaults:
2583 // all_ref_pics_intra = 0 : all samples can use any type of reference.
2584 // intra_pred_used = 1 : intra prediction may or may not be used.
2585 // max_ref_per_pic = 15 : reserved value to indicate that any number of
2586 // reference images can be used.
2587 uint8_t ccstValue = (0 << 7) | /* all_ref_pics_intra */
2588 (1 << 6) | /* intra_pred_used */
2589 (15 << 2); /* max_ref_per_pic */
2590 avio_wb32(pb, 0); /* size */
2591 ffio_wfourcc(pb, "ccst");
2592 avio_wb32(pb, 0); /* Version & flags */
2593 avio_w8(pb, ccstValue);
2594 avio_wb24(pb, 0); /* reserved */
2595 return update_size(pb, pos);
2596 }
2597
2598 static int mov_write_aux_tag(AVIOContext *pb, const char *aux_type)
2599 {
2600 int64_t pos = avio_tell(pb);
2601 avio_wb32(pb, 0); /* size */
2602 ffio_wfourcc(pb, aux_type);
2603 avio_wb32(pb, 0); /* Version & flags */
2604 avio_write(pb, "urn:mpeg:mpegB:cicp:systems:auxiliary:alpha\0", 44);
2605 return update_size(pb, pos);
2606 }
2607
2608 205 static int mov_write_video_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2609 {
2610 205 int ret = AVERROR_BUG;
2611 205 int64_t pos = avio_tell(pb);
2612 const AVPacketSideData *sd;
2613 205 char compressor_name[32] = { 0 };
2614 205 int avid = 0;
2615
2616
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)
2617
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)
2618
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)
2619
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)
2620
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)
2621 #if FF_API_V408_CODECID
2622
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V308
2623
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V408
2624
1/2
✓ Branch 0 taken 201 times.
✗ Branch 1 not taken.
201 || track->par->codec_id == AV_CODEC_ID_V410
2625 #endif
2626
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);
2627
2628 205 avio_wb32(pb, 0); /* size */
2629
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->encryption_scheme != MOV_ENC_NONE) {
2630 ffio_wfourcc(pb, "encv");
2631 } else {
2632 205 avio_wl32(pb, track->tag); // store it byteswapped
2633 }
2634 205 avio_wb32(pb, 0); /* Reserved */
2635 205 avio_wb16(pb, 0); /* Reserved */
2636 205 avio_wb16(pb, 1); /* Data-reference index */
2637
2638
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 201 times.
205 if (uncompressed_ycbcr) {
2639 4 avio_wb16(pb, 2); /* Codec stream version */
2640 } else {
2641 201 avio_wb16(pb, 0); /* Codec stream version */
2642 }
2643 205 avio_wb16(pb, 0); /* Codec stream revision (=0) */
2644
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
205 if (track->mode == MODE_MOV) {
2645 138 ffio_wfourcc(pb, "FFMP"); /* Vendor */
2646
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) {
2647 17 avio_wb32(pb, 0); /* Temporal Quality */
2648 17 avio_wb32(pb, 0x400); /* Spatial Quality = lossless*/
2649 } else {
2650 121 avio_wb32(pb, 0x200); /* Temporal Quality = normal */
2651 121 avio_wb32(pb, 0x200); /* Spatial Quality = normal */
2652 }
2653 } else {
2654 67 ffio_fill(pb, 0, 3 * 4); /* Reserved */
2655 }
2656 205 avio_wb16(pb, track->par->width); /* Video width */
2657 205 avio_wb16(pb, track->height); /* Video height */
2658 205 avio_wb32(pb, 0x00480000); /* Horizontal resolution 72dpi */
2659 205 avio_wb32(pb, 0x00480000); /* Vertical resolution 72dpi */
2660 205 avio_wb32(pb, 0); /* Data size (= 0) */
2661 205 avio_wb16(pb, 1); /* Frame count (= 1) */
2662
2663 205 find_compressor(compressor_name, 32, track);
2664 205 avio_w8(pb, strlen(compressor_name));
2665 205 avio_write(pb, compressor_name, 31);
2666
2667
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 67 times.
205 if (track->mode == MODE_MOV &&
2668
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))
2669 avio_wb16(pb, 0x18);
2670
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)
2671 31 avio_wb16(pb, track->par->bits_per_coded_sample |
2672
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 28 times.
31 (track->par->format == AV_PIX_FMT_GRAY8 ? 0x20 : 0));
2673 else
2674 174 avio_wb16(pb, 0x18); /* Reserved */
2675
2676
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) {
2677 int pal_size, i;
2678 5 avio_wb16(pb, 0); /* Color table ID */
2679 5 avio_wb32(pb, 0); /* Color table seed */
2680 5 avio_wb16(pb, 0x8000); /* Color table flags */
2681
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)
2682 return AVERROR(EINVAL);
2683 5 pal_size = 1 << track->par->bits_per_coded_sample;
2684 5 avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */
2685
2/2
✓ Branch 0 taken 1040 times.
✓ Branch 1 taken 5 times.
1045 for (i = 0; i < pal_size; i++) {
2686 1040 uint32_t rgb = track->palette[i];
2687 1040 uint16_t r = (rgb >> 16) & 0xff;
2688 1040 uint16_t g = (rgb >> 8) & 0xff;
2689 1040 uint16_t b = rgb & 0xff;
2690 1040 avio_wb16(pb, 0);
2691 1040 avio_wb16(pb, (r << 8) | r);
2692 1040 avio_wb16(pb, (g << 8) | g);
2693 1040 avio_wb16(pb, (b << 8) | b);
2694 }
2695 } else
2696 200 avio_wb16(pb, 0xffff); /* Reserved */
2697
2698
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 180 times.
205 if (track->tag == MKTAG('m','p','4','v'))
2699 25 mov_write_esds_tag(pb, track);
2700
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 else if (track->par->codec_id == AV_CODEC_ID_H263)
2701 mov_write_d263_tag(pb);
2702
2/2
✓ Branch 0 taken 177 times.
✓ Branch 1 taken 3 times.
180 else if (track->par->codec_id == AV_CODEC_ID_AVUI ||
2703
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 177 times.
177 track->par->codec_id == AV_CODEC_ID_SVQ3) {
2704 3 mov_write_extradata_tag(pb, track);
2705 3 avio_wb32(pb, 0);
2706
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 154 times.
177 } else if (track->par->codec_id == AV_CODEC_ID_DNXHD) {
2707 23 mov_write_avid_tag(pb, track);
2708 23 avid = 1;
2709
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 151 times.
154 } else if (track->par->codec_id == AV_CODEC_ID_HEVC) {
2710 3 mov_write_hvcc_tag(pb, track);
2711
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 if (track->st->disposition & AV_DISPOSITION_MULTILAYER) {
2712 1 ret = mov_write_lhvc_tag(pb, track);
2713
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
2714 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'lhvC' atom for multilayer stream.\n");
2715 }
2716
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 150 times.
151 } else if (track->par->codec_id == AV_CODEC_ID_VVC)
2717 1 mov_write_vvcc_tag(pb, track);
2718
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)) {
2719 53 mov_write_avcc_tag(pb, track);
2720
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 53 times.
53 if (track->mode == MODE_IPOD)
2721 mov_write_uuid_tag_ipod(pb);
2722 }
2723
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 96 times.
97 else if (track->par->codec_id ==AV_CODEC_ID_EVC) {
2724 1 mov_write_evcc_tag(pb, track);
2725
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 96 times.
96 } else if (track->par->codec_id == AV_CODEC_ID_VP9) {
2726 mov_write_vpcc_tag(mov->fc, pb, track);
2727
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 95 times.
96 } else if (track->par->codec_id == AV_CODEC_ID_AV1) {
2728 1 mov_write_av1c_tag(pb, track);
2729
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)
2730 mov_write_dvc1_tag(pb, track);
2731
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 else if (track->par->codec_id == AV_CODEC_ID_VP6F ||
2732
1/2
✓ Branch 0 taken 95 times.
✗ Branch 1 not taken.
95 track->par->codec_id == AV_CODEC_ID_VP6A) {
2733 /* Don't write any potential extradata here - the cropping
2734 * is signalled via the normal width/height fields. */
2735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 95 times.
95 } else if (track->par->codec_id == AV_CODEC_ID_R10K) {
2736 if (track->par->codec_tag == MKTAG('R','1','0','k'))
2737 mov_write_dpxe_tag(pb, track);
2738
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 91 times.
95 } else if (track->vos_len > 0)
2739 4 mov_write_glbl_tag(pb, track);
2740
2741
2/2
✓ Branch 0 taken 152 times.
✓ Branch 1 taken 53 times.
205 if (track->par->codec_id != AV_CODEC_ID_H264 &&
2742
2/2
✓ Branch 0 taken 127 times.
✓ Branch 1 taken 25 times.
152 track->par->codec_id != AV_CODEC_ID_MPEG4 &&
2743
2/2
✓ Branch 0 taken 104 times.
✓ Branch 1 taken 23 times.
127 track->par->codec_id != AV_CODEC_ID_DNXHD) {
2744 104 int field_order = track->par->field_order;
2745
2746
2/2
✓ Branch 0 taken 95 times.
✓ Branch 1 taken 9 times.
104 if (field_order != AV_FIELD_UNKNOWN)
2747 95 mov_write_fiel_tag(pb, track, field_order);
2748 }
2749
2750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->flags & FF_MOV_FLAG_WRITE_GAMA) {
2751 if (track->mode == MODE_MOV)
2752 mov_write_gama_tag(s, pb, track, mov->gamma);
2753 else
2754 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'gama' atom. Format is not MOV.\n");
2755 }
2756
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) {
2757 405 int has_color_info = track->par->color_primaries != AVCOL_PRI_UNSPECIFIED &&
2758
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 &&
2759
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 track->par->color_space != AVCOL_SPC_UNSPECIFIED;
2760
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 ||
2761 191 av_packet_side_data_get(track->st->codecpar->coded_side_data, track->st->codecpar->nb_coded_side_data,
2762 AV_PKT_DATA_ICC_PROFILE)) {
2763
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;
2764 9 mov_write_colr_tag(pb, track, prefer_icc);
2765 }
2766
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 } else if (mov->flags & FF_MOV_FLAG_WRITE_COLR) {
2767 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'colr' atom. Format is not MOV or MP4 or AVIF.\n");
2768 }
2769
2770
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) {
2771 200 mov_write_clli_tag(pb, track);
2772 200 mov_write_mdcv_tag(pb, track);
2773 200 mov_write_amve_tag(pb, track);
2774 }
2775
2776
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) {
2777 const AVPacketSideData *stereo_3d = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2778 track->st->codecpar->nb_coded_side_data,
2779 AV_PKT_DATA_STEREO3D);
2780 const AVPacketSideData *spherical_mapping = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2781 track->st->codecpar->nb_coded_side_data,
2782 AV_PKT_DATA_SPHERICAL);
2783 if (stereo_3d)
2784 mov_write_st3d_tag(s, pb, (AVStereo3D*)stereo_3d->data);
2785 if (spherical_mapping)
2786 mov_write_sv3d_tag(mov->fc, pb, (AVSphericalMapping*)spherical_mapping->data);
2787 }
2788
2789
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 &&
2790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 mov->fc->strict_std_compliance <= FF_COMPLIANCE_UNOFFICIAL)) {
2791 138 const AVStereo3D *stereo3d = NULL;
2792 138 const AVSphericalMapping *spherical_mapping = NULL;
2793
2794 138 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2795 138 track->st->codecpar->nb_coded_side_data,
2796 AV_PKT_DATA_STEREO3D);
2797
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (sd)
2798 1 stereo3d = (AVStereo3D *)sd->data;
2799
2800 138 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2801 138 track->st->codecpar->nb_coded_side_data,
2802 AV_PKT_DATA_SPHERICAL);
2803
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (sd)
2804 1 spherical_mapping = (AVSphericalMapping *)sd->data;
2805
2806
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)
2807 1 mov_write_vexu_tag(s, pb, stereo3d, spherical_mapping);
2808
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 137 times.
138 if (stereo3d)
2809 1 mov_write_hfov_tag(s, pb, stereo3d);
2810 }
2811
2812
2/2
✓ Branch 0 taken 62 times.
✓ Branch 1 taken 143 times.
205 if (track->mode == MODE_MP4) {
2813 62 const AVPacketSideData *dovi = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2814 62 track->st->codecpar->nb_coded_side_data,
2815 AV_PKT_DATA_DOVI_CONF);
2816
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) {
2817 mov_write_dvcc_dvvc_tag(s, pb, (AVDOVIDecoderConfigurationRecord *)dovi->data);
2818
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 62 times.
62 } else if (dovi) {
2819 av_log(mov->fc, AV_LOG_WARNING, "Not writing 'dvcC'/'dvvC' box. Requires -strict unofficial.\n");
2820 }
2821 }
2822
2823
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) {
2824 6 mov_write_pasp_tag(pb, track);
2825 }
2826
2827 205 sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
2828 205 track->st->codecpar->nb_coded_side_data,
2829 AV_PKT_DATA_FRAME_CROPPING);
2830
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) {
2831 1 uint64_t top = AV_RL32(sd->data + 0);
2832 1 uint64_t bottom = AV_RL32(sd->data + 4);
2833 1 uint64_t left = AV_RL32(sd->data + 8);
2834 1 uint64_t right = AV_RL32(sd->data + 12);
2835
2836
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if ((left + right) >= track->par->width ||
2837
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 (top + bottom) >= track->height) {
2838 av_log(s, AV_LOG_ERROR, "Invalid cropping dimensions in stream side data\n");
2839 return AVERROR(EINVAL);
2840 }
2841
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)
2842 1 mov_write_clap_tag(pb, track, top, bottom, left, right);
2843
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 200 times.
204 } else if (uncompressed_ycbcr)
2844 4 mov_write_clap_tag(pb, track, 0, 0, 0, 0);
2845
2846
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (mov->encryption_scheme != MOV_ENC_NONE) {
2847 ff_mov_cenc_write_sinf_tag(track, pb, mov->encryption_kid);
2848 }
2849
2850
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 &&
2851 62 ((ret = mov_write_btrt_tag(pb, track)) < 0))
2852 return ret;
2853
2854 /* extra padding for avid stsd */
2855 /* https://developer.apple.com/library/mac/documentation/QuickTime/QTFF/QTFFChap2/qtff2.html#//apple_ref/doc/uid/TP40000939-CH204-61112 */
2856
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 182 times.
205 if (avid)
2857 23 avio_wb32(pb, 0);
2858
2859
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (track->mode == MODE_AVIF) {
2860 mov_write_ccst_tag(pb);
2861 if (mov->nb_streams > 0 && track == &mov->tracks[1])
2862 mov_write_aux_tag(pb, "auxi");
2863 }
2864
2865 205 return update_size(pb, pos);
2866 }
2867
2868 2 static int mov_write_rtp_tag(AVIOContext *pb, MOVTrack *track)
2869 {
2870 2 int64_t pos = avio_tell(pb);
2871 2 avio_wb32(pb, 0); /* size */
2872 2 ffio_wfourcc(pb, "rtp ");
2873 2 avio_wb32(pb, 0); /* Reserved */
2874 2 avio_wb16(pb, 0); /* Reserved */
2875 2 avio_wb16(pb, 1); /* Data-reference index */
2876
2877 2 avio_wb16(pb, 1); /* Hint track version */
2878 2 avio_wb16(pb, 1); /* Highest compatible version */
2879 2 avio_wb32(pb, track->max_packet_size); /* Max packet size */
2880
2881 2 avio_wb32(pb, 12); /* size */
2882 2 ffio_wfourcc(pb, "tims");
2883 2 avio_wb32(pb, track->timescale);
2884
2885 2 return update_size(pb, pos);
2886 }
2887
2888 2 static int mov_write_source_reference_tag(AVIOContext *pb, MOVTrack *track, const char *reel_name)
2889 {
2890 2 uint64_t str_size =strlen(reel_name);
2891 2 int64_t pos = avio_tell(pb);
2892
2893
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (str_size >= UINT16_MAX){
2894 av_log(NULL, AV_LOG_ERROR, "reel_name length %"PRIu64" is too large\n", str_size);
2895 avio_wb16(pb, 0);
2896 return AVERROR(EINVAL);
2897 }
2898
2899 2 avio_wb32(pb, 0); /* size */
2900 2 ffio_wfourcc(pb, "name"); /* Data format */
2901 2 avio_wb16(pb, str_size); /* string size */
2902 2 avio_wb16(pb, track->language); /* langcode */
2903 2 avio_write(pb, reel_name, str_size); /* reel name */
2904 2 return update_size(pb,pos);
2905 }
2906
2907 13 static int mov_write_tmcd_tag(AVIOContext *pb, MOVTrack *track)
2908 {
2909 13 int64_t pos = avio_tell(pb);
2910 #if 1
2911 int frame_duration;
2912 int nb_frames;
2913 13 AVDictionaryEntry *t = NULL;
2914
2915
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) {
2916 av_log(NULL, AV_LOG_ERROR, "avg_frame_rate not set for tmcd track.\n");
2917 return AVERROR(EINVAL);
2918 } else {
2919 13 frame_duration = av_rescale(track->timescale, track->st->avg_frame_rate.den, track->st->avg_frame_rate.num);
2920
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);
2921 }
2922
2923
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (nb_frames > 255) {
2924 av_log(NULL, AV_LOG_ERROR, "fps %d is too large\n", nb_frames);
2925 return AVERROR(EINVAL);
2926 }
2927
2928 13 avio_wb32(pb, 0); /* size */
2929 13 ffio_wfourcc(pb, "tmcd"); /* Data format */
2930 13 avio_wb32(pb, 0); /* Reserved */
2931 13 avio_wb32(pb, 1); /* Data reference index */
2932 13 avio_wb32(pb, 0); /* Flags */
2933 13 avio_wb32(pb, track->timecode_flags); /* Flags (timecode) */
2934 13 avio_wb32(pb, track->timescale); /* Timescale */
2935 13 avio_wb32(pb, frame_duration); /* Frame duration */
2936 13 avio_w8(pb, nb_frames); /* Number of frames */
2937 13 avio_w8(pb, 0); /* Reserved */
2938
2939 13 t = av_dict_get(track->st->metadata, "reel_name", NULL, 0);
2940
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)
2941 2 mov_write_source_reference_tag(pb, track, t->value);
2942 else
2943 11 avio_wb16(pb, 0); /* zero size */
2944 #else
2945
2946 avio_wb32(pb, 0); /* size */
2947 ffio_wfourcc(pb, "tmcd"); /* Data format */
2948 avio_wb32(pb, 0); /* Reserved */
2949 avio_wb32(pb, 1); /* Data reference index */
2950 if (track->par->extradata_size)
2951 avio_write(pb, track->par->extradata, track->par->extradata_size);
2952 #endif
2953 13 return update_size(pb, pos);
2954 }
2955
2956 1 static int mov_write_gpmd_tag(AVIOContext *pb, const MOVTrack *track)
2957 {
2958 1 int64_t pos = avio_tell(pb);
2959 1 avio_wb32(pb, 0); /* size */
2960 1 ffio_wfourcc(pb, "gpmd");
2961 1 avio_wb32(pb, 0); /* Reserved */
2962 1 avio_wb16(pb, 0); /* Reserved */
2963 1 avio_wb16(pb, 1); /* Data-reference index */
2964 1 avio_wb32(pb, 0); /* Reserved */
2965 1 return update_size(pb, pos);
2966 }
2967
2968 333 static int mov_write_stsd_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
2969 {
2970 333 int64_t pos = avio_tell(pb);
2971 333 int ret = 0;
2972 333 avio_wb32(pb, 0); /* size */
2973 333 ffio_wfourcc(pb, "stsd");
2974 333 avio_wb32(pb, 0); /* version & flags */
2975 333 avio_wb32(pb, 1); /* entry count */
2976
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
2977 205 ret = mov_write_video_tag(s, pb, mov, track);
2978
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
2979 108 ret = mov_write_audio_tag(s, pb, mov, track);
2980
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)
2981 4 ret = mov_write_subtitle_tag(s, pb, track);
2982
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 else if (track->par->codec_tag == MKTAG('r','t','p',' '))
2983 2 ret = mov_write_rtp_tag(pb, track);
2984
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 else if (track->par->codec_tag == MKTAG('t','m','c','d'))
2985 13 ret = mov_write_tmcd_tag(pb, track);
2986
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (track->par->codec_tag == MKTAG('g','p','m','d'))
2987 1 ret = mov_write_gpmd_tag(pb, track);
2988
2989
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (ret < 0)
2990 return ret;
2991
2992 333 return update_size(pb, pos);
2993 }
2994
2995 9 static int mov_write_ctts_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
2996 {
2997 9 MOVMuxContext *mov = s->priv_data;
2998 MOVCtts *ctts_entries;
2999 9 uint32_t entries = 0;
3000 uint32_t atom_size;
3001 int i;
3002
3003 9 ctts_entries = av_malloc_array((track->entry + 1), sizeof(*ctts_entries)); /* worst case */
3004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (!ctts_entries)
3005 return AVERROR(ENOMEM);
3006 9 ctts_entries[0].count = 1;
3007 9 ctts_entries[0].duration = track->cluster[0].cts;
3008
2/2
✓ Branch 0 taken 551 times.
✓ Branch 1 taken 9 times.
560 for (i = 1; i < track->entry; i++) {
3009
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 421 times.
551 if (track->cluster[i].cts == ctts_entries[entries].duration) {
3010 130 ctts_entries[entries].count++; /* compress */
3011 } else {
3012 421 entries++;
3013 421 ctts_entries[entries].duration = track->cluster[i].cts;
3014 421 ctts_entries[entries].count = 1;
3015 }
3016 }
3017 9 entries++; /* last one */
3018 9 atom_size = 16 + (entries * 8);
3019 9 avio_wb32(pb, atom_size); /* size */
3020 9 ffio_wfourcc(pb, "ctts");
3021
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
3022 avio_w8(pb, 1); /* version */
3023 else
3024 9 avio_w8(pb, 0); /* version */
3025 9 avio_wb24(pb, 0); /* flags */
3026 9 avio_wb32(pb, entries); /* entry count */
3027
2/2
✓ Branch 0 taken 430 times.
✓ Branch 1 taken 9 times.
439 for (i = 0; i < entries; i++) {
3028 430 avio_wb32(pb, ctts_entries[i].count);
3029 430 avio_wb32(pb, ctts_entries[i].duration);
3030 }
3031 9 av_free(ctts_entries);
3032 9 return atom_size;
3033 }
3034
3035 /* Time to sample atom */
3036 333 static int mov_write_stts_tag(AVIOContext *pb, MOVTrack *track)
3037 {
3038 333 MOVStts *stts_entries = NULL;
3039 333 uint32_t entries = -1;
3040 uint32_t atom_size;
3041 int i;
3042
3043
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) {
3044 33 stts_entries = av_malloc(sizeof(*stts_entries)); /* one entry */
3045
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (!stts_entries)
3046 return AVERROR(ENOMEM);
3047 33 stts_entries[0].count = track->sample_count;
3048 33 stts_entries[0].duration = 1;
3049 33 entries = 1;
3050 } else {
3051
2/2
✓ Branch 0 taken 210 times.
✓ Branch 1 taken 90 times.
300 if (track->entry) {
3052 210 stts_entries = av_malloc_array(track->entry, sizeof(*stts_entries)); /* worst case */
3053
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 210 times.
210 if (!stts_entries)
3054 return AVERROR(ENOMEM);
3055 }
3056
2/2
✓ Branch 0 taken 12206 times.
✓ Branch 1 taken 300 times.
12506 for (i = 0; i < track->entry; i++) {
3057 12206 int duration = get_cluster_duration(track, i);
3058
4/4
✓ Branch 0 taken 11996 times.
✓ Branch 1 taken 210 times.
✓ Branch 2 taken 11591 times.
✓ Branch 3 taken 405 times.
12206 if (i && duration == stts_entries[entries].duration) {
3059 11591 stts_entries[entries].count++; /* compress */
3060 } else {
3061 615 entries++;
3062 615 stts_entries[entries].duration = duration;
3063 615 stts_entries[entries].count = 1;
3064 }
3065 }
3066 300 entries++; /* last one */
3067 }
3068 333 atom_size = 16 + (entries * 8);
3069 333 avio_wb32(pb, atom_size); /* size */
3070 333 ffio_wfourcc(pb, "stts");
3071 333 avio_wb32(pb, 0); /* version & flags */
3072 333 avio_wb32(pb, entries); /* entry count */
3073
2/2
✓ Branch 0 taken 648 times.
✓ Branch 1 taken 333 times.
981 for (i = 0; i < entries; i++) {
3074 648 avio_wb32(pb, stts_entries[i].count);
3075 648 avio_wb32(pb, stts_entries[i].duration);
3076 }
3077 333 av_free(stts_entries);
3078 333 return atom_size;
3079 }
3080
3081 333 static int mov_write_dref_tag(AVIOContext *pb)
3082 {
3083 333 avio_wb32(pb, 28); /* size */
3084 333 ffio_wfourcc(pb, "dref");
3085 333 avio_wb32(pb, 0); /* version & flags */
3086 333 avio_wb32(pb, 1); /* entry count */
3087
3088 333 avio_wb32(pb, 0xc); /* size */
3089 //FIXME add the alis and rsrc atom
3090 333 ffio_wfourcc(pb, "url ");
3091 333 avio_wb32(pb, 1); /* version & flags */
3092
3093 333 return 28;
3094 }
3095
3096 53 static int mov_preroll_write_stbl_atoms(AVIOContext *pb, MOVTrack *track)
3097 {
3098 struct sgpd_entry {
3099 int count;
3100 int16_t roll_distance;
3101 int group_description_index;
3102 };
3103
3104 53 struct sgpd_entry *sgpd_entries = NULL;
3105 53 int entries = -1;
3106 53 int group = 0;
3107 int i, j;
3108
3109 53 const int OPUS_SEEK_PREROLL_MS = 80;
3110 53 int roll_samples = av_rescale_q(OPUS_SEEK_PREROLL_MS,
3111 53 (AVRational){1, 1000},
3112 53 (AVRational){1, 48000});
3113
3114
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 12 times.
53 if (!track->entry)
3115 41 return 0;
3116
3117 12 sgpd_entries = av_malloc_array(track->entry, sizeof(*sgpd_entries));
3118
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!sgpd_entries)
3119 return AVERROR(ENOMEM);
3120
3121
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);
3122
3123
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (track->par->codec_id == AV_CODEC_ID_OPUS) {
3124 for (i = 0; i < track->entry; i++) {
3125 int roll_samples_remaining = roll_samples;
3126 int distance = 0;
3127 for (j = i - 1; j >= 0; j--) {
3128 roll_samples_remaining -= get_cluster_duration(track, j);
3129 distance++;
3130 if (roll_samples_remaining <= 0)
3131 break;
3132 }
3133 /* We don't have enough preceeding samples to compute a valid
3134 roll_distance here, so this sample can't be independently
3135 decoded. */
3136 if (roll_samples_remaining > 0)
3137 distance = 0;
3138 /* Verify distance is a maximum of 32 (2.5ms) packets. */
3139 if (distance > 32)
3140 return AVERROR_INVALIDDATA;
3141 if (i && distance == sgpd_entries[entries].roll_distance) {
3142 sgpd_entries[entries].count++;
3143 } else {
3144 entries++;
3145 sgpd_entries[entries].count = 1;
3146 sgpd_entries[entries].roll_distance = distance;
3147 sgpd_entries[entries].group_description_index = distance ? ++group : 0;
3148 }
3149 }
3150 } else {
3151 12 entries++;
3152 12 sgpd_entries[entries].count = track->sample_count;
3153 12 sgpd_entries[entries].roll_distance = 1;
3154 12 sgpd_entries[entries].group_description_index = ++group;
3155 }
3156 12 entries++;
3157
3158
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
12 if (!group) {
3159 av_free(sgpd_entries);
3160 return 0;
3161 }
3162
3163 /* Write sgpd tag */
3164 12 avio_wb32(pb, 24 + (group * 2)); /* size */
3165 12 ffio_wfourcc(pb, "sgpd");
3166 12 avio_wb32(pb, 1 << 24); /* fullbox */
3167 12 ffio_wfourcc(pb, "roll");
3168 12 avio_wb32(pb, 2); /* default_length */
3169 12 avio_wb32(pb, group); /* entry_count */
3170
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3171
1/2
✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
12 if (sgpd_entries[i].group_description_index) {
3172 12 avio_wb16(pb, -sgpd_entries[i].roll_distance); /* roll_distance */
3173 }
3174 }
3175
3176 /* Write sbgp tag */
3177 12 avio_wb32(pb, 20 + (entries * 8)); /* size */
3178 12 ffio_wfourcc(pb, "sbgp");
3179 12 avio_wb32(pb, 0); /* fullbox */
3180 12 ffio_wfourcc(pb, "roll");
3181 12 avio_wb32(pb, entries); /* entry_count */
3182
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 12 times.
24 for (i = 0; i < entries; i++) {
3183 12 avio_wb32(pb, sgpd_entries[i].count); /* sample_count */
3184 12 avio_wb32(pb, sgpd_entries[i].group_description_index); /* group_description_index */
3185 }
3186
3187 12 av_free(sgpd_entries);
3188 12 return 0;
3189 }
3190
3191 333 static int mov_write_stbl_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3192 {
3193 333 int64_t pos = avio_tell(pb);
3194 333 int ret = 0;
3195
3196 333 avio_wb32(pb, 0); /* size */
3197 333 ffio_wfourcc(pb, "stbl");
3198
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_stsd_tag(s, pb, mov, track)) < 0)
3199 return ret;
3200 333 mov_write_stts_tag(pb, track);
3201
2/2
✓ Branch 0 taken 128 times.
✓ Branch 1 taken 205 times.
333 if ((track->par->codec_type == AVMEDIA_TYPE_VIDEO ||
3202
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
3203
1/2
✓ Branch 0 taken 128 times.
✗ Branch 1 not taken.
128 track->par->codec_id == AV_CODEC_ID_MPEGH_3D_AUDIO ||
3204
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 126 times.
128 track->par->codec_tag == MKTAG('r','t','p',' ')) &&
3205
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)
3206 58 mov_write_stss_tag(pb, track, MOV_SYNC_SAMPLE);
3207
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)
3208 3 mov_write_sdtp_tag(pb, track);
3209
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)
3210 mov_write_stss_tag(pb, track, MOV_PARTIAL_SYNC_SAMPLE);
3211
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO &&
3212
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) {
3213
3214
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
9 if ((ret = mov_write_ctts_tag(s, pb, track)) < 0)
3215 return ret;
3216 }
3217 333 mov_write_stsc_tag(pb, track);
3218 333 mov_write_stsz_tag(pb, track);
3219 333 mov_write_stco_tag(pb, track);
3220
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (track->cenc.aes_ctr) {
3221 ff_mov_cenc_write_stbl_atoms(&track->cenc, pb);
3222 }
3223
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) {
3224 53 mov_preroll_write_stbl_atoms(pb, track);
3225 }
3226 333 return update_size(pb, pos);
3227 }
3228
3229 333 static int mov_write_dinf_tag(AVIOContext *pb)
3230 {
3231 333 int64_t pos = avio_tell(pb);
3232 333 avio_wb32(pb, 0); /* size */
3233 333 ffio_wfourcc(pb, "dinf");
3234 333 mov_write_dref_tag(pb);
3235 333 return update_size(pb, pos);
3236 }
3237
3238 6 static int mov_write_nmhd_tag(AVIOContext *pb)
3239 {
3240 6 avio_wb32(pb, 12);
3241 6 ffio_wfourcc(pb, "nmhd");
3242 6 avio_wb32(pb, 0);
3243 6 return 12;
3244 }
3245
3246 1 static int mov_write_sthd_tag(AVIOContext *pb)
3247 {
3248 1 avio_wb32(pb, 12);
3249 1 ffio_wfourcc(pb, "sthd");
3250 1 avio_wb32(pb, 0);
3251 1 return 12;
3252 }
3253
3254 9 static int mov_write_tcmi_tag(AVIOContext *pb, MOVTrack *track)
3255 {
3256 9 int64_t pos = avio_tell(pb);
3257 9 const char *font = "Lucida Grande";
3258 9 avio_wb32(pb, 0); /* size */
3259 9 ffio_wfourcc(pb, "tcmi"); /* timecode media information atom */
3260 9 avio_wb32(pb, 0); /* version & flags */
3261 9 avio_wb16(pb, 0); /* text font */
3262 9 avio_wb16(pb, 0); /* text face */
3263 9 avio_wb16(pb, 12); /* text size */
3264 9 avio_wb16(pb, 0); /* (unknown, not in the QT specs...) */
3265 9 avio_wb16(pb, 0x0000); /* text color (red) */
3266 9 avio_wb16(pb, 0x0000); /* text color (green) */
3267 9 avio_wb16(pb, 0x0000); /* text color (blue) */
3268 9 avio_wb16(pb, 0xffff); /* background color (red) */
3269 9 avio_wb16(pb, 0xffff); /* background color (green) */
3270 9 avio_wb16(pb, 0xffff); /* background color (blue) */
3271 9 avio_w8(pb, strlen(font)); /* font len (part of the pascal string) */
3272 9 avio_write(pb, font, strlen(font)); /* font name */
3273 9 return update_size(pb, pos);
3274 }
3275
3276 11 static int mov_write_gmhd_tag(AVIOContext *pb, MOVTrack *track)
3277 {
3278 11 int64_t pos = avio_tell(pb);
3279 11 avio_wb32(pb, 0); /* size */
3280 11 ffio_wfourcc(pb, "gmhd");
3281 11 avio_wb32(pb, 0x18); /* gmin size */
3282 11 ffio_wfourcc(pb, "gmin");/* generic media info */
3283 11 avio_wb32(pb, 0); /* version & flags */
3284 11 avio_wb16(pb, 0x40); /* graphics mode = */
3285 11 avio_wb16(pb, 0x8000); /* opColor (r?) */
3286 11 avio_wb16(pb, 0x8000); /* opColor (g?) */
3287 11 avio_wb16(pb, 0x8000); /* opColor (b?) */
3288 11 avio_wb16(pb, 0); /* balance */
3289 11 avio_wb16(pb, 0); /* reserved */
3290
3291 /*
3292 * This special text atom is required for
3293 * Apple Quicktime chapters. The contents
3294 * don't appear to be documented, so the
3295 * bytes are copied verbatim.
3296 */
3297
1/2
✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
11 if (track->tag != MKTAG('c','6','0','8')) {
3298 11 avio_wb32(pb, 0x2C); /* size */
3299 11 ffio_wfourcc(pb, "text");
3300 11 avio_wb16(pb, 0x01);
3301 11 avio_wb32(pb, 0x00);
3302 11 avio_wb32(pb, 0x00);
3303 11 avio_wb32(pb, 0x00);
3304 11 avio_wb32(pb, 0x01);
3305 11 avio_wb32(pb, 0x00);
3306 11 avio_wb32(pb, 0x00);
3307 11 avio_wb32(pb, 0x00);
3308 11 avio_wb32(pb, 0x00004000);
3309 11 avio_wb16(pb, 0x0000);
3310 }
3311
3312
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 2 times.
11 if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3313 9 int64_t tmcd_pos = avio_tell(pb);
3314 9 avio_wb32(pb, 0); /* size */
3315 9 ffio_wfourcc(pb, "tmcd");
3316 9 mov_write_tcmi_tag(pb, track);
3317 9 update_size(pb, tmcd_pos);
3318
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3319 1 int64_t gpmd_pos = avio_tell(pb);
3320 1 avio_wb32(pb, 0); /* size */
3321 1 ffio_wfourcc(pb, "gpmd");
3322 1 avio_wb32(pb, 0); /* version */
3323 1 update_size(pb, gpmd_pos);
3324 }
3325 11 return update_size(pb, pos);
3326 }
3327
3328 108 static int mov_write_smhd_tag(AVIOContext *pb)
3329 {
3330 108 avio_wb32(pb, 16); /* size */
3331 108 ffio_wfourcc(pb, "smhd");
3332 108 avio_wb32(pb, 0); /* version & flags */
3333 108 avio_wb16(pb, 0); /* reserved (balance, normally = 0) */
3334 108 avio_wb16(pb, 0); /* reserved */
3335 108 return 16;
3336 }
3337
3338 205 static int mov_write_vmhd_tag(AVIOContext *pb)
3339 {
3340 205 avio_wb32(pb, 0x14); /* size (always 0x14) */
3341 205 ffio_wfourcc(pb, "vmhd");
3342 205 avio_wb32(pb, 0x01); /* version & flags */
3343 205 avio_wb64(pb, 0); /* reserved (graphics mode = copy) */
3344 205 return 0x14;
3345 }
3346
3347 218 static int is_clcp_track(MOVTrack *track)
3348 {
3349
1/2
✓ Branch 0 taken 218 times.
✗ Branch 1 not taken.
436 return track->tag == MKTAG('c','7','0','8') ||
3350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 218 times.
218 track->tag == MKTAG('c','6','0','8');
3351 }
3352
3353 520 static int mov_write_hdlr_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track)
3354 {
3355 520 MOVMuxContext *mov = s->priv_data;
3356 520 const char *hdlr, *descr = NULL, *hdlr_type = NULL;
3357 520 int64_t pos = avio_tell(pb);
3358 size_t descr_len;
3359
3360 520 hdlr = "dhlr";
3361 520 hdlr_type = "url ";
3362 520 descr = "DataHandler";
3363
3364
2/2
✓ Branch 0 taken 333 times.
✓ Branch 1 taken 187 times.
520 if (track) {
3365
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 hdlr = (track->mode == MODE_MOV) ? "mhlr" : "\0\0\0\0";
3366
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
3367
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 if (track->mode == MODE_AVIF) {
3368 hdlr_type = (track == &mov->tracks[0]) ? "pict" : "auxv";
3369 descr = "PictureHandler";
3370 } else {
3371 205 hdlr_type = "vide";
3372 205 descr = "VideoHandler";
3373 }
3374
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
3375 108 hdlr_type = "soun";
3376 108 descr = "SoundHandler";
3377
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 } else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3378
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if (is_clcp_track(track)) {
3379 hdlr_type = "clcp";
3380 descr = "ClosedCaptionHandler";
3381 } else {
3382
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (track->tag == MKTAG('t','x','3','g')) {
3383 1 hdlr_type = "sbtl";
3384
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 } else if (track->tag == MKTAG('m','p','4','s')) {
3385 hdlr_type = "subp";
3386
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3387 1 hdlr_type = "subt";
3388 } else {
3389 2 hdlr_type = "text";
3390 }
3391 4 descr = "SubtitleHandler";
3392 }
3393
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->par->codec_tag == MKTAG('r','t','p',' ')) {
3394 2 hdlr_type = "hint";
3395 2 descr = "HintHandler";
3396
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->par->codec_tag == MKTAG('t','m','c','d')) {
3397 13 hdlr_type = "tmcd";
3398 13 descr = "TimeCodeHandler";
3399
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->par->codec_tag == MKTAG('g','p','m','d')) {
3400 1 hdlr_type = "meta";
3401 1 descr = "GoPro MET"; // GoPro Metadata
3402 } else {
3403 av_log(s, AV_LOG_WARNING,
3404 "Unknown hdlr_type for %s, writing dummy values\n",
3405 av_fourcc2str(track->par->codec_tag));
3406 }
3407
2/2
✓ Branch 0 taken 330 times.
✓ Branch 1 taken 3 times.
333 if (track->st) {
3408 // hdlr.name is used by some players to identify the content title
3409 // of the track. So if an alternate handler description is
3410 // specified, use it.
3411 AVDictionaryEntry *t;
3412 330 t = av_dict_get(track->st->metadata, "handler_name", NULL, 0);
3413
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))
3414 21 descr = t->value;
3415 }
3416 }
3417
3418
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 */
3419 descr = "";
3420
3421 520 avio_wb32(pb, 0); /* size */
3422 520 ffio_wfourcc(pb, "hdlr");
3423 520 avio_wb32(pb, 0); /* Version & flags */
3424 520 avio_write(pb, hdlr, 4); /* handler */
3425 520 ffio_wfourcc(pb, hdlr_type); /* handler type */
3426 520 avio_wb32(pb, 0); /* reserved */
3427 520 avio_wb32(pb, 0); /* reserved */
3428 520 avio_wb32(pb, 0); /* reserved */
3429 520 descr_len = strlen(descr);
3430
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)
3431 374 avio_w8(pb, descr_len); /* pascal string */
3432 520 avio_write(pb, descr, descr_len); /* handler description */
3433
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)
3434 146 avio_w8(pb, 0); /* c string */
3435 520 return update_size(pb, pos);
3436 }
3437
3438 static int mov_write_pitm_tag(AVIOContext *pb, int item_id)
3439 {
3440 int64_t pos = avio_tell(pb);
3441 avio_wb32(pb, 0); /* size */
3442 ffio_wfourcc(pb, "pitm");
3443 avio_wb32(pb, 0); /* Version & flags */
3444 avio_wb16(pb, item_id); /* item_id */
3445 return update_size(pb, pos);
3446 }
3447
3448 static int mov_write_iloc_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3449 {
3450 int64_t pos = avio_tell(pb);
3451 avio_wb32(pb, 0); /* size */
3452 ffio_wfourcc(pb, "iloc");
3453 avio_wb32(pb, 0); /* Version & flags */
3454 avio_w8(pb, (4 << 4) + 4); /* offset_size(4) and length_size(4) */
3455 avio_w8(pb, 0); /* base_offset_size(4) and reserved(4) */
3456 avio_wb16(pb, mov->nb_streams); /* item_count */
3457
3458 for (int i = 0; i < mov->nb_streams; i++) {
3459 avio_wb16(pb, i + 1); /* item_id */
3460 avio_wb16(pb, 0); /* data_reference_index */
3461 avio_wb16(pb, 1); /* extent_count */
3462 mov->avif_extent_pos[i] = avio_tell(pb);
3463 avio_wb32(pb, 0); /* extent_offset (written later) */
3464 // For animated AVIF, we simply write the first packet's size.
3465 avio_wb32(pb, mov->avif_extent_length[i]); /* extent_length */
3466 }
3467
3468 return update_size(pb, pos);
3469 }
3470
3471 static int mov_write_iinf_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3472 {
3473 int64_t iinf_pos = avio_tell(pb);
3474 avio_wb32(pb, 0); /* size */
3475 ffio_wfourcc(pb, "iinf");
3476 avio_wb32(pb, 0); /* Version & flags */
3477 avio_wb16(pb, mov->nb_streams); /* entry_count */
3478
3479 for (int i = 0; i < mov->nb_streams; i++) {
3480 int64_t infe_pos = avio_tell(pb);
3481 avio_wb32(pb, 0); /* size */
3482 ffio_wfourcc(pb, "infe");
3483 avio_w8(pb, 0x2); /* Version */
3484 avio_wb24(pb, 0); /* flags */
3485 avio_wb16(pb, i + 1); /* item_id */
3486 avio_wb16(pb, 0); /* item_protection_index */
3487 avio_write(pb, "av01", 4); /* item_type */
3488 avio_write(pb, !i ? "Color\0" : "Alpha\0", 6); /* item_name */
3489 update_size(pb, infe_pos);
3490 }
3491
3492 return update_size(pb, iinf_pos);
3493 }
3494
3495
3496 static int mov_write_iref_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3497 {
3498 int64_t auxl_pos;
3499 int64_t iref_pos = avio_tell(pb);
3500 avio_wb32(pb, 0); /* size */
3501 ffio_wfourcc(pb, "iref");
3502 avio_wb32(pb, 0); /* Version & flags */
3503
3504 auxl_pos = avio_tell(pb);
3505 avio_wb32(pb, 0); /* size */
3506 ffio_wfourcc(pb, "auxl");
3507 avio_wb16(pb, 2); /* from_item_ID */
3508 avio_wb16(pb, 1); /* reference_count */
3509 avio_wb16(pb, 1); /* to_item_ID */
3510 update_size(pb, auxl_pos);
3511
3512 return update_size(pb, iref_pos);
3513 }
3514
3515 static int mov_write_ispe_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3516 int stream_index)
3517 {
3518 int64_t pos = avio_tell(pb);
3519 avio_wb32(pb, 0); /* size */
3520 ffio_wfourcc(pb, "ispe");
3521 avio_wb32(pb, 0); /* Version & flags */
3522 avio_wb32(pb, s->streams[stream_index]->codecpar->width); /* image_width */
3523 avio_wb32(pb, s->streams[stream_index]->codecpar->height); /* image_height */
3524 return update_size(pb, pos);
3525 }
3526
3527 static int mov_write_pixi_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s,
3528 int stream_index)
3529 {
3530 int64_t pos = avio_tell(pb);
3531 const AVPixFmtDescriptor *pixdesc =
3532 av_pix_fmt_desc_get(s->streams[stream_index]->codecpar->format);
3533 avio_wb32(pb, 0); /* size */
3534 ffio_wfourcc(pb, "pixi");
3535 avio_wb32(pb, 0); /* Version & flags */
3536 avio_w8(pb, pixdesc->nb_components); /* num_channels */
3537 for (int i = 0; i < pixdesc->nb_components; ++i) {
3538 avio_w8(pb, pixdesc->comp[i].depth); /* bits_per_channel */
3539 }
3540 return update_size(pb, pos);
3541 }
3542
3543 static int mov_write_ipco_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3544 {
3545 int64_t pos = avio_tell(pb);
3546 avio_wb32(pb, 0); /* size */
3547 ffio_wfourcc(pb, "ipco");
3548 for (int i = 0; i < mov->nb_streams; i++) {
3549 mov_write_ispe_tag(pb, mov, s, i);
3550 mov_write_pixi_tag(pb, mov, s, i);
3551 mov_write_av1c_tag(pb, &mov->tracks[i]);
3552 if (!i)
3553 mov_write_colr_tag(pb, &mov->tracks[0], 0);
3554 else
3555 mov_write_aux_tag(pb, "auxC");
3556 }
3557 return update_size(pb, pos);
3558 }
3559
3560 static int mov_write_ipma_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3561 {
3562 int64_t pos = avio_tell(pb);
3563 avio_wb32(pb, 0); /* size */
3564 ffio_wfourcc(pb, "ipma");
3565 avio_wb32(pb, 0); /* Version & flags */
3566 avio_wb32(pb, mov->nb_streams); /* entry_count */
3567
3568 for (int i = 0, index = 1; i < mov->nb_streams; i++) {
3569 avio_wb16(pb, i + 1); /* item_ID */
3570 avio_w8(pb, 4); /* association_count */
3571
3572 // ispe association.
3573 avio_w8(pb, index++); /* essential and property_index */
3574 // pixi association.
3575 avio_w8(pb, index++); /* essential and property_index */
3576 // av1C association.
3577 avio_w8(pb, 0x80 | index++); /* essential and property_index */
3578 // colr/auxC association.
3579 avio_w8(pb, index++); /* essential and property_index */
3580 }
3581 return update_size(pb, pos);
3582 }
3583
3584 static int mov_write_iprp_tag(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
3585 {
3586 int64_t pos = avio_tell(pb);
3587 avio_wb32(pb, 0); /* size */
3588 ffio_wfourcc(pb, "iprp");
3589 mov_write_ipco_tag(pb, mov, s);
3590 mov_write_ipma_tag(pb, mov, s);
3591 return update_size(pb, pos);
3592 }
3593
3594 2 static int mov_write_hmhd_tag(AVIOContext *pb)
3595 {
3596 /* This atom must be present, but leaving the values at zero
3597 * seems harmless. */
3598 2 avio_wb32(pb, 28); /* size */
3599 2 ffio_wfourcc(pb, "hmhd");
3600 2 avio_wb32(pb, 0); /* version, flags */
3601 2 avio_wb16(pb, 0); /* maxPDUsize */
3602 2 avio_wb16(pb, 0); /* avgPDUsize */
3603 2 avio_wb32(pb, 0); /* maxbitrate */
3604 2 avio_wb32(pb, 0); /* avgbitrate */
3605 2 avio_wb32(pb, 0); /* reserved */
3606 2 return 28;
3607 }
3608
3609 333 static int mov_write_minf_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov, MOVTrack *track)
3610 {
3611 333 int64_t pos = avio_tell(pb);
3612 int ret;
3613
3614 333 avio_wb32(pb, 0); /* size */
3615 333 ffio_wfourcc(pb, "minf");
3616
2/2
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 128 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO)
3617 205 mov_write_vmhd_tag(pb);
3618
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 20 times.
128 else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3619 108 mov_write_smhd_tag(pb);
3620
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 16 times.
20 else if (track->par->codec_type == AVMEDIA_TYPE_SUBTITLE) {
3621
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)) {
3622 1 mov_write_gmhd_tag(pb, track);
3623
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 2 times.
3 } else if (track->tag == MOV_MP4_TTML_TAG) {
3624 1 mov_write_sthd_tag(pb);
3625 } else {
3626 2 mov_write_nmhd_tag(pb);
3627 }
3628
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 14 times.
16 } else if (track->tag == MKTAG('r','t','p',' ')) {
3629 2 mov_write_hmhd_tag(pb);
3630
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
14 } else if (track->tag == MKTAG('t','m','c','d')) {
3631
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 9 times.
13 if (track->mode != MODE_MOV)
3632 4 mov_write_nmhd_tag(pb);
3633 else
3634 9 mov_write_gmhd_tag(pb, track);
3635
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 } else if (track->tag == MKTAG('g','p','m','d')) {
3636 1 mov_write_gmhd_tag(pb, track);
3637 }
3638
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 */
3639 187 mov_write_hdlr_tag(s, pb, NULL);
3640 333 mov_write_dinf_tag(pb);
3641
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_stbl_tag(s, pb, mov, track)) < 0)
3642 return ret;
3643 333 return update_size(pb, pos);
3644 }
3645
3646 1294 static void get_pts_range(MOVMuxContext *mov, MOVTrack *track,
3647 int64_t *start, int64_t *end)
3648 {
3649
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) {
3650 // tmcd tracks gets track_duration set in mov_write_moov_tag from
3651 // another track's duration, while the end_pts may be left at zero.
3652 // Calculate the pts duration for that track instead.
3653 38 get_pts_range(mov, &mov->tracks[track->src_track], start, end);
3654 38 *start = av_rescale(*start, track->timescale,
3655 38 mov->tracks[track->src_track].timescale);
3656 38 *end = av_rescale(*end, track->timescale,
3657 38 mov->tracks[track->src_track].timescale);
3658 38 return;
3659 }
3660
2/2
✓ Branch 0 taken 1198 times.
✓ Branch 1 taken 58 times.
1256 if (track->end_pts != AV_NOPTS_VALUE &&
3661
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 track->start_dts != AV_NOPTS_VALUE &&
3662
1/2
✓ Branch 0 taken 1198 times.
✗ Branch 1 not taken.
1198 track->start_cts != AV_NOPTS_VALUE) {
3663 1198 *start = track->start_dts + track->start_cts;
3664 1198 *end = track->end_pts;
3665 1198 return;
3666 }
3667 58 *start = 0;
3668 58 *end = track->track_duration;
3669 }
3670
3671 616 static int64_t calc_samples_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3672 {
3673 int64_t start, end;
3674 616 get_pts_range(mov, track, &start, &end);
3675 616 return end - start;
3676 }
3677
3678 // Calculate the actual duration of the track, after edits.
3679 // If it starts with a pts < 0, that is removed by the edit list.
3680 // If it starts with a pts > 0, the edit list adds a delay before that.
3681 // Thus, with edit lists enabled, the post-edit output of the file is
3682 // starting with pts=0.
3683 640 static int64_t calc_pts_duration(MOVMuxContext *mov, MOVTrack *track)
3684 {
3685 int64_t start, end;
3686 640 get_pts_range(mov, track, &start, &end);
3687
2/2
✓ Branch 0 taken 572 times.
✓ Branch 1 taken 68 times.
640 if (mov->use_editlist != 0)
3688 572 start = 0;
3689 640 return end - start;
3690 }
3691
3692 903 static int mov_mdhd_mvhd_tkhd_version(MOVMuxContext *mov, MOVTrack *track, int64_t duration)
3693 {
3694
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)
3695 14 return 1;
3696
2/2
✓ Branch 0 taken 885 times.
✓ Branch 1 taken 4 times.
889 if (duration < INT32_MAX)
3697 885 return 0;
3698 4 return 1;
3699 }
3700
3701 333 static int mov_write_mdhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3702 MOVTrack *track)
3703 {
3704 333 int64_t duration = calc_samples_pts_duration(mov, track);
3705 333 int version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3706
3707
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
333 (version == 1) ? avio_wb32(pb, 44) : avio_wb32(pb, 32); /* size */
3708 333 ffio_wfourcc(pb, "mdhd");
3709 333 avio_w8(pb, version);
3710 333 avio_wb24(pb, 0); /* flags */
3711
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 322 times.
333 if (version == 1) {
3712 11 avio_wb64(pb, track->time);
3713 11 avio_wb64(pb, track->time);
3714 } else {
3715 322 avio_wb32(pb, track->time); /* creation time */
3716 322 avio_wb32(pb, track->time); /* modification time */
3717 }
3718 333 avio_wb32(pb, track->timescale); /* time scale (sample rate for audio) */
3719
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)
3720
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3721
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 243 times.
326 else if (!track->entry)
3722
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 79 times.
83 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3723 else
3724
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration); /* duration */
3725 333 avio_wb16(pb, track->language); /* language */
3726 333 avio_wb16(pb, 0); /* reserved (quality) */
3727
3728
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) {
3729 av_log(NULL, AV_LOG_ERROR,
3730 "FATAL error, file duration too long for timebase, this file will not be\n"
3731 "playable with QuickTime. Choose a different timebase with "
3732 "-video_track_timescale or a different container format\n");
3733 }
3734
3735 333 return 32;
3736 }
3737
3738 333 static int mov_write_mdia_tag(AVFormatContext *s, AVIOContext *pb,
3739 MOVMuxContext *mov, MOVTrack *track)
3740 {
3741 333 int64_t pos = avio_tell(pb);
3742 int ret;
3743
3744 333 avio_wb32(pb, 0); /* size */
3745 333 ffio_wfourcc(pb, "mdia");
3746 333 mov_write_mdhd_tag(pb, mov, track);
3747 333 mov_write_hdlr_tag(s, pb, track);
3748
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_minf_tag(s, pb, mov, track)) < 0)
3749 return ret;
3750 333 return update_size(pb, pos);
3751 }
3752
3753 /* transformation matrix
3754 |a b u|
3755 |c d v|
3756 |tx ty w| */
3757 569 static void write_matrix(AVIOContext *pb, int16_t a, int16_t b, int16_t c,
3758 int16_t d, int16_t tx, int16_t ty)
3759 {
3760 569 avio_wb32(pb, a << 16); /* 16.16 format */
3761 569 avio_wb32(pb, b << 16); /* 16.16 format */
3762 569 avio_wb32(pb, 0); /* u in 2.30 format */
3763 569 avio_wb32(pb, c << 16); /* 16.16 format */
3764 569 avio_wb32(pb, d << 16); /* 16.16 format */
3765 569 avio_wb32(pb, 0); /* v in 2.30 format */
3766 569 avio_wb32(pb, tx << 16); /* 16.16 format */
3767 569 avio_wb32(pb, ty << 16); /* 16.16 format */
3768 569 avio_wb32(pb, 1 << 30); /* w in 2.30 format */
3769 569 }
3770
3771 333 static int mov_write_tkhd_tag(AVIOContext *pb, MOVMuxContext *mov,
3772 MOVTrack *track, AVStream *st)
3773 {
3774 666 int64_t duration = av_rescale_rnd(calc_pts_duration(mov, track),
3775 333 mov->movie_timescale, track->timescale,
3776 AV_ROUND_UP);
3777 int version;
3778 333 int flags = MOV_TKHD_FLAG_IN_MOVIE;
3779 333 int group = 0;
3780
3781 333 uint32_t *display_matrix = NULL;
3782 int i;
3783
3784
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mov->mode == MODE_AVIF)
3785 if (!mov->avif_loop_count)
3786 duration = INT64_MAX;
3787 else
3788 duration *= mov->avif_loop_count;
3789
3790
2/2
✓ Branch 0 taken 320 times.
✓ Branch 1 taken 13 times.
333 if (st) {
3791 const AVPacketSideData *sd;
3792
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (mov->per_stream_grouping)
3793 group = st->index;
3794 else
3795 320 group = st->codecpar->codec_type;
3796
3797 320 sd = av_packet_side_data_get(st->codecpar->coded_side_data,
3798 320 st->codecpar->nb_coded_side_data,
3799 AV_PKT_DATA_DISPLAYMATRIX);
3800
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))
3801 1 display_matrix = (uint32_t *)sd->data;
3802 }
3803
3804
2/2
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 25 times.
333 if (track->flags & MOV_TRACK_ENABLED)
3805 308 flags |= MOV_TKHD_FLAG_ENABLED;
3806
3807 333 version = mov_mdhd_mvhd_tkhd_version(mov, track, duration);
3808
3809
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 326 times.
333 (version == 1) ? avio_wb32(pb, 104) : avio_wb32(pb, 92); /* size */
3810 333 ffio_wfourcc(pb, "tkhd");
3811 333 avio_w8(pb, version);
3812 333 avio_wb24(pb, flags);
3813
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 326 times.
333 if (version == 1) {
3814 7 avio_wb64(pb, track->time);
3815 7 avio_wb64(pb, track->time);
3816 } else {
3817 326 avio_wb32(pb, track->time); /* creation time */
3818 326 avio_wb32(pb, track->time); /* modification time */
3819 }
3820 333 avio_wb32(pb, track->track_id); /* track-id */
3821 333 avio_wb32(pb, 0); /* reserved */
3822
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)
3823
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 (version == 1) ? avio_wb64(pb, UINT64_C(0xffffffffffffffff)) : avio_wb32(pb, 0xffffffff);
3824
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 243 times.
326 else if (!track->entry)
3825
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 (version == 1) ? avio_wb64(pb, 0) : avio_wb32(pb, 0);
3826 else
3827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 243 times.
243 (version == 1) ? avio_wb64(pb, duration) : avio_wb32(pb, duration);
3828
3829 333 avio_wb32(pb, 0); /* reserved */
3830 333 avio_wb32(pb, 0); /* reserved */
3831 333 avio_wb16(pb, 0); /* layer */
3832 333 avio_wb16(pb, group); /* alternate group) */
3833 /* Volume, only for audio */
3834
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
333 if (track->par->codec_type == AVMEDIA_TYPE_AUDIO)
3835 108 avio_wb16(pb, 0x0100);
3836 else
3837 225 avio_wb16(pb, 0);
3838 333 avio_wb16(pb, 0); /* reserved */
3839
3840 /* Matrix structure */
3841
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 332 times.
333 if (display_matrix) {
3842
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 1 times.
10 for (i = 0; i < 9; i++)
3843 9 avio_wb32(pb, display_matrix[i]);
3844 } else {
3845 332 write_matrix(pb, 1, 0, 0, 1, 0, 0);
3846 }
3847 /* Track width and height, for visual only */
3848
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 ||
3849
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 112 times.
323 track->par->codec_type == AVMEDIA_TYPE_SUBTITLE)) {
3850 int64_t track_width_1616;
3851
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) {
3852 138 track_width_1616 = track->par->width * 0x10000ULL;
3853 } else {
3854 70 track_width_1616 = av_rescale(st->sample_aspect_ratio.num,
3855 70 track->par->width * 0x10000LL,
3856 70 st->sample_aspect_ratio.den);
3857
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 68 times.
70 if (!track_width_1616 ||
3858
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 ||
3859 track_width_1616 > UINT32_MAX)
3860 68 track_width_1616 = track->par->width * 0x10000ULL;
3861 }
3862
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (track_width_1616 > UINT32_MAX) {
3863 av_log(mov->fc, AV_LOG_WARNING, "track width is too large\n");
3864 track_width_1616 = 0;
3865 }
3866 208 avio_wb32(pb, track_width_1616);
3867
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 208 times.
208 if (track->height > 0xFFFF) {
3868 av_log(mov->fc, AV_LOG_WARNING, "track height is too large\n");
3869 avio_wb32(pb, 0);
3870 } else
3871 208 avio_wb32(pb, track->height * 0x10000U);
3872 } else {
3873 125 avio_wb32(pb, 0);
3874 125 avio_wb32(pb, 0);
3875 }
3876 333 return 0x5c;
3877 }
3878
3879 1 static int mov_write_tapt_tag(AVIOContext *pb, MOVTrack *track)
3880 {
3881 1 int32_t width = av_rescale(track->par->sample_aspect_ratio.num, track->par->width,
3882 1 track->par->sample_aspect_ratio.den);
3883
3884 1 int64_t pos = avio_tell(pb);
3885
3886 1 avio_wb32(pb, 0); /* size */
3887 1 ffio_wfourcc(pb, "tapt");
3888
3889 1 avio_wb32(pb, 20);
3890 1 ffio_wfourcc(pb, "clef");
3891 1 avio_wb32(pb, 0);
3892 1 avio_wb32(pb, width << 16);
3893 1 avio_wb32(pb, track->par->height << 16);
3894
3895 1 avio_wb32(pb, 20);
3896 1 ffio_wfourcc(pb, "prof");
3897 1 avio_wb32(pb, 0);
3898 1 avio_wb32(pb, width << 16);
3899 1 avio_wb32(pb, track->par->height << 16);
3900
3901 1 avio_wb32(pb, 20);
3902 1 ffio_wfourcc(pb, "enof");
3903 1 avio_wb32(pb, 0);
3904 1 avio_wb32(pb, track->par->width << 16);
3905 1 avio_wb32(pb, track->par->height << 16);
3906
3907 1 return update_size(pb, pos);
3908 }
3909
3910 // This box is written in the following cases:
3911 // * Seems important for the psp playback. Without it the movie seems to hang.
3912 // * Used for specifying the looping behavior of animated AVIF (as specified
3913 // in Section 9.6 of the HEIF specification ISO/IEC 23008-12).
3914 283 static int mov_write_edts_tag(AVIOContext *pb, MOVMuxContext *mov,
3915 MOVTrack *track)
3916 {
3917 566 int64_t duration = av_rescale_rnd(calc_samples_pts_duration(mov, track),
3918 283 mov->movie_timescale, track->timescale,
3919 AV_ROUND_UP);
3920 283 int version = duration < INT32_MAX ? 0 : 1;
3921 int entry_size, entry_count, size;
3922 283 int64_t delay, start_ct = track->start_cts;
3923 283 int64_t start_dts = track->start_dts;
3924 283 int flags = 0;
3925
3926
2/2
✓ Branch 0 taken 229 times.
✓ Branch 1 taken 54 times.
283 if (track->entry) {
3927
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) {
3928
3929 av_log(mov->fc, AV_LOG_DEBUG,
3930 "EDTS using dts:%"PRId64" cts:%d instead of dts:%"PRId64" cts:%"PRId64" tid:%d\n",
3931 track->cluster[0].dts, track->cluster[0].cts,
3932 start_dts, start_ct, track->track_id);
3933 start_dts = track->cluster[0].dts;
3934 start_ct = track->cluster[0].cts;
3935 }
3936 }
3937
3938 283 delay = av_rescale_rnd(start_dts + start_ct, mov->movie_timescale,
3939 283 track->timescale, AV_ROUND_DOWN);
3940
3941
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (mov->mode == MODE_AVIF) {
3942 delay = 0;
3943 // Section 9.6.3 of ISO/IEC 23008-12: flags specifies repetition of the
3944 // edit list as follows: (flags & 1) equal to 0 specifies that the edit
3945 // list is not repeated, while (flags & 1) equal to 1 specifies that the
3946 // edit list is repeated.
3947 flags = mov->avif_loop_count != 1;
3948 start_ct = 0;
3949 }
3950
3951 283 version |= delay < INT32_MAX ? 0 : 1;
3952
3953
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 entry_size = (version == 1) ? 20 : 12;
3954
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 entry_count = 1 + (delay > 0);
3955 283 size = 24 + entry_count * entry_size;
3956
3957 /* write the atom data */
3958 283 avio_wb32(pb, size);
3959 283 ffio_wfourcc(pb, "edts");
3960 283 avio_wb32(pb, size - 8);
3961 283 ffio_wfourcc(pb, "elst");
3962 283 avio_w8(pb, version);
3963 283 avio_wb24(pb, flags); /* flags */
3964
3965 283 avio_wb32(pb, entry_count);
3966
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 281 times.
283 if (delay > 0) { /* add an empty edit to delay presentation */
3967 /* In the positive delay case, the delay includes the cts
3968 * offset, and the second edit list entry below trims out
3969 * the same amount from the actual content. This makes sure
3970 * that the offset last sample is included in the edit
3971 * list duration as well. */
3972
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (version == 1) {
3973 avio_wb64(pb, delay);
3974 avio_wb64(pb, -1);
3975 } else {
3976 2 avio_wb32(pb, delay);
3977 2 avio_wb32(pb, -1);
3978 }
3979 2 avio_wb32(pb, 0x00010000);
3980
1/2
✓ Branch 0 taken 281 times.
✗ Branch 1 not taken.
281 } else if (mov->mode != MODE_AVIF) {
3981 /* Avoid accidentally ending up with start_ct = -1 which has got a
3982 * special meaning. Normally start_ct should end up positive or zero
3983 * here, but use FFMIN in case dts is a small positive integer
3984 * rounded to 0 when represented in movie timescale units. */
3985
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);
3986 281 start_ct = -FFMIN(start_dts, 0);
3987 /* Note, this delay is calculated from the pts of the first sample,
3988 * ensuring that we don't reduce the duration for cases with
3989 * dts<0 pts=0. */
3990 281 duration += delay;
3991 }
3992
3993 /* For fragmented files, we don't know the full length yet. Setting
3994 * duration to 0 allows us to only specify the offset, including
3995 * the rest of the content (from all future fragments) without specifying
3996 * an explicit duration. */
3997
2/2
✓ Branch 0 taken 58 times.
✓ Branch 1 taken 225 times.
283 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
3998 58 duration = 0;
3999
4000 /* duration */
4001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 283 times.
283 if (version == 1) {
4002 avio_wb64(pb, duration);
4003 avio_wb64(pb, start_ct);
4004 } else {
4005 283 avio_wb32(pb, duration);
4006 283 avio_wb32(pb, start_ct);
4007 }
4008 283 avio_wb32(pb, 0x00010000);
4009 283 return size;
4010 }
4011
4012 14 static int mov_write_tref_tag(AVIOContext *pb, MOVTrack *track)
4013 {
4014 14 avio_wb32(pb, 20); // size
4015 14 ffio_wfourcc(pb, "tref");
4016 14 avio_wb32(pb, 12); // size (subatom)
4017 14 avio_wl32(pb, track->tref_tag);
4018 14 avio_wb32(pb, track->tref_id);
4019 14 return 20;
4020 }
4021
4022 // goes at the end of each track! ... Critical for PSP playback ("Incompatible data" without it)
4023 2 static int mov_write_uuid_tag_psp(AVIOContext *pb, MOVTrack *mov)
4024 {
4025 2 avio_wb32(pb, 0x34); /* size ... reports as 28 in mp4box! */
4026 2 ffio_wfourcc(pb, "uuid");
4027 2 ffio_wfourcc(pb, "USMT");
4028 2 avio_wb32(pb, 0x21d24fce);
4029 2 avio_wb32(pb, 0xbb88695c);
4030 2 avio_wb32(pb, 0xfac9c740);
4031 2 avio_wb32(pb, 0x1c); // another size here!
4032 2 ffio_wfourcc(pb, "MTDT");
4033 2 avio_wb32(pb, 0x00010012);
4034 2 avio_wb32(pb, 0x0a);
4035 2 avio_wb32(pb, 0x55c40000);
4036 2 avio_wb32(pb, 0x1);
4037 2 avio_wb32(pb, 0x0);
4038 2 return 0x34;
4039 }
4040
4041 2 static int mov_write_udta_sdp(AVIOContext *pb, MOVTrack *track)
4042 {
4043 2 AVFormatContext *ctx = track->rtp_ctx;
4044 2 char buf[1000] = "";
4045 int len;
4046
4047 2 ff_sdp_write_media(buf, sizeof(buf), ctx->streams[0], track->src_track,
4048 NULL, NULL, 0, 0, ctx);
4049 2 av_strlcatf(buf, sizeof(buf), "a=control:streamid=%d\r\n", track->track_id);
4050 2 len = strlen(buf);
4051
4052 2 avio_wb32(pb, len + 24);
4053 2 ffio_wfourcc(pb, "udta");
4054 2 avio_wb32(pb, len + 16);
4055 2 ffio_wfourcc(pb, "hnti");
4056 2 avio_wb32(pb, len + 8);
4057 2 ffio_wfourcc(pb, "sdp ");
4058 2 avio_write(pb, buf, len);
4059 2 return len + 24;
4060 }
4061
4062 312 static int mov_write_track_metadata(AVIOContext *pb, AVStream *st,
4063 const char *tag, const char *str)
4064 {
4065 312 int64_t pos = avio_tell(pb);
4066 312 AVDictionaryEntry *t = av_dict_get(st->metadata, str, NULL, 0);
4067
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))
4068 311 return 0;
4069
4070 1 avio_wb32(pb, 0); /* size */
4071 1 ffio_wfourcc(pb, tag); /* type */
4072 1 avio_write(pb, t->value, strlen(t->value)); /* UTF8 string value */
4073 1 return update_size(pb, pos);
4074 }
4075
4076 2 static int mov_write_track_kind(AVIOContext *pb, const char *scheme_uri,
4077 const char *value)
4078 {
4079 2 int64_t pos = avio_tell(pb);
4080
4081 /* Box|FullBox basics */
4082 2 avio_wb32(pb, 0); /* size placeholder */
4083 2 ffio_wfourcc(pb, (const unsigned char *)"kind");
4084 2 avio_w8(pb, 0); /* version = 0 */
4085 2 avio_wb24(pb, 0); /* flags = 0 */
4086
4087 /* Required null-terminated scheme URI */
4088 2 avio_write(pb, (const unsigned char *)scheme_uri,
4089 2 strlen(scheme_uri));
4090 2 avio_w8(pb, 0);
4091
4092 /* Optional value string */
4093
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])
4094 2 avio_write(pb, (const unsigned char *)value,
4095 2 strlen(value));
4096
4097 2 avio_w8(pb, 0);
4098
4099 2 return update_size(pb, pos);
4100 }
4101
4102 131 static int mov_write_track_kinds(AVIOContext *pb, AVStream *st)
4103 {
4104 131 int ret = AVERROR_BUG;
4105
4106
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++) {
4107 131 const struct MP4TrackKindMapping map = ff_mov_track_kind_table[i];
4108
4109
2/2
✓ Branch 0 taken 655 times.
✓ Branch 1 taken 131 times.
786 for (int j = 0; map.value_maps[j].disposition; j++) {
4110 655 const struct MP4TrackKindValueMapping value_map = map.value_maps[j];
4111
2/2
✓ Branch 0 taken 653 times.
✓ Branch 1 taken 2 times.
655 if (!(st->disposition & value_map.disposition))
4112 653 continue;
4113
4114
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)
4115 return ret;
4116 }
4117 }
4118
4119 131 return 0;
4120 }
4121
4122 333 static int mov_write_track_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4123 AVStream *st)
4124 {
4125 AVIOContext *pb_buf;
4126 int ret, size;
4127 uint8_t *buf;
4128
4129
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 320 times.
333 if (!st)
4130 13 return 0;
4131
4132 320 ret = avio_open_dyn_buf(&pb_buf);
4133
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 320 times.
320 if (ret < 0)
4134 return ret;
4135
4136
2/2
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 8 times.
320 if (mov->mode & (MODE_MP4|MODE_MOV))
4137 312 mov_write_track_metadata(pb_buf, st, "name", "title");
4138
4139
2/2
✓ Branch 0 taken 131 times.
✓ Branch 1 taken 189 times.
320 if (mov->mode & MODE_MP4) {
4140
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 131 times.
131 if ((ret = mov_write_track_kinds(pb_buf, st)) < 0)
4141 return ret;
4142 }
4143
4144
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 317 times.
320 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4145 3 avio_wb32(pb, size + 8);
4146 3 ffio_wfourcc(pb, "udta");
4147 3 avio_write(pb, buf, size);
4148 }
4149 320 ffio_free_dyn_buf(&pb_buf);
4150
4151 320 return 0;
4152 }
4153
4154 333 static int mov_write_trak_tag(AVFormatContext *s, AVIOContext *pb, MOVMuxContext *mov,
4155 MOVTrack *track, AVStream *st)
4156 {
4157 333 int64_t pos = avio_tell(pb);
4158 333 int entry_backup = track->entry;
4159 333 int chunk_backup = track->chunkCount;
4160 int ret;
4161
4162 /* If we want to have an empty moov, but some samples already have been
4163 * buffered (delay_moov), pretend that no samples have been written yet. */
4164
2/2
✓ Branch 0 taken 90 times.
✓ Branch 1 taken 243 times.
333 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV)
4165 90 track->chunkCount = track->entry = 0;
4166
4167 333 avio_wb32(pb, 0); /* size */
4168 333 ffio_wfourcc(pb, "trak");
4169 333 mov_write_tkhd_tag(pb, mov, track, st);
4170
4171 av_assert2(mov->use_editlist >= 0);
4172
4173
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 26 times.
333 if (track->start_dts != AV_NOPTS_VALUE) {
4174
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 24 times.
307 if (mov->use_editlist)
4175 283 mov_write_edts_tag(pb, mov, track); // PSP Movies and several other cases require edts box
4176
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))
4177 av_log(mov->fc, AV_LOG_WARNING,
4178 "Not writing any edit list even though one would have been required\n");
4179 }
4180
4181
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (mov->is_animated_avif)
4182 mov_write_edts_tag(pb, mov, track);
4183
4184
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 319 times.
333 if (track->tref_tag)
4185 14 mov_write_tref_tag(pb, track);
4186
4187
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 333 times.
333 if ((ret = mov_write_mdia_tag(s, pb, mov, track)) < 0)
4188 return ret;
4189
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
333 if (track->mode == MODE_PSP)
4190 2 mov_write_uuid_tag_psp(pb, track); // PSP Movies require this uuid box
4191
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 331 times.
333 if (track->tag == MKTAG('r','t','p',' '))
4192 2 mov_write_udta_sdp(pb, track);
4193
2/2
✓ Branch 0 taken 187 times.
✓ Branch 1 taken 146 times.
333 if (track->mode == MODE_MOV) {
4194
2/2
✓ Branch 0 taken 138 times.
✓ Branch 1 taken 49 times.
187 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
4195 138 double sample_aspect_ratio = av_q2d(st->sample_aspect_ratio);
4196
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) {
4197 1 mov_write_tapt_tag(pb, track);
4198 }
4199 }
4200
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) {
4201 mov_write_tapt_tag(pb, track);
4202 }
4203 }
4204 333 mov_write_track_udta_tag(pb, mov, st);
4205 333 track->entry = entry_backup;
4206 333 track->chunkCount = chunk_backup;
4207 333 return update_size(pb, pos);
4208 }
4209
4210 static int mov_write_iods_tag(AVIOContext *pb, MOVMuxContext *mov)
4211 {
4212 int i, has_audio = 0, has_video = 0;
4213 int64_t pos = avio_tell(pb);
4214 int audio_profile = mov->iods_audio_profile;
4215 int video_profile = mov->iods_video_profile;
4216 for (i = 0; i < mov->nb_tracks; i++) {
4217 if (mov->tracks[i].entry > 0 || mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4218 has_audio |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_AUDIO;
4219 has_video |= mov->tracks[i].par->codec_type == AVMEDIA_TYPE_VIDEO;
4220 }
4221 }
4222 if (audio_profile < 0)
4223 audio_profile = 0xFF - has_audio;
4224 if (video_profile < 0)
4225 video_profile = 0xFF - has_video;
4226 avio_wb32(pb, 0x0); /* size */
4227 ffio_wfourcc(pb, "iods");
4228 avio_wb32(pb, 0); /* version & flags */
4229 put_descr(pb, 0x10, 7);
4230 avio_wb16(pb, 0x004f);
4231 avio_w8(pb, 0xff);
4232 avio_w8(pb, 0xff);
4233 avio_w8(pb, audio_profile);
4234 avio_w8(pb, video_profile);
4235 avio_w8(pb, 0xff);
4236 return update_size(pb, pos);
4237 }
4238
4239 108 static int mov_write_trex_tag(AVIOContext *pb, MOVTrack *track)
4240 {
4241 108 avio_wb32(pb, 0x20); /* size */
4242 108 ffio_wfourcc(pb, "trex");
4243 108 avio_wb32(pb, 0); /* version & flags */
4244 108 avio_wb32(pb, track->track_id); /* track ID */
4245 108 avio_wb32(pb, 1); /* default sample description index */
4246 108 avio_wb32(pb, 0); /* default sample duration */
4247 108 avio_wb32(pb, 0); /* default sample size */
4248 108 avio_wb32(pb, 0); /* default sample flags */
4249 108 return 0;
4250 }
4251
4252 56 static int mov_write_mvex_tag(AVIOContext *pb, MOVMuxContext *mov)
4253 {
4254 56 int64_t pos = avio_tell(pb);
4255 int i;
4256 56 avio_wb32(pb, 0x0); /* size */
4257 56 ffio_wfourcc(pb, "mvex");
4258
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 56 times.
164 for (i = 0; i < mov->nb_tracks; i++)
4259 108 mov_write_trex_tag(pb, &mov->tracks[i]);
4260 56 return update_size(pb, pos);
4261 }
4262
4263 237 static int mov_write_mvhd_tag(AVIOContext *pb, MOVMuxContext *mov)
4264 {
4265 237 int max_track_id = 1, i;
4266 237 int64_t max_track_len = 0;
4267 int version;
4268 int timescale;
4269
4270
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
4271
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) {
4272 614 int64_t max_track_len_temp = av_rescale_rnd(
4273 307 calc_pts_duration(mov, &mov->tracks[i]),
4274 307 mov->movie_timescale,
4275 307 mov->tracks[i].timescale,
4276 AV_ROUND_UP);
4277
2/2
✓ Branch 0 taken 237 times.
✓ Branch 1 taken 70 times.
307 if (max_track_len < max_track_len_temp)
4278 237 max_track_len = max_track_len_temp;
4279
2/2
✓ Branch 0 taken 83 times.
✓ Branch 1 taken 224 times.
307 if (max_track_id < mov->tracks[i].track_id)
4280 83 max_track_id = mov->tracks[i].track_id;
4281 }
4282 }
4283 /* If using delay_moov, make sure the output is the same as if no
4284 * samples had been written yet. */
4285
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 190 times.
237 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV) {
4286 47 max_track_len = 0;
4287 47 max_track_id = 1;
4288 }
4289
4290 237 version = mov_mdhd_mvhd_tkhd_version(mov, NULL, max_track_len);
4291
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 avio_wb32(pb, version == 1 ? 120 : 108); /* size */
4292
4293 237 ffio_wfourcc(pb, "mvhd");
4294 237 avio_w8(pb, version);
4295 237 avio_wb24(pb, 0); /* flags */
4296
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 237 times.
237 if (version == 1) {
4297 avio_wb64(pb, mov->time);
4298 avio_wb64(pb, mov->time);
4299 } else {
4300 237 avio_wb32(pb, mov->time); /* creation time */
4301 237 avio_wb32(pb, mov->time); /* modification time */
4302 }
4303
4304 237 timescale = mov->movie_timescale;
4305
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)
4306 timescale = mov->tracks[0].timescale;
4307
4308 237 avio_wb32(pb, timescale);
4309
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 */
4310
4311 237 avio_wb32(pb, 0x00010000); /* reserved (preferred rate) 1.0 = normal */
4312 237 avio_wb16(pb, 0x0100); /* reserved (preferred volume) 1.0 = normal */
4313 237 ffio_fill(pb, 0, 2 + 2 * 4); /* reserved */
4314
4315 /* Matrix structure */
4316 237 write_matrix(pb, 1, 0, 0, 1, 0, 0);
4317
4318 237 avio_wb32(pb, 0); /* reserved (preview time) */
4319 237 avio_wb32(pb, 0); /* reserved (preview duration) */
4320 237 avio_wb32(pb, 0); /* reserved (poster time) */
4321 237 avio_wb32(pb, 0); /* reserved (selection time) */
4322 237 avio_wb32(pb, 0); /* reserved (selection duration) */
4323 237 avio_wb32(pb, 0); /* reserved (current time) */
4324 237 avio_wb32(pb, max_track_id + 1); /* Next track id */
4325 237 return 0x6c;
4326 }
4327
4328 82 static int mov_write_itunes_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4329 AVFormatContext *s)
4330 {
4331 82 avio_wb32(pb, 33); /* size */
4332 82 ffio_wfourcc(pb, "hdlr");
4333 82 avio_wb32(pb, 0);
4334 82 avio_wb32(pb, 0);
4335 82 ffio_wfourcc(pb, "mdir");
4336 82 ffio_wfourcc(pb, "appl");
4337 82 avio_wb32(pb, 0);
4338 82 avio_wb32(pb, 0);
4339 82 avio_w8(pb, 0);
4340 82 return 33;
4341 }
4342
4343 /* helper function to write a data tag with the specified string as data */
4344 54 static int mov_write_string_data_tag(AVIOContext *pb, const char *data, int lang, int long_style)
4345 {
4346 54 size_t data_len = strlen(data);
4347
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 34 times.
54 if (long_style) {
4348 20 int size = 16 + data_len;
4349 20 avio_wb32(pb, size); /* size */
4350 20 ffio_wfourcc(pb, "data");
4351 20 avio_wb32(pb, 1);
4352 20 avio_wb32(pb, 0);
4353 20 avio_write(pb, data, data_len);
4354 20 return size;
4355 } else {
4356 34 avio_wb16(pb, data_len); /* string length */
4357
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 8 times.
34 if (!lang)
4358 26 lang = ff_mov_iso639_to_lang("und", 1);
4359 34 avio_wb16(pb, lang);
4360 34 avio_write(pb, data, data_len);
4361 34 return data_len + 4;
4362 }
4363 }
4364
4365 54 static int mov_write_string_tag(AVIOContext *pb, const char *name,
4366 const char *value, int lang, int long_style)
4367 {
4368 54 int size = 0;
4369
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]) {
4370 54 int64_t pos = avio_tell(pb);
4371 54 avio_wb32(pb, 0); /* size */
4372 54 ffio_wfourcc(pb, name);
4373 54 mov_write_string_data_tag(pb, value, lang, long_style);
4374 54 size = update_size(pb, pos);
4375 }
4376 54 return size;
4377 }
4378
4379 3714 static AVDictionaryEntry *get_metadata_lang(AVFormatContext *s,
4380 const char *tag, int *lang)
4381 {
4382 int l, len, len2;
4383 3714 AVDictionaryEntry *t, *t2 = NULL;
4384 char tag2[16];
4385
4386 3714 *lang = 0;
4387
4388
2/2
✓ Branch 1 taken 3662 times.
✓ Branch 2 taken 52 times.
3714 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4389 3662 return NULL;
4390
4391 52 len = strlen(t->key);
4392 52 snprintf(tag2, sizeof(tag2), "%s-", tag);
4393
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))) {
4394 8 len2 = strlen(t2->key);
4395
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)
4396
1/2
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
8 && (l = ff_mov_iso639_to_lang(&t2->key[len2 - 3], 1)) >= 0) {
4397 8 *lang = l;
4398 8 return t;
4399 }
4400 }
4401 44 return t;
4402 }
4403
4404 3632 static int mov_write_string_metadata(AVFormatContext *s, AVIOContext *pb,
4405 const char *name, const char *tag,
4406 int long_style)
4407 {
4408 int lang;
4409 3632 AVDictionaryEntry *t = get_metadata_lang(s, tag, &lang);
4410
2/2
✓ Branch 0 taken 3580 times.
✓ Branch 1 taken 52 times.
3632 if (!t)
4411 3580 return 0;
4412 52 return mov_write_string_tag(pb, name, t->value, lang, long_style);
4413 }
4414
4415 /* iTunes bpm number */
4416 82 static int mov_write_tmpo_tag(AVIOContext *pb, AVFormatContext *s)
4417 {
4418 82 AVDictionaryEntry *t = av_dict_get(s->metadata, "tmpo", NULL, 0);
4419
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 int size = 0, tmpo = t ? atoi(t->value) : 0;
4420
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (tmpo) {
4421 size = 26;
4422 avio_wb32(pb, size);
4423 ffio_wfourcc(pb, "tmpo");
4424 avio_wb32(pb, size-8); /* size */
4425 ffio_wfourcc(pb, "data");
4426 avio_wb32(pb, 0x15); //type specifier
4427 avio_wb32(pb, 0);
4428 avio_wb16(pb, tmpo); // data
4429 }
4430 82 return size;
4431 }
4432
4433 /* 3GPP TS 26.244 */
4434 82 static int mov_write_loci_tag(AVFormatContext *s, AVIOContext *pb)
4435 {
4436 int lang;
4437 82 int64_t pos = avio_tell(pb);
4438 double latitude, longitude, altitude;
4439 int32_t latitude_fix, longitude_fix, altitude_fix;
4440 82 AVDictionaryEntry *t = get_metadata_lang(s, "location", &lang);
4441 82 const char *ptr, *place = "";
4442 char *end;
4443 static const char *astronomical_body = "earth";
4444
1/2
✓ Branch 0 taken 82 times.
✗ Branch 1 not taken.
82 if (!t)
4445 82 return 0;
4446
4447 ptr = t->value;
4448 latitude = strtod(ptr, &end);
4449 if (end == ptr) {
4450 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4451 return 0;
4452 }
4453 ptr = end;
4454 longitude = strtod(ptr, &end);
4455 if (end == ptr) {
4456 av_log(s, AV_LOG_WARNING, "malformed location metadata\n");
4457 return 0;
4458 }
4459 ptr = end;
4460 altitude = strtod(ptr, &end);
4461 /* If no altitude was present, the default 0 should be fine */
4462 if (*end == '/')
4463 place = end + 1;
4464
4465 latitude_fix = (int32_t) ((1 << 16) * latitude);
4466 longitude_fix = (int32_t) ((1 << 16) * longitude);
4467 altitude_fix = (int32_t) ((1 << 16) * altitude);
4468
4469 avio_wb32(pb, 0); /* size */
4470 ffio_wfourcc(pb, "loci"); /* type */
4471 avio_wb32(pb, 0); /* version + flags */
4472 avio_wb16(pb, lang);
4473 avio_write(pb, place, strlen(place) + 1);
4474 avio_w8(pb, 0); /* role of place (0 == shooting location, 1 == real location, 2 == fictional location) */
4475 avio_wb32(pb, longitude_fix);
4476 avio_wb32(pb, latitude_fix);
4477 avio_wb32(pb, altitude_fix);
4478 avio_write(pb, astronomical_body, strlen(astronomical_body) + 1);
4479 avio_w8(pb, 0); /* additional notes, null terminated string */
4480
4481 return update_size(pb, pos);
4482 }
4483
4484 /* iTunes track or disc number */
4485 164 static int mov_write_trkn_tag(AVIOContext *pb, MOVMuxContext *mov,
4486 AVFormatContext *s, int disc)
4487 {
4488
2/2
✓ Branch 0 taken 82 times.
✓ Branch 1 taken 82 times.
164 AVDictionaryEntry *t = av_dict_get(s->metadata,
4489 disc ? "disc" : "track",
4490 NULL, 0);
4491
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 162 times.
164 int size = 0, track = t ? atoi(t->value) : 0;
4492
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 162 times.
164 if (track) {
4493 2 int tracks = 0;
4494 2 char *slash = strchr(t->value, '/');
4495
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (slash)
4496 2 tracks = atoi(slash + 1);
4497 2 avio_wb32(pb, 32); /* size */
4498
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 ffio_wfourcc(pb, disc ? "disk" : "trkn");
4499 2 avio_wb32(pb, 24); /* size */
4500 2 ffio_wfourcc(pb, "data");
4501 2 avio_wb32(pb, 0); // 8 bytes empty
4502 2 avio_wb32(pb, 0);
4503 2 avio_wb16(pb, 0); // empty
4504 2 avio_wb16(pb, track); // track / disc number
4505 2 avio_wb16(pb, tracks); // total track / disc number
4506 2 avio_wb16(pb, 0); // empty
4507 2 size = 32;
4508 }
4509 164 return size;
4510 }
4511
4512 492 static int mov_write_int8_metadata(AVFormatContext *s, AVIOContext *pb,
4513 const char *name, const char *tag,
4514 int len)
4515 {
4516 492 AVDictionaryEntry *t = NULL;
4517 uint8_t num;
4518 492 int size = 24 + len;
4519
4520
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)
4521 return -1;
4522
4523
2/2
✓ Branch 1 taken 490 times.
✓ Branch 2 taken 2 times.
492 if (!(t = av_dict_get(s->metadata, tag, NULL, 0)))
4524 490 return 0;
4525 2 num = atoi(t->value);
4526
4527 2 avio_wb32(pb, size);
4528 2 ffio_wfourcc(pb, name);
4529 2 avio_wb32(pb, size - 8);
4530 2 ffio_wfourcc(pb, "data");
4531 2 avio_wb32(pb, 0x15);
4532 2 avio_wb32(pb, 0);
4533
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (len==4) avio_wb32(pb, num);
4534 2 else avio_w8 (pb, num);
4535
4536 2 return size;
4537 }
4538
4539 82 static int mov_write_covr(AVIOContext *pb, AVFormatContext *s)
4540 {
4541 82 MOVMuxContext *mov = s->priv_data;
4542 82 int64_t pos = 0;
4543
4544
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 82 times.
221 for (int i = 0; i < mov->nb_streams; i++) {
4545 139 MOVTrack *trk = &mov->tracks[i];
4546
4547
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)
4548 137 continue;
4549
4550
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (!pos) {
4551 1 pos = avio_tell(pb);
4552 1 avio_wb32(pb, 0);
4553 1 ffio_wfourcc(pb, "covr");
4554 }
4555 2 avio_wb32(pb, 16 + trk->cover_image->size);
4556 2 ffio_wfourcc(pb, "data");
4557 2 avio_wb32(pb, trk->tag);
4558 2 avio_wb32(pb , 0);
4559 2 avio_write(pb, trk->cover_image->data, trk->cover_image->size);
4560 }
4561
4562
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 81 times.
82 return pos ? update_size(pb, pos) : 0;
4563 }
4564
4565 /* iTunes meta data list */
4566 82 static int mov_write_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4567 AVFormatContext *s)
4568 {
4569 82 int64_t pos = avio_tell(pb);
4570 82 avio_wb32(pb, 0); /* size */
4571 82 ffio_wfourcc(pb, "ilst");
4572 82 mov_write_string_metadata(s, pb, "\251nam", "title" , 1);
4573 82 mov_write_string_metadata(s, pb, "\251ART", "artist" , 1);
4574 82 mov_write_string_metadata(s, pb, "aART", "album_artist", 1);
4575 82 mov_write_string_metadata(s, pb, "\251wrt", "composer" , 1);
4576 82 mov_write_string_metadata(s, pb, "\251alb", "album" , 1);
4577 82 mov_write_string_metadata(s, pb, "\251day", "date" , 1);
4578
1/2
✓ Branch 1 taken 82 times.
✗ Branch 2 not taken.
82 if (!mov_write_string_metadata(s, pb, "\251too", "encoding_tool", 1)) {
4579
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 80 times.
82 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4580 2 mov_write_string_tag(pb, "\251too", LIBAVFORMAT_IDENT, 0, 1);
4581 }
4582 82 mov_write_string_metadata(s, pb, "\251cmt", "comment" , 1);
4583 82 mov_write_string_metadata(s, pb, "\251gen", "genre" , 1);
4584 82 mov_write_string_metadata(s, pb, "cprt", "copyright", 1);
4585 82 mov_write_string_metadata(s, pb, "\251grp", "grouping" , 1);
4586 82 mov_write_string_metadata(s, pb, "\251lyr", "lyrics" , 1);
4587 82 mov_write_string_metadata(s, pb, "desc", "description",1);
4588 82 mov_write_string_metadata(s, pb, "ldes", "synopsis" , 1);
4589 82 mov_write_string_metadata(s, pb, "tvsh", "show" , 1);
4590 82 mov_write_string_metadata(s, pb, "tven", "episode_id",1);
4591 82 mov_write_string_metadata(s, pb, "tvnn", "network" , 1);
4592 82 mov_write_string_metadata(s, pb, "keyw", "keywords" , 1);
4593 82 mov_write_int8_metadata (s, pb, "tves", "episode_sort",4);
4594 82 mov_write_int8_metadata (s, pb, "tvsn", "season_number",4);
4595 82 mov_write_int8_metadata (s, pb, "stik", "media_type",1);
4596 82 mov_write_int8_metadata (s, pb, "hdvd", "hd_video", 1);
4597 82 mov_write_int8_metadata (s, pb, "pgap", "gapless_playback",1);
4598 82 mov_write_int8_metadata (s, pb, "cpil", "compilation", 1);
4599 82 mov_write_covr(pb, s);
4600 82 mov_write_trkn_tag(pb, mov, s, 0); // track number
4601 82 mov_write_trkn_tag(pb, mov, s, 1); // disc number
4602 82 mov_write_tmpo_tag(pb, s);
4603 82 return update_size(pb, pos);
4604 }
4605
4606 static int mov_write_mdta_hdlr_tag(AVIOContext *pb, MOVMuxContext *mov,
4607 AVFormatContext *s)
4608 {
4609 avio_wb32(pb, 33); /* size */
4610 ffio_wfourcc(pb, "hdlr");
4611 avio_wb32(pb, 0);
4612 avio_wb32(pb, 0);
4613 ffio_wfourcc(pb, "mdta");
4614 avio_wb32(pb, 0);
4615 avio_wb32(pb, 0);
4616 avio_wb32(pb, 0);
4617 avio_w8(pb, 0);
4618 return 33;
4619 }
4620
4621 static int mov_write_mdta_keys_tag(AVIOContext *pb, MOVMuxContext *mov,
4622 AVFormatContext *s)
4623 {
4624 const AVDictionaryEntry *t = NULL;
4625 int64_t pos = avio_tell(pb);
4626 int64_t curpos, entry_pos;
4627 int count = 0;
4628
4629 avio_wb32(pb, 0); /* size */
4630 ffio_wfourcc(pb, "keys");
4631 avio_wb32(pb, 0);
4632 entry_pos = avio_tell(pb);
4633 avio_wb32(pb, 0); /* entry count */
4634
4635 while (t = av_dict_iterate(s->metadata, t)) {
4636 size_t key_len = strlen(t->key);
4637 avio_wb32(pb, key_len + 8);
4638 ffio_wfourcc(pb, "mdta");
4639 avio_write(pb, t->key, key_len);
4640 count += 1;
4641 }
4642 curpos = avio_tell(pb);
4643 avio_seek(pb, entry_pos, SEEK_SET);
4644 avio_wb32(pb, count); // rewrite entry count
4645 avio_seek(pb, curpos, SEEK_SET);
4646
4647 return update_size(pb, pos);
4648 }
4649
4650 static int mov_write_mdta_ilst_tag(AVIOContext *pb, MOVMuxContext *mov,
4651 AVFormatContext *s)
4652 {
4653 const AVDictionaryEntry *t = NULL;
4654 int64_t pos = avio_tell(pb);
4655 int count = 1; /* keys are 1-index based */
4656
4657 avio_wb32(pb, 0); /* size */
4658 ffio_wfourcc(pb, "ilst");
4659
4660 while (t = av_dict_iterate(s->metadata, t)) {
4661 int64_t entry_pos = avio_tell(pb);
4662 avio_wb32(pb, 0); /* size */
4663 avio_wb32(pb, count); /* key */
4664 mov_write_string_data_tag(pb, t->value, 0, 1);
4665 update_size(pb, entry_pos);
4666 count += 1;
4667 }
4668 return update_size(pb, pos);
4669 }
4670
4671 /* meta data tags */
4672 82 static int mov_write_meta_tag(AVIOContext *pb, MOVMuxContext *mov,
4673 AVFormatContext *s)
4674 {
4675 82 int size = 0;
4676 82 int64_t pos = avio_tell(pb);
4677 82 avio_wb32(pb, 0); /* size */
4678 82 ffio_wfourcc(pb, "meta");
4679 82 avio_wb32(pb, 0);
4680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 if (mov->flags & FF_MOV_FLAG_USE_MDTA) {
4681 mov_write_mdta_hdlr_tag(pb, mov, s);
4682 mov_write_mdta_keys_tag(pb, mov, s);
4683 mov_write_mdta_ilst_tag(pb, mov, s);
4684
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 } else if (mov->mode == MODE_AVIF) {
4685 mov_write_hdlr_tag(s, pb, &mov->tracks[0]);
4686 // We always write the primary item id as 1 since only one track is
4687 // supported for AVIF.
4688 mov_write_pitm_tag(pb, 1);
4689 mov_write_iloc_tag(pb, mov, s);
4690 mov_write_iinf_tag(pb, mov, s);
4691 if (mov->nb_streams > 1)
4692 mov_write_iref_tag(pb, mov, s);
4693 mov_write_iprp_tag(pb, mov, s);
4694 } else {
4695 /* iTunes metadata tag */
4696 82 mov_write_itunes_hdlr_tag(pb, mov, s);
4697 82 mov_write_ilst_tag(pb, mov, s);
4698 }
4699 82 size = update_size(pb, pos);
4700 82 return size;
4701 }
4702
4703 154 static int mov_write_raw_metadata_tag(AVFormatContext *s, AVIOContext *pb,
4704 const char *name, const char *key)
4705 {
4706 int len;
4707 AVDictionaryEntry *t;
4708
4709
1/2
✓ Branch 1 taken 154 times.
✗ Branch 2 not taken.
154 if (!(t = av_dict_get(s->metadata, key, NULL, 0)))
4710 154 return 0;
4711
4712 len = strlen(t->value);
4713 if (len > 0) {
4714 int size = len + 8;
4715 avio_wb32(pb, size);
4716 ffio_wfourcc(pb, name);
4717 avio_write(pb, t->value, len);
4718 return size;
4719 }
4720 return 0;
4721 }
4722
4723 static int ascii_to_wc(AVIOContext *pb, const uint8_t *b)
4724 {
4725 int val;
4726 while (*b) {
4727 GET_UTF8(val, *b++, return -1;)
4728 avio_wb16(pb, val);
4729 }
4730 avio_wb16(pb, 0x00);
4731 return 0;
4732 }
4733
4734 static uint16_t language_code(const char *str)
4735 {
4736 return (((str[0] - 0x60) & 0x1F) << 10) +
4737 (((str[1] - 0x60) & 0x1F) << 5) +
4738 (( str[2] - 0x60) & 0x1F);
4739 }
4740
4741 static int mov_write_3gp_udta_tag(AVIOContext *pb, AVFormatContext *s,
4742 const char *tag, const char *str)
4743 {
4744 int64_t pos = avio_tell(pb);
4745 AVDictionaryEntry *t = av_dict_get(s->metadata, str, NULL, 0);
4746 if (!t || !utf8len(t->value))
4747 return 0;
4748 avio_wb32(pb, 0); /* size */
4749 ffio_wfourcc(pb, tag); /* type */
4750 avio_wb32(pb, 0); /* version + flags */
4751 if (!strcmp(tag, "yrrc"))
4752 avio_wb16(pb, atoi(t->value));
4753 else {
4754 avio_wb16(pb, language_code("eng")); /* language */
4755 avio_write(pb, t->value, strlen(t->value) + 1); /* UTF8 string value */
4756 if (!strcmp(tag, "albm") &&
4757 (t = av_dict_get(s->metadata, "track", NULL, 0)))
4758 avio_w8(pb, atoi(t->value));
4759 }
4760 return update_size(pb, pos);
4761 }
4762
4763 1 static int mov_write_chpl_tag(AVIOContext *pb, AVFormatContext *s)
4764 {
4765 1 int64_t pos = avio_tell(pb);
4766 1 int i, nb_chapters = FFMIN(s->nb_chapters, 255);
4767
4768 1 avio_wb32(pb, 0); // size
4769 1 ffio_wfourcc(pb, "chpl");
4770 1 avio_wb32(pb, 0x01000000); // version + flags
4771 1 avio_wb32(pb, 0); // unknown
4772 1 avio_w8(pb, nb_chapters);
4773
4774
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < nb_chapters; i++) {
4775 4 AVChapter *c = s->chapters[i];
4776 AVDictionaryEntry *t;
4777 4 avio_wb64(pb, av_rescale_q(c->start, c->time_base, (AVRational){1,10000000}));
4778
4779
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
4780
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 int len = FFMIN(strlen(t->value), 255);
4781 4 avio_w8(pb, len);
4782 4 avio_write(pb, t->value, len);
4783 } else
4784 avio_w8(pb, 0);
4785 }
4786 1 return update_size(pb, pos);
4787 }
4788
4789 236 static int mov_write_udta_tag(AVIOContext *pb, MOVMuxContext *mov,
4790 AVFormatContext *s)
4791 {
4792 AVIOContext *pb_buf;
4793 int ret, size;
4794 uint8_t *buf;
4795
4796 236 ret = avio_open_dyn_buf(&pb_buf);
4797
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (ret < 0)
4798 return ret;
4799
4800
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 236 times.
236 if (mov->mode & MODE_3GP) {
4801 mov_write_3gp_udta_tag(pb_buf, s, "perf", "artist");
4802 mov_write_3gp_udta_tag(pb_buf, s, "titl", "title");
4803 mov_write_3gp_udta_tag(pb_buf, s, "auth", "author");
4804 mov_write_3gp_udta_tag(pb_buf, s, "gnre", "genre");
4805 mov_write_3gp_udta_tag(pb_buf, s, "dscp", "comment");
4806 mov_write_3gp_udta_tag(pb_buf, s, "albm", "album");
4807 mov_write_3gp_udta_tag(pb_buf, s, "cprt", "copyright");
4808 mov_write_3gp_udta_tag(pb_buf, s, "yrrc", "date");
4809 mov_write_loci_tag(s, pb_buf);
4810
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
4811 154 mov_write_string_metadata(s, pb_buf, "\251ART", "artist", 0);
4812 154 mov_write_string_metadata(s, pb_buf, "\251nam", "title", 0);
4813 154 mov_write_string_metadata(s, pb_buf, "\251aut", "author", 0);
4814 154 mov_write_string_metadata(s, pb_buf, "\251alb", "album", 0);
4815 154 mov_write_string_metadata(s, pb_buf, "\251day", "date", 0);
4816 154 mov_write_string_metadata(s, pb_buf, "\251swr", "encoder", 0);
4817 // currently ignored by mov.c
4818 154 mov_write_string_metadata(s, pb_buf, "\251des", "comment", 0);
4819 // add support for libquicktime, this atom is also actually read by mov.c
4820 154 mov_write_string_metadata(s, pb_buf, "\251cmt", "comment", 0);
4821 154 mov_write_string_metadata(s, pb_buf, "\251gen", "genre", 0);
4822 154 mov_write_string_metadata(s, pb_buf, "\251cpy", "copyright", 0);
4823 154 mov_write_string_metadata(s, pb_buf, "\251mak", "make", 0);
4824 154 mov_write_string_metadata(s, pb_buf, "\251mod", "model", 0);
4825 154 mov_write_string_metadata(s, pb_buf, "\251xyz", "location", 0);
4826 154 mov_write_string_metadata(s, pb_buf, "\251key", "keywords", 0);
4827 154 mov_write_raw_metadata_tag(s, pb_buf, "XMP_", "xmp");
4828 } else {
4829 /* iTunes meta data */
4830 82 mov_write_meta_tag(pb_buf, mov, s);
4831 82 mov_write_loci_tag(s, pb_buf);
4832 }
4833
4834
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))
4835 1 mov_write_chpl_tag(pb_buf, s);
4836
4837
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 126 times.
236 if ((size = avio_get_dyn_buf(pb_buf, &buf)) > 0) {
4838 110 avio_wb32(pb, size + 8);
4839 110 ffio_wfourcc(pb, "udta");
4840 110 avio_write(pb, buf, size);
4841 }
4842 236 ffio_free_dyn_buf(&pb_buf);
4843
4844 236 return 0;
4845 }
4846
4847 static void mov_write_psp_udta_tag(AVIOContext *pb,
4848 const char *str, const char *lang, int type)
4849 {
4850 int len = utf8len(str) + 1;
4851 if (len <= 0)
4852 return;
4853 avio_wb16(pb, len * 2 + 10); /* size */
4854 avio_wb32(pb, type); /* type */
4855 avio_wb16(pb, language_code(lang)); /* language */
4856 avio_wb16(pb, 0x01); /* ? */
4857 ascii_to_wc(pb, str);
4858 }
4859
4860 1 static int mov_write_uuidusmt_tag(AVIOContext *pb, AVFormatContext *s)
4861 {
4862 1 AVDictionaryEntry *title = av_dict_get(s->metadata, "title", NULL, 0);
4863 int64_t pos, pos2;
4864
4865
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (title) {
4866 pos = avio_tell(pb);
4867 avio_wb32(pb, 0); /* size placeholder*/
4868 ffio_wfourcc(pb, "uuid");
4869 ffio_wfourcc(pb, "USMT");
4870 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
4871 avio_wb32(pb, 0xbb88695c);
4872 avio_wb32(pb, 0xfac9c740);
4873
4874 pos2 = avio_tell(pb);
4875 avio_wb32(pb, 0); /* size placeholder*/
4876 ffio_wfourcc(pb, "MTDT");
4877 avio_wb16(pb, 4);
4878
4879 // ?
4880 avio_wb16(pb, 0x0C); /* size */
4881 avio_wb32(pb, 0x0B); /* type */
4882 avio_wb16(pb, language_code("und")); /* language */
4883 avio_wb16(pb, 0x0); /* ? */
4884 avio_wb16(pb, 0x021C); /* data */
4885
4886 if (!(s->flags & AVFMT_FLAG_BITEXACT))
4887 mov_write_psp_udta_tag(pb, LIBAVFORMAT_IDENT, "eng", 0x04);
4888 mov_write_psp_udta_tag(pb, title->value, "eng", 0x01);
4889 mov_write_psp_udta_tag(pb, "2006/04/01 11:11:11", "und", 0x03);
4890
4891 update_size(pb, pos2);
4892 return update_size(pb, pos);
4893 }
4894
4895 1 return 0;
4896 }
4897
4898 307 static void build_chunks(MOVTrack *trk)
4899 {
4900 int i;
4901 307 MOVIentry *chunk = &trk->cluster[0];
4902 307 uint64_t chunkSize = chunk->size;
4903 307 chunk->chunkNum = 1;
4904
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 252 times.
307 if (trk->chunkCount)
4905 55 return;
4906 252 trk->chunkCount = 1;
4907
2/2
✓ Branch 0 taken 14753 times.
✓ Branch 1 taken 252 times.
15005 for (i = 1; i<trk->entry; i++){
4908
2/2
✓ Branch 0 taken 12852 times.
✓ Branch 1 taken 1901 times.
14753 if (chunk->pos + chunkSize == trk->cluster[i].pos &&
4909
2/2
✓ Branch 0 taken 12207 times.
✓ Branch 1 taken 645 times.
12852 chunkSize + trk->cluster[i].size < (1<<20)){
4910 12207 chunkSize += trk->cluster[i].size;
4911 12207 chunk->samples_in_chunk += trk->cluster[i].entries;
4912 } else {
4913 2546 trk->cluster[i].chunkNum = chunk->chunkNum+1;
4914 2546 chunk=&trk->cluster[i];
4915 2546 chunkSize = chunk->size;
4916 2546 trk->chunkCount++;
4917 }
4918 }
4919 }
4920
4921 /**
4922 * Assign track ids. If option "use_stream_ids_as_track_ids" is set,
4923 * the stream ids are used as track ids.
4924 *
4925 * This assumes mov->tracks and s->streams are in the same order and
4926 * there are no gaps in either of them (so mov->tracks[n] refers to
4927 * s->streams[n]).
4928 *
4929 * As an exception, there can be more entries in
4930 * s->streams than in mov->tracks, in which case new track ids are
4931 * generated (starting after the largest found stream id).
4932 */
4933 237 static int mov_setup_track_ids(MOVMuxContext *mov, AVFormatContext *s)
4934 {
4935 int i;
4936
4937
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 209 times.
237 if (mov->track_ids_ok)
4938 28 return 0;
4939
4940
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->use_stream_ids_as_track_ids) {
4941 1 int next_generated_track_id = 0;
4942
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
4943 2 AVStream *st = mov->tracks[i].st;
4944
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (st->id > next_generated_track_id)
4945 2 next_generated_track_id = st->id;
4946 }
4947
4948
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
4949
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))
4950 continue;
4951
4952
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;
4953 }
4954 } else {
4955 208 int last_track_id = 0;
4956
2/2
✓ Branch 0 taken 274 times.
✓ Branch 1 taken 208 times.
482 for (i = 0; i < mov->nb_tracks; i++) {
4957
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))
4958 2 continue;
4959
4960 272 last_track_id =
4961 272 mov->tracks[i].track_id = (mov->tracks[i].st
4962 269 ? FFMAX(mov->tracks[i].st->index, last_track_id)
4963
2/2
✓ Branch 0 taken 269 times.
✓ Branch 1 taken 3 times.
272 : FFMAX(i, last_track_id)) + 1;
4964 }
4965 }
4966
4967 209 mov->track_ids_ok = 1;
4968
4969 209 return 0;
4970 }
4971
4972 237 static int mov_write_moov_tag(AVIOContext *pb, MOVMuxContext *mov,
4973 AVFormatContext *s)
4974 {
4975 int i;
4976 237 int64_t pos = avio_tell(pb);
4977 237 avio_wb32(pb, 0); /* size placeholder*/
4978 237 ffio_wfourcc(pb, "moov");
4979
4980 237 mov_setup_track_ids(mov, s);
4981
4982
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
4983
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))
4984 2 continue;
4985
4986 333 mov->tracks[i].time = mov->time;
4987
4988
2/2
✓ Branch 0 taken 307 times.
✓ Branch 1 taken 26 times.
333 if (mov->tracks[i].entry)
4989 307 build_chunks(&mov->tracks[i]);
4990 }
4991
4992
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
237 if (mov->chapter_track)
4993
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 for (i = 0; i < mov->nb_streams; i++) {
4994 1 mov->tracks[i].tref_tag = MKTAG('c','h','a','p');
4995 1 mov->tracks[i].tref_id = mov->tracks[mov->chapter_track].track_id;
4996 }
4997
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
4998 335 MOVTrack *track = &mov->tracks[i];
4999
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 333 times.
335 if (track->tag == MKTAG('r','t','p',' ')) {
5000 2 track->tref_tag = MKTAG('h','i','n','t');
5001 2 track->tref_id = mov->tracks[track->src_track].track_id;
5002
2/2
✓ Branch 0 taken 108 times.
✓ Branch 1 taken 225 times.
333 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5003 108 const AVPacketSideData *sd = av_packet_side_data_get(track->st->codecpar->coded_side_data,
5004 108 track->st->codecpar->nb_coded_side_data,
5005 AV_PKT_DATA_FALLBACK_TRACK );
5006
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)) {
5007 int *fallback = (int *)sd->data;
5008 if (*fallback >= 0 && *fallback < mov->nb_tracks) {
5009 track->tref_tag = MKTAG('f','a','l','l');
5010 track->tref_id = mov->tracks[*fallback].track_id;
5011 }
5012 }
5013 }
5014 }
5015
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5016
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 322 times.
335 if (mov->tracks[i].tag == MKTAG('t','m','c','d')) {
5017 13 int src_trk = mov->tracks[i].src_track;
5018 13 mov->tracks[src_trk].tref_tag = mov->tracks[i].tag;
5019 13 mov->tracks[src_trk].tref_id = mov->tracks[i].track_id;
5020 //src_trk may have a different timescale than the tmcd track
5021 13 mov->tracks[i].track_duration = av_rescale(mov->tracks[src_trk].track_duration,
5022 13 mov->tracks[i].timescale,
5023 13 mov->tracks[src_trk].timescale);
5024 }
5025 }
5026
5027 237 mov_write_mvhd_tag(pb, mov);
5028
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)
5029 mov_write_iods_tag(pb, mov);
5030
2/2
✓ Branch 0 taken 335 times.
✓ Branch 1 taken 237 times.
572 for (i = 0; i < mov->nb_tracks; i++) {
5031
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 ||
5032
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 mov->mode == MODE_AVIF) {
5033
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);
5034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 333 times.
333 if (ret < 0)
5035 return ret;
5036 }
5037 }
5038
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 181 times.
237 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5039 56 mov_write_mvex_tag(pb, mov); /* QuickTime requires trak to precede this */
5040
5041
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 236 times.
237 if (mov->mode == MODE_PSP)
5042 1 mov_write_uuidusmt_tag(pb, s);
5043
1/2
✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
236 else if (mov->mode != MODE_AVIF)
5044 236 mov_write_udta_tag(pb, mov, s);
5045
5046 237 return update_size(pb, pos);
5047 }
5048
5049 static void param_write_int(AVIOContext *pb, const char *name, int value)
5050 {
5051 avio_printf(pb, "<param name=\"%s\" value=\"%d\" valuetype=\"data\"/>\n", name, value);
5052 }
5053
5054 static void param_write_string(AVIOContext *pb, const char *name, const char *value)
5055 {
5056 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, value);
5057 }
5058
5059 static void param_write_hex(AVIOContext *pb, const char *name, const uint8_t *value, int len)
5060 {
5061 char buf[150];
5062 len = FFMIN(sizeof(buf) / 2 - 1, len);
5063 ff_data_to_hex(buf, value, len, 0);
5064 avio_printf(pb, "<param name=\"%s\" value=\"%s\" valuetype=\"data\"/>\n", name, buf);
5065 }
5066
5067 static int mov_write_isml_manifest(AVIOContext *pb, MOVMuxContext *mov, AVFormatContext *s)
5068 {
5069 int64_t pos = avio_tell(pb);
5070 int i;
5071
5072 static const AVUUID uuid = {
5073 0xa5, 0xd4, 0x0b, 0x30, 0xe8, 0x14, 0x11, 0xdd,
5074 0xba, 0x2f, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66
5075 };
5076
5077 avio_wb32(pb, 0);
5078 ffio_wfourcc(pb, "uuid");
5079 avio_write(pb, uuid, AV_UUID_LEN);
5080 avio_wb32(pb, 0);
5081
5082 avio_printf(pb, "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n");
5083 avio_printf(pb, "<smil xmlns=\"http://www.w3.org/2001/SMIL20/Language\">\n");
5084 avio_printf(pb, "<head>\n");
5085 if (!(mov->fc->flags & AVFMT_FLAG_BITEXACT))
5086 avio_printf(pb, "<meta name=\"creator\" content=\"%s\" />\n",
5087 LIBAVFORMAT_IDENT);
5088 avio_printf(pb, "</head>\n");
5089 avio_printf(pb, "<body>\n");
5090 avio_printf(pb, "<switch>\n");
5091
5092 mov_setup_track_ids(mov, s);
5093
5094 for (i = 0; i < mov->nb_tracks; i++) {
5095 MOVTrack *track = &mov->tracks[i];
5096 struct mpeg4_bit_rate_values bit_rates =
5097 calculate_mpeg4_bit_rates(track);
5098 const char *type;
5099 int track_id = track->track_id;
5100 char track_name_buf[32] = { 0 };
5101
5102 AVStream *st = track->st;
5103 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
5104
5105 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO && !is_cover_image(st)) {
5106 type = "video";
5107 } else if (track->par->codec_type == AVMEDIA_TYPE_AUDIO) {
5108 type = "audio";
5109 } else {
5110 continue;
5111 }
5112
5113 avio_printf(pb, "<%s systemBitrate=\"%"PRIu32"\">\n", type,
5114 bit_rates.avg_bit_rate);
5115 param_write_int(pb, "systemBitrate", bit_rates.avg_bit_rate);
5116 param_write_int(pb, "trackID", track_id);
5117 param_write_string(pb, "systemLanguage", lang ? lang->value : "und");
5118
5119 /* Build track name piece by piece: */
5120 /* 1. track type */
5121 av_strlcat(track_name_buf, type, sizeof(track_name_buf));
5122 /* 2. track language, if available */
5123 if (lang)
5124 av_strlcatf(track_name_buf, sizeof(track_name_buf),
5125 "_%s", lang->value);
5126 /* 3. special type suffix */
5127 /* "_cc" = closed captions, "_ad" = audio_description */
5128 if (st->disposition & AV_DISPOSITION_HEARING_IMPAIRED)
5129 av_strlcat(track_name_buf, "_cc", sizeof(track_name_buf));
5130 else if (st->disposition & AV_DISPOSITION_VISUAL_IMPAIRED)
5131 av_strlcat(track_name_buf, "_ad", sizeof(track_name_buf));
5132
5133 param_write_string(pb, "trackName", track_name_buf);
5134
5135 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
5136 if (track->par->codec_id == AV_CODEC_ID_H264) {
5137 uint8_t *ptr;
5138 int size = track->par->extradata_size;
5139 if (!ff_avc_write_annexb_extradata(track->par->extradata, &ptr,
5140 &size)) {
5141 param_write_hex(pb, "CodecPrivateData",
5142 ptr ? ptr : track->par->extradata,
5143 size);
5144 av_free(ptr);
5145 }
5146 param_write_string(pb, "FourCC", "H264");
5147 } else if (track->par->codec_id == AV_CODEC_ID_VC1) {
5148 param_write_string(pb, "FourCC", "WVC1");
5149 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5150 track->par->extradata_size);
5151 }
5152 param_write_int(pb, "MaxWidth", track->par->width);
5153 param_write_int(pb, "MaxHeight", track->par->height);
5154 param_write_int(pb, "DisplayWidth", track->par->width);
5155 param_write_int(pb, "DisplayHeight", track->par->height);
5156 } else {
5157 if (track->par->codec_id == AV_CODEC_ID_AAC) {
5158 switch (track->par->profile) {
5159 case AV_PROFILE_AAC_HE_V2:
5160 param_write_string(pb, "FourCC", "AACP");
5161 break;
5162 case AV_PROFILE_AAC_HE:
5163 param_write_string(pb, "FourCC", "AACH");
5164 break;
5165 default:
5166 param_write_string(pb, "FourCC", "AACL");
5167 }
5168 } else if (track->par->codec_id == AV_CODEC_ID_WMAPRO) {
5169 param_write_string(pb, "FourCC", "WMAP");
5170 }
5171 param_write_hex(pb, "CodecPrivateData", track->par->extradata,
5172 track->par->extradata_size);
5173 param_write_int(pb, "AudioTag", ff_codec_get_tag(ff_codec_wav_tags,
5174 track->par->codec_id));
5175 param_write_int(pb, "Channels", track->par->ch_layout.nb_channels);
5176 param_write_int(pb, "SamplingRate", track->tag == MKTAG('i','a','m','f') ?
5177 0 : track->par->sample_rate);
5178 param_write_int(pb, "BitsPerSample", 16);
5179 param_write_int(pb, "PacketSize", track->par->block_align ?
5180 track->par->block_align : 4);
5181 }
5182 avio_printf(pb, "</%s>\n", type);
5183 }
5184 avio_printf(pb, "</switch>\n");
5185 avio_printf(pb, "</body>\n");
5186 avio_printf(pb, "</smil>\n");
5187
5188 return update_size(pb, pos);
5189 }
5190
5191 142 static int mov_write_mfhd_tag(AVIOContext *pb, MOVMuxContext *mov)
5192 {
5193 142 avio_wb32(pb, 16);
5194 142 ffio_wfourcc(pb, "mfhd");
5195 142 avio_wb32(pb, 0);
5196 142 avio_wb32(pb, mov->fragments);
5197 142 return 0;
5198 }
5199
5200 10742 static uint32_t get_sample_flags(MOVTrack *track, MOVIentry *entry)
5201 {
5202
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 :
5203 (MOV_FRAG_SAMPLE_FLAG_DEPENDS_YES | MOV_FRAG_SAMPLE_FLAG_IS_NON_SYNC);
5204 }
5205
5206 234 static int mov_write_tfhd_tag(AVIOContext *pb, MOVMuxContext *mov,
5207 MOVTrack *track, int64_t moof_offset)
5208 {
5209 234 int64_t pos = avio_tell(pb);
5210 234 uint32_t flags = MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5211 MOV_TFHD_BASE_DATA_OFFSET;
5212
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (!track->entry) {
5213 flags |= MOV_TFHD_DURATION_IS_EMPTY;
5214 } else {
5215 234 flags |= MOV_TFHD_DEFAULT_FLAGS;
5216 }
5217
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET)
5218 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5219
2/2
✓ Branch 0 taken 78 times.
✓ Branch 1 taken 156 times.
234 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) {
5220 78 flags &= ~MOV_TFHD_BASE_DATA_OFFSET;
5221 78 flags |= MOV_TFHD_DEFAULT_BASE_IS_MOOF;
5222 }
5223 /* CMAF requires all values to be explicit in tfhd atoms */
5224
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 226 times.
234 if (mov->flags & FF_MOV_FLAG_CMAF)
5225 8 flags |= MOV_TFHD_STSD_ID;
5226
5227 /* Don't set a default sample size, the silverlight player refuses
5228 * to play files with that set. Don't set a default sample duration,
5229 * WMP freaks out if it is set. Don't set a base data offset, PIFF
5230 * file format says it MUST NOT be set. */
5231
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (track->mode == MODE_ISM)
5232 30 flags &= ~(MOV_TFHD_DEFAULT_SIZE | MOV_TFHD_DEFAULT_DURATION |
5233 MOV_TFHD_BASE_DATA_OFFSET | MOV_TFHD_STSD_ID);
5234
5235 234 avio_wb32(pb, 0); /* size placeholder */
5236 234 ffio_wfourcc(pb, "tfhd");
5237 234 avio_w8(pb, 0); /* version */
5238 234 avio_wb24(pb, flags);
5239
5240 234 avio_wb32(pb, track->track_id); /* track-id */
5241
2/2
✓ Branch 0 taken 126 times.
✓ Branch 1 taken 108 times.
234 if (flags & MOV_TFHD_BASE_DATA_OFFSET)
5242 126 avio_wb64(pb, moof_offset);
5243
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 226 times.
234 if (flags & MOV_TFHD_STSD_ID) {
5244 8 avio_wb32(pb, 1);
5245 }
5246
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (flags & MOV_TFHD_DEFAULT_DURATION) {
5247 204 track->default_duration = get_cluster_duration(track, 0);
5248 204 avio_wb32(pb, track->default_duration);
5249 }
5250
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (flags & MOV_TFHD_DEFAULT_SIZE) {
5251
1/2
✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
204 track->default_size = track->entry ? track->cluster[0].size : 1;
5252 204 avio_wb32(pb, track->default_size);
5253 } else
5254 30 track->default_size = -1;
5255
5256
1/2
✓ Branch 0 taken 234 times.
✗ Branch 1 not taken.
234 if (flags & MOV_TFHD_DEFAULT_FLAGS) {
5257 /* Set the default flags based on the second sample, if available.
5258 * If the first sample is different, that can be signaled via a separate field. */
5259
2/2
✓ Branch 0 taken 224 times.
✓ Branch 1 taken 10 times.
234 if (track->entry > 1)
5260 224 track->default_sample_flags = get_sample_flags(track, &track->cluster[1]);
5261 else
5262 10 track->default_sample_flags =
5263 10 track->par->codec_type == AVMEDIA_TYPE_VIDEO ?
5264
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) :
5265 MOV_FRAG_SAMPLE_FLAG_DEPENDS_NO;
5266 234 avio_wb32(pb, track->default_sample_flags);
5267 }
5268
5269 234 return update_size(pb, pos);
5270 }
5271
5272 234 static int mov_write_trun_tag(AVIOContext *pb, MOVMuxContext *mov,
5273 MOVTrack *track, int moof_size,
5274 int first, int end)
5275 {
5276 234 int64_t pos = avio_tell(pb);
5277 234 uint32_t flags = MOV_TRUN_DATA_OFFSET;
5278 int i;
5279
5280
2/2
✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 234 times.
10278 for (i = first; i < end; i++) {
5281
2/2
✓ Branch 1 taken 618 times.
✓ Branch 2 taken 9426 times.
10044 if (get_cluster_duration(track, i) != track->default_duration)
5282 618 flags |= MOV_TRUN_SAMPLE_DURATION;
5283
2/2
✓ Branch 0 taken 500 times.
✓ Branch 1 taken 9544 times.
10044 if (track->cluster[i].size != track->default_size)
5284 500 flags |= MOV_TRUN_SAMPLE_SIZE;
5285
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)
5286 10 flags |= MOV_TRUN_SAMPLE_FLAGS;
5287 }
5288
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 &&
5289
2/2
✓ Branch 1 taken 110 times.
✓ Branch 2 taken 116 times.
226 get_sample_flags(track, &track->cluster[first]) != track->default_sample_flags)
5290 110 flags |= MOV_TRUN_FIRST_SAMPLE_FLAGS;
5291
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 166 times.
234 if (track->flags & MOV_TRACK_CTTS)
5292 68 flags |= MOV_TRUN_SAMPLE_CTS;
5293
5294 234 avio_wb32(pb, 0); /* size placeholder */
5295 234 ffio_wfourcc(pb, "trun");
5296
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 180 times.
234 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5297 54 avio_w8(pb, 1); /* version */
5298 else
5299 180 avio_w8(pb, 0); /* version */
5300 234 avio_wb24(pb, flags);
5301
5302 234 avio_wb32(pb, end - first); /* sample count */
5303
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 234 times.
234 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
5304 !(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF) &&
5305 !mov->first_trun)
5306 avio_wb32(pb, 0); /* Later tracks follow immediately after the previous one */
5307 else
5308 234 avio_wb32(pb, moof_size + 8 + track->data_offset +
5309 234 track->cluster[first].pos); /* data offset */
5310
2/2
✓ Branch 0 taken 110 times.
✓ Branch 1 taken 124 times.
234 if (flags & MOV_TRUN_FIRST_SAMPLE_FLAGS)
5311 110 avio_wb32(pb, get_sample_flags(track, &track->cluster[first]));
5312
5313
2/2
✓ Branch 0 taken 10044 times.
✓ Branch 1 taken 234 times.
10278 for (i = first; i < end; i++) {
5314
2/2
✓ Branch 0 taken 722 times.
✓ Branch 1 taken 9322 times.
10044 if (flags & MOV_TRUN_SAMPLE_DURATION)
5315 722 avio_wb32(pb, get_cluster_duration(track, i));
5316
2/2
✓ Branch 0 taken 1064 times.
✓ Branch 1 taken 8980 times.
10044 if (flags & MOV_TRUN_SAMPLE_SIZE)
5317 1064 avio_wb32(pb, track->cluster[i].size);
5318
2/2
✓ Branch 0 taken 372 times.
✓ Branch 1 taken 9672 times.
10044 if (flags & MOV_TRUN_SAMPLE_FLAGS)
5319 372 avio_wb32(pb, get_sample_flags(track, &track->cluster[i]));
5320
2/2
✓ Branch 0 taken 1980 times.
✓ Branch 1 taken 8064 times.
10044 if (flags & MOV_TRUN_SAMPLE_CTS)
5321 1980 avio_wb32(pb, track->cluster[i].cts);
5322 }
5323
5324 234 mov->first_trun = 0;
5325 234 return update_size(pb, pos);
5326 }
5327
5328 30 static int mov_write_tfxd_tag(AVIOContext *pb, MOVTrack *track)
5329 {
5330 30 int64_t pos = avio_tell(pb);
5331 static const uint8_t uuid[] = {
5332 0x6d, 0x1d, 0x9b, 0x05, 0x42, 0xd5, 0x44, 0xe6,
5333 0x80, 0xe2, 0x14, 0x1d, 0xaf, 0xf7, 0x57, 0xb2
5334 };
5335
5336 30 avio_wb32(pb, 0); /* size placeholder */
5337 30 ffio_wfourcc(pb, "uuid");
5338 30 avio_write(pb, uuid, AV_UUID_LEN);
5339 30 avio_w8(pb, 1);
5340 30 avio_wb24(pb, 0);
5341 30 avio_wb64(pb, track->cluster[0].dts + track->cluster[0].cts);
5342 30 avio_wb64(pb, track->end_pts -
5343 30 (track->cluster[0].dts + track->cluster[0].cts));
5344
5345 30 return update_size(pb, pos);
5346 }
5347
5348 static int mov_write_tfrf_tag(AVIOContext *pb, MOVMuxContext *mov,
5349 MOVTrack *track, int entry)
5350 {
5351 int n = track->nb_frag_info - 1 - entry, i;
5352 int size = 8 + 16 + 4 + 1 + 16*n;
5353 static const uint8_t uuid[] = {
5354 0xd4, 0x80, 0x7e, 0xf2, 0xca, 0x39, 0x46, 0x95,
5355 0x8e, 0x54, 0x26, 0xcb, 0x9e, 0x46, 0xa7, 0x9f
5356 };
5357
5358 if (entry < 0)
5359 return 0;
5360
5361 avio_seek(pb, track->frag_info[entry].tfrf_offset, SEEK_SET);
5362 avio_wb32(pb, size);
5363 ffio_wfourcc(pb, "uuid");
5364 avio_write(pb, uuid, AV_UUID_LEN);
5365 avio_w8(pb, 1);
5366 avio_wb24(pb, 0);
5367 avio_w8(pb, n);
5368 for (i = 0; i < n; i++) {
5369 int index = entry + 1 + i;
5370 avio_wb64(pb, track->frag_info[index].time);
5371 avio_wb64(pb, track->frag_info[index].duration);
5372 }
5373 if (n < mov->ism_lookahead) {
5374 int free_size = 16 * (mov->ism_lookahead - n);
5375 avio_wb32(pb, free_size);
5376 ffio_wfourcc(pb, "free");
5377 ffio_fill(pb, 0, free_size - 8);
5378 }
5379
5380 return 0;
5381 }
5382
5383 117 static int mov_write_tfrf_tags(AVIOContext *pb, MOVMuxContext *mov,
5384 MOVTrack *track)
5385 {
5386 117 int64_t pos = avio_tell(pb);
5387 int i;
5388
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 for (i = 0; i < mov->ism_lookahead; i++) {
5389 /* Update the tfrf tag for the last ism_lookahead fragments,
5390 * nb_frag_info - 1 is the next fragment to be written. */
5391 mov_write_tfrf_tag(pb, mov, track, track->nb_frag_info - 2 - i);
5392 }
5393 117 avio_seek(pb, pos, SEEK_SET);
5394 117 return 0;
5395 }
5396
5397 71 static int mov_add_tfra_entries(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5398 int size)
5399 {
5400 int i;
5401
2/2
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 71 times.
204 for (i = 0; i < mov->nb_tracks; i++) {
5402 133 MOVTrack *track = &mov->tracks[i];
5403 MOVFragmentInfo *info;
5404
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)
5405 16 continue;
5406 117 track->nb_frag_info++;
5407
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 54 times.
117 if (track->nb_frag_info >= track->frag_info_capacity) {
5408 63 unsigned new_capacity = track->nb_frag_info + MOV_FRAG_INFO_ALLOC_INCREMENT;
5409
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 63 times.
63 if (av_reallocp_array(&track->frag_info,
5410 new_capacity,
5411 sizeof(*track->frag_info)))
5412 return AVERROR(ENOMEM);
5413 63 track->frag_info_capacity = new_capacity;
5414 }
5415 117 info = &track->frag_info[track->nb_frag_info - 1];
5416 117 info->offset = avio_tell(pb);
5417 117 info->size = size;
5418 // Try to recreate the original pts for the first packet
5419 // from the fields we have stored
5420 117 info->time = track->cluster[0].dts + track->cluster[0].cts;
5421 117 info->duration = track->end_pts -
5422 117 (track->cluster[0].dts + track->cluster[0].cts);
5423 // If the pts is less than zero, we will have trimmed
5424 // away parts of the media track using an edit list,
5425 // and the corresponding start presentation time is zero.
5426
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 109 times.
117 if (info->time < 0) {
5427 8 info->duration += info->time;
5428 8 info->time = 0;
5429 }
5430 117 info->tfrf_offset = 0;
5431 117 mov_write_tfrf_tags(pb, mov, track);
5432 }
5433 71 return 0;
5434 }
5435
5436 static void mov_prune_frag_info(MOVMuxContext *mov, int tracks, int max)
5437 {
5438 int i;
5439 for (i = 0; i < mov->nb_tracks; i++) {
5440 MOVTrack *track = &mov->tracks[i];
5441 if ((tracks >= 0 && i != tracks) || !track->entry)
5442 continue;
5443 if (track->nb_frag_info > max) {
5444 memmove(track->frag_info, track->frag_info + (track->nb_frag_info - max), max * sizeof(*track->frag_info));
5445 track->nb_frag_info = max;
5446 }
5447 }
5448 }
5449
5450 204 static int mov_write_tfdt_tag(AVIOContext *pb, MOVTrack *track)
5451 {
5452 204 int64_t pos = avio_tell(pb);
5453
5454 204 avio_wb32(pb, 0); /* size */
5455 204 ffio_wfourcc(pb, "tfdt");
5456 204 avio_w8(pb, 1); /* version */
5457 204 avio_wb24(pb, 0);
5458 204 avio_wb64(pb, track->cluster[0].dts - track->start_dts);
5459 204 return update_size(pb, pos);
5460 }
5461
5462 234 static int mov_write_traf_tag(AVIOContext *pb, MOVMuxContext *mov,
5463 MOVTrack *track, int64_t moof_offset,
5464 int moof_size)
5465 {
5466 234 int64_t pos = avio_tell(pb);
5467 234 int i, start = 0;
5468 234 avio_wb32(pb, 0); /* size placeholder */
5469 234 ffio_wfourcc(pb, "traf");
5470
5471 234 mov_write_tfhd_tag(pb, mov, track, moof_offset);
5472
2/2
✓ Branch 0 taken 204 times.
✓ Branch 1 taken 30 times.
234 if (mov->mode != MODE_ISM)
5473 204 mov_write_tfdt_tag(pb, track);
5474
2/2
✓ Branch 0 taken 9810 times.
✓ Branch 1 taken 234 times.
10044 for (i = 1; i < track->entry; i++) {
5475
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) {
5476 mov_write_trun_tag(pb, mov, track, moof_size, start, i);
5477 start = i;
5478 }
5479 }
5480 234 mov_write_trun_tag(pb, mov, track, moof_size, start, track->entry);
5481
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 204 times.
234 if (mov->mode == MODE_ISM) {
5482 30 mov_write_tfxd_tag(pb, track);
5483
5484
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
30 if (mov->ism_lookahead) {
5485 int size = 16 + 4 + 1 + 16 * mov->ism_lookahead;
5486
5487 if (track->nb_frag_info > 0) {
5488 MOVFragmentInfo *info = &track->frag_info[track->nb_frag_info - 1];
5489 if (!info->tfrf_offset)
5490 info->tfrf_offset = avio_tell(pb);
5491 }
5492 avio_wb32(pb, 8 + size);
5493 ffio_wfourcc(pb, "free");
5494 ffio_fill(pb, 0, size);
5495 }
5496 }
5497
5498 234 return update_size(pb, pos);
5499 }
5500
5501 142 static int mov_write_moof_tag_internal(AVIOContext *pb, MOVMuxContext *mov,
5502 int tracks, int moof_size)
5503 {
5504 142 int64_t pos = avio_tell(pb);
5505 int i;
5506
5507 142 avio_wb32(pb, 0); /* size placeholder */
5508 142 ffio_wfourcc(pb, "moof");
5509 142 mov->first_trun = 1;
5510
5511 142 mov_write_mfhd_tag(pb, mov);
5512
2/2
✓ Branch 0 taken 266 times.
✓ Branch 1 taken 142 times.
408 for (i = 0; i < mov->nb_tracks; i++) {
5513 266 MOVTrack *track = &mov->tracks[i];
5514
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)
5515 24 continue;
5516
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 234 times.
242 if (!track->entry)
5517 8 continue;
5518 234 mov_write_traf_tag(pb, mov, track, pos, moof_size);
5519 }
5520
5521 142 return update_size(pb, pos);
5522 }
5523
5524 70 static int mov_write_sidx_tag(AVIOContext *pb,
5525 MOVTrack *track, int ref_size, int total_sidx_size)
5526 {
5527 70 int64_t pos = avio_tell(pb), offset_pos, end_pos;
5528 int64_t presentation_time, duration, offset;
5529 unsigned starts_with_SAP;
5530 int i, entries;
5531
5532
1/2
✓ Branch 0 taken 70 times.
✗ Branch 1 not taken.
70 if (track->entry) {
5533 70 entries = 1;
5534 70 presentation_time = track->cluster[0].dts + track->cluster[0].cts -
5535 70 track->start_dts - track->start_cts;
5536 70 duration = track->end_pts -
5537 70 (track->cluster[0].dts + track->cluster[0].cts);
5538 70 starts_with_SAP = track->cluster[0].flags & MOV_SYNC_SAMPLE;
5539
5540 // pts<0 should be cut away using edts
5541
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (presentation_time < 0) {
5542 duration += presentation_time;
5543 presentation_time = 0;
5544 }
5545 } else {
5546 entries = track->nb_frag_info;
5547 if (entries <= 0)
5548 return 0;
5549 presentation_time = track->frag_info[0].time;
5550 /* presentation_time <= 0 is handled by mov_add_tfra_entries() */
5551 if (presentation_time > 0)
5552 presentation_time -= track->start_dts + track->start_cts;
5553 }
5554
5555 70 avio_wb32(pb, 0); /* size */
5556 70 ffio_wfourcc(pb, "sidx");
5557 70 avio_w8(pb, 1); /* version */
5558 70 avio_wb24(pb, 0);
5559 70 avio_wb32(pb, track->track_id); /* reference_ID */
5560 70 avio_wb32(pb, track->timescale); /* timescale */
5561 70 avio_wb64(pb, presentation_time); /* earliest_presentation_time */
5562 70 offset_pos = avio_tell(pb);
5563 70 avio_wb64(pb, 0); /* first_offset (offset to referenced moof) */
5564 70 avio_wb16(pb, 0); /* reserved */
5565
5566 70 avio_wb16(pb, entries); /* reference_count */
5567
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 70 times.
140 for (i = 0; i < entries; i++) {
5568
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 70 times.
70 if (!track->entry) {
5569 if (i > 1 && track->frag_info[i].offset != track->frag_info[i - 1].offset + track->frag_info[i - 1].size) {
5570 av_log(NULL, AV_LOG_ERROR, "Non-consecutive fragments, writing incorrect sidx\n");
5571 }
5572 duration = track->frag_info[i].duration;
5573 ref_size = track->frag_info[i].size;
5574 starts_with_SAP = 1;
5575 }
5576 70 avio_wb32(pb, (0 << 31) | (ref_size & 0x7fffffff)); /* reference_type (0 = media) | referenced_size */
5577 70 avio_wb32(pb, duration); /* subsegment_duration */
5578 70 avio_wb32(pb, (starts_with_SAP << 31) | (0 << 28) | 0); /* starts_with_SAP | SAP_type | SAP_delta_time */
5579 }
5580
5581 70 end_pos = avio_tell(pb);
5582 70 offset = pos + total_sidx_size - end_pos;
5583 70 avio_seek(pb, offset_pos, SEEK_SET);
5584 70 avio_wb64(pb, offset);
5585 70 avio_seek(pb, end_pos, SEEK_SET);
5586 70 return update_size(pb, pos);
5587 }
5588
5589 20 static int mov_write_sidx_tags(AVIOContext *pb, MOVMuxContext *mov,
5590 int tracks, int ref_size)
5591 {
5592 int i, round, ret;
5593 AVIOContext *avio_buf;
5594 20 int total_size = 0;
5595
2/2
✓ Branch 0 taken 40 times.
✓ Branch 1 taken 20 times.
60 for (round = 0; round < 2; round++) {
5596 // First run one round to calculate the total size of all
5597 // sidx atoms.
5598 // This would be much simpler if we'd only write one sidx
5599 // atom, for the first track in the moof.
5600
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0) {
5601
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 20 times.
20 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5602 return ret;
5603 } else {
5604 20 avio_buf = pb;
5605 }
5606
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 40 times.
110 for (i = 0; i < mov->nb_tracks; i++) {
5607 70 MOVTrack *track = &mov->tracks[i];
5608
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)
5609 continue;
5610 // When writing a sidx for the full file, entry is 0, but
5611 // we want to include all tracks. ref_size is 0 in this case,
5612 // since we read it from frag_info instead.
5613
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)
5614 continue;
5615 70 total_size -= mov_write_sidx_tag(avio_buf, track, ref_size,
5616 total_size);
5617 }
5618
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 20 times.
40 if (round == 0)
5619 20 total_size = ffio_close_null_buf(avio_buf);
5620 }
5621 20 return 0;
5622 }
5623
5624 static int mov_write_prft_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks)
5625 {
5626 int64_t pos = avio_tell(pb), pts_us, ntp_ts;
5627 MOVTrack *first_track;
5628 int flags = 24;
5629
5630 /* PRFT should be associated with at most one track. So, choosing only the
5631 * first track. */
5632 if (tracks > 0)
5633 return 0;
5634 first_track = &(mov->tracks[0]);
5635
5636 if (!first_track->entry) {
5637 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, no entries in the track\n");
5638 return 0;
5639 }
5640
5641 if (first_track->cluster[0].pts == AV_NOPTS_VALUE) {
5642 av_log(mov->fc, AV_LOG_WARNING, "Unable to write PRFT, first PTS is invalid\n");
5643 return 0;
5644 }
5645
5646 if (mov->write_prft == MOV_PRFT_SRC_WALLCLOCK) {
5647 if (first_track->cluster[0].prft.wallclock) {
5648 /* Round the NTP time to whole milliseconds. */
5649 ntp_ts = ff_get_formatted_ntp_time((first_track->cluster[0].prft.wallclock / 1000) * 1000 +
5650 NTP_OFFSET_US);
5651 flags = first_track->cluster[0].prft.flags;
5652 } else
5653 ntp_ts = ff_get_formatted_ntp_time(ff_ntp_time());
5654 } else if (mov->write_prft == MOV_PRFT_SRC_PTS) {
5655 pts_us = av_rescale_q(first_track->cluster[0].pts,
5656 first_track->st->time_base, AV_TIME_BASE_Q);
5657 ntp_ts = ff_get_formatted_ntp_time(pts_us + NTP_OFFSET_US);
5658 } else {
5659 av_log(mov->fc, AV_LOG_WARNING, "Unsupported PRFT box configuration: %d\n",
5660 mov->write_prft);
5661 return 0;
5662 }
5663
5664 avio_wb32(pb, 0); // Size place holder
5665 ffio_wfourcc(pb, "prft"); // Type
5666 avio_w8(pb, 1); // Version
5667 avio_wb24(pb, flags); // Flags
5668 avio_wb32(pb, first_track->track_id); // reference track ID
5669 avio_wb64(pb, ntp_ts); // NTP time stamp
5670 avio_wb64(pb, first_track->cluster[0].pts); //media time
5671 return update_size(pb, pos);
5672 }
5673
5674 71 static int mov_write_moof_tag(AVIOContext *pb, MOVMuxContext *mov, int tracks,
5675 int64_t mdat_size)
5676 {
5677 AVIOContext *avio_buf;
5678 int ret, moof_size;
5679
5680
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 71 times.
71 if ((ret = ffio_open_null_buf(&avio_buf)) < 0)
5681 return ret;
5682 71 mov_write_moof_tag_internal(avio_buf, mov, tracks, 0);
5683 71 moof_size = ffio_close_null_buf(avio_buf);
5684
5685
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 51 times.
71 if (mov->flags & FF_MOV_FLAG_DASH &&
5686
1/2
✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
20 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX)))
5687 20 mov_write_sidx_tags(pb, mov, tracks, moof_size + 8 + mdat_size);
5688
5689
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)
5690 mov_write_prft_tag(pb, mov, tracks);
5691
5692
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX ||
5693
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 !(mov->flags & FF_MOV_FLAG_SKIP_TRAILER) ||
5694 mov->ism_lookahead) {
5695
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)
5696 return ret;
5697
1/2
✓ Branch 0 taken 71 times.
✗ Branch 1 not taken.
71 if (!(mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) &&
5698
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 71 times.
71 mov->flags & FF_MOV_FLAG_SKIP_TRAILER) {
5699 mov_prune_frag_info(mov, tracks, mov->ism_lookahead + 1);
5700 }
5701 }
5702
5703 71 return mov_write_moof_tag_internal(pb, mov, tracks, moof_size);
5704 }
5705
5706 61 static int mov_write_tfra_tag(AVIOContext *pb, MOVTrack *track)
5707 {
5708 61 int64_t pos = avio_tell(pb);
5709 int i;
5710
5711 61 avio_wb32(pb, 0); /* size placeholder */
5712 61 ffio_wfourcc(pb, "tfra");
5713 61 avio_w8(pb, 1); /* version */
5714 61 avio_wb24(pb, 0);
5715
5716 61 avio_wb32(pb, track->track_id);
5717 61 avio_wb32(pb, 0); /* length of traf/trun/sample num */
5718 61 avio_wb32(pb, track->nb_frag_info);
5719
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 61 times.
175 for (i = 0; i < track->nb_frag_info; i++) {
5720 114 avio_wb64(pb, track->frag_info[i].time);
5721 114 avio_wb64(pb, track->frag_info[i].offset + track->data_offset);
5722 114 avio_w8(pb, 1); /* traf number */
5723 114 avio_w8(pb, 1); /* trun number */
5724 114 avio_w8(pb, 1); /* sample number */
5725 }
5726
5727 61 return update_size(pb, pos);
5728 }
5729
5730 33 static int mov_write_mfra_tag(AVIOContext *pb, MOVMuxContext *mov)
5731 {
5732 AVIOContext *mfra_pb;
5733 int i, ret, sz;
5734 uint8_t *buf;
5735
5736 33 ret = avio_open_dyn_buf(&mfra_pb);
5737
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (ret < 0)
5738 return ret;
5739
5740 33 avio_wb32(mfra_pb, 0); /* size placeholder */
5741 33 ffio_wfourcc(mfra_pb, "mfra");
5742 /* An empty mfra atom is enough to indicate to the publishing point that
5743 * the stream has ended. */
5744
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_ISML)
5745 goto done_mfra;
5746
5747
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++) {
5748 63 MOVTrack *track = &mov->tracks[i];
5749
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 2 times.
63 if (track->nb_frag_info)
5750 61 mov_write_tfra_tag(mfra_pb, track);
5751 }
5752
5753 33 avio_wb32(mfra_pb, 16);
5754 33 ffio_wfourcc(mfra_pb, "mfro");
5755 33 avio_wb32(mfra_pb, 0); /* version + flags */
5756 33 avio_wb32(mfra_pb, avio_tell(mfra_pb) + 4);
5757
5758 33 done_mfra:
5759
5760 33 sz = update_size(mfra_pb, 0);
5761 33 ret = avio_get_dyn_buf(mfra_pb, &buf);
5762 33 avio_write(pb, buf, ret);
5763 33 ffio_free_dyn_buf(&mfra_pb);
5764
5765 33 return sz;
5766 }
5767
5768 175 static int mov_write_mdat_tag(AVIOContext *pb, MOVMuxContext *mov)
5769 {
5770 175 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
5771
2/2
✓ Branch 0 taken 145 times.
✓ Branch 1 taken 30 times.
175 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
5772
5773 175 mov->mdat_pos = avio_tell(pb);
5774 175 avio_wb32(pb, 0); /* size placeholder*/
5775 175 ffio_wfourcc(pb, "mdat");
5776 175 return 0;
5777 }
5778
5779 418 static void mov_write_ftyp_tag_internal(AVIOContext *pb, AVFormatContext *s,
5780 int has_h264, int has_video, int write_minor)
5781 {
5782 418 MOVMuxContext *mov = s->priv_data;
5783 418 int minor = 0x200;
5784
5785
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)
5786 ffio_wfourcc(pb, mov->major_brand);
5787
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 else if (mov->mode == MODE_3GP) {
5788 ffio_wfourcc(pb, has_h264 ? "3gp6" : "3gp4");
5789 minor = has_h264 ? 0x100 : 0x200;
5790
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 } else if (mov->mode == MODE_AVIF) {
5791 ffio_wfourcc(pb, mov->is_animated_avif ? "avis" : "avif");
5792 minor = 0;
5793
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 418 times.
418 } else if (mov->mode & MODE_3G2) {
5794 ffio_wfourcc(pb, has_h264 ? "3g2b" : "3g2a");
5795 minor = has_h264 ? 0x20000 : 0x10000;
5796
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 416 times.
418 } else if (mov->mode == MODE_PSP)
5797 2 ffio_wfourcc(pb, "MSNV");
5798
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 &&
5799
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 52 times.
58 mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5800 6 ffio_wfourcc(pb, "iso6"); // Required when using signed CTS offsets in trun boxes
5801
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)
5802 22 ffio_wfourcc(pb, "iso5"); // Required when using default-base-is-moof
5803
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)
5804 ffio_wfourcc(pb, "iso4");
5805
2/2
✓ Branch 0 taken 86 times.
✓ Branch 1 taken 302 times.
388 else if (mov->mode == MODE_MP4)
5806 86 ffio_wfourcc(pb, "isom");
5807
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 300 times.
302 else if (mov->mode == MODE_IPOD)
5808
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 ffio_wfourcc(pb, has_video ? "M4V ":"M4A ");
5809
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 292 times.
300 else if (mov->mode == MODE_ISM)
5810 8 ffio_wfourcc(pb, "isml");
5811
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 292 times.
292 else if (mov->mode == MODE_F4V)
5812 ffio_wfourcc(pb, "f4v ");
5813 else
5814 292 ffio_wfourcc(pb, "qt ");
5815
5816
2/2
✓ Branch 0 taken 209 times.
✓ Branch 1 taken 209 times.
418 if (write_minor)
5817 209 avio_wb32(pb, minor);
5818 418 }
5819
5820 209 static int mov_write_ftyp_tag(AVIOContext *pb, AVFormatContext *s)
5821 {
5822 209 MOVMuxContext *mov = s->priv_data;
5823 209 int64_t pos = avio_tell(pb);
5824 209 int has_h264 = 0, has_av1 = 0, has_video = 0, has_dolby = 0, has_id3 = 0;
5825 209 int has_iamf = 0;
5826
5827 #if CONFIG_IAMFENC
5828
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 204 times.
209 for (int i = 0; i < s->nb_stream_groups; i++) {
5829 5 const AVStreamGroup *stg = s->stream_groups[i];
5830
5831
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT ||
5832 stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION) {
5833 5 has_iamf = 1;
5834 5 break;
5835 }
5836 }
5837 #endif
5838
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (int i = 0; i < mov->nb_streams; i++) {
5839 267 AVStream *st = mov->tracks[i].st;
5840
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 265 times.
267 if (is_cover_image(st))
5841 2 continue;
5842
2/2
✓ Branch 0 taken 178 times.
✓ Branch 1 taken 87 times.
265 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
5843 178 has_video = 1;
5844
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 231 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_H264)
5845 34 has_h264 = 1;
5846
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 264 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_AV1)
5847 1 has_av1 = 1;
5848
2/2
✓ Branch 0 taken 261 times.
✓ Branch 1 taken 4 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_AC3 ||
5849
2/2
✓ Branch 0 taken 260 times.
✓ Branch 1 taken 1 times.
261 st->codecpar->codec_id == AV_CODEC_ID_EAC3 ||
5850
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 ||
5851 260 av_packet_side_data_get(st->codecpar->coded_side_data,
5852 260 st->codecpar->nb_coded_side_data,
5853 AV_PKT_DATA_DOVI_CONF))
5854 5 has_dolby = 1;
5855
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 265 times.
265 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3)
5856 has_id3 = 1;
5857 }
5858
5859 209 avio_wb32(pb, 0); /* size */
5860 209 ffio_wfourcc(pb, "ftyp");
5861
5862 // Write major brand
5863 209 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 1);
5864 // Write the major brand as the first compatible brand as well
5865 209 mov_write_ftyp_tag_internal(pb, s, has_h264, has_video, 0);
5866
5867 // Write compatible brands, ensuring that we don't write the major brand as a
5868 // compatible brand a second time.
5869
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (mov->mode == MODE_ISM) {
5870 4 ffio_wfourcc(pb, "piff");
5871
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
205 } else if (mov->mode == MODE_AVIF) {
5872 const AVPixFmtDescriptor *pix_fmt_desc =
5873 av_pix_fmt_desc_get(s->streams[0]->codecpar->format);
5874 const int depth = pix_fmt_desc->comp[0].depth;
5875 if (mov->is_animated_avif) {
5876 // For animated AVIF, major brand is "avis". Add "avif" as a
5877 // compatible brand.
5878 ffio_wfourcc(pb, "avif");
5879 ffio_wfourcc(pb, "msf1");
5880 ffio_wfourcc(pb, "iso8");
5881 }
5882 ffio_wfourcc(pb, "mif1");
5883 ffio_wfourcc(pb, "miaf");
5884 if (depth == 8 || depth == 10) {
5885 // MA1B and MA1A brands are based on AV1 profile. Short hand for
5886 // computing that is based on chroma subsampling type. 420 chroma
5887 // subsampling is MA1B. 444 chroma subsampling is MA1A.
5888 if (!pix_fmt_desc->log2_chroma_w && !pix_fmt_desc->log2_chroma_h) {
5889 // 444 chroma subsampling.
5890 ffio_wfourcc(pb, "MA1A");
5891 } else {
5892 // 420 chroma subsampling.
5893 ffio_wfourcc(pb, "MA1B");
5894 }
5895 }
5896
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 146 times.
205 } else if (mov->mode != MODE_MOV) {
5897 // We add tfdt atoms when fragmenting, signal this with the iso6 compatible
5898 // brand, if not already the major brand. This is compatible with users that
5899 // don't understand tfdt.
5900
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 2 times.
59 if (mov->mode == MODE_MP4) {
5901
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
57 if (mov->flags & FF_MOV_FLAG_CMAF)
5902 1 ffio_wfourcc(pb, "cmfc");
5903
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))
5904 26 ffio_wfourcc(pb, "iso6");
5905
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 56 times.
57 if (has_av1)
5906 1 ffio_wfourcc(pb, "av01");
5907
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 54 times.
57 if (has_dolby)
5908 3 ffio_wfourcc(pb, "dby1");
5909
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 52 times.
57 if (has_iamf)
5910 5 ffio_wfourcc(pb, "iamf");
5911 } else {
5912
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
5913 ffio_wfourcc(pb, "iso6");
5914
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
5915 ffio_wfourcc(pb, "iso5");
5916
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 else if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS)
5917 ffio_wfourcc(pb, "iso4");
5918 }
5919 // Brands prior to iso5 can't be signaled when using default-base-is-moof
5920
2/2
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 12 times.
59 if (!(mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)) {
5921 // write isom for mp4 only if it it's not the major brand already.
5922
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)
5923 4 ffio_wfourcc(pb, "isom");
5924 47 ffio_wfourcc(pb, "iso2");
5925
2/2
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 27 times.
47 if (has_h264)
5926 20 ffio_wfourcc(pb, "avc1");
5927 }
5928 }
5929
5930
2/2
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 152 times.
209 if (mov->mode == MODE_MP4)
5931 57 ffio_wfourcc(pb, "mp41");
5932
5933
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)
5934 ffio_wfourcc(pb, "dash");
5935
5936
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (has_id3)
5937 ffio_wfourcc(pb, "aid3");
5938
5939 209 return update_size(pb, pos);
5940 }
5941
5942 1 static int mov_write_uuidprof_tag(AVIOContext *pb, AVFormatContext *s)
5943 {
5944 1 AVStream *video_st = s->streams[0];
5945 1 AVCodecParameters *video_par = s->streams[0]->codecpar;
5946 1 AVCodecParameters *audio_par = s->streams[1]->codecpar;
5947 1 int audio_rate = audio_par->sample_rate;
5948 2 int64_t frame_rate = video_st->avg_frame_rate.den ?
5949
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 :
5950 0;
5951 1 int audio_kbitrate = audio_par->bit_rate / 1000;
5952 1 int video_kbitrate = FFMIN(video_par->bit_rate / 1000, 800 - audio_kbitrate);
5953
5954
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) {
5955 av_log(s, AV_LOG_ERROR, "Frame rate %f outside supported range\n", frame_rate / (double)0x10000);
5956 return AVERROR(EINVAL);
5957 }
5958
5959 1 avio_wb32(pb, 0x94); /* size */
5960 1 ffio_wfourcc(pb, "uuid");
5961 1 ffio_wfourcc(pb, "PROF");
5962
5963 1 avio_wb32(pb, 0x21d24fce); /* 96 bit UUID */
5964 1 avio_wb32(pb, 0xbb88695c);
5965 1 avio_wb32(pb, 0xfac9c740);
5966
5967 1 avio_wb32(pb, 0x0); /* ? */
5968 1 avio_wb32(pb, 0x3); /* 3 sections ? */
5969
5970 1 avio_wb32(pb, 0x14); /* size */
5971 1 ffio_wfourcc(pb, "FPRF");
5972 1 avio_wb32(pb, 0x0); /* ? */
5973 1 avio_wb32(pb, 0x0); /* ? */
5974 1 avio_wb32(pb, 0x0); /* ? */
5975
5976 1 avio_wb32(pb, 0x2c); /* size */
5977 1 ffio_wfourcc(pb, "APRF"); /* audio */
5978 1 avio_wb32(pb, 0x0);
5979 1 avio_wb32(pb, 0x2); /* TrackID */
5980 1 ffio_wfourcc(pb, "mp4a");
5981 1 avio_wb32(pb, 0x20f);
5982 1 avio_wb32(pb, 0x0);
5983 1 avio_wb32(pb, audio_kbitrate);
5984 1 avio_wb32(pb, audio_kbitrate);
5985 1 avio_wb32(pb, audio_rate);
5986 1 avio_wb32(pb, audio_par->ch_layout.nb_channels);
5987
5988 1 avio_wb32(pb, 0x34); /* size */
5989 1 ffio_wfourcc(pb, "VPRF"); /* video */
5990 1 avio_wb32(pb, 0x0);
5991 1 avio_wb32(pb, 0x1); /* TrackID */
5992
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 if (video_par->codec_id == AV_CODEC_ID_H264) {
5993 1 ffio_wfourcc(pb, "avc1");
5994 1 avio_wb16(pb, 0x014D);
5995 1 avio_wb16(pb, 0x0015);
5996 } else {
5997 ffio_wfourcc(pb, "mp4v");
5998 avio_wb16(pb, 0x0000);
5999 avio_wb16(pb, 0x0103);
6000 }
6001 1 avio_wb32(pb, 0x0);
6002 1 avio_wb32(pb, video_kbitrate);
6003 1 avio_wb32(pb, video_kbitrate);
6004 1 avio_wb32(pb, frame_rate);
6005 1 avio_wb32(pb, frame_rate);
6006 1 avio_wb16(pb, video_par->width);
6007 1 avio_wb16(pb, video_par->height);
6008 1 avio_wb32(pb, 0x010001); /* ? */
6009
6010 1 return 0;
6011 }
6012
6013 209 static int mov_write_identification(AVIOContext *pb, AVFormatContext *s)
6014 {
6015 209 MOVMuxContext *mov = s->priv_data;
6016 int i;
6017
6018 209 mov_write_ftyp_tag(pb,s);
6019
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->mode == MODE_PSP) {
6020 1 int video_streams_nb = 0, audio_streams_nb = 0, other_streams_nb = 0;
6021
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_streams; i++) {
6022 2 AVStream *st = mov->tracks[i].st;
6023
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if (is_cover_image(st))
6024 continue;
6025
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
6026 1 video_streams_nb++;
6027
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO)
6028 1 audio_streams_nb++;
6029 else
6030 other_streams_nb++;
6031 }
6032
6033
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) {
6034 av_log(s, AV_LOG_ERROR, "PSP mode need one video and one audio stream\n");
6035 return AVERROR(EINVAL);
6036 }
6037 1 return mov_write_uuidprof_tag(pb, s);
6038 }
6039 208 return 0;
6040 }
6041
6042 8 static int mov_parse_mpeg2_frame(AVPacket *pkt, uint32_t *flags)
6043 {
6044 8 uint32_t c = -1;
6045 8 int i, closed_gop = 0;
6046
6047
1/2
✓ Branch 0 taken 368 times.
✗ Branch 1 not taken.
368 for (i = 0; i < pkt->size - 4; i++) {
6048 368 c = (c << 8) + pkt->data[i];
6049
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 360 times.
368 if (c == 0x1b8) { // gop
6050 8 closed_gop = pkt->data[i + 4] >> 6 & 0x01;
6051
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 352 times.
360 } else if (c == 0x100) { // pic
6052 8 int temp_ref = (pkt->data[i + 1] << 2) | (pkt->data[i + 2] >> 6);
6053
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
6054 8 *flags = MOV_SYNC_SAMPLE;
6055 else
6056 *flags = MOV_PARTIAL_SYNC_SAMPLE;
6057 8 break;
6058 }
6059 }
6060 8 return 0;
6061 }
6062
6063 static void mov_parse_vc1_frame(AVPacket *pkt, MOVTrack *trk)
6064 {
6065 const uint8_t *start, *next, *end = pkt->data + pkt->size;
6066 int seq = 0, entry = 0;
6067 int key = pkt->flags & AV_PKT_FLAG_KEY;
6068 start = find_next_marker(pkt->data, end);
6069 for (next = start; next < end; start = next) {
6070 next = find_next_marker(start + 4, end);
6071 switch (AV_RB32(start)) {
6072 case VC1_CODE_SEQHDR:
6073 seq = 1;
6074 break;
6075 case VC1_CODE_ENTRYPOINT:
6076 entry = 1;
6077 break;
6078 case VC1_CODE_SLICE:
6079 trk->vc1_info.slices = 1;
6080 break;
6081 }
6082 }
6083 if (!trk->entry && trk->vc1_info.first_packet_seen)
6084 trk->vc1_info.first_frag_written = 1;
6085 if (!trk->entry && !trk->vc1_info.first_frag_written) {
6086 /* First packet in first fragment */
6087 trk->vc1_info.first_packet_seq = seq;
6088 trk->vc1_info.first_packet_entry = entry;
6089 trk->vc1_info.first_packet_seen = 1;
6090 } else if ((seq && !trk->vc1_info.packet_seq) ||
6091 (entry && !trk->vc1_info.packet_entry)) {
6092 int i;
6093 for (i = 0; i < trk->entry; i++)
6094 trk->cluster[i].flags &= ~MOV_SYNC_SAMPLE;
6095 trk->has_keyframes = 0;
6096 if (seq)
6097 trk->vc1_info.packet_seq = 1;
6098 if (entry)
6099 trk->vc1_info.packet_entry = 1;
6100 if (!trk->vc1_info.first_frag_written) {
6101 /* First fragment */
6102 if ((!seq || trk->vc1_info.first_packet_seq) &&
6103 (!entry || trk->vc1_info.first_packet_entry)) {
6104 /* First packet had the same headers as this one, readd the
6105 * sync sample flag. */
6106 trk->cluster[0].flags |= MOV_SYNC_SAMPLE;
6107 trk->has_keyframes = 1;
6108 }
6109 }
6110 }
6111 if (trk->vc1_info.packet_seq && trk->vc1_info.packet_entry)
6112 key = seq && entry;
6113 else if (trk->vc1_info.packet_seq)
6114 key = seq;
6115 else if (trk->vc1_info.packet_entry)
6116 key = entry;
6117 if (key) {
6118 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6119 trk->has_keyframes++;
6120 }
6121 }
6122
6123 static void mov_parse_truehd_frame(AVPacket *pkt, MOVTrack *trk)
6124 {
6125 int length;
6126
6127 if (pkt->size < 8)
6128 return;
6129
6130 length = (AV_RB16(pkt->data) & 0xFFF) * 2;
6131 if (length < 8 || length > pkt->size)
6132 return;
6133
6134 if (AV_RB32(pkt->data + 4) == 0xF8726FBA) {
6135 trk->cluster[trk->entry].flags |= MOV_SYNC_SAMPLE;
6136 trk->has_keyframes++;
6137 }
6138
6139 return;
6140 }
6141
6142 static int mov_flush_fragment_interleaving(AVFormatContext *s, MOVTrack *track)
6143 {
6144 MOVMuxContext *mov = s->priv_data;
6145 int ret, buf_size;
6146 uint8_t *buf;
6147 int i, offset;
6148
6149 if (!track->mdat_buf)
6150 return 0;
6151 if (!mov->mdat_buf) {
6152 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6153 return ret;
6154 }
6155 buf_size = avio_get_dyn_buf(track->mdat_buf, &buf);
6156
6157 offset = avio_tell(mov->mdat_buf);
6158 avio_write(mov->mdat_buf, buf, buf_size);
6159 ffio_free_dyn_buf(&track->mdat_buf);
6160
6161 for (i = track->entries_flushed; i < track->entry; i++)
6162 track->cluster[i].pos += offset;
6163 track->entries_flushed = track->entry;
6164 return 0;
6165 }
6166
6167 2 static int mov_write_squashed_packet(AVFormatContext *s, MOVTrack *track)
6168 {
6169 2 MOVMuxContext *mov = s->priv_data;
6170 2 AVPacket *squashed_packet = mov->pkt;
6171 2 int ret = AVERROR_BUG;
6172
6173
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 switch (track->st->codecpar->codec_id) {
6174 2 case AV_CODEC_ID_TTML: {
6175 2 int had_packets = !!track->squashed_packet_queue.head;
6176
6177
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) {
6178 goto finish_squash;
6179 }
6180
6181 // We have generated a padding packet (no actual input packets in
6182 // queue) and its duration is zero. Skipping writing it.
6183
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) {
6184 goto finish_squash;
6185 }
6186
6187 2 track->end_reliable = 1;
6188 2 break;
6189 }
6190 default:
6191 ret = AVERROR(EINVAL);
6192 goto finish_squash;
6193 }
6194
6195 2 squashed_packet->stream_index = track->st->index;
6196
6197 2 ret = mov_write_single_packet(s, squashed_packet);
6198
6199 2 finish_squash:
6200 2 av_packet_unref(squashed_packet);
6201
6202 2 return ret;
6203 }
6204
6205 315 static int mov_write_squashed_packets(AVFormatContext *s)
6206 {
6207 315 MOVMuxContext *mov = s->priv_data;
6208
6209
2/2
✓ Branch 0 taken 459 times.
✓ Branch 1 taken 315 times.
774 for (int i = 0; i < mov->nb_streams; i++) {
6210 459 MOVTrack *track = &mov->tracks[i];
6211 459 int ret = AVERROR_BUG;
6212
6213
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) {
6214
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = mov_write_squashed_packet(s, track)) < 0) {
6215 av_log(s, AV_LOG_ERROR,
6216 "Failed to write squashed packet for %s stream with "
6217 "index %d and track id %d. Error: %s\n",
6218 avcodec_get_name(track->st->codecpar->codec_id),
6219 track->st->index, track->track_id,
6220 av_err2str(ret));
6221 return ret;
6222 }
6223 }
6224 }
6225
6226 315 return 0;
6227 }
6228
6229 129 static int mov_finish_fragment(MOVMuxContext *mov, MOVTrack *track,
6230 int64_t ref_pos)
6231 {
6232 int i;
6233
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 125 times.
129 if (!track->entry)
6234 4 return 0;
6235
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 120 times.
125 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
6236
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 5 times.
41 for (i = 0; i < track->entry; i++)
6237 36 track->cluster[i].pos += ref_pos + track->data_offset;
6238
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)) {
6239 // First flush. If this was a case of not using empty moov, reset chunking.
6240
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
20 for (i = 0; i < track->entry; i++) {
6241 18 track->cluster[i].chunkNum = 0;
6242 18 track->cluster[i].samples_in_chunk = track->cluster[i].entries;
6243 }
6244 }
6245
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (av_reallocp_array(&track->cluster_written,
6246 5 track->entry_written + track->entry,
6247 sizeof(*track->cluster)))
6248 return AVERROR(ENOMEM);
6249 5 memcpy(&track->cluster_written[track->entry_written],
6250 5 track->cluster, track->entry * sizeof(*track->cluster));
6251 5 track->entry_written += track->entry;
6252 }
6253 125 track->entry = 0;
6254 125 track->entries_flushed = 0;
6255 125 track->end_reliable = 0;
6256 125 return 0;
6257 }
6258
6259 106 static int mov_flush_fragment(AVFormatContext *s, int force)
6260 {
6261 106 MOVMuxContext *mov = s->priv_data;
6262 106 int i, first_track = -1;
6263 106 int64_t mdat_size = 0, mdat_start = 0;
6264 int ret;
6265 106 int has_video = 0, starts_with_key = 0, first_video_track = 1;
6266
6267
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 106 times.
106 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT))
6268 return 0;
6269
6270 // Check if we have any tracks that require squashing.
6271 // In that case, we'll have to write the packet here.
6272
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 106 times.
106 if ((ret = mov_write_squashed_packets(s)) < 0)
6273 return ret;
6274
6275 // Try to fill in the duration of the last packet in each stream
6276 // from queued packets in the interleave queues. If the flushing
6277 // of fragments was triggered automatically by an AVPacket, we
6278 // already have reliable info for the end of that track, but other
6279 // tracks may need to be filled in.
6280
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 106 times.
298 for (i = 0; i < mov->nb_streams; i++) {
6281 192 MOVTrack *track = &mov->tracks[i];
6282
2/2
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 38 times.
192 if (!track->end_reliable) {
6283 154 const AVPacket *pkt = ff_interleaved_peek(s, i);
6284
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 148 times.
154 if (pkt) {
6285 int64_t offset, dts, pts;
6286 6 ff_get_muxer_ts_offset(s, i, &offset);
6287 6 pts = pkt->pts + offset;
6288 6 dts = pkt->dts + offset;
6289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (track->dts_shift != AV_NOPTS_VALUE)
6290 dts += track->dts_shift;
6291 6 track->track_duration = dts - track->start_dts;
6292
1/2
✓ Branch 0 taken 6 times.
✗ Branch 1 not taken.
6 if (pts != AV_NOPTS_VALUE)
6293 6 track->end_pts = pts;
6294 else
6295 track->end_pts = dts;
6296 }
6297 }
6298 }
6299
6300
2/2
✓ Branch 0 taken 198 times.
✓ Branch 1 taken 106 times.
304 for (i = 0; i < mov->nb_tracks; i++) {
6301 198 MOVTrack *track = &mov->tracks[i];
6302
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 153 times.
198 if (track->entry <= 1)
6303 45 continue;
6304 // Sample durations are calculated as the diff of dts values,
6305 // but for the last sample in a fragment, we don't know the dts
6306 // of the first sample in the next fragment, so we have to rely
6307 // on what was set as duration in the AVPacket. Not all callers
6308 // set this though, so we might want to replace it with an
6309 // estimate if it currently is zero.
6310
2/2
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 2 times.
153 if (get_cluster_duration(track, track->entry - 1) != 0)
6311 151 continue;
6312 // Use the duration (i.e. dts diff) of the second last sample for
6313 // the last one. This is a wild guess (and fatal if it turns out
6314 // to be too long), but probably the best we can do - having a zero
6315 // duration is bad as well.
6316 2 track->track_duration += get_cluster_duration(track, track->entry - 2);
6317 2 track->end_pts += get_cluster_duration(track, track->entry - 2);
6318
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (!mov->missing_duration_warned) {
6319 2 av_log(s, AV_LOG_WARNING,
6320 "Estimating the duration of the last packet in a "
6321 "fragment, consider setting the duration field in "
6322 "AVPacket instead.\n");
6323 2 mov->missing_duration_warned = 1;
6324 }
6325 }
6326
6327
2/2
✓ Branch 0 taken 23 times.
✓ Branch 1 taken 83 times.
106 if (!mov->moov_written) {
6328 23 int64_t pos = avio_tell(s->pb);
6329 uint8_t *buf;
6330 int buf_size, moov_size;
6331
6332
2/2
✓ Branch 0 taken 45 times.
✓ Branch 1 taken 19 times.
64 for (i = 0; i < mov->nb_tracks; i++)
6333
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))
6334 4 break;
6335 /* Don't write the initial moov unless all tracks have data */
6336
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)
6337 2 return 0;
6338
6339 21 moov_size = get_moov_size(s);
6340
2/2
✓ Branch 0 taken 41 times.
✓ Branch 1 taken 21 times.
62 for (i = 0; i < mov->nb_tracks; i++)
6341 41 mov->tracks[i].data_offset = pos + moov_size + 8;
6342
6343 21 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_HEADER);
6344
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
6345 17 mov_write_identification(s->pb, s);
6346
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
21 if ((ret = mov_write_moov_tag(s->pb, mov, s)) < 0)
6347 return ret;
6348
6349
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 4 times.
21 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV) {
6350
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
17 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6351 mov->reserved_header_pos = avio_tell(s->pb);
6352 17 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6353 17 mov->moov_written = 1;
6354 17 return 0;
6355 }
6356
6357 4 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
6358 4 avio_wb32(s->pb, buf_size + 8);
6359 4 ffio_wfourcc(s->pb, "mdat");
6360 4 avio_write(s->pb, buf, buf_size);
6361 4 ffio_free_dyn_buf(&mov->mdat_buf);
6362
6363
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
6364 mov->reserved_header_pos = avio_tell(s->pb);
6365
6366 4 mov->moov_written = 1;
6367 4 mov->mdat_size = 0;
6368
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 4 times.
12 for (i = 0; i < mov->nb_tracks; i++)
6369 8 mov_finish_fragment(mov, &mov->tracks[i], 0);
6370 4 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6371 4 return 0;
6372 }
6373
6374
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
83 if (mov->frag_interleave) {
6375 for (i = 0; i < mov->nb_tracks; i++) {
6376 MOVTrack *track = &mov->tracks[i];
6377 int ret;
6378 if ((ret = mov_flush_fragment_interleaving(s, track)) < 0)
6379 return ret;
6380 }
6381
6382 if (!mov->mdat_buf)
6383 return 0;
6384 mdat_size = avio_tell(mov->mdat_buf);
6385 }
6386
6387
2/2
✓ Branch 0 taken 153 times.
✓ Branch 1 taken 83 times.
236 for (i = 0; i < mov->nb_tracks; i++) {
6388 153 MOVTrack *track = &mov->tracks[i];
6389
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)
6390 19 track->data_offset = 0;
6391 else
6392 134 track->data_offset = mdat_size;
6393
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 80 times.
153 if (track->par->codec_type == AVMEDIA_TYPE_VIDEO) {
6394 73 has_video = 1;
6395
1/2
✓ Branch 0 taken 73 times.
✗ Branch 1 not taken.
73 if (first_video_track) {
6396
2/2
✓ Branch 0 taken 61 times.
✓ Branch 1 taken 12 times.
73 if (track->entry)
6397 61 starts_with_key = track->cluster[0].flags & MOV_SYNC_SAMPLE;
6398 73 first_video_track = 0;
6399 }
6400 }
6401
2/2
✓ Branch 0 taken 36 times.
✓ Branch 1 taken 117 times.
153 if (!track->entry)
6402 36 continue;
6403
1/2
✓ Branch 0 taken 117 times.
✗ Branch 1 not taken.
117 if (track->mdat_buf)
6404 117 mdat_size += avio_tell(track->mdat_buf);
6405
2/2
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 50 times.
117 if (first_track < 0)
6406 67 first_track = i;
6407 }
6408
6409
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 67 times.
83 if (!mdat_size)
6410 16 return 0;
6411
6412
2/2
✓ Branch 0 taken 64 times.
✓ Branch 1 taken 3 times.
67 avio_write_marker(s->pb,
6413 67 av_rescale(mov->tracks[first_track].cluster[0].dts, AV_TIME_BASE, mov->tracks[first_track].timescale),
6414
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);
6415
6416
2/2
✓ Branch 0 taken 125 times.
✓ Branch 1 taken 67 times.
192 for (i = 0; i < mov->nb_tracks; i++) {
6417 125 MOVTrack *track = &mov->tracks[i];
6418 125 int buf_size, write_moof = 1, moof_tracks = -1;
6419 uint8_t *buf;
6420
6421
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 106 times.
125 if (mov->flags & FF_MOV_FLAG_SEPARATE_MOOF) {
6422
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 15 times.
19 if (!track->entry)
6423 8 continue;
6424 15 mdat_size = avio_tell(track->mdat_buf);
6425 15 moof_tracks = i;
6426 } else {
6427 106 write_moof = i == first_track;
6428 }
6429
6430
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 50 times.
121 if (write_moof) {
6431 71 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6432
6433 71 mov_write_moof_tag(s->pb, mov, moof_tracks, mdat_size);
6434 71 mov->fragments++;
6435
6436 71 avio_wb32(s->pb, mdat_size + 8);
6437 71 ffio_wfourcc(s->pb, "mdat");
6438 71 mdat_start = avio_tell(s->pb);
6439 }
6440
6441 121 mov_finish_fragment(mov, &mov->tracks[i], mdat_start);
6442
1/2
✓ Branch 0 taken 121 times.
✗ Branch 1 not taken.
121 if (!mov->frag_interleave) {
6443
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 117 times.
121 if (!track->mdat_buf)
6444 4 continue;
6445 117 buf_size = avio_close_dyn_buf(track->mdat_buf, &buf);
6446 117 track->mdat_buf = NULL;
6447 } else {
6448 if (!mov->mdat_buf)
6449 continue;
6450 buf_size = avio_close_dyn_buf(mov->mdat_buf, &buf);
6451 mov->mdat_buf = NULL;
6452 }
6453
6454 117 avio_write(s->pb, buf, buf_size);
6455 117 av_free(buf);
6456 }
6457
6458 67 mov->mdat_size = 0;
6459
6460 67 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_FLUSH_POINT);
6461 67 return 0;
6462 }
6463
6464 61 static int mov_auto_flush_fragment(AVFormatContext *s, int force)
6465 {
6466 61 MOVMuxContext *mov = s->priv_data;
6467 61 int had_moov = mov->moov_written;
6468 61 int ret = mov_flush_fragment(s, force);
6469
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
61 if (ret < 0)
6470 return ret;
6471 // If using delay_moov, the first flush only wrote the moov,
6472 // not the actual moof+mdat pair, thus flush once again.
6473
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)
6474 9 ret = mov_flush_fragment(s, force);
6475 61 return ret;
6476 }
6477
6478 36163 static int check_pkt(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6479 {
6480 int64_t ref;
6481 uint64_t duration;
6482
6483
2/2
✓ Branch 0 taken 35525 times.
✓ Branch 1 taken 638 times.
36163 if (trk->entry) {
6484 35525 ref = trk->cluster[trk->entry - 1].dts;
6485
2/2
✓ Branch 0 taken 114 times.
✓ Branch 1 taken 524 times.
638 } else if ( trk->start_dts != AV_NOPTS_VALUE
6486
2/2
✓ Branch 0 taken 106 times.
✓ Branch 1 taken 8 times.
114 && !trk->frag_discont) {
6487 106 ref = trk->start_dts + trk->track_duration;
6488 } else
6489 532 ref = pkt->dts; // Skip tests for the first packet
6490
6491
2/2
✓ Branch 0 taken 1655 times.
✓ Branch 1 taken 34508 times.
36163 if (trk->dts_shift != AV_NOPTS_VALUE) {
6492 /* With negative CTS offsets we have set an offset to the DTS,
6493 * reverse this for the check. */
6494 1655 ref -= trk->dts_shift;
6495 }
6496
6497 36163 duration = pkt->dts - ref;
6498
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) {
6499 av_log(s, AV_LOG_WARNING, "Packet duration: %"PRId64" / dts: %"PRId64" is out of range\n",
6500 duration, pkt->dts);
6501
6502 pkt->dts = ref + 1;
6503 pkt->pts = AV_NOPTS_VALUE;
6504 }
6505
6506
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) {
6507 av_log(s, AV_LOG_ERROR, "Application provided duration: %"PRId64" is invalid\n", pkt->duration);
6508 return AVERROR(EINVAL);
6509 }
6510 36163 return 0;
6511 }
6512
6513 18100 int ff_mov_write_packet(AVFormatContext *s, AVPacket *pkt)
6514 {
6515 18100 MOVMuxContext *mov = s->priv_data;
6516 18100 AVIOContext *pb = s->pb;
6517 MOVTrack *trk;
6518 AVCodecParameters *par;
6519 AVProducerReferenceTime *prft;
6520 18100 unsigned int samples_in_chunk = 0;
6521 18100 int size = pkt->size, ret = 0, offset = 0;
6522 size_t prft_size;
6523 18100 uint8_t *reformatted_data = NULL;
6524
6525
2/2
✓ Branch 0 taken 18054 times.
✓ Branch 1 taken 46 times.
18100 if (pkt->stream_index < s->nb_streams)
6526 18054 trk = s->streams[pkt->stream_index]->priv_data;
6527 else // Timecode or chapter
6528 46 trk = &mov->tracks[pkt->stream_index];
6529 18100 par = trk->par;
6530
6531 18100 ret = check_pkt(s, trk, pkt);
6532
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (ret < 0)
6533 return ret;
6534
6535
2/2
✓ Branch 0 taken 17498 times.
✓ Branch 1 taken 602 times.
18100 if (pkt->pts != AV_NOPTS_VALUE &&
6536
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)) {
6537 av_log(s, AV_LOG_WARNING, "pts/dts pair unsupported\n");
6538 return AVERROR_PATCHWELCOME;
6539 }
6540
6541
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) {
6542 int ret;
6543
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) {
6544
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) {
6545 if (trk->entry - trk->entries_flushed >= mov->frag_interleave) {
6546 if ((ret = mov_flush_fragment_interleaving(s, trk)) < 0)
6547 return ret;
6548 }
6549 }
6550
6551
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 4905 times.
5022 if (!trk->mdat_buf) {
6552
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 117 times.
117 if ((ret = avio_open_dyn_buf(&trk->mdat_buf)) < 0)
6553 return ret;
6554 }
6555 5022 pb = trk->mdat_buf;
6556 } else {
6557
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 234 times.
238 if (!mov->mdat_buf) {
6558
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
4 if ((ret = avio_open_dyn_buf(&mov->mdat_buf)) < 0)
6559 return ret;
6560 }
6561 238 pb = mov->mdat_buf;
6562 }
6563 }
6564
6565
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (par->codec_id == AV_CODEC_ID_AMR_NB) {
6566 /* We must find out how many AMR blocks there are in one packet */
6567 static const uint16_t packed_size[16] =
6568 {13, 14, 16, 18, 20, 21, 27, 32, 6, 0, 0, 0, 0, 0, 0, 1};
6569 int len = 0;
6570
6571 while (len < size && samples_in_chunk < 100) {
6572 len += packed_size[(pkt->data[len] >> 3) & 0x0F];
6573 samples_in_chunk++;
6574 }
6575 if (samples_in_chunk > 1) {
6576 av_log(s, AV_LOG_ERROR, "fatal error, input is not a single packet, implement a AVParser for it\n");
6577 return -1;
6578 }
6579
1/2
✓ Branch 0 taken 18100 times.
✗ Branch 1 not taken.
18100 } else if (par->codec_id == AV_CODEC_ID_ADPCM_MS ||
6580
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 par->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV) {
6581 samples_in_chunk = trk->par->frame_size;
6582
2/2
✓ Branch 0 taken 1297 times.
✓ Branch 1 taken 16803 times.
18100 } else if (trk->sample_size)
6583 1297 samples_in_chunk = size / trk->sample_size;
6584 else
6585 16803 samples_in_chunk = 1;
6586
6587
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18100 times.
18100 if (samples_in_chunk < 1) {
6588 av_log(s, AV_LOG_ERROR, "fatal error, input packet contains no samples\n");
6589 return AVERROR_PATCHWELCOME;
6590 }
6591
6592 /* copy extradata if it exists */
6593
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 &&
6594
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) &&
6595
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 (par->codec_id != AV_CODEC_ID_DNXHD)) {
6596 2 trk->vos_len = par->extradata_size;
6597 2 trk->vos_data = av_malloc(trk->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
6598
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!trk->vos_data) {
6599 ret = AVERROR(ENOMEM);
6600 goto err;
6601 }
6602 2 memcpy(trk->vos_data, par->extradata, trk->vos_len);
6603 2 memset(trk->vos_data + trk->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6604 }
6605
6606
2/2
✓ Branch 0 taken 17985 times.
✓ Branch 1 taken 115 times.
18100 if ((par->codec_id == AV_CODEC_ID_DNXHD ||
6607
2/2
✓ Branch 0 taken 15397 times.
✓ Branch 1 taken 2588 times.
17985 par->codec_id == AV_CODEC_ID_H264 ||
6608
2/2
✓ Branch 0 taken 15242 times.
✓ Branch 1 taken 155 times.
15397 par->codec_id == AV_CODEC_ID_HEVC ||
6609
2/2
✓ Branch 0 taken 15232 times.
✓ Branch 1 taken 10 times.
15242 par->codec_id == AV_CODEC_ID_VVC ||
6610
1/2
✓ Branch 0 taken 15232 times.
✗ Branch 1 not taken.
15232 par->codec_id == AV_CODEC_ID_VP9 ||
6611
2/2
✓ Branch 0 taken 14932 times.
✓ Branch 1 taken 300 times.
15232 par->codec_id == AV_CODEC_ID_EVC ||
6612
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 &&
6613
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)) {
6614 /* copy frame to create needed atoms */
6615 24 trk->vos_len = size;
6616 24 trk->vos_data = av_malloc(size + AV_INPUT_BUFFER_PADDING_SIZE);
6617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24 times.
24 if (!trk->vos_data) {
6618 ret = AVERROR(ENOMEM);
6619 goto err;
6620 }
6621 24 memcpy(trk->vos_data, pkt->data, size);
6622 24 memset(trk->vos_data + size, 0, AV_INPUT_BUFFER_PADDING_SIZE);
6623 }
6624
6625
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 &&
6626
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5540 times.
5540 (AV_RB16(pkt->data) & 0xfff0) == 0xfff0) {
6627 if (!trk->st->nb_frames) {
6628 av_log(s, AV_LOG_ERROR, "Malformed AAC bitstream detected: "
6629 "use the audio bitstream filter 'aac_adtstoasc' to fix it "
6630 "('-bsf:a aac_adtstoasc' option with ffmpeg)\n");
6631 return -1;
6632 }
6633 av_log(s, AV_LOG_WARNING, "aac bitstream error\n");
6634 }
6635
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)) {
6636 /* from x264 or from bytestream H.264 */
6637 /* NAL reformatting needed */
6638
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) {
6639 ret = ff_nal_parse_units_buf(pkt->data, &reformatted_data,
6640 &size);
6641 if (ret < 0)
6642 return ret;
6643 avio_write(pb, reformatted_data, size);
6644 } else {
6645
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 498 times.
498 if (trk->cenc.aes_ctr) {
6646 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6647 if (size < 0) {
6648 ret = size;
6649 goto err;
6650 }
6651 } else {
6652 498 size = ff_nal_parse_units(pb, pkt->data, pkt->size);
6653 }
6654 }
6655
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 &&
6656
3/4
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 144 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 11 times.
155 (AV_RB24(trk->vos_data) == 1 || AV_RB32(trk->vos_data) == 1)) {
6657 /* extradata is Annex B, assume the bitstream is too and convert it */
6658
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) {
6659 ret = ff_hevc_annexb2mp4_buf(pkt->data, &reformatted_data,
6660 &size, 0, NULL);
6661 if (ret < 0)
6662 return ret;
6663 avio_write(pb, reformatted_data, size);
6664 } else {
6665
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 144 times.
144 if (trk->cenc.aes_ctr) {
6666 size = ff_mov_cenc_avc_parse_nal_units(&trk->cenc, pb, pkt->data, size);
6667 if (size < 0) {
6668 ret = size;
6669 goto err;
6670 }
6671 } else {
6672 144 size = ff_hevc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6673 }
6674 }
6675
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 &&
6676
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)) {
6677 /* extradata is Annex B, assume the bitstream is too and convert it */
6678
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) {
6679 ret = ff_vvc_annexb2mp4_buf(pkt->data, &reformatted_data,
6680 &size, 0, NULL);
6681 if (ret < 0)
6682 return ret;
6683 avio_write(pb, reformatted_data, size);
6684 } else {
6685 10 size = ff_vvc_annexb2mp4(pb, pkt->data, pkt->size, 0, NULL);
6686 }
6687
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 17444 times.
17448 } else if (par->codec_id == AV_CODEC_ID_AV1) {
6688
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) {
6689 ret = ff_av1_filter_obus_buf(pkt->data, &reformatted_data,
6690 &size, &offset);
6691 if (ret < 0)
6692 return ret;
6693 avio_write(pb, reformatted_data, size);
6694 } else {
6695 4 size = ff_av1_filter_obus(pb, pkt->data, pkt->size);
6696
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]) {
6697 mov->avif_extent_length[pkt->stream_index] = size;
6698 }
6699 }
6700
6701
2/2
✓ Branch 0 taken 17057 times.
✓ Branch 1 taken 387 times.
17444 } else if (par->codec_id == AV_CODEC_ID_AC3 ||
6702
2/2
✓ Branch 0 taken 652 times.
✓ Branch 1 taken 16405 times.
17057 par->codec_id == AV_CODEC_ID_EAC3) {
6703 1039 size = handle_eac3(mov, pkt, trk);
6704
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1039 times.
1039 if (size < 0)
6705 return size;
6706
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1038 times.
1039 else if (!size)
6707 1 goto end;
6708 1038 avio_write(pb, pkt->data, size);
6709
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16405 times.
16405 } else if (par->codec_id == AV_CODEC_ID_EIA_608) {
6710 size = 8;
6711
6712 for (int i = 0; i < pkt->size; i += 3) {
6713 if (pkt->data[i] == 0xFC) {
6714 size += 2;
6715 }
6716 }
6717 avio_wb32(pb, size);
6718 ffio_wfourcc(pb, "cdat");
6719 for (int i = 0; i < pkt->size; i += 3) {
6720 if (pkt->data[i] == 0xFC) {
6721 avio_w8(pb, pkt->data[i + 1]);
6722 avio_w8(pb, pkt->data[i + 2]);
6723 }
6724 }
6725 } else {
6726
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16405 times.
16405 if (trk->cenc.aes_ctr) {
6727 if (par->codec_id == AV_CODEC_ID_H264 && par->extradata_size > 4) {
6728 int nal_size_length = (par->extradata[4] & 0x3) + 1;
6729 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6730 } else if(par->codec_id == AV_CODEC_ID_HEVC && par->extradata_size > 21) {
6731 int nal_size_length = (par->extradata[21] & 0x3) + 1;
6732 ret = ff_mov_cenc_avc_write_nal_units(s, &trk->cenc, nal_size_length, pb, pkt->data, size);
6733 } else if(par->codec_id == AV_CODEC_ID_VVC) {
6734 ret = AVERROR_PATCHWELCOME;
6735 } else {
6736 ret = ff_mov_cenc_write_packet(&trk->cenc, pb, pkt->data, size);
6737 }
6738
6739 if (ret) {
6740 goto err;
6741 }
6742 } else {
6743 16405 avio_write(pb, pkt->data, size);
6744 }
6745 }
6746
6747
2/2
✓ Branch 0 taken 273 times.
✓ Branch 1 taken 17826 times.
18099 if (trk->entry >= trk->cluster_capacity) {
6748 273 unsigned new_capacity = trk->entry + MOV_INDEX_CLUSTER_SIZE;
6749 273 void *cluster = av_realloc_array(trk->cluster, new_capacity, sizeof(*trk->cluster));
6750
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 273 times.
273 if (!cluster) {
6751 ret = AVERROR(ENOMEM);
6752 goto err;
6753 }
6754 273 trk->cluster = cluster;
6755 273 trk->cluster_capacity = new_capacity;
6756 }
6757
6758 18099 trk->cluster[trk->entry].pos = avio_tell(pb) - size;
6759 18099 trk->cluster[trk->entry].samples_in_chunk = samples_in_chunk;
6760 18099 trk->cluster[trk->entry].chunkNum = 0;
6761 18099 trk->cluster[trk->entry].size = size;
6762 18099 trk->cluster[trk->entry].entries = samples_in_chunk;
6763 18099 trk->cluster[trk->entry].dts = pkt->dts;
6764 18099 trk->cluster[trk->entry].pts = pkt->pts;
6765
2/2
✓ Branch 0 taken 18097 times.
✓ Branch 1 taken 2 times.
18099 if (!trk->squash_fragment_samples_to_one &&
6766
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) {
6767
2/2
✓ Branch 0 taken 71 times.
✓ Branch 1 taken 4 times.
75 if (!trk->frag_discont) {
6768 /* First packet of a new fragment. We already wrote the duration
6769 * of the last packet of the previous fragment based on track_duration,
6770 * which might not exactly match our dts. Therefore adjust the dts
6771 * of this packet to be what the previous packets duration implies. */
6772 71 trk->cluster[trk->entry].dts = trk->start_dts + trk->track_duration;
6773 /* We also may have written the pts and the corresponding duration
6774 * in sidx/tfrf/tfxd tags; make sure the sidx pts and duration match up with
6775 * the next fragment. This means the cts of the first sample must
6776 * be the same in all fragments, unless end_pts was updated by
6777 * the packet causing the fragment to be written. */
6778
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 57 times.
71 if ((mov->flags & FF_MOV_FLAG_DASH &&
6779
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
14 !(mov->flags & (FF_MOV_FLAG_GLOBAL_SIDX | FF_MOV_FLAG_SKIP_SIDX))) ||
6780
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 47 times.
57 mov->mode == MODE_ISM)
6781 24 pkt->pts = pkt->dts + trk->end_pts - trk->cluster[trk->entry].dts;
6782 } else {
6783 /* New fragment, but discontinuous from previous fragments.
6784 * Pretend the duration sum of the earlier fragments is
6785 * pkt->dts - trk->start_dts. */
6786 4 trk->end_pts = AV_NOPTS_VALUE;
6787 4 trk->frag_discont = 0;
6788 }
6789 }
6790
6791
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 &&
6792
2/2
✓ Branch 0 taken 19 times.
✓ Branch 1 taken 11 times.
30 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO) {
6793 /* Not using edit lists and shifting the first track to start from zero.
6794 * If the other streams start from a later timestamp, we won't be able
6795 * to signal the difference in starting time without an edit list.
6796 * Thus move the timestamp for this first sample to 0, increasing
6797 * its duration instead. */
6798 19 trk->cluster[trk->entry].dts = trk->start_dts = 0;
6799 }
6800
2/2
✓ Branch 0 taken 240 times.
✓ Branch 1 taken 17859 times.
18099 if (trk->start_dts == AV_NOPTS_VALUE) {
6801 240 trk->start_dts = pkt->dts;
6802
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 234 times.
240 if (trk->frag_discont) {
6803
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 2 times.
6 if (mov->use_editlist) {
6804 /* Pretend the whole stream started at pts=0, with earlier fragments
6805 * already written. If the stream started at pts=0, the duration sum
6806 * of earlier fragments would have been pkt->pts. */
6807 4 trk->start_dts = pkt->dts - pkt->pts;
6808 } else {
6809 /* Pretend the whole stream started at dts=0, with earlier fragments
6810 * already written, with a duration summing up to pkt->dts. */
6811 2 trk->start_dts = 0;
6812 }
6813 6 trk->frag_discont = 0;
6814
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)
6815 2 av_log(s, AV_LOG_WARNING,
6816 "Track %d starts with a nonzero dts %"PRId64", while the moov "
6817 "already has been written. Set the delay_moov flag to handle "
6818 "this case.\n",
6819 pkt->stream_index, pkt->dts);
6820 }
6821 18099 trk->track_duration = pkt->dts - trk->start_dts + pkt->duration;
6822 18099 trk->last_sample_is_subtitle_end = 0;
6823
6824
2/2
✓ Branch 0 taken 602 times.
✓ Branch 1 taken 17497 times.
18099 if (pkt->pts == AV_NOPTS_VALUE) {
6825 602 av_log(s, AV_LOG_WARNING, "pts has no value\n");
6826 602 pkt->pts = pkt->dts;
6827 }
6828
2/2
✓ Branch 0 taken 1018 times.
✓ Branch 1 taken 17081 times.
18099 if (pkt->dts != pkt->pts)
6829 1018 trk->flags |= MOV_TRACK_CTTS;
6830 18099 trk->cluster[trk->entry].cts = pkt->pts - pkt->dts;
6831 18099 trk->cluster[trk->entry].flags = 0;
6832
2/2
✓ Branch 0 taken 259 times.
✓ Branch 1 taken 17840 times.
18099 if (trk->start_cts == AV_NOPTS_VALUE)
6833 259 trk->start_cts = pkt->pts - pkt->dts;
6834
2/2
✓ Branch 0 taken 263 times.
✓ Branch 1 taken 17836 times.
18099 if (trk->end_pts == AV_NOPTS_VALUE)
6835 263 trk->end_pts = trk->cluster[trk->entry].dts +
6836 263 trk->cluster[trk->entry].cts + pkt->duration;
6837 else
6838 17836 trk->end_pts = FFMAX(trk->end_pts, trk->cluster[trk->entry].dts +
6839 trk->cluster[trk->entry].cts +
6840 pkt->duration);
6841
6842
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
18099 if (par->codec_id == AV_CODEC_ID_VC1) {
6843 mov_parse_vc1_frame(pkt, trk);
6844
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18099 times.
18099 } else if (par->codec_id == AV_CODEC_ID_TRUEHD) {
6845 mov_parse_truehd_frame(pkt, trk);
6846
2/2
✓ Branch 0 taken 13459 times.
✓ Branch 1 taken 4640 times.
18099 } else if (pkt->flags & AV_PKT_FLAG_KEY) {
6847
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 &&
6848
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 1 times.
9 trk->entry > 0) { // force sync sample for the first key frame
6849 8 mov_parse_mpeg2_frame(pkt, &trk->cluster[trk->entry].flags);
6850
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
8 if (trk->cluster[trk->entry].flags & MOV_PARTIAL_SYNC_SAMPLE)
6851 trk->flags |= MOV_TRACK_STPS;
6852 } else {
6853 13451 trk->cluster[trk->entry].flags = MOV_SYNC_SAMPLE;
6854 }
6855
1/2
✓ Branch 0 taken 13459 times.
✗ Branch 1 not taken.
13459 if (trk->cluster[trk->entry].flags & MOV_SYNC_SAMPLE)
6856 13459 trk->has_keyframes++;
6857 }
6858
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 18092 times.
18099 if (pkt->flags & AV_PKT_FLAG_DISPOSABLE) {
6859 7 trk->cluster[trk->entry].flags |= MOV_DISPOSABLE_SAMPLE;
6860 7 trk->has_disposable++;
6861 }
6862
6863 18099 prft = (AVProducerReferenceTime *)av_packet_get_side_data(pkt, AV_PKT_DATA_PRFT, &prft_size);
6864
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))
6865 memcpy(&trk->cluster[trk->entry].prft, prft, prft_size);
6866 else
6867 18099 memset(&trk->cluster[trk->entry].prft, 0, sizeof(AVProducerReferenceTime));
6868
6869 18099 trk->entry++;
6870 18099 trk->sample_count += samples_in_chunk;
6871 18099 mov->mdat_size += size;
6872
6873
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)
6874 82 ff_mov_add_hinted_packet(s, pkt, trk->hint_track, trk->entry,
6875
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 82 times.
82 reformatted_data ? reformatted_data + offset
6876 : NULL, size);
6877
6878 18100 end:
6879 18100 err:
6880
6881
1/2
✓ Branch 0 taken 18100 times.
✗ Branch 1 not taken.
18100 if (pkt->data != reformatted_data)
6882 18100 av_free(reformatted_data);
6883 18100 return ret;
6884 }
6885
6886 18063 static int mov_write_single_packet(AVFormatContext *s, AVPacket *pkt)
6887 {
6888 18063 MOVMuxContext *mov = s->priv_data;
6889 18063 MOVTrack *trk = s->streams[pkt->stream_index]->priv_data;
6890 18063 AVCodecParameters *par = trk->par;
6891 18063 int64_t frag_duration = 0;
6892 18063 int size = pkt->size;
6893
6894 18063 int ret = check_pkt(s, trk, pkt);
6895
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18063 times.
18063 if (ret < 0)
6896 return ret;
6897
6898
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 18058 times.
18063 if (mov->flags & FF_MOV_FLAG_FRAG_DISCONT) {
6899
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < mov->nb_streams; i++)
6900 10 mov->tracks[i].frag_discont = 1;
6901 5 mov->flags &= ~FF_MOV_FLAG_FRAG_DISCONT;
6902 }
6903
6904
2/2
✓ Branch 0 taken 810 times.
✓ Branch 1 taken 17253 times.
18063 if (mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS) {
6905
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 799 times.
810 if (trk->dts_shift == AV_NOPTS_VALUE)
6906 11 trk->dts_shift = pkt->pts - pkt->dts;
6907 810 pkt->dts += trk->dts_shift;
6908 }
6909
6910
1/2
✓ Branch 0 taken 18063 times.
✗ Branch 1 not taken.
18063 if (trk->par->codec_id == AV_CODEC_ID_MP4ALS ||
6911
2/2
✓ Branch 0 taken 12521 times.
✓ Branch 1 taken 5542 times.
18063 trk->par->codec_id == AV_CODEC_ID_AAC ||
6912
2/2
✓ Branch 0 taken 12517 times.
✓ Branch 1 taken 4 times.
12521 trk->par->codec_id == AV_CODEC_ID_AV1 ||
6913
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 12462 times.
12517 trk->par->codec_id == AV_CODEC_ID_FLAC) {
6914 size_t side_size;
6915 5601 uint8_t *side = av_packet_get_side_data(pkt, AV_PKT_DATA_NEW_EXTRADATA, &side_size);
6916
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))) {
6917 6 void *newextra = av_mallocz(side_size + AV_INPUT_BUFFER_PADDING_SIZE);
6918
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!newextra)
6919 return AVERROR(ENOMEM);
6920 6 av_free(par->extradata);
6921 6 par->extradata = newextra;
6922 6 memcpy(par->extradata, side, side_size);
6923 6 par->extradata_size = side_size;
6924
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 times.
6 if (!pkt->size) // Flush packet
6925 5 mov->need_rewrite_extradata = 1;
6926 }
6927 }
6928
6929
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18054 times.
18063 if (!pkt->size) {
6930
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) {
6931 4 trk->start_dts = pkt->dts;
6932
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 if (pkt->pts != AV_NOPTS_VALUE)
6933 4 trk->start_cts = pkt->pts - pkt->dts;
6934 else
6935 trk->start_cts = 0;
6936 }
6937
6938 9 return 0; /* Discard 0 sized packets */
6939 }
6940
6941
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)
6942 17731 frag_duration = av_rescale_q(pkt->dts - trk->cluster[0].dts,
6943 17731 s->streams[pkt->stream_index]->time_base,
6944 17731 AV_TIME_BASE_Q);
6945
2/2
✓ Branch 0 taken 173 times.
✓ Branch 1 taken 17881 times.
18054 if ((mov->max_fragment_duration &&
6946
2/2
✓ Branch 0 taken 170 times.
✓ Branch 1 taken 3 times.
173 frag_duration >= mov->max_fragment_duration) ||
6947
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) ||
6948
2/2
✓ Branch 0 taken 3673 times.
✓ Branch 1 taken 14378 times.
18051 (mov->flags & FF_MOV_FLAG_FRAG_KEYFRAME &&
6949
2/2
✓ Branch 0 taken 1125 times.
✓ Branch 1 taken 2548 times.
3673 par->codec_type == AVMEDIA_TYPE_VIDEO &&
6950
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) ||
6951
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 18026 times.
18026 (mov->flags & FF_MOV_FLAG_FRAG_EVERY_FRAME)) {
6952
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (frag_duration >= mov->min_fragment_duration) {
6953
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (trk->entry) {
6954 // Set the duration of this track to line up with the next
6955 // sample in this track. This avoids relying on AVPacket
6956 // duration, but only helps for this particular track, not
6957 // for the other ones that are flushed at the same time.
6958 //
6959 // If we have trk->entry == 0, no fragment will be written
6960 // for this track, and we can't adjust the track end here.
6961 28 trk->track_duration = pkt->dts - trk->start_dts;
6962
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (pkt->pts != AV_NOPTS_VALUE)
6963 28 trk->end_pts = pkt->pts;
6964 else
6965 trk->end_pts = pkt->dts;
6966 28 trk->end_reliable = 1;
6967 }
6968 28 mov_auto_flush_fragment(s, 0);
6969 }
6970 }
6971
6972 18054 return ff_mov_write_packet(s, pkt);
6973 }
6974
6975 3 static int mov_write_subtitle_end_packet(AVFormatContext *s,
6976 int stream_index,
6977 int64_t dts) {
6978 3 MOVMuxContext *mov = s->priv_data;
6979 3 AVPacket *end = mov->pkt;
6980 3 uint8_t data[2] = {0};
6981 int ret;
6982
6983 3 end->size = sizeof(data);
6984 3 end->data = data;
6985 3 end->pts = dts;
6986 3 end->dts = dts;
6987 3 end->duration = 0;
6988 3 end->stream_index = stream_index;
6989
6990 3 ret = mov_write_single_packet(s, end);
6991 3 av_packet_unref(end);
6992
6993 3 return ret;
6994 }
6995
6996 #if CONFIG_IAMFENC
6997 275 static int mov_build_iamf_packet(AVFormatContext *s, MOVTrack *trk, AVPacket *pkt)
6998 {
6999 uint8_t *data;
7000 int ret;
7001
7002
2/2
✓ Branch 0 taken 55 times.
✓ Branch 1 taken 220 times.
275 if (pkt->stream_index == trk->first_iamf_idx) {
7003 55 ret = ff_iamf_write_parameter_blocks(trk->iamf, trk->iamf_buf, pkt, s);
7004
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
55 if (ret < 0)
7005 return ret;
7006 }
7007
7008 275 ret = ff_iamf_write_audio_frame(trk->iamf, trk->iamf_buf,
7009 275 s->streams[pkt->stream_index]->id, pkt);
7010
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 275 times.
275 if (ret < 0)
7011 return ret;
7012
7013
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (pkt->stream_index != trk->last_iamf_idx)
7014 220 return AVERROR(EAGAIN);
7015
7016 55 ret = avio_close_dyn_buf(trk->iamf_buf, &data);
7017 55 trk->iamf_buf = NULL;
7018
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 50 times.
55 if (!ret) {
7019
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (pkt->size) {
7020 // Either all or none of the packets for a single
7021 // IA Sample may be empty.
7022 av_log(s, AV_LOG_ERROR, "Unexpected packet from "
7023 "stream #%d\n", pkt->stream_index);
7024 ret = AVERROR_INVALIDDATA;
7025 }
7026 5 av_free(data);
7027 5 return ret;
7028 }
7029
7030 50 av_buffer_unref(&pkt->buf);
7031 50 pkt->buf = av_buffer_create(data, ret, NULL, NULL, 0);
7032
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
50 if (!pkt->buf) {
7033 av_free(data);
7034 return AVERROR(ENOMEM);
7035 }
7036 50 pkt->data = data;
7037 50 pkt->size = ret;
7038 50 pkt->stream_index = trk->first_iamf_idx;
7039
7040 50 return avio_open_dyn_buf(&trk->iamf_buf);
7041 }
7042 #endif
7043
7044 2 static int mov_write_emsg_tag(AVIOContext *pb, AVStream *st, AVPacket *pkt)
7045 {
7046 2 int64_t pos = avio_tell(pb);
7047 2 const char *scheme_id_uri = "https://aomedia.org/emsg/ID3";
7048 2 const char *value = "";
7049
7050
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 av_assert0(st->time_base.num == 1);
7051
7052 2 avio_write_marker(pb,
7053 2 av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q),
7054 AVIO_DATA_MARKER_BOUNDARY_POINT);
7055
7056 2 avio_wb32(pb, 0); /* size */
7057 2 ffio_wfourcc(pb, "emsg");
7058 2 avio_w8(pb, 1); /* version */
7059 2 avio_wb24(pb, 0);
7060 2 avio_wb32(pb, st->time_base.den); /* timescale */
7061 2 avio_wb64(pb, pkt->pts); /* presentation_time */
7062 2 avio_wb32(pb, 0xFFFFFFFFU); /* event_duration */
7063 2 avio_wb32(pb, 0); /* id */
7064 /* null terminated UTF8 strings */
7065 2 avio_write(pb, scheme_id_uri, strlen(scheme_id_uri) + 1);
7066 2 avio_write(pb, value, strlen(value) + 1);
7067 2 avio_write(pb, pkt->data, pkt->size);
7068
7069 2 return update_size(pb, pos);
7070 }
7071
7072 18391 static int mov_write_packet(AVFormatContext *s, AVPacket *pkt)
7073 {
7074 18391 MOVMuxContext *mov = s->priv_data;
7075 MOVTrack *trk;
7076
7077
2/2
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 18356 times.
18391 if (!pkt) {
7078 35 mov_flush_fragment(s, 1);
7079 35 return 1;
7080 }
7081
7082
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) {
7083 2 mov_write_emsg_tag(s->pb, s->streams[pkt->stream_index], pkt);
7084 2 return 0;
7085 }
7086
7087 18354 trk = s->streams[pkt->stream_index]->priv_data;
7088
7089 #if CONFIG_IAMFENC
7090
2/2
✓ Branch 0 taken 275 times.
✓ Branch 1 taken 18079 times.
18354 if (trk->iamf) {
7091 275 int ret = mov_build_iamf_packet(s, trk, pkt);
7092
2/2
✓ Branch 0 taken 220 times.
✓ Branch 1 taken 55 times.
275 if (ret < 0) {
7093
1/2
✓ Branch 0 taken 220 times.
✗ Branch 1 not taken.
220 if (ret == AVERROR(EAGAIN))
7094 220 return 0;
7095 av_log(s, AV_LOG_ERROR, "Error assembling an IAMF packet "
7096 "for stream #%d\n", trk->st->index);
7097 return ret;
7098 }
7099 }
7100 #endif
7101
7102
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 18132 times.
18134 if (is_cover_image(trk->st)) {
7103 int ret;
7104
7105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (trk->st->nb_frames >= 1) {
7106 if (trk->st->nb_frames == 1)
7107 av_log(s, AV_LOG_WARNING, "Got more than one picture in stream %d,"
7108 " ignoring.\n", pkt->stream_index);
7109 return 0;
7110 }
7111
7112
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = av_packet_ref(trk->cover_image, pkt)) < 0)
7113 return ret;
7114
7115 2 return 0;
7116 } else {
7117 int i;
7118
7119
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 18123 times.
18132 if (!pkt->size)
7120 9 return mov_write_single_packet(s, pkt); /* Passthrough. */
7121
7122 /*
7123 * Subtitles require special handling.
7124 *
7125 * 1) For full complaince, every track must have a sample at
7126 * dts == 0, which is rarely true for subtitles. So, as soon
7127 * as we see any packet with dts > 0, write an empty subtitle
7128 * at dts == 0 for any subtitle track with no samples in it.
7129 *
7130 * 2) For each subtitle track, check if the current packet's
7131 * dts is past the duration of the last subtitle sample. If
7132 * so, we now need to write an end sample for that subtitle.
7133 *
7134 * This must be done conditionally to allow for subtitles that
7135 * immediately replace each other, in which case an end sample
7136 * is not needed, and is, in fact, actively harmful.
7137 *
7138 * 3) See mov_write_trailer for how the final end sample is
7139 * handled.
7140 */
7141
2/2
✓ Branch 0 taken 32861 times.
✓ Branch 1 taken 18123 times.
50984 for (i = 0; i < mov->nb_tracks; i++) {
7142 32861 MOVTrack *trk = &mov->tracks[i];
7143 int ret;
7144
7145
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 32858 times.
32861 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
7146
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 trk->track_duration < pkt->dts &&
7147
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)) {
7148 2 ret = mov_write_subtitle_end_packet(s, i, trk->track_duration);
7149
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (ret < 0) return ret;
7150 2 trk->last_sample_is_subtitle_end = 1;
7151 }
7152 }
7153
7154
2/2
✓ Branch 0 taken 74 times.
✓ Branch 1 taken 18049 times.
18123 if (trk->squash_fragment_samples_to_one) {
7155 /*
7156 * If the track has to have its samples squashed into one sample,
7157 * we just take it into the track's queue.
7158 * This will then be utilized as the samples get written in either
7159 * mov_flush_fragment or when the mux is finalized in
7160 * mov_write_trailer.
7161 */
7162 74 int ret = AVERROR_BUG;
7163
7164
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 74 times.
74 if (pkt->pts == AV_NOPTS_VALUE) {
7165 av_log(s, AV_LOG_ERROR,
7166 "Packets without a valid presentation timestamp are "
7167 "not supported with packet squashing!\n");
7168 return AVERROR(EINVAL);
7169 }
7170
7171 /* The following will reset pkt and is only allowed to be used
7172 * because we return immediately. afterwards. */
7173
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 74 times.
74 if ((ret = avpriv_packet_list_put(&trk->squashed_packet_queue,
7174 pkt, NULL, 0)) < 0) {
7175 return ret;
7176 }
7177
7178 74 return 0;
7179 }
7180
7181
7182
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) {
7183 3702 AVPacket *opkt = pkt;
7184 int reshuffle_ret, ret;
7185
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 3677 times.
3702 if (trk->is_unaligned_qt_rgb) {
7186
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;
7187 25 int expected_stride = ((trk->par->width * bpc + 15) >> 4)*2;
7188 25 reshuffle_ret = ff_reshuffle_raw_rgb(s, &pkt, trk->par, expected_stride);
7189
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (reshuffle_ret < 0)
7190 return reshuffle_ret;
7191 } else
7192 3677 reshuffle_ret = 0;
7193
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) {
7194 5 ret = ff_get_packet_palette(s, opkt, reshuffle_ret, trk->palette);
7195
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7196 goto fail;
7197
1/2
✓ Branch 0 taken 5 times.
✗ Branch 1 not taken.
5 if (ret)
7198 5 trk->pal_done++;
7199
2/2
✓ Branch 0 taken 825 times.
✓ Branch 1 taken 2872 times.
3697 } else if (trk->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7200
1/2
✓ Branch 0 taken 825 times.
✗ Branch 1 not taken.
825 (trk->par->format == AV_PIX_FMT_GRAY8 ||
7201
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 825 times.
825 trk->par->format == AV_PIX_FMT_MONOBLACK)) {
7202 ret = av_packet_make_writable(pkt);
7203 if (ret < 0)
7204 goto fail;
7205 for (i = 0; i < pkt->size; i++)
7206 pkt->data[i] = ~pkt->data[i];
7207 }
7208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3702 times.
3702 if (reshuffle_ret) {
7209 ret = mov_write_single_packet(s, pkt);
7210 fail:
7211 if (reshuffle_ret)
7212 av_packet_free(&pkt);
7213 return ret;
7214 }
7215 }
7216
7217 18049 return mov_write_single_packet(s, pkt);
7218 }
7219 }
7220
7221 // QuickTime chapters involve an additional text track with the chapter names
7222 // as samples, and a tref pointing from the other tracks to the chapter one.
7223 1 static int mov_create_chapter_track(AVFormatContext *s, int tracknum)
7224 {
7225 static const uint8_t stub_header[] = {
7226 // TextSampleEntry
7227 0x00, 0x00, 0x00, 0x01, // displayFlags
7228 0x00, 0x00, // horizontal + vertical justification
7229 0x00, 0x00, 0x00, 0x00, // bgColourRed/Green/Blue/Alpha
7230 // BoxRecord
7231 0x00, 0x00, 0x00, 0x00, // defTextBoxTop/Left
7232 0x00, 0x00, 0x00, 0x00, // defTextBoxBottom/Right
7233 // StyleRecord
7234 0x00, 0x00, 0x00, 0x00, // startChar + endChar
7235 0x00, 0x01, // fontID
7236 0x00, 0x00, // fontStyleFlags + fontSize
7237 0x00, 0x00, 0x00, 0x00, // fgColourRed/Green/Blue/Alpha
7238 // FontTableBox
7239 0x00, 0x00, 0x00, 0x0D, // box size
7240 'f', 't', 'a', 'b', // box atom name
7241 0x00, 0x01, // entry count
7242 // FontRecord
7243 0x00, 0x01, // font ID
7244 0x00, // font name length
7245 };
7246 1 MOVMuxContext *mov = s->priv_data;
7247 1 MOVTrack *track = &mov->tracks[tracknum];
7248 1 AVPacket *pkt = mov->pkt;
7249 int i, len;
7250 int ret;
7251
7252 1 track->mode = mov->mode;
7253 1 track->tag = MKTAG('t','e','x','t');
7254 1 track->timescale = mov->movie_timescale;
7255 1 track->par = avcodec_parameters_alloc();
7256
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (!track->par)
7257 return AVERROR(ENOMEM);
7258 1 track->par->codec_type = AVMEDIA_TYPE_SUBTITLE;
7259 1 ret = ff_alloc_extradata(track->par, sizeof(stub_header));
7260
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 if (ret < 0)
7261 return ret;
7262 1 memcpy(track->par->extradata, stub_header, sizeof(stub_header));
7263
7264 1 pkt->stream_index = tracknum;
7265 1 pkt->flags = AV_PKT_FLAG_KEY;
7266
7267
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 for (i = 0; i < s->nb_chapters; i++) {
7268 4 AVChapter *c = s->chapters[i];
7269 AVDictionaryEntry *t;
7270
7271 4 int64_t end = av_rescale_q(c->end, c->time_base, (AVRational){1,mov->movie_timescale});
7272 4 pkt->pts = pkt->dts = av_rescale_q(c->start, c->time_base, (AVRational){1,mov->movie_timescale});
7273 4 pkt->duration = end - pkt->dts;
7274
7275
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 if ((t = av_dict_get(c->metadata, "title", NULL, 0))) {
7276 static const char encd[12] = {
7277 0x00, 0x00, 0x00, 0x0C,
7278 'e', 'n', 'c', 'd',
7279 0x00, 0x00, 0x01, 0x00 };
7280 4 len = strlen(t->value);
7281 4 pkt->size = len + 2 + 12;
7282 4 pkt->data = av_malloc(pkt->size);
7283
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
4 if (!pkt->data) {
7284 av_packet_unref(pkt);
7285 return AVERROR(ENOMEM);
7286 }
7287 4 AV_WB16(pkt->data, len);
7288 4 memcpy(pkt->data + 2, t->value, len);
7289 4 memcpy(pkt->data + len + 2, encd, sizeof(encd));
7290 4 ff_mov_write_packet(s, pkt);
7291 4 av_freep(&pkt->data);
7292 }
7293 }
7294
7295 1 av_packet_unref(mov->pkt);
7296
7297 1 return 0;
7298 }
7299
7300
7301 13 static int mov_check_timecode_track(AVFormatContext *s, AVTimecode *tc, AVStream *src_st, const char *tcstr)
7302 {
7303 int ret;
7304
7305 /* compute the frame number */
7306 13 ret = av_timecode_init_from_string(tc, src_st->avg_frame_rate, tcstr, s);
7307 13 return ret;
7308 }
7309
7310 6 static int mov_create_timecode_track(AVFormatContext *s, int index, int src_index, AVTimecode tc)
7311 {
7312 6 MOVMuxContext *mov = s->priv_data;
7313 6 MOVTrack *track = &mov->tracks[index];
7314 6 AVStream *src_st = mov->tracks[src_index].st;
7315 uint8_t data[4];
7316 6 AVPacket *pkt = mov->pkt;
7317 6 AVRational rate = src_st->avg_frame_rate;
7318 int ret;
7319
7320 /* tmcd track based on video stream */
7321 6 track->mode = mov->mode;
7322 6 track->tag = MKTAG('t','m','c','d');
7323 6 track->src_track = src_index;
7324 6 track->timescale = mov->tracks[src_index].timescale;
7325
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 if (tc.flags & AV_TIMECODE_FLAG_DROPFRAME)
7326 3 track->timecode_flags |= MOV_TIMECODE_FLAG_DROPFRAME;
7327
7328 /* set st to src_st for metadata access*/
7329 6 track->st = src_st;
7330
7331 /* encode context: tmcd data stream */
7332 6 track->par = avcodec_parameters_alloc();
7333
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!track->par)
7334 return AVERROR(ENOMEM);
7335 6 track->par->codec_type = AVMEDIA_TYPE_DATA;
7336 6 track->par->codec_tag = track->tag;
7337 6 track->st->avg_frame_rate = rate;
7338
7339 /* the tmcd track just contains one packet with the frame number */
7340 6 pkt->data = data;
7341 6 pkt->stream_index = index;
7342 6 pkt->flags = AV_PKT_FLAG_KEY;
7343 6 pkt->pts = pkt->dts = av_rescale_q(tc.start, av_inv_q(rate), (AVRational){1,mov->movie_timescale});
7344 6 pkt->size = 4;
7345 6 AV_WB32(pkt->data, tc.start);
7346 6 ret = ff_mov_write_packet(s, pkt);
7347 6 av_packet_unref(pkt);
7348 6 return ret;
7349 }
7350
7351 /*
7352 * st->disposition controls the "enabled" flag in the tkhd tag.
7353 * QuickTime will not play a track if it is not enabled. So make sure
7354 * that one track of each type (audio, video, subtitle) is enabled.
7355 *
7356 * Subtitles are special. For audio and video, setting "enabled" also
7357 * makes the track "default" (i.e. it is rendered when played). For
7358 * subtitles, an "enabled" subtitle is not rendered by default, but
7359 * if no subtitle is enabled, the subtitle menu in QuickTime will be
7360 * empty!
7361 */
7362 209 static void enable_tracks(AVFormatContext *s)
7363 {
7364 209 MOVMuxContext *mov = s->priv_data;
7365 int i;
7366 int enabled[AVMEDIA_TYPE_NB];
7367 int first[AVMEDIA_TYPE_NB];
7368
7369
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 209 times.
1254 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7370 1045 enabled[i] = 0;
7371 1045 first[i] = -1;
7372 }
7373
7374
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (i = 0; i < mov->nb_streams; i++) {
7375 267 AVStream *st = mov->tracks[i].st;
7376
7377
1/2
✓ Branch 0 taken 267 times.
✗ Branch 1 not taken.
267 if (st->codecpar->codec_type <= AVMEDIA_TYPE_UNKNOWN ||
7378
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 ||
7379 267 is_cover_image(st))
7380 2 continue;
7381
7382
2/2
✓ Branch 0 taken 251 times.
✓ Branch 1 taken 14 times.
265 if (first[st->codecpar->codec_type] < 0)
7383 251 first[st->codecpar->codec_type] = i;
7384
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 236 times.
265 if (st->disposition & AV_DISPOSITION_DEFAULT) {
7385 29 mov->tracks[i].flags |= MOV_TRACK_ENABLED;
7386 29 enabled[st->codecpar->codec_type]++;
7387 }
7388 }
7389
7390
2/2
✓ Branch 0 taken 1045 times.
✓ Branch 1 taken 209 times.
1254 for (i = 0; i < AVMEDIA_TYPE_NB; i++) {
7391
2/2
✓ Branch 0 taken 627 times.
✓ Branch 1 taken 418 times.
1045 switch (i) {
7392 627 case AVMEDIA_TYPE_VIDEO:
7393 case AVMEDIA_TYPE_AUDIO:
7394 case AVMEDIA_TYPE_SUBTITLE:
7395
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 627 times.
627 if (enabled[i] > 1)
7396 mov->per_stream_grouping = 1;
7397
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)
7398 224 mov->tracks[first[i]].flags |= MOV_TRACK_ENABLED;
7399 627 break;
7400 }
7401 }
7402 209 }
7403
7404 209 static void mov_free(AVFormatContext *s)
7405 {
7406 209 MOVMuxContext *mov = s->priv_data;
7407
7408
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (int i = 0; i < s->nb_streams; i++)
7409 288 s->streams[i]->priv_data = NULL;
7410
7411
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!mov->tracks)
7412 return;
7413
7414
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->chapter_track) {
7415 1 avcodec_parameters_free(&mov->tracks[mov->chapter_track].par);
7416 }
7417
7418
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 209 times.
485 for (int i = 0; i < mov->nb_tracks; i++) {
7419 276 MOVTrack *const track = &mov->tracks[i];
7420
7421
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 274 times.
276 if (track->tag == MKTAG('r','t','p',' '))
7422 2 ff_mov_close_hinting(track);
7423
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)
7424 6 av_freep(&track->par);
7425 276 av_freep(&track->cluster);
7426 276 av_freep(&track->cluster_written);
7427 276 av_freep(&track->frag_info);
7428 276 av_packet_free(&track->cover_image);
7429
7430
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 271 times.
276 if (track->eac3_priv) {
7431 5 struct eac3_info *info = track->eac3_priv;
7432 5 av_packet_free(&info->pkt);
7433 5 av_freep(&track->eac3_priv);
7434 }
7435
2/2
✓ Branch 0 taken 143 times.
✓ Branch 1 taken 133 times.
276 if (track->vos_len)
7436 143 av_freep(&track->vos_data);
7437
7438 276 ff_mov_cenc_free(&track->cenc);
7439 276 ffio_free_dyn_buf(&track->mdat_buf);
7440
7441 #if CONFIG_IAMFENC
7442 276 ffio_free_dyn_buf(&track->iamf_buf);
7443
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 271 times.
276 if (track->iamf)
7444 5 ff_iamf_uninit_context(track->iamf);
7445 276 av_freep(&track->iamf);
7446 #endif
7447
7448 276 avpriv_packet_list_free(&track->squashed_packet_queue);
7449 }
7450
7451 209 av_freep(&mov->tracks);
7452 209 ffio_free_dyn_buf(&mov->mdat_buf);
7453 }
7454
7455 static uint32_t rgb_to_yuv(uint32_t rgb)
7456 {
7457 uint8_t r, g, b;
7458 int y, cb, cr;
7459
7460 r = (rgb >> 16) & 0xFF;
7461 g = (rgb >> 8) & 0xFF;
7462 b = (rgb ) & 0xFF;
7463
7464 y = av_clip_uint8(( 16000 + 257 * r + 504 * g + 98 * b)/1000);
7465 cb = av_clip_uint8((128000 - 148 * r - 291 * g + 439 * b)/1000);
7466 cr = av_clip_uint8((128000 + 439 * r - 368 * g - 71 * b)/1000);
7467
7468 return (y << 16) | (cr << 8) | cb;
7469 }
7470
7471 static int mov_create_dvd_sub_decoder_specific_info(MOVTrack *track,
7472 AVStream *st)
7473 {
7474 int i, width = 720, height = 480;
7475 int have_palette = 0, have_size = 0;
7476 uint32_t palette[16];
7477 char *cur = st->codecpar->extradata;
7478
7479 while (cur && *cur) {
7480 if (strncmp("palette:", cur, 8) == 0) {
7481 int i, count;
7482 count = sscanf(cur + 8,
7483 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7484 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7485 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32", "
7486 "%06"PRIx32", %06"PRIx32", %06"PRIx32", %06"PRIx32"",
7487 &palette[ 0], &palette[ 1], &palette[ 2], &palette[ 3],
7488 &palette[ 4], &palette[ 5], &palette[ 6], &palette[ 7],
7489 &palette[ 8], &palette[ 9], &palette[10], &palette[11],
7490 &palette[12], &palette[13], &palette[14], &palette[15]);
7491
7492 for (i = 0; i < count; i++) {
7493 palette[i] = rgb_to_yuv(palette[i]);
7494 }
7495 have_palette = 1;
7496 } else if (!strncmp("size:", cur, 5)) {
7497 sscanf(cur + 5, "%dx%d", &width, &height);
7498 have_size = 1;
7499 }
7500 if (have_palette && have_size)
7501 break;
7502 cur += strcspn(cur, "\n\r");
7503 cur += strspn(cur, "\n\r");
7504 }
7505 if (have_palette) {
7506 track->vos_data = av_malloc(16*4 + AV_INPUT_BUFFER_PADDING_SIZE);
7507 if (!track->vos_data)
7508 return AVERROR(ENOMEM);
7509 for (i = 0; i < 16; i++) {
7510 AV_WB32(track->vos_data + i * 4, palette[i]);
7511 }
7512 memset(track->vos_data + 16*4, 0, AV_INPUT_BUFFER_PADDING_SIZE);
7513 track->vos_len = 16 * 4;
7514 }
7515 st->codecpar->width = width;
7516 st->codecpar->height = track->height = height;
7517
7518 return 0;
7519 }
7520
7521 #if CONFIG_IAMFENC
7522 209 static int mov_init_iamf_track(AVFormatContext *s)
7523 {
7524 209 MOVMuxContext *mov = s->priv_data;
7525 MOVTrack *track;
7526 IAMFContext *iamf;
7527 209 int first_iamf_idx = INT_MAX, last_iamf_idx = 0;
7528 209 int nb_audio_elements = 0, nb_mix_presentations = 0;
7529 int ret;
7530
7531
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209 times.
219 for (int i = 0; i < s->nb_stream_groups; i++) {
7532 10 const AVStreamGroup *stg = s->stream_groups[i];
7533
7534
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7535 5 nb_audio_elements++;
7536
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type == AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION)
7537 5 nb_mix_presentations++;
7538 }
7539
7540
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)
7541 204 return 0;
7542
7543
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) {
7544 av_log(s, AV_LOG_ERROR, "There must be >= 1 and <= 2 IAMF_AUDIO_ELEMENT and at least "
7545 "one IAMF_MIX_PRESENTATION stream groups to write a IMAF track\n");
7546 return AVERROR(EINVAL);
7547 }
7548
7549 5 iamf = av_mallocz(sizeof(*iamf));
7550
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (!iamf)
7551 return AVERROR(ENOMEM);
7552
7553
7554
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7555 10 const AVStreamGroup *stg = s->stream_groups[i];
7556
2/3
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
10 switch(stg->type) {
7557 5 case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT:
7558
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7559 25 first_iamf_idx = FFMIN(stg->streams[j]->index, first_iamf_idx);
7560 25 last_iamf_idx = FFMAX(stg->streams[j]->index, last_iamf_idx);
7561 }
7562
7563 5 ret = ff_iamf_add_audio_element(iamf, stg, s);
7564 5 break;
7565 5 case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION:
7566 5 ret = ff_iamf_add_mix_presentation(iamf, stg, s);
7567 5 break;
7568 default:
7569 av_assert0(0);
7570 }
7571
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
10 if (ret < 0)
7572 return ret;
7573 }
7574
7575 5 track = &mov->tracks[first_iamf_idx];
7576 5 track->iamf = iamf;
7577 5 track->first_iamf_idx = first_iamf_idx;
7578 5 track->last_iamf_idx = last_iamf_idx;
7579 5 track->tag = MKTAG('i','a','m','f');
7580
7581
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
15 for (int i = 0; i < s->nb_stream_groups; i++) {
7582 10 AVStreamGroup *stg = s->stream_groups[i];
7583
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7584 5 continue;
7585
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++)
7586 25 stg->streams[j]->priv_data = track;
7587 }
7588
7589 5 ret = avio_open_dyn_buf(&track->iamf_buf);
7590
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
5 if (ret < 0)
7591 return ret;
7592
7593 5 return 0;
7594 }
7595 #endif
7596
7597 209 static int mov_init(AVFormatContext *s)
7598 {
7599 209 MOVMuxContext *mov = s->priv_data;
7600 209 int has_iamf = 0;
7601 int i, ret;
7602
7603 209 mov->fc = s;
7604 209 mov->pkt = ffformatcontext(s)->pkt;
7605
7606 /* Default mode == MP4 */
7607 209 mov->mode = MODE_MP4;
7608
7609 #define IS_MODE(muxer, config) (CONFIG_ ## config ## _MUXER && !strcmp(#muxer, s->oformat->name))
7610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (IS_MODE(3gp, TGP)) mov->mode = MODE_3GP;
7611
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 else if (IS_MODE(3g2, TG2)) mov->mode = MODE_3GP|MODE_3G2;
7612
2/2
✓ Branch 0 taken 146 times.
✓ Branch 1 taken 63 times.
209 else if (IS_MODE(mov, MOV)) mov->mode = MODE_MOV;
7613
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 62 times.
63 else if (IS_MODE(psp, PSP)) mov->mode = MODE_PSP;
7614
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 61 times.
62 else if (IS_MODE(ipod, IPOD)) mov->mode = MODE_IPOD;
7615
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 57 times.
61 else if (IS_MODE(ismv, ISMV)) mov->mode = MODE_ISM;
7616
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 else if (IS_MODE(f4v, F4V)) mov->mode = MODE_F4V;
7617
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
57 else if (IS_MODE(avif, AVIF)) mov->mode = MODE_AVIF;
7618 #undef IS_MODE
7619
7620
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 192 times.
209 if (mov->flags & FF_MOV_FLAG_DELAY_MOOV)
7621 17 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV;
7622
7623
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->mode == MODE_AVIF)
7624 mov->flags |= FF_MOV_FLAG_DELAY_MOOV;
7625
7626 /* Set the FRAGMENT flag if any of the fragmentation methods are
7627 * enabled. */
7628
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 ||
7629
2/2
✓ Branch 0 taken 29 times.
✓ Branch 1 taken 179 times.
208 mov->flags & (FF_MOV_FLAG_EMPTY_MOOV |
7630 FF_MOV_FLAG_FRAG_KEYFRAME |
7631 FF_MOV_FLAG_FRAG_CUSTOM |
7632 FF_MOV_FLAG_FRAG_EVERY_FRAME))
7633 30 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7634
7635 /* Set other implicit flags immediately */
7636
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
7637 1 mov->flags |= FF_MOV_FLAG_FRAGMENT;
7638
7639
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 205 times.
209 if (mov->mode == MODE_ISM)
7640 4 mov->flags |= FF_MOV_FLAG_EMPTY_MOOV | FF_MOV_FLAG_SEPARATE_MOOF |
7641 FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7642
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 198 times.
209 if (mov->flags & FF_MOV_FLAG_DASH)
7643 11 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7644 FF_MOV_FLAG_DEFAULT_BASE_MOOF;
7645
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_CMAF)
7646 1 mov->flags |= FF_MOV_FLAG_FRAGMENT | FF_MOV_FLAG_EMPTY_MOOV |
7647 FF_MOV_FLAG_DEFAULT_BASE_MOOF | FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7648
7649
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) {
7650 29 av_log(s, AV_LOG_VERBOSE, "Empty MOOV enabled; disabling automatic bitstream filtering\n");
7651 29 s->flags &= ~AVFMT_FLAG_AUTO_BSF;
7652 }
7653
7654
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) {
7655 av_log(s, AV_LOG_WARNING, "Global SIDX enabled; Ignoring skip_sidx option\n");
7656 mov->flags &= ~FF_MOV_FLAG_SKIP_SIDX;
7657 }
7658
7659
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
7660 3 mov->reserved_moov_size = -1;
7661 }
7662
7663
2/2
✓ Branch 0 taken 202 times.
✓ Branch 1 taken 7 times.
209 if (mov->use_editlist < 0) {
7664 202 mov->use_editlist = 1;
7665
2/2
✓ Branch 0 taken 27 times.
✓ Branch 1 taken 175 times.
202 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
7666
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 15 times.
27 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
7667 // If we can avoid needing an edit list by shifting the
7668 // tracks, prefer that over (trying to) write edit lists
7669 // in fragmented output.
7670
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 11 times.
12 if (s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_AUTO ||
7671
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->avoid_negative_ts == AVFMT_AVOID_NEG_TS_MAKE_ZERO)
7672 11 mov->use_editlist = 0;
7673 }
7674
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 201 times.
202 if (mov->flags & FF_MOV_FLAG_CMAF) {
7675 // CMAF Track requires negative cts offsets without edit lists
7676 1 mov->use_editlist = 0;
7677 }
7678 }
7679
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
7680
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)
7681 1 av_log(s, AV_LOG_WARNING, "No meaningful edit list will be written when using empty_moov without delay_moov\n");
7682
7683
3/4
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
209 if (mov->flags & FF_MOV_FLAG_CMAF && mov->use_editlist) {
7684 av_log(s, AV_LOG_WARNING, "Edit list enabled; Assuming writing CMAF Track File\n");
7685 mov->flags &= ~FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS;
7686 }
7687
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 &&
7688
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 6 times.
16 !(mov->flags & FF_MOV_FLAG_NEGATIVE_CTS_OFFSETS))
7689 10 s->avoid_negative_ts = AVFMT_AVOID_NEG_TS_MAKE_ZERO;
7690
7691 /* Clear the omit_tfhd_offset flag if default_base_moof is set;
7692 * if the latter is set that's enough and omit_tfhd_offset doesn't
7693 * add anything extra on top of that. */
7694
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_OMIT_TFHD_OFFSET &&
7695 mov->flags & FF_MOV_FLAG_DEFAULT_BASE_MOOF)
7696 mov->flags &= ~FF_MOV_FLAG_OMIT_TFHD_OFFSET;
7697
7698
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->frag_interleave &&
7699 mov->flags & (FF_MOV_FLAG_OMIT_TFHD_OFFSET | FF_MOV_FLAG_SEPARATE_MOOF)) {
7700 av_log(s, AV_LOG_ERROR,
7701 "Sample interleaving in fragments is mutually exclusive with "
7702 "omit_tfhd_offset and separate_moof\n");
7703 return AVERROR(EINVAL);
7704 }
7705
7706 /* Non-seekable output is ok if using fragmentation. If ism_lookahead
7707 * is enabled, we don't support non-seekable output at all. */
7708
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 181 times.
209 if (!(s->pb->seekable & AVIO_SEEKABLE_NORMAL) &&
7709
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 ||
7710
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 mov->mode == MODE_AVIF)) {
7711 av_log(s, AV_LOG_ERROR, "muxer does not support non seekable output\n");
7712 return AVERROR(EINVAL);
7713 }
7714
7715 /* AVIF output must have at most two video streams (one for YUV and one for
7716 * alpha). */
7717
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->mode == MODE_AVIF) {
7718 if (s->nb_streams > 2) {
7719 av_log(s, AV_LOG_ERROR, "AVIF output requires exactly one or two streams\n");
7720 return AVERROR(EINVAL);
7721 }
7722 if (s->streams[0]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
7723 (s->nb_streams > 1 && s->streams[1]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO)) {
7724 av_log(s, AV_LOG_ERROR, "AVIF output supports only video streams\n");
7725 return AVERROR(EINVAL);
7726 }
7727 if (s->nb_streams > 1) {
7728 const AVPixFmtDescriptor *pixdesc =
7729 av_pix_fmt_desc_get(s->streams[1]->codecpar->format);
7730 if (pixdesc->nb_components != 1) {
7731 av_log(s, AV_LOG_ERROR, "Second stream for AVIF (alpha) output must have exactly one plane\n");
7732 return AVERROR(EINVAL);
7733 }
7734 }
7735 s->streams[0]->disposition |= AV_DISPOSITION_DEFAULT;
7736 }
7737
7738 #if CONFIG_IAMFENC
7739
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 209 times.
219 for (i = 0; i < s->nb_stream_groups; i++) {
7740 10 AVStreamGroup *stg = s->stream_groups[i];
7741
7742
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 5 times.
10 if (stg->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT)
7743 5 continue;
7744
7745
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 5 times.
30 for (int j = 0; j < stg->nb_streams; j++) {
7746 25 AVStream *st = stg->streams[j];
7747
7748
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (st->priv_data) {
7749 av_log(s, AV_LOG_ERROR, "Stream %d is present in more than one Stream Group of type "
7750 "IAMF Audio Element\n", j);
7751 return AVERROR(EINVAL);
7752 }
7753 25 st->priv_data = st;
7754 }
7755 5 has_iamf = 1;
7756
7757
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
7758 5 mov->nb_tracks++;
7759 }
7760 #endif
7761
7762
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (i = 0; i < s->nb_streams; i++) {
7763 288 AVStream *st = s->streams[i];
7764
2/2
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 263 times.
288 if (st->priv_data)
7765 25 continue;
7766 // Don't produce a track in the output file for timed ID3 streams.
7767
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 262 times.
263 if (st->codecpar->codec_id == AV_CODEC_ID_TIMED_ID3) {
7768 // Leave priv_data set to NULL for these AVStreams that don't
7769 // have a corresponding track.
7770 1 continue;
7771 }
7772 262 st->priv_data = st;
7773 262 mov->nb_tracks++;
7774 }
7775
7776 209 mov->nb_streams = mov->nb_tracks;
7777
7778
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)
7779 1 mov->chapter_track = mov->nb_tracks++;
7780
7781
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
7782
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < s->nb_streams; i++)
7783
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(s->streams[i]))
7784 2 mov->nb_tracks++;
7785 }
7786
7787
1/2
✓ Branch 0 taken 209 times.
✗ Branch 1 not taken.
209 if (mov->write_btrt < 0) {
7788 209 mov->write_btrt = mov->mode == MODE_MP4;
7789 }
7790
7791
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)
7792
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 3 times.
6 || mov->write_tmcd == 1) {
7793 206 AVDictionaryEntry *global_tcr = av_dict_get(s->metadata, "timecode",
7794 NULL, 0);
7795
7796 /* +1 tmcd track for each video stream with a timecode */
7797
2/2
✓ Branch 0 taken 283 times.
✓ Branch 1 taken 206 times.
489 for (i = 0; i < s->nb_streams; i++) {
7798 283 AVStream *st = s->streams[i];
7799 283 AVDictionaryEntry *t = global_tcr;
7800
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 &&
7801
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 171 times.
171 (t || (t=av_dict_get(st->metadata, "timecode", NULL, 0)))) {
7802 AVTimecode tc;
7803 7 ret = mov_check_timecode_track(s, &tc, st, t->value);
7804
1/2
✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
7 if (ret >= 0)
7805 7 mov->nb_meta_tmcd++;
7806 }
7807 }
7808
7809 /* check if there is already a tmcd track to remux */
7810
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 199 times.
206 if (mov->nb_meta_tmcd) {
7811
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 7 times.
20 for (i = 0; i < s->nb_streams; i++) {
7812 13 AVStream *st = s->streams[i];
7813
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 10 times.
13 if (st->codecpar->codec_tag == MKTAG('t','m','c','d')) {
7814 3 av_log(s, AV_LOG_WARNING, "You requested a copy of the original timecode track "
7815 "so timecode metadata are now ignored\n");
7816 3 mov->nb_meta_tmcd = 0;
7817 }
7818 }
7819 }
7820
7821 206 mov->nb_tracks += mov->nb_meta_tmcd;
7822 }
7823
7824 // Reserve an extra stream for chapters for the case where chapters
7825 // are written in the trailer
7826 209 mov->tracks = av_calloc(mov->nb_tracks + 1, sizeof(*mov->tracks));
7827
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (!mov->tracks)
7828 return AVERROR(ENOMEM);
7829
7830
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) {
7831 if (strcmp(mov->encryption_scheme_str, "cenc-aes-ctr") == 0) {
7832 mov->encryption_scheme = MOV_ENC_CENC_AES_CTR;
7833
7834 if (mov->encryption_key_len != AES_CTR_KEY_SIZE) {
7835 av_log(s, AV_LOG_ERROR, "Invalid encryption key len %d expected %d\n",
7836 mov->encryption_key_len, AES_CTR_KEY_SIZE);
7837 return AVERROR(EINVAL);
7838 }
7839
7840 if (mov->encryption_kid_len != CENC_KID_SIZE) {
7841 av_log(s, AV_LOG_ERROR, "Invalid encryption kid len %d expected %d\n",
7842 mov->encryption_kid_len, CENC_KID_SIZE);
7843 return AVERROR(EINVAL);
7844 }
7845 } else {
7846 av_log(s, AV_LOG_ERROR, "unsupported encryption scheme %s\n",
7847 mov->encryption_scheme_str);
7848 return AVERROR(EINVAL);
7849 }
7850 }
7851
7852 #if CONFIG_IAMFENC
7853 209 ret = mov_init_iamf_track(s);
7854
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (ret < 0)
7855 return ret;
7856 #endif
7857
7858
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (int j = 0, i = 0; j < s->nb_streams; j++) {
7859 288 AVStream *st = s->streams[j];
7860
7861
2/2
✓ Branch 0 taken 26 times.
✓ Branch 1 taken 262 times.
288 if (st != st->priv_data) {
7862
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 21 times.
26 if (has_iamf)
7863 5 i += has_iamf--;
7864 26 continue;
7865 }
7866 262 st->priv_data = &mov->tracks[i++];
7867 }
7868
7869
2/2
✓ Branch 0 taken 288 times.
✓ Branch 1 taken 209 times.
497 for (i = 0; i < s->nb_streams; i++) {
7870 288 AVStream *st= s->streams[i];
7871 288 MOVTrack *track = st->priv_data;
7872 288 AVDictionaryEntry *lang = av_dict_get(st->metadata, "language", NULL,0);
7873
7874
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 287 times.
288 if (!track)
7875 1 continue;
7876
7877
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 20 times.
287 if (!track->st) {
7878 267 track->st = st;
7879 267 track->par = st->codecpar;
7880 }
7881
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);
7882
2/2
✓ Branch 0 taken 155 times.
✓ Branch 1 taken 132 times.
287 if (track->language < 0)
7883 155 track->language = 32767; // Unspecified Macintosh language code
7884 287 track->mode = mov->mode;
7885
2/2
✓ Branch 0 taken 262 times.
✓ Branch 1 taken 25 times.
287 if (!track->tag)
7886 262 track->tag = mov_find_codec_tag(s, track);
7887
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (!track->tag) {
7888 av_log(s, AV_LOG_ERROR, "Could not find tag for codec %s in stream #%d, "
7889 "codec not currently supported in container\n",
7890 avcodec_get_name(st->codecpar->codec_id), i);
7891 return AVERROR(EINVAL);
7892 }
7893 /* If hinting of this track is enabled by a later hint track,
7894 * this is updated. */
7895 287 track->hint_track = -1;
7896 287 track->start_dts = AV_NOPTS_VALUE;
7897 287 track->start_cts = AV_NOPTS_VALUE;
7898 287 track->end_pts = AV_NOPTS_VALUE;
7899 287 track->dts_shift = AV_NOPTS_VALUE;
7900
2/2
✓ Branch 0 taken 180 times.
✓ Branch 1 taken 107 times.
287 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
7901
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') ||
7902
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') ||
7903
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')) {
7904 if (st->codecpar->width != 720 || (st->codecpar->height != 608 && st->codecpar->height != 512)) {
7905 av_log(s, AV_LOG_ERROR, "D-10/IMX must use 720x608 or 720x512 video resolution\n");
7906 return AVERROR(EINVAL);
7907 }
7908 track->height = track->tag >> 24 == 'n' ? 486 : 576;
7909 }
7910
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 if (mov->video_track_timescale) {
7911 track->timescale = mov->video_track_timescale;
7912 if (mov->mode == MODE_ISM && mov->video_track_timescale != 10000000)
7913 av_log(s, AV_LOG_WARNING, "Warning: some tools, like mp4split, assume a timescale of 10000000 for ISMV.\n");
7914 } else {
7915 180 track->timescale = st->time_base.den;
7916
2/2
✓ Branch 0 taken 1467 times.
✓ Branch 1 taken 180 times.
1647 while(track->timescale < 10000)
7917 1467 track->timescale *= 2;
7918 }
7919
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) {
7920 av_log(s, AV_LOG_ERROR, "Resolution %dx%d too large for mov/mp4\n", st->codecpar->width, st->codecpar->height);
7921 return AVERROR(EINVAL);
7922 }
7923
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)
7924 2 av_log(s, AV_LOG_WARNING,
7925 "WARNING codec timebase is very high. If duration is too long,\n"
7926 "file may not be playable by quicktime. Specify a shorter timebase\n"
7927 "or choose different container.\n");
7928
2/2
✓ Branch 0 taken 130 times.
✓ Branch 1 taken 50 times.
180 if (track->mode == MODE_MOV &&
7929
2/2
✓ Branch 0 taken 17 times.
✓ Branch 1 taken 113 times.
130 track->par->codec_id == AV_CODEC_ID_RAWVIDEO &&
7930
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 16 times.
17 track->tag == MKTAG('r','a','w',' ')) {
7931 1 enum AVPixelFormat pix_fmt = track->par->format;
7932
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)
7933 pix_fmt = AV_PIX_FMT_MONOWHITE;
7934 1 track->is_unaligned_qt_rgb =
7935 pix_fmt == AV_PIX_FMT_RGB24 ||
7936 pix_fmt == AV_PIX_FMT_BGR24 ||
7937 pix_fmt == AV_PIX_FMT_PAL8 ||
7938 pix_fmt == AV_PIX_FMT_GRAY8 ||
7939
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 ||
7940 pix_fmt == AV_PIX_FMT_MONOBLACK;
7941 }
7942
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) {
7943 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
7944 return AVERROR(EINVAL);
7945
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 179 times.
180 } else if (track->par->codec_id == AV_CODEC_ID_AV1 &&
7946
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) {
7947 av_log(s, AV_LOG_ERROR, "%s only supported in MP4 and AVIF.\n", avcodec_get_name(track->par->codec_id));
7948 return AVERROR(EINVAL);
7949
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 180 times.
180 } else if (track->par->codec_id == AV_CODEC_ID_VP8) {
7950 /* altref frames handling is not defined in the spec as of version v1.0,
7951 * so just forbid muxing VP8 streams altogether until a new version does */
7952 av_log(s, AV_LOG_ERROR, "VP8 muxing is currently not supported.\n");
7953 return AVERROR_PATCHWELCOME;
7954 }
7955
2/2
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 178 times.
180 if (is_cover_image(st)) {
7956 2 track->cover_image = av_packet_alloc();
7957
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (!track->cover_image)
7958 return AVERROR(ENOMEM);
7959 }
7960
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 7 times.
107 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
7961 100 track->timescale = st->codecpar->sample_rate;
7962
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)) {
7963 6 av_log(s, AV_LOG_WARNING, "track %d: codec frame size is not set\n", i);
7964 6 track->audio_vbr = 1;
7965
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 }else if (st->codecpar->codec_id == AV_CODEC_ID_ADPCM_MS ||
7966
1/2
✓ Branch 0 taken 94 times.
✗ Branch 1 not taken.
94 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_WAV ||
7967
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 94 times.
94 st->codecpar->codec_id == AV_CODEC_ID_ILBC){
7968 if (!st->codecpar->block_align) {
7969 av_log(s, AV_LOG_ERROR, "track %d: codec block align is not set for adpcm\n", i);
7970 return AVERROR(EINVAL);
7971 }
7972 track->sample_size = st->codecpar->block_align;
7973
2/2
✓ Branch 0 taken 69 times.
✓ Branch 1 taken 25 times.
94 }else if (st->codecpar->frame_size > 1){ /* assume compressed audio */
7974 69 track->audio_vbr = 1;
7975 }else{
7976 25 track->sample_size = (av_get_bits_per_sample(st->codecpar->codec_id) >> 3) *
7977 25 st->codecpar->ch_layout.nb_channels;
7978 }
7979
1/2
✓ Branch 0 taken 100 times.
✗ Branch 1 not taken.
100 if (st->codecpar->codec_id == AV_CODEC_ID_ILBC ||
7980
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 100 times.
100 st->codecpar->codec_id == AV_CODEC_ID_ADPCM_IMA_QT) {
7981 track->audio_vbr = 1;
7982 }
7983
2/2
✓ Branch 0 taken 68 times.
✓ Branch 1 taken 32 times.
100 if (track->mode != MODE_MOV &&
7984
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) {
7985 if (s->strict_std_compliance >= FF_COMPLIANCE_NORMAL) {
7986 av_log(s, AV_LOG_ERROR, "track %d: muxing mp3 at %dhz is not standard, to mux anyway set strict to -1\n",
7987 i, track->par->sample_rate);
7988 return AVERROR(EINVAL);
7989 } else {
7990 av_log(s, AV_LOG_WARNING, "track %d: muxing mp3 at %dhz is not standard in MP4\n",
7991 i, track->par->sample_rate);
7992 }
7993 }
7994
2/2
✓ Branch 0 taken 75 times.
✓ Branch 1 taken 25 times.
100 if (track->par->codec_id == AV_CODEC_ID_FLAC ||
7995
1/2
✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
75 track->par->codec_id == AV_CODEC_ID_TRUEHD ||
7996
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
75 track->par->codec_id == AV_CODEC_ID_OPUS) {
7997
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->mode != MODE_MP4) {
7998 av_log(s, AV_LOG_ERROR, "%s only supported in MP4.\n", avcodec_get_name(track->par->codec_id));
7999 return AVERROR(EINVAL);
8000 }
8001
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 25 times.
25 if (track->par->codec_id == AV_CODEC_ID_TRUEHD &&
8002 s->strict_std_compliance > FF_COMPLIANCE_EXPERIMENTAL) {
8003 av_log(s, AV_LOG_ERROR,
8004 "%s in MP4 support is experimental, add "
8005 "'-strict %d' if you want to use it.\n",
8006 avcodec_get_name(track->par->codec_id), FF_COMPLIANCE_EXPERIMENTAL);
8007 return AVERROR_EXPERIMENTAL;
8008 }
8009 }
8010
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 4 times.
7 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) {
8011 3 track->timescale = st->time_base.den;
8012
8013
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (track->par->codec_id == AV_CODEC_ID_TTML) {
8014 /* 14496-30 requires us to use a single sample per fragment
8015 for TTML, for which we define a per-track flag.
8016
8017 We set the flag in case we are receiving TTML paragraphs
8018 from the input, in other words in case we are not doing
8019 stream copy. */
8020 2 track->squash_fragment_samples_to_one =
8021 2 ff_is_ttml_stream_paragraph_based(track->par);
8022
8023
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (mov->flags & FF_MOV_FLAG_FRAGMENT &&
8024 track->squash_fragment_samples_to_one) {
8025 av_log(s, AV_LOG_ERROR,
8026 "Fragmentation is not currently supported for "
8027 "TTML in MP4/ISMV (track synchronization between "
8028 "subtitles and other media is not yet implemented)!\n");
8029 return AVERROR_PATCHWELCOME;
8030 }
8031
8032
1/2
✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
2 if (track->mode != MODE_ISM &&
8033
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
2 track->par->codec_tag == MOV_ISMV_TTML_TAG &&
8034
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) {
8035 av_log(s, AV_LOG_ERROR,
8036 "ISMV style TTML support with the 'dfxp' tag in "
8037 "non-ISMV formats is not officially supported. Add "
8038 "'-strict unofficial' if you want to use it.\n");
8039 return AVERROR_EXPERIMENTAL;
8040 }
8041 }
8042
1/2
✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
4 } else if (st->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
8043 4 track->timescale = st->time_base.den;
8044 } else {
8045 track->timescale = mov->movie_timescale;
8046 }
8047
1/2
✓ Branch 0 taken 287 times.
✗ Branch 1 not taken.
287 if (!track->height)
8048 287 track->height = st->codecpar->height;
8049 /* The Protected Interoperable File Format (PIFF) standard, used by ISMV recommends but
8050 doesn't mandate a track timescale of 10,000,000. The muxer allows a custom timescale
8051 for video tracks, so if user-set, it isn't overwritten */
8052
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 282 times.
287 if (mov->mode == MODE_ISM &&
8053
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 1 times.
5 (st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO ||
8054
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))) {
8055 5 track->timescale = 10000000;
8056 }
8057
8058 287 avpriv_set_pts_info(st, 64, 1, track->timescale);
8059
8060
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 287 times.
287 if (mov->encryption_scheme == MOV_ENC_CENC_AES_CTR) {
8061 ret = ff_mov_cenc_init(&track->cenc, mov->encryption_key,
8062 (track->par->codec_id == AV_CODEC_ID_H264 || track->par->codec_id == AV_CODEC_ID_HEVC ||
8063 track->par->codec_id == AV_CODEC_ID_VVC),
8064 s->flags & AVFMT_FLAG_BITEXACT);
8065 if (ret)
8066 return ret;
8067 }
8068 }
8069
8070 209 enable_tracks(s);
8071 209 return 0;
8072 }
8073
8074 209 static int mov_write_header(AVFormatContext *s)
8075 {
8076 209 AVIOContext *pb = s->pb;
8077 209 MOVMuxContext *mov = s->priv_data;
8078 209 int ret, hint_track = 0, tmcd_track = 0, nb_tracks = mov->nb_streams;
8079
8080
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)
8081 1 nb_tracks++;
8082
8083
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8084 1 hint_track = nb_tracks;
8085
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8086
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st))
8087 2 nb_tracks++;
8088 }
8089 }
8090
8091
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203 times.
209 if (mov->nb_meta_tmcd)
8092 6 tmcd_track = nb_tracks;
8093
8094
2/2
✓ Branch 0 taken 267 times.
✓ Branch 1 taken 209 times.
476 for (int i = 0; i < mov->nb_streams; i++) {
8095 267 MOVTrack *track = &mov->tracks[i];
8096 267 AVStream *st = track->st;
8097
8098 /* copy extradata if it exists */
8099
2/2
✓ Branch 0 taken 117 times.
✓ Branch 1 taken 150 times.
267 if (st->codecpar->extradata_size) {
8100
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (st->codecpar->codec_id == AV_CODEC_ID_DVD_SUBTITLE)
8101 mov_create_dvd_sub_decoder_specific_info(track, st);
8102
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) {
8103 117 track->vos_len = st->codecpar->extradata_size;
8104 117 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8105
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 117 times.
117 if (!track->vos_data) {
8106 return AVERROR(ENOMEM);
8107 }
8108 117 memcpy(track->vos_data, st->codecpar->extradata, track->vos_len);
8109 117 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8110 }
8111 }
8112
8113
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 ||
8114 80 av_channel_layout_compare(&track->par->ch_layout,
8115 80 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8116 253 continue;
8117
8118
2/2
✓ Branch 0 taken 33 times.
✓ Branch 1 taken 14 times.
47 for (int j = 0; j < mov->nb_streams; j++) {
8119 33 AVStream *stj= mov->tracks[j].st;
8120 33 MOVTrack *trackj= &mov->tracks[j];
8121
2/2
✓ Branch 0 taken 14 times.
✓ Branch 1 taken 19 times.
33 if (j == i)
8122 14 continue;
8123
8124
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 8 times.
19 if (stj->codecpar->codec_type == AVMEDIA_TYPE_AUDIO &&
8125
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 ||
8126 7 !av_channel_layout_compare(&trackj->par->ch_layout,
8127 7 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO))
8128 )
8129 4 track->mono_as_fc = -1;
8130
8131
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 &&
8132 11 av_channel_layout_compare(&trackj->par->ch_layout,
8133 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) &&
8134
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
8135 )
8136 7 track->mono_as_fc++;
8137
8138
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 ||
8139 11 av_channel_layout_compare(&trackj->par->ch_layout,
8140 11 &(AVChannelLayout)AV_CHANNEL_LAYOUT_MONO) ||
8141 trackj->language != track->language ||
8142 trackj->tag != track->tag
8143 )
8144 19 continue;
8145 track->multichannel_as_mono++;
8146 }
8147 }
8148
8149
2/2
✓ Branch 0 taken 192 times.
✓ Branch 1 taken 17 times.
209 if (!(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8150
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 192 times.
192 if ((ret = mov_write_identification(pb, s)) < 0)
8151 return ret;
8152 }
8153
8154
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 206 times.
209 if (mov->reserved_moov_size){
8155 3 mov->reserved_header_pos = avio_tell(pb);
8156
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->reserved_moov_size > 0)
8157 avio_skip(pb, mov->reserved_moov_size);
8158 }
8159
8160
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 175 times.
209 if (mov->flags & FF_MOV_FLAG_FRAGMENT) {
8161 /* If no fragmentation options have been set, set a default. */
8162
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 30 times.
34 if (!(mov->flags & (FF_MOV_FLAG_FRAG_KEYFRAME |
8163 FF_MOV_FLAG_FRAG_CUSTOM |
8164 4 FF_MOV_FLAG_FRAG_EVERY_FRAME)) &&
8165
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)
8166 4 mov->flags |= FF_MOV_FLAG_FRAG_KEYFRAME;
8167
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
34 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8168 1 avio_wb32(pb, 8); // placeholder for extended size field (64 bit)
8169
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 ffio_wfourcc(pb, mov->mode == MODE_MOV ? "wide" : "free");
8170 1 mov->mdat_pos = avio_tell(pb);
8171 }
8172
1/2
✓ Branch 0 taken 175 times.
✗ Branch 1 not taken.
175 } else if (mov->mode != MODE_AVIF) {
8173
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 172 times.
175 if (mov->flags & FF_MOV_FLAG_FASTSTART)
8174 3 mov->reserved_header_pos = avio_tell(pb);
8175 175 mov_write_mdat_tag(pb, mov);
8176 }
8177
8178 209 ff_parse_creation_time_metadata(s, &mov->time, 1);
8179
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->time)
8180 mov->time += 0x7C25B080; // 1970 based -> 1904 based
8181
8182
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->chapter_track)
8183
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
1 if ((ret = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8184 return ret;
8185
8186
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 208 times.
209 if (mov->flags & FF_MOV_FLAG_RTP_HINT) {
8187
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (int i = 0; i < mov->nb_streams; i++) {
8188
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 if (rtp_hinting_needed(mov->tracks[i].st)) {
8189
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
2 if ((ret = ff_mov_init_hinting(s, hint_track, i)) < 0)
8190 return ret;
8191 2 hint_track++;
8192 }
8193 }
8194 }
8195
8196
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 203 times.
209 if (mov->nb_meta_tmcd) {
8197 6 const AVDictionaryEntry *t, *global_tcr = av_dict_get(s->metadata,
8198 "timecode", NULL, 0);
8199 /* Initialize the tmcd tracks */
8200
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 6 times.
14 for (int i = 0; i < mov->nb_streams; i++) {
8201 8 AVStream *st = mov->tracks[i].st;
8202 8 t = global_tcr;
8203
8204
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 2 times.
8 if (st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
8205 AVTimecode tc;
8206
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8207 t = av_dict_get(st->metadata, "timecode", NULL, 0);
8208
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6 times.
6 if (!t)
8209 continue;
8210
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if (mov_check_timecode_track(s, &tc, st, t->value) < 0)
8211 continue;
8212
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 6 times.
6 if ((ret = mov_create_timecode_track(s, tmcd_track, i, tc)) < 0)
8213 return ret;
8214 6 tmcd_track++;
8215 }
8216 }
8217 }
8218
8219 209 avio_flush(pb);
8220
8221
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 209 times.
209 if (mov->flags & FF_MOV_FLAG_ISML)
8222 mov_write_isml_manifest(pb, mov, s);
8223
8224
2/2
✓ Branch 0 taken 30 times.
✓ Branch 1 taken 179 times.
209 if (mov->flags & FF_MOV_FLAG_EMPTY_MOOV &&
8225
2/2
✓ Branch 0 taken 13 times.
✓ Branch 1 taken 17 times.
30 !(mov->flags & FF_MOV_FLAG_DELAY_MOOV)) {
8226
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
13 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8227 return ret;
8228 13 mov->moov_written = 1;
8229
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
13 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX)
8230 mov->reserved_header_pos = avio_tell(pb);
8231 }
8232
8233 209 return 0;
8234 }
8235
8236 27 static int get_moov_size(AVFormatContext *s)
8237 {
8238 int ret;
8239 AVIOContext *moov_buf;
8240 27 MOVMuxContext *mov = s->priv_data;
8241
8242
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = ffio_open_null_buf(&moov_buf)) < 0)
8243 return ret;
8244
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 27 times.
27 if ((ret = mov_write_moov_tag(moov_buf, mov, s)) < 0)
8245 return ret;
8246 27 return ffio_close_null_buf(moov_buf);
8247 }
8248
8249 static int get_sidx_size(AVFormatContext *s)
8250 {
8251 int ret;
8252 AVIOContext *buf;
8253 MOVMuxContext *mov = s->priv_data;
8254
8255 if ((ret = ffio_open_null_buf(&buf)) < 0)
8256 return ret;
8257 mov_write_sidx_tags(buf, mov, -1, 0);
8258 return ffio_close_null_buf(buf);
8259 }
8260
8261 /*
8262 * This function gets the moov size if moved to the top of the file: the chunk
8263 * offset table can switch between stco (32-bit entries) to co64 (64-bit
8264 * entries) when the moov is moved to the beginning, so the size of the moov
8265 * would change. It also updates the chunk offset tables.
8266 */
8267 3 static int compute_moov_size(AVFormatContext *s)
8268 {
8269 int i, moov_size, moov_size2;
8270 3 MOVMuxContext *mov = s->priv_data;
8271
8272 3 moov_size = get_moov_size(s);
8273
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8274 return moov_size;
8275
8276
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
11 for (i = 0; i < mov->nb_tracks; i++)
8277 8 mov->tracks[i].data_offset += moov_size;
8278
8279 3 moov_size2 = get_moov_size(s);
8280
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 < 0)
8281 return moov_size2;
8282
8283 /* if the size changed, we just switched from stco to co64 and need to
8284 * update the offsets */
8285
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size2 != moov_size)
8286 for (i = 0; i < mov->nb_tracks; i++)
8287 mov->tracks[i].data_offset += moov_size2 - moov_size;
8288
8289 3 return moov_size2;
8290 }
8291
8292 static int compute_sidx_size(AVFormatContext *s)
8293 {
8294 int i, sidx_size;
8295 MOVMuxContext *mov = s->priv_data;
8296
8297 sidx_size = get_sidx_size(s);
8298 if (sidx_size < 0)
8299 return sidx_size;
8300
8301 for (i = 0; i < mov->nb_tracks; i++)
8302 mov->tracks[i].data_offset += sidx_size;
8303
8304 return sidx_size;
8305 }
8306
8307 3 static int shift_data(AVFormatContext *s)
8308 {
8309 int moov_size;
8310 3 MOVMuxContext *mov = s->priv_data;
8311
8312
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (mov->flags & FF_MOV_FLAG_FRAGMENT)
8313 moov_size = compute_sidx_size(s);
8314 else
8315 3 moov_size = compute_moov_size(s);
8316
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (moov_size < 0)
8317 return moov_size;
8318
8319 3 return ff_format_shift_data(s, mov->reserved_header_pos, moov_size);
8320 }
8321
8322 209 static int mov_write_trailer(AVFormatContext *s)
8323 {
8324 209 MOVMuxContext *mov = s->priv_data;
8325 209 AVIOContext *pb = s->pb;
8326 209 int res = 0;
8327 int i;
8328 int64_t moov_pos;
8329
8330
2/2
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 204 times.
209 if (mov->need_rewrite_extradata) {
8331
2/2
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 5 times.
12 for (i = 0; i < mov->nb_streams; i++) {
8332 7 MOVTrack *track = &mov->tracks[i];
8333 7 AVCodecParameters *par = track->par;
8334
8335 7 track->vos_len = par->extradata_size;
8336 7 av_freep(&track->vos_data);
8337 7 track->vos_data = av_malloc(track->vos_len + AV_INPUT_BUFFER_PADDING_SIZE);
8338
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
7 if (!track->vos_data)
8339 return AVERROR(ENOMEM);
8340 7 memcpy(track->vos_data, par->extradata, track->vos_len);
8341 7 memset(track->vos_data + track->vos_len, 0, AV_INPUT_BUFFER_PADDING_SIZE);
8342 }
8343 5 mov->need_rewrite_extradata = 0;
8344 }
8345
8346 /*
8347 * Before actually writing the trailer, make sure that there are no
8348 * dangling subtitles, that need a terminating sample.
8349 */
8350
2/2
✓ Branch 0 taken 276 times.
✓ Branch 1 taken 209 times.
485 for (i = 0; i < mov->nb_tracks; i++) {
8351 276 MOVTrack *trk = &mov->tracks[i];
8352
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 275 times.
276 if (trk->par->codec_id == AV_CODEC_ID_MOV_TEXT &&
8353
1/2
✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
1 !trk->last_sample_is_subtitle_end) {
8354 1 mov_write_subtitle_end_packet(s, i, trk->track_duration);
8355 1 trk->last_sample_is_subtitle_end = 1;
8356 }
8357 }
8358
8359 // Check if we have any tracks that require squashing.
8360 // In that case, we'll have to write the packet here.
8361
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 209 times.
209 if ((res = mov_write_squashed_packets(s)) < 0)
8362 return res;
8363
8364 // If there were no chapters when the header was written, but there
8365 // are chapters now, write them in the trailer. This only works
8366 // when we are not doing fragments.
8367
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)) {
8368
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) {
8369 mov->chapter_track = mov->nb_tracks++;
8370 if ((res = mov_create_chapter_track(s, mov->chapter_track)) < 0)
8371 return res;
8372 }
8373 }
8374
8375
2/2
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 175 times.
209 if (!(mov->flags & FF_MOV_FLAG_FRAGMENT) ||
8376
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 33 times.
34 mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8377
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 175 times.
176 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED) {
8378 1 mov_flush_fragment(s, 1);
8379 1 mov->mdat_size = avio_tell(pb) - mov->mdat_pos - 8;
8380
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 for (i = 0; i < mov->nb_tracks; i++) {
8381 2 MOVTrack *track = &mov->tracks[i];
8382 2 track->data_offset = 0;
8383 2 av_free(track->cluster);
8384 2 track->cluster = track->cluster_written;
8385 2 track->entry = track->entry_written;
8386 2 track->cluster_written = NULL;
8387 2 track->entry_written = 0;
8388 2 track->chunkCount = 0; // Force build_chunks to rebuild the list of chunks
8389 }
8390 // Clear the empty_moov flag, as we do want the moov to include
8391 // all the samples at this point.
8392 1 mov->flags &= ~FF_MOV_FLAG_EMPTY_MOOV;
8393 }
8394
8395 176 moov_pos = avio_tell(pb);
8396
8397 /* Write size of mdat tag */
8398
1/2
✓ Branch 0 taken 176 times.
✗ Branch 1 not taken.
176 if (mov->mdat_size + 8 <= UINT32_MAX) {
8399 176 avio_seek(pb, mov->mdat_pos, SEEK_SET);
8400 176 avio_wb32(pb, mov->mdat_size + 8);
8401
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 175 times.
176 if (mov->flags & FF_MOV_FLAG_HYBRID_FRAGMENTED)
8402 1 ffio_wfourcc(pb, "mdat"); // overwrite the original moov into a mdat
8403 } else {
8404 /* overwrite 'wide' placeholder atom */
8405 avio_seek(pb, mov->mdat_pos - 8, SEEK_SET);
8406 /* special value: real atom size will be 64 bit value after
8407 * tag field */
8408 avio_wb32(pb, 1);
8409 ffio_wfourcc(pb, "mdat");
8410 avio_wb64(pb, mov->mdat_size + 16);
8411 }
8412
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);
8413
8414
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 173 times.
176 if (mov->flags & FF_MOV_FLAG_FASTSTART) {
8415 3 av_log(s, AV_LOG_INFO, "Starting second pass: moving the moov atom to the beginning of the file\n");
8416 3 res = shift_data(s);
8417
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3 times.
3 if (res < 0)
8418 return res;
8419 3 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8420
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3 times.
3 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8421 return res;
8422
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 173 times.
173 } else if (mov->reserved_moov_size > 0) {
8423 int64_t size;
8424 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8425 return res;
8426 size = mov->reserved_moov_size - (avio_tell(pb) - mov->reserved_header_pos);
8427 if (size < 8){
8428 av_log(s, AV_LOG_ERROR, "reserved_moov_size is too small, needed %"PRId64" additional\n", 8-size);
8429 return AVERROR(EINVAL);
8430 }
8431 avio_wb32(pb, size);
8432 ffio_wfourcc(pb, "free");
8433 ffio_fill(pb, 0, size - 8);
8434 avio_seek(pb, moov_pos, SEEK_SET);
8435 } else {
8436
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 173 times.
173 if ((res = mov_write_moov_tag(pb, mov, s)) < 0)
8437 return res;
8438 }
8439 176 res = 0;
8440 } else {
8441 33 mov_auto_flush_fragment(s, 1);
8442
2/2
✓ Branch 0 taken 63 times.
✓ Branch 1 taken 33 times.
96 for (i = 0; i < mov->nb_tracks; i++)
8443 63 mov->tracks[i].data_offset = 0;
8444
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (mov->flags & FF_MOV_FLAG_GLOBAL_SIDX) {
8445 int64_t end;
8446 av_log(s, AV_LOG_INFO, "Starting second pass: inserting sidx atoms\n");
8447 res = shift_data(s);
8448 if (res < 0)
8449 return res;
8450 end = avio_tell(pb);
8451 avio_seek(pb, mov->reserved_header_pos, SEEK_SET);
8452 mov_write_sidx_tags(pb, mov, -1, 0);
8453 avio_seek(pb, end, SEEK_SET);
8454 }
8455
1/2
✓ Branch 0 taken 33 times.
✗ Branch 1 not taken.
33 if (!(mov->flags & FF_MOV_FLAG_SKIP_TRAILER)) {
8456 33 avio_write_marker(s->pb, AV_NOPTS_VALUE, AVIO_DATA_MARKER_TRAILER);
8457 33 res = mov_write_mfra_tag(pb, mov);
8458
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 33 times.
33 if (res < 0)
8459 return res;
8460 }
8461 }
8462
8463 209 return res;
8464 }
8465
8466 232 static int mov_check_bitstream(AVFormatContext *s, AVStream *st,
8467 const AVPacket *pkt)
8468 {
8469 232 int ret = 1;
8470
8471
2/2
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 223 times.
232 if (st->codecpar->codec_id == AV_CODEC_ID_AAC) {
8472
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)
8473 ret = ff_stream_add_bitstream_filter(st, "aac_adtstoasc", NULL);
8474
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 223 times.
223 } else if (st->codecpar->codec_id == AV_CODEC_ID_VP9) {
8475 ret = ff_stream_add_bitstream_filter(st, "vp9_superframe", NULL);
8476 }
8477
8478 232 return ret;
8479 }
8480
8481 #if CONFIG_AVIF_MUXER
8482 static int avif_write_trailer(AVFormatContext *s)
8483 {
8484 AVIOContext *pb = s->pb;
8485 MOVMuxContext *mov = s->priv_data;
8486 int64_t pos_backup, extent_offsets[2];
8487 uint8_t *buf;
8488 int buf_size, moov_size;
8489
8490 if (mov->moov_written) return 0;
8491
8492 mov->is_animated_avif = s->streams[0]->nb_frames > 1;
8493 if (mov->is_animated_avif && mov->nb_streams > 1) {
8494 // For animated avif with alpha channel, we need to write a tref tag
8495 // with type "auxl".
8496 mov->tracks[1].tref_tag = MKTAG('a', 'u', 'x', 'l');
8497 mov->tracks[1].tref_id = 1;
8498 }
8499 mov_write_identification(pb, s);
8500 mov_write_meta_tag(pb, mov, s);
8501
8502 moov_size = get_moov_size(s);
8503 for (int i = 0; i < mov->nb_tracks; i++)
8504 mov->tracks[i].data_offset = avio_tell(pb) + moov_size + 8;
8505
8506 if (mov->is_animated_avif) {
8507 int ret;
8508 if ((ret = mov_write_moov_tag(pb, mov, s)) < 0)
8509 return ret;
8510 }
8511
8512 buf_size = avio_get_dyn_buf(mov->mdat_buf, &buf);
8513 avio_wb32(pb, buf_size + 8);
8514 ffio_wfourcc(pb, "mdat");
8515
8516 // The offset for the YUV planes is the starting position of mdat.
8517 extent_offsets[0] = avio_tell(pb);
8518 // The offset for alpha plane is YUV offset + YUV size.
8519 extent_offsets[1] = extent_offsets[0] + mov->avif_extent_length[0];
8520
8521 avio_write(pb, buf, buf_size);
8522
8523 // write extent offsets.
8524 pos_backup = avio_tell(pb);
8525 for (int i = 0; i < mov->nb_streams; i++) {
8526 if (extent_offsets[i] != (uint32_t)extent_offsets[i]) {
8527 av_log(s, AV_LOG_ERROR, "extent offset does not fit in 32 bits\n");
8528 return AVERROR_INVALIDDATA;
8529 }
8530 avio_seek(pb, mov->avif_extent_pos[i], SEEK_SET);
8531 avio_wb32(pb, extent_offsets[i]); /* rewrite offset */
8532 }
8533 avio_seek(pb, pos_backup, SEEK_SET);
8534
8535 return 0;
8536 }
8537 #endif
8538
8539 #if CONFIG_TGP_MUXER || CONFIG_TG2_MUXER
8540 static const AVCodecTag codec_3gp_tags[] = {
8541 { AV_CODEC_ID_H263, MKTAG('s','2','6','3') },
8542 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8543 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8544 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8545 { AV_CODEC_ID_AMR_NB, MKTAG('s','a','m','r') },
8546 { AV_CODEC_ID_AMR_WB, MKTAG('s','a','w','b') },
8547 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8548 { AV_CODEC_ID_NONE, 0 },
8549 };
8550 static const AVCodecTag *const codec_3gp_tags_list[] = { codec_3gp_tags, NULL };
8551 #endif
8552
8553 static const AVCodecTag codec_mp4_tags[] = {
8554 { AV_CODEC_ID_MPEG4, MKTAG('m', 'p', '4', 'v') },
8555 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '1') },
8556 { AV_CODEC_ID_H264, MKTAG('a', 'v', 'c', '3') },
8557 { AV_CODEC_ID_HEVC, MKTAG('h', 'e', 'v', '1') },
8558 { AV_CODEC_ID_HEVC, MKTAG('h', 'v', 'c', '1') },
8559 { AV_CODEC_ID_HEVC, MKTAG('d', 'v', 'h', '1') },
8560 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'c', '1') },
8561 { AV_CODEC_ID_VVC, MKTAG('v', 'v', 'i', '1') },
8562 { AV_CODEC_ID_EVC, MKTAG('e', 'v', 'c', '1') },
8563 { AV_CODEC_ID_MPEG2VIDEO, MKTAG('m', 'p', '4', 'v') },
8564 { AV_CODEC_ID_MPEG1VIDEO, MKTAG('m', 'p', '4', 'v') },
8565 { AV_CODEC_ID_MJPEG, MKTAG('m', 'p', '4', 'v') },
8566 { AV_CODEC_ID_PNG, MKTAG('m', 'p', '4', 'v') },
8567 { AV_CODEC_ID_JPEG2000, MKTAG('m', 'p', '4', 'v') },
8568 { AV_CODEC_ID_VC1, MKTAG('v', 'c', '-', '1') },
8569 { AV_CODEC_ID_DIRAC, MKTAG('d', 'r', 'a', 'c') },
8570 { AV_CODEC_ID_TSCC2, MKTAG('m', 'p', '4', 'v') },
8571 { AV_CODEC_ID_VP9, MKTAG('v', 'p', '0', '9') },
8572 { AV_CODEC_ID_AV1, MKTAG('a', 'v', '0', '1') },
8573 { AV_CODEC_ID_AAC, MKTAG('m', 'p', '4', 'a') },
8574 { AV_CODEC_ID_ALAC, MKTAG('a', 'l', 'a', 'c') },
8575 { AV_CODEC_ID_MP4ALS, MKTAG('m', 'p', '4', 'a') },
8576 { AV_CODEC_ID_MP3, MKTAG('m', 'p', '4', 'a') },
8577 { AV_CODEC_ID_MP2, MKTAG('m', 'p', '4', 'a') },
8578 { AV_CODEC_ID_AC3, MKTAG('a', 'c', '-', '3') },
8579 { AV_CODEC_ID_EAC3, MKTAG('e', 'c', '-', '3') },
8580 { AV_CODEC_ID_DTS, MKTAG('m', 'p', '4', 'a') },
8581 { AV_CODEC_ID_TRUEHD, MKTAG('m', 'l', 'p', 'a') },
8582 { AV_CODEC_ID_FLAC, MKTAG('f', 'L', 'a', 'C') },
8583 { AV_CODEC_ID_OPUS, MKTAG('O', 'p', 'u', 's') },
8584 { AV_CODEC_ID_VORBIS, MKTAG('m', 'p', '4', 'a') },
8585 { AV_CODEC_ID_QCELP, MKTAG('m', 'p', '4', 'a') },
8586 { AV_CODEC_ID_EVRC, MKTAG('m', 'p', '4', 'a') },
8587 { AV_CODEC_ID_DVD_SUBTITLE, MKTAG('m', 'p', '4', 's') },
8588 { AV_CODEC_ID_MOV_TEXT, MKTAG('t', 'x', '3', 'g') },
8589 { AV_CODEC_ID_BIN_DATA, MKTAG('g', 'p', 'm', 'd') },
8590 { AV_CODEC_ID_MPEGH_3D_AUDIO, MKTAG('m', 'h', 'm', '1') },
8591 { AV_CODEC_ID_TTML, MOV_MP4_TTML_TAG },
8592 { AV_CODEC_ID_TTML, MOV_ISMV_TTML_TAG },
8593 { AV_CODEC_ID_FFV1, MKTAG('F', 'F', 'V', '1') },
8594
8595 /* ISO/IEC 23003-5 integer formats */
8596 { AV_CODEC_ID_PCM_S16BE, MOV_MP4_IPCM_TAG },
8597 { AV_CODEC_ID_PCM_S16LE, MOV_MP4_IPCM_TAG },
8598 { AV_CODEC_ID_PCM_S24BE, MOV_MP4_IPCM_TAG },
8599 { AV_CODEC_ID_PCM_S24LE, MOV_MP4_IPCM_TAG },
8600 { AV_CODEC_ID_PCM_S32BE, MOV_MP4_IPCM_TAG },
8601 { AV_CODEC_ID_PCM_S32LE, MOV_MP4_IPCM_TAG },
8602 /* ISO/IEC 23003-5 floating-point formats */
8603 { AV_CODEC_ID_PCM_F32BE, MOV_MP4_FPCM_TAG },
8604 { AV_CODEC_ID_PCM_F32LE, MOV_MP4_FPCM_TAG },
8605 { AV_CODEC_ID_PCM_F64BE, MOV_MP4_FPCM_TAG },
8606 { AV_CODEC_ID_PCM_F64LE, MOV_MP4_FPCM_TAG },
8607
8608 { AV_CODEC_ID_NONE, 0 },
8609 };
8610 #if CONFIG_MP4_MUXER || CONFIG_PSP_MUXER
8611 static const AVCodecTag *const mp4_codec_tags_list[] = { codec_mp4_tags, NULL };
8612 #endif
8613
8614 static const AVCodecTag codec_ism_tags[] = {
8615 { AV_CODEC_ID_WMAPRO , MKTAG('w', 'm', 'a', ' ') },
8616 { AV_CODEC_ID_TTML , MOV_ISMV_TTML_TAG },
8617 { AV_CODEC_ID_NONE , 0 },
8618 };
8619
8620 static const AVCodecTag codec_ipod_tags[] = {
8621 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8622 { AV_CODEC_ID_MPEG4, MKTAG('m','p','4','v') },
8623 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8624 { AV_CODEC_ID_ALAC, MKTAG('a','l','a','c') },
8625 { AV_CODEC_ID_AC3, MKTAG('a','c','-','3') },
8626 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','x','3','g') },
8627 { AV_CODEC_ID_MOV_TEXT, MKTAG('t','e','x','t') },
8628 { AV_CODEC_ID_NONE, 0 },
8629 };
8630
8631 static const AVCodecTag codec_f4v_tags[] = {
8632 { AV_CODEC_ID_MP3, MKTAG('.','m','p','3') },
8633 { AV_CODEC_ID_AAC, MKTAG('m','p','4','a') },
8634 { AV_CODEC_ID_H264, MKTAG('a','v','c','1') },
8635 { AV_CODEC_ID_VP6A, MKTAG('V','P','6','A') },
8636 { AV_CODEC_ID_VP6F, MKTAG('V','P','6','F') },
8637 { AV_CODEC_ID_NONE, 0 },
8638 };
8639
8640 #if CONFIG_AVIF_MUXER
8641
8642 static const AVOption avif_options[] = {
8643 { "movie_timescale", "set movie timescale", offsetof(MOVMuxContext, movie_timescale), AV_OPT_TYPE_INT, {.i64 = MOV_TIMESCALE}, 1, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM},
8644 { "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 },
8645 { NULL },
8646 };
8647 static const AVCodecTag codec_avif_tags[] = {
8648 { AV_CODEC_ID_AV1, MKTAG('a','v','0','1') },
8649 { AV_CODEC_ID_NONE, 0 },
8650 };
8651 static const AVCodecTag *const codec_avif_tags_list[] = { codec_avif_tags, NULL };
8652
8653 static const AVClass mov_avif_muxer_class = {
8654 .class_name = "avif muxer",
8655 .item_name = av_default_item_name,
8656 .option = avif_options,
8657 .version = LIBAVUTIL_VERSION_INT,
8658 };
8659 #endif
8660
8661 #if CONFIG_MOV_MUXER
8662 const FFOutputFormat ff_mov_muxer = {
8663 .p.name = "mov",
8664 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime / MOV"),
8665 .p.extensions = "mov",
8666 .priv_data_size = sizeof(MOVMuxContext),
8667 .p.audio_codec = AV_CODEC_ID_AAC,
8668 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8669 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8670 .init = mov_init,
8671 .write_header = mov_write_header,
8672 .write_packet = mov_write_packet,
8673 .write_trailer = mov_write_trailer,
8674 .deinit = mov_free,
8675 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS
8676 #if FF_API_ALLOW_FLUSH
8677 | AVFMT_ALLOW_FLUSH
8678 #endif
8679 ,
8680 .p.codec_tag = (const AVCodecTag* const []){
8681 ff_codec_movvideo_tags, ff_codec_movaudio_tags, ff_codec_movsubtitle_tags, 0
8682 },
8683 .check_bitstream = mov_check_bitstream,
8684 .p.priv_class = &mov_isobmff_muxer_class,
8685 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8686 };
8687 #endif
8688 #if CONFIG_TGP_MUXER
8689 const FFOutputFormat ff_tgp_muxer = {
8690 .p.name = "3gp",
8691 .p.long_name = NULL_IF_CONFIG_SMALL("3GP (3GPP file format)"),
8692 .p.extensions = "3gp",
8693 .priv_data_size = sizeof(MOVMuxContext),
8694 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8695 .p.video_codec = AV_CODEC_ID_H263,
8696 .init = mov_init,
8697 .write_header = mov_write_header,
8698 .write_packet = mov_write_packet,
8699 .write_trailer = mov_write_trailer,
8700 .deinit = mov_free,
8701 #if FF_API_ALLOW_FLUSH
8702 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8703 #else
8704 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8705 #endif
8706 .p.codec_tag = codec_3gp_tags_list,
8707 .check_bitstream = mov_check_bitstream,
8708 .p.priv_class = &mov_isobmff_muxer_class,
8709 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8710 };
8711 #endif
8712 #if CONFIG_MP4_MUXER
8713 const FFOutputFormat ff_mp4_muxer = {
8714 .p.name = "mp4",
8715 .p.long_name = NULL_IF_CONFIG_SMALL("MP4 (MPEG-4 Part 14)"),
8716 .p.mime_type = "video/mp4",
8717 .p.extensions = "mp4",
8718 .priv_data_size = sizeof(MOVMuxContext),
8719 .p.audio_codec = AV_CODEC_ID_AAC,
8720 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8721 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8722 .init = mov_init,
8723 .write_header = mov_write_header,
8724 .write_packet = mov_write_packet,
8725 .write_trailer = mov_write_trailer,
8726 .deinit = mov_free,
8727 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE | AVFMT_VARIABLE_FPS
8728 #if FF_API_ALLOW_FLUSH
8729 | AVFMT_ALLOW_FLUSH
8730 #endif
8731 ,
8732 .p.codec_tag = mp4_codec_tags_list,
8733 .check_bitstream = mov_check_bitstream,
8734 .p.priv_class = &mov_isobmff_muxer_class,
8735 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8736 };
8737 #endif
8738 #if CONFIG_PSP_MUXER
8739 const FFOutputFormat ff_psp_muxer = {
8740 .p.name = "psp",
8741 .p.long_name = NULL_IF_CONFIG_SMALL("PSP MP4 (MPEG-4 Part 14)"),
8742 .p.extensions = "mp4,psp",
8743 .priv_data_size = sizeof(MOVMuxContext),
8744 .p.audio_codec = AV_CODEC_ID_AAC,
8745 .p.video_codec = CONFIG_LIBX264_ENCODER ?
8746 AV_CODEC_ID_H264 : AV_CODEC_ID_MPEG4,
8747 .init = mov_init,
8748 .write_header = mov_write_header,
8749 .write_packet = mov_write_packet,
8750 .write_trailer = mov_write_trailer,
8751 .deinit = mov_free,
8752 #if FF_API_ALLOW_FLUSH
8753 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8754 #else
8755 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8756 #endif
8757 .p.codec_tag = mp4_codec_tags_list,
8758 .check_bitstream = mov_check_bitstream,
8759 .p.priv_class = &mov_isobmff_muxer_class,
8760 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8761 };
8762 #endif
8763 #if CONFIG_TG2_MUXER
8764 const FFOutputFormat ff_tg2_muxer = {
8765 .p.name = "3g2",
8766 .p.long_name = NULL_IF_CONFIG_SMALL("3GP2 (3GPP2 file format)"),
8767 .p.extensions = "3g2",
8768 .priv_data_size = sizeof(MOVMuxContext),
8769 .p.audio_codec = AV_CODEC_ID_AMR_NB,
8770 .p.video_codec = AV_CODEC_ID_H263,
8771 .init = mov_init,
8772 .write_header = mov_write_header,
8773 .write_packet = mov_write_packet,
8774 .write_trailer = mov_write_trailer,
8775 .deinit = mov_free,
8776 #if FF_API_ALLOW_FLUSH
8777 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8778 #else
8779 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8780 #endif
8781 .p.codec_tag = codec_3gp_tags_list,
8782 .check_bitstream = mov_check_bitstream,
8783 .p.priv_class = &mov_isobmff_muxer_class,
8784 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8785 };
8786 #endif
8787 #if CONFIG_IPOD_MUXER
8788 const FFOutputFormat ff_ipod_muxer = {
8789 .p.name = "ipod",
8790 .p.long_name = NULL_IF_CONFIG_SMALL("iPod H.264 MP4 (MPEG-4 Part 14)"),
8791 .p.mime_type = "video/mp4",
8792 .p.extensions = "m4v,m4a,m4b",
8793 .priv_data_size = sizeof(MOVMuxContext),
8794 .p.audio_codec = AV_CODEC_ID_AAC,
8795 .p.video_codec = AV_CODEC_ID_H264,
8796 .init = mov_init,
8797 .write_header = mov_write_header,
8798 .write_packet = mov_write_packet,
8799 .write_trailer = mov_write_trailer,
8800 .deinit = mov_free,
8801 #if FF_API_ALLOW_FLUSH
8802 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8803 #else
8804 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8805 #endif
8806 .p.codec_tag = (const AVCodecTag* const []){ codec_ipod_tags, 0 },
8807 .check_bitstream = mov_check_bitstream,
8808 .p.priv_class = &mov_isobmff_muxer_class,
8809 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8810 };
8811 #endif
8812 #if CONFIG_ISMV_MUXER
8813 const FFOutputFormat ff_ismv_muxer = {
8814 .p.name = "ismv",
8815 .p.long_name = NULL_IF_CONFIG_SMALL("ISMV/ISMA (Smooth Streaming)"),
8816 .p.mime_type = "video/mp4",
8817 .p.extensions = "ismv,isma",
8818 .priv_data_size = sizeof(MOVMuxContext),
8819 .p.audio_codec = AV_CODEC_ID_AAC,
8820 .p.video_codec = AV_CODEC_ID_H264,
8821 .init = mov_init,
8822 .write_header = mov_write_header,
8823 .write_packet = mov_write_packet,
8824 .write_trailer = mov_write_trailer,
8825 .deinit = mov_free,
8826 #if FF_API_ALLOW_FLUSH
8827 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH | AVFMT_TS_NEGATIVE,
8828 #else
8829 .p.flags = AVFMT_GLOBALHEADER | AVFMT_TS_NEGATIVE,
8830 #endif
8831 .p.codec_tag = (const AVCodecTag* const []){
8832 codec_mp4_tags, codec_ism_tags, 0 },
8833 .check_bitstream = mov_check_bitstream,
8834 .p.priv_class = &mov_isobmff_muxer_class,
8835 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8836 };
8837 #endif
8838 #if CONFIG_F4V_MUXER
8839 const FFOutputFormat ff_f4v_muxer = {
8840 .p.name = "f4v",
8841 .p.long_name = NULL_IF_CONFIG_SMALL("F4V Adobe Flash Video"),
8842 .p.mime_type = "application/f4v",
8843 .p.extensions = "f4v",
8844 .priv_data_size = sizeof(MOVMuxContext),
8845 .p.audio_codec = AV_CODEC_ID_AAC,
8846 .p.video_codec = AV_CODEC_ID_H264,
8847 .init = mov_init,
8848 .write_header = mov_write_header,
8849 .write_packet = mov_write_packet,
8850 .write_trailer = mov_write_trailer,
8851 .deinit = mov_free,
8852 #if FF_API_ALLOW_FLUSH
8853 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
8854 #else
8855 .p.flags = AVFMT_GLOBALHEADER,
8856 #endif
8857 .p.codec_tag = (const AVCodecTag* const []){ codec_f4v_tags, 0 },
8858 .check_bitstream = mov_check_bitstream,
8859 .p.priv_class = &mov_isobmff_muxer_class,
8860 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8861 };
8862 #endif
8863 #if CONFIG_AVIF_MUXER
8864 const FFOutputFormat ff_avif_muxer = {
8865 .p.name = "avif",
8866 .p.long_name = NULL_IF_CONFIG_SMALL("AVIF"),
8867 .p.mime_type = "image/avif",
8868 .p.extensions = "avif",
8869 .priv_data_size = sizeof(MOVMuxContext),
8870 .p.video_codec = AV_CODEC_ID_AV1,
8871 .init = mov_init,
8872 .write_header = mov_write_header,
8873 .write_packet = mov_write_packet,
8874 .write_trailer = avif_write_trailer,
8875 .deinit = mov_free,
8876 #if FF_API_ALLOW_FLUSH
8877 .p.flags = AVFMT_GLOBALHEADER | AVFMT_ALLOW_FLUSH,
8878 #else
8879 .p.flags = AVFMT_GLOBALHEADER,
8880 #endif
8881 .p.codec_tag = codec_avif_tags_list,
8882 .p.priv_class = &mov_avif_muxer_class,
8883 .flags_internal = FF_OFMT_FLAG_ALLOW_FLUSH,
8884 };
8885 #endif
8886