Line | Branch | Exec | Source |
---|---|---|---|
1 | /* | ||
2 | * Muxer/output file setup. | ||
3 | * | ||
4 | * This file is part of FFmpeg. | ||
5 | * | ||
6 | * FFmpeg is free software; you can redistribute it and/or | ||
7 | * modify it under the terms of the GNU Lesser General Public | ||
8 | * License as published by the Free Software Foundation; either | ||
9 | * version 2.1 of the License, or (at your option) any later version. | ||
10 | * | ||
11 | * FFmpeg is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | ||
14 | * Lesser General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU Lesser General Public | ||
17 | * License along with FFmpeg; if not, write to the Free Software | ||
18 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||
19 | */ | ||
20 | |||
21 | #include <string.h> | ||
22 | |||
23 | #include "cmdutils.h" | ||
24 | #include "ffmpeg.h" | ||
25 | #include "ffmpeg_mux.h" | ||
26 | #include "ffmpeg_sched.h" | ||
27 | #include "fopen_utf8.h" | ||
28 | |||
29 | #include "libavformat/avformat.h" | ||
30 | #include "libavformat/avio.h" | ||
31 | |||
32 | #include "libavcodec/avcodec.h" | ||
33 | |||
34 | #include "libavfilter/avfilter.h" | ||
35 | |||
36 | #include "libavutil/avassert.h" | ||
37 | #include "libavutil/avstring.h" | ||
38 | #include "libavutil/avutil.h" | ||
39 | #include "libavutil/bprint.h" | ||
40 | #include "libavutil/dict.h" | ||
41 | #include "libavutil/display.h" | ||
42 | #include "libavutil/getenv_utf8.h" | ||
43 | #include "libavutil/iamf.h" | ||
44 | #include "libavutil/intreadwrite.h" | ||
45 | #include "libavutil/log.h" | ||
46 | #include "libavutil/mem.h" | ||
47 | #include "libavutil/opt.h" | ||
48 | #include "libavutil/parseutils.h" | ||
49 | #include "libavutil/pixdesc.h" | ||
50 | |||
51 | #define DEFAULT_PASS_LOGFILENAME_PREFIX "ffmpeg2pass" | ||
52 | |||
53 | 6542 | static int check_opt_bitexact(void *ctx, const AVDictionary *opts, | |
54 | const char *opt_name, int flag) | ||
55 | { | ||
56 | 6542 | const AVDictionaryEntry *e = av_dict_get(opts, opt_name, NULL, 0); | |
57 | |||
58 |
2/2✓ Branch 0 taken 5559 times.
✓ Branch 1 taken 983 times.
|
6542 | if (e) { |
59 | 5559 | const AVOption *o = av_opt_find(ctx, opt_name, NULL, 0, 0); | |
60 | 5559 | int val = 0; | |
61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5559 times.
|
5559 | if (!o) |
62 | ✗ | return 0; | |
63 | 5559 | av_opt_eval_flags(ctx, o, e->value, &val); | |
64 | 5559 | return !!(val & flag); | |
65 | } | ||
66 | 983 | return 0; | |
67 | } | ||
68 | |||
69 | 8896 | static int choose_encoder(const OptionsContext *o, AVFormatContext *s, | |
70 | MuxStream *ms, const AVCodec **enc) | ||
71 | { | ||
72 | 8896 | OutputStream *ost = &ms->ost; | |
73 | 8896 | enum AVMediaType type = ost->type; | |
74 | 8896 | const char *codec_name = NULL; | |
75 | |||
76 | 8896 | *enc = NULL; | |
77 | |||
78 | 8896 | opt_match_per_stream_str(ost, &o->codec_names, s, ost->st, &codec_name); | |
79 | |||
80 |
4/4✓ Branch 0 taken 1728 times.
✓ Branch 1 taken 7168 times.
✓ Branch 2 taken 93 times.
✓ Branch 3 taken 1635 times.
|
8896 | if (type != AVMEDIA_TYPE_VIDEO && |
81 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 80 times.
|
93 | type != AVMEDIA_TYPE_AUDIO && |
82 | type != AVMEDIA_TYPE_SUBTITLE) { | ||
83 |
3/4✓ Branch 0 taken 6 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
|
13 | if (codec_name && strcmp(codec_name, "copy")) { |
84 | ✗ | const char *type_str = av_get_media_type_string(type); | |
85 | ✗ | av_log(ost, AV_LOG_FATAL, | |
86 | "Encoder '%s' specified, but only '-codec copy' supported " | ||
87 | "for %s streams\n", codec_name, type_str); | ||
88 | ✗ | return AVERROR(ENOSYS); | |
89 | } | ||
90 | 13 | return 0; | |
91 | } | ||
92 | |||
93 |
2/2✓ Branch 0 taken 4113 times.
✓ Branch 1 taken 4770 times.
|
8883 | if (!codec_name) { |
94 | 4113 | ms->par_in->codec_id = av_guess_codec(s->oformat, NULL, s->url, NULL, ost->type); | |
95 | 4113 | *enc = avcodec_find_encoder(ms->par_in->codec_id); | |
96 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4113 times.
|
4113 | if (!*enc) { |
97 | ✗ | av_log(ost, AV_LOG_FATAL, "Automatic encoder selection failed " | |
98 | "Default encoder for format %s (codec %s) is " | ||
99 | "probably disabled. Please choose an encoder manually.\n", | ||
100 | ✗ | s->oformat->name, avcodec_get_name(ms->par_in->codec_id)); | |
101 | ✗ | return AVERROR_ENCODER_NOT_FOUND; | |
102 | } | ||
103 |
2/2✓ Branch 0 taken 4059 times.
✓ Branch 1 taken 711 times.
|
4770 | } else if (strcmp(codec_name, "copy")) { |
104 | 4059 | int ret = find_codec(ost, codec_name, ost->type, 1, enc); | |
105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4059 times.
|
4059 | if (ret < 0) |
106 | ✗ | return ret; | |
107 | 4059 | ms->par_in->codec_id = (*enc)->id; | |
108 | } | ||
109 | |||
110 | 8883 | return 0; | |
111 | } | ||
112 | |||
113 | ✗ | static char *get_line(AVIOContext *s, AVBPrint *bprint) | |
114 | { | ||
115 | char c; | ||
116 | |||
117 | ✗ | while ((c = avio_r8(s)) && c != '\n') | |
118 | ✗ | av_bprint_chars(bprint, c, 1); | |
119 | |||
120 | ✗ | if (!av_bprint_is_complete(bprint)) | |
121 | ✗ | return NULL; | |
122 | |||
123 | ✗ | return bprint->str; | |
124 | } | ||
125 | |||
126 | ✗ | static int get_preset_file_2(const char *preset_name, const char *codec_name, AVIOContext **s) | |
127 | { | ||
128 | ✗ | int i, ret = -1; | |
129 | char filename[1000]; | ||
130 | ✗ | char *env_avconv_datadir = getenv_utf8("AVCONV_DATADIR"); | |
131 | ✗ | char *env_home = getenv_utf8("HOME"); | |
132 | ✗ | const char *base[3] = { env_avconv_datadir, | |
133 | env_home, | ||
134 | AVCONV_DATADIR, | ||
135 | }; | ||
136 | |||
137 | ✗ | for (i = 0; i < FF_ARRAY_ELEMS(base) && ret < 0; i++) { | |
138 | ✗ | if (!base[i]) | |
139 | ✗ | continue; | |
140 | ✗ | if (codec_name) { | |
141 | ✗ | snprintf(filename, sizeof(filename), "%s%s/%s-%s.avpreset", base[i], | |
142 | i != 1 ? "" : "/.avconv", codec_name, preset_name); | ||
143 | ✗ | ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); | |
144 | } | ||
145 | ✗ | if (ret < 0) { | |
146 | ✗ | snprintf(filename, sizeof(filename), "%s%s/%s.avpreset", base[i], | |
147 | i != 1 ? "" : "/.avconv", preset_name); | ||
148 | ✗ | ret = avio_open2(s, filename, AVIO_FLAG_READ, &int_cb, NULL); | |
149 | } | ||
150 | } | ||
151 | ✗ | freeenv_utf8(env_home); | |
152 | ✗ | freeenv_utf8(env_avconv_datadir); | |
153 | ✗ | return ret; | |
154 | } | ||
155 | |||
156 | typedef struct EncStatsFile { | ||
157 | char *path; | ||
158 | AVIOContext *io; | ||
159 | } EncStatsFile; | ||
160 | |||
161 | static EncStatsFile *enc_stats_files; | ||
162 | static int nb_enc_stats_files; | ||
163 | |||
164 | ✗ | static int enc_stats_get_file(AVIOContext **io, const char *path) | |
165 | { | ||
166 | EncStatsFile *esf; | ||
167 | int ret; | ||
168 | |||
169 | ✗ | for (int i = 0; i < nb_enc_stats_files; i++) | |
170 | ✗ | if (!strcmp(path, enc_stats_files[i].path)) { | |
171 | ✗ | *io = enc_stats_files[i].io; | |
172 | ✗ | return 0; | |
173 | } | ||
174 | |||
175 | ✗ | ret = GROW_ARRAY(enc_stats_files, nb_enc_stats_files); | |
176 | ✗ | if (ret < 0) | |
177 | ✗ | return ret; | |
178 | |||
179 | ✗ | esf = &enc_stats_files[nb_enc_stats_files - 1]; | |
180 | |||
181 | ✗ | ret = avio_open2(&esf->io, path, AVIO_FLAG_WRITE, &int_cb, NULL); | |
182 | ✗ | if (ret < 0) { | |
183 | ✗ | av_log(NULL, AV_LOG_ERROR, "Error opening stats file '%s': %s\n", | |
184 | ✗ | path, av_err2str(ret)); | |
185 | ✗ | return ret; | |
186 | } | ||
187 | |||
188 | ✗ | esf->path = av_strdup(path); | |
189 | ✗ | if (!esf->path) | |
190 | ✗ | return AVERROR(ENOMEM); | |
191 | |||
192 | ✗ | *io = esf->io; | |
193 | |||
194 | ✗ | return 0; | |
195 | } | ||
196 | |||
197 | 8403 | void of_enc_stats_close(void) | |
198 | { | ||
199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8403 times.
|
8403 | for (int i = 0; i < nb_enc_stats_files; i++) { |
200 | ✗ | av_freep(&enc_stats_files[i].path); | |
201 | ✗ | avio_closep(&enc_stats_files[i].io); | |
202 | } | ||
203 | 8403 | av_freep(&enc_stats_files); | |
204 | 8403 | nb_enc_stats_files = 0; | |
205 | 8403 | } | |
206 | |||
207 | ✗ | static int unescape(char **pdst, size_t *dst_len, | |
208 | const char **pstr, char delim) | ||
209 | { | ||
210 | ✗ | const char *str = *pstr; | |
211 | char *dst; | ||
212 | size_t len, idx; | ||
213 | |||
214 | ✗ | *pdst = NULL; | |
215 | |||
216 | ✗ | len = strlen(str); | |
217 | ✗ | if (!len) | |
218 | ✗ | return 0; | |
219 | |||
220 | ✗ | dst = av_malloc(len + 1); | |
221 | ✗ | if (!dst) | |
222 | ✗ | return AVERROR(ENOMEM); | |
223 | |||
224 | ✗ | for (idx = 0; *str; idx++, str++) { | |
225 | ✗ | if (str[0] == '\\' && str[1]) | |
226 | ✗ | str++; | |
227 | ✗ | else if (*str == delim) | |
228 | ✗ | break; | |
229 | |||
230 | ✗ | dst[idx] = *str; | |
231 | } | ||
232 | ✗ | if (!idx) { | |
233 | ✗ | av_freep(&dst); | |
234 | ✗ | return 0; | |
235 | } | ||
236 | |||
237 | ✗ | dst[idx] = 0; | |
238 | |||
239 | ✗ | *pdst = dst; | |
240 | ✗ | *dst_len = idx; | |
241 | ✗ | *pstr = str; | |
242 | |||
243 | ✗ | return 0; | |
244 | } | ||
245 | |||
246 | ✗ | static int enc_stats_init(OutputStream *ost, EncStats *es, int pre, | |
247 | const char *path, const char *fmt_spec) | ||
248 | { | ||
249 | static const struct { | ||
250 | enum EncStatsType type; | ||
251 | const char *str; | ||
252 | unsigned pre_only:1; | ||
253 | unsigned post_only:1; | ||
254 | unsigned need_input_data:1; | ||
255 | } fmt_specs[] = { | ||
256 | { ENC_STATS_FILE_IDX, "fidx" }, | ||
257 | { ENC_STATS_STREAM_IDX, "sidx" }, | ||
258 | { ENC_STATS_FRAME_NUM, "n" }, | ||
259 | { ENC_STATS_FRAME_NUM_IN, "ni", 0, 0, 1 }, | ||
260 | { ENC_STATS_TIMEBASE, "tb" }, | ||
261 | { ENC_STATS_TIMEBASE_IN, "tbi", 0, 0, 1 }, | ||
262 | { ENC_STATS_PTS, "pts" }, | ||
263 | { ENC_STATS_PTS_TIME, "t" }, | ||
264 | { ENC_STATS_PTS_IN, "ptsi", 0, 0, 1 }, | ||
265 | { ENC_STATS_PTS_TIME_IN, "ti", 0, 0, 1 }, | ||
266 | { ENC_STATS_DTS, "dts", 0, 1 }, | ||
267 | { ENC_STATS_DTS_TIME, "dt", 0, 1 }, | ||
268 | { ENC_STATS_SAMPLE_NUM, "sn", 1 }, | ||
269 | { ENC_STATS_NB_SAMPLES, "samp", 1 }, | ||
270 | { ENC_STATS_PKT_SIZE, "size", 0, 1 }, | ||
271 | { ENC_STATS_BITRATE, "br", 0, 1 }, | ||
272 | { ENC_STATS_AVG_BITRATE, "abr", 0, 1 }, | ||
273 | { ENC_STATS_KEYFRAME, "key", 0, 1 }, | ||
274 | }; | ||
275 | ✗ | const char *next = fmt_spec; | |
276 | |||
277 | int ret; | ||
278 | |||
279 | ✗ | while (*next) { | |
280 | EncStatsComponent *c; | ||
281 | char *val; | ||
282 | size_t val_len; | ||
283 | |||
284 | // get the sequence up until next opening brace | ||
285 | ✗ | ret = unescape(&val, &val_len, &next, '{'); | |
286 | ✗ | if (ret < 0) | |
287 | ✗ | return ret; | |
288 | |||
289 | ✗ | if (val) { | |
290 | ✗ | ret = GROW_ARRAY(es->components, es->nb_components); | |
291 | ✗ | if (ret < 0) { | |
292 | ✗ | av_freep(&val); | |
293 | ✗ | return ret; | |
294 | } | ||
295 | |||
296 | ✗ | c = &es->components[es->nb_components - 1]; | |
297 | ✗ | c->type = ENC_STATS_LITERAL; | |
298 | ✗ | c->str = val; | |
299 | ✗ | c->str_len = val_len; | |
300 | } | ||
301 | |||
302 | ✗ | if (!*next) | |
303 | ✗ | break; | |
304 | ✗ | next++; | |
305 | |||
306 | // get the part inside braces | ||
307 | ✗ | ret = unescape(&val, &val_len, &next, '}'); | |
308 | ✗ | if (ret < 0) | |
309 | ✗ | return ret; | |
310 | |||
311 | ✗ | if (!val) { | |
312 | ✗ | av_log(NULL, AV_LOG_ERROR, | |
313 | "Empty formatting directive in: %s\n", fmt_spec); | ||
314 | ✗ | return AVERROR(EINVAL); | |
315 | } | ||
316 | |||
317 | ✗ | if (!*next) { | |
318 | ✗ | av_log(NULL, AV_LOG_ERROR, | |
319 | "Missing closing brace in: %s\n", fmt_spec); | ||
320 | ✗ | ret = AVERROR(EINVAL); | |
321 | ✗ | goto fail; | |
322 | } | ||
323 | ✗ | next++; | |
324 | |||
325 | ✗ | ret = GROW_ARRAY(es->components, es->nb_components); | |
326 | ✗ | if (ret < 0) | |
327 | ✗ | goto fail; | |
328 | |||
329 | ✗ | c = &es->components[es->nb_components - 1]; | |
330 | |||
331 | ✗ | for (size_t i = 0; i < FF_ARRAY_ELEMS(fmt_specs); i++) { | |
332 | ✗ | if (!strcmp(val, fmt_specs[i].str)) { | |
333 | ✗ | if ((pre && fmt_specs[i].post_only) || (!pre && fmt_specs[i].pre_only)) { | |
334 | ✗ | av_log(NULL, AV_LOG_ERROR, | |
335 | "Format directive '%s' may only be used %s-encoding\n", | ||
336 | val, pre ? "post" : "pre"); | ||
337 | ✗ | ret = AVERROR(EINVAL); | |
338 | ✗ | goto fail; | |
339 | } | ||
340 | |||
341 | ✗ | c->type = fmt_specs[i].type; | |
342 | |||
343 | ✗ | if (fmt_specs[i].need_input_data && !ost->ist) { | |
344 | ✗ | av_log(ost, AV_LOG_WARNING, | |
345 | "Format directive '%s' is unavailable, because " | ||
346 | "this output stream has no associated input stream\n", | ||
347 | val); | ||
348 | } | ||
349 | |||
350 | ✗ | break; | |
351 | } | ||
352 | } | ||
353 | |||
354 | ✗ | if (!c->type) { | |
355 | ✗ | av_log(NULL, AV_LOG_ERROR, "Invalid format directive: %s\n", val); | |
356 | ✗ | ret = AVERROR(EINVAL); | |
357 | ✗ | goto fail; | |
358 | } | ||
359 | |||
360 | ✗ | fail: | |
361 | ✗ | av_freep(&val); | |
362 | ✗ | if (ret < 0) | |
363 | ✗ | return ret; | |
364 | } | ||
365 | |||
366 | ✗ | ret = pthread_mutex_init(&es->lock, NULL); | |
367 | ✗ | if (ret) | |
368 | ✗ | return AVERROR(ret); | |
369 | ✗ | es->lock_initialized = 1; | |
370 | |||
371 | ✗ | ret = enc_stats_get_file(&es->io, path); | |
372 | ✗ | if (ret < 0) | |
373 | ✗ | return ret; | |
374 | |||
375 | ✗ | return 0; | |
376 | } | ||
377 | |||
378 | 2427 | static const char *output_stream_item_name(void *obj) | |
379 | { | ||
380 | 2427 | const MuxStream *ms = obj; | |
381 | |||
382 | 2427 | return ms->log_name; | |
383 | } | ||
384 | |||
385 | static const AVClass output_stream_class = { | ||
386 | .class_name = "OutputStream", | ||
387 | .version = LIBAVUTIL_VERSION_INT, | ||
388 | .item_name = output_stream_item_name, | ||
389 | .category = AV_CLASS_CATEGORY_MUXER, | ||
390 | }; | ||
391 | |||
392 | 8896 | static MuxStream *mux_stream_alloc(Muxer *mux, enum AVMediaType type) | |
393 | { | ||
394 | 8896 | const char *type_str = av_get_media_type_string(type); | |
395 | MuxStream *ms; | ||
396 | |||
397 | 8896 | ms = allocate_array_elem(&mux->of.streams, sizeof(*ms), &mux->of.nb_streams); | |
398 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8896 times.
|
8896 | if (!ms) |
399 | ✗ | return NULL; | |
400 | |||
401 | 8896 | ms->ost.file = &mux->of; | |
402 | 8896 | ms->ost.index = mux->of.nb_streams - 1; | |
403 | 8896 | ms->ost.type = type; | |
404 | |||
405 | 8896 | ms->ost.class = &output_stream_class; | |
406 | |||
407 | 8896 | ms->sch_idx = -1; | |
408 | 8896 | ms->sch_idx_enc = -1; | |
409 | |||
410 |
1/2✓ Branch 0 taken 8896 times.
✗ Branch 1 not taken.
|
8896 | snprintf(ms->log_name, sizeof(ms->log_name), "%cost#%d:%d", |
411 | 8896 | type_str ? *type_str : '?', mux->of.index, ms->ost.index); | |
412 | |||
413 | 8896 | return ms; | |
414 | } | ||
415 | |||
416 | 8130 | static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc, | |
417 | OutputStream *ost, char **dst) | ||
418 | { | ||
419 | 8130 | const char *filters = NULL; | |
420 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
421 | 8130 | const char *filters_script = NULL; | |
422 | |||
423 | 8130 | opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script); | |
424 | #endif | ||
425 | 8130 | opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters); | |
426 | |||
427 |
2/2✓ Branch 0 taken 1337 times.
✓ Branch 1 taken 6793 times.
|
8130 | if (!ost->ist) { |
428 | 1337 | if ( | |
429 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
430 |
2/4✓ Branch 0 taken 1337 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1337 times.
|
1337 | filters_script || |
431 | #endif | ||
432 | filters) { | ||
433 | ✗ | av_log(ost, AV_LOG_ERROR, | |
434 | "%s '%s' was specified for a stream fed from a complex " | ||
435 | "filtergraph. Simple and complex filtering cannot be used " | ||
436 | "together for the same stream.\n", | ||
437 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
438 | ✗ | filters ? "Filtergraph" : "Filtergraph script", | |
439 | ✗ | filters ? filters : filters_script | |
440 | #else | ||
441 | "Filtergraph", filters | ||
442 | #endif | ||
443 | ); | ||
444 | ✗ | return AVERROR(EINVAL); | |
445 | } | ||
446 | 1337 | return 0; | |
447 | } | ||
448 | |||
449 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
450 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
6793 | if (filters_script && filters) { |
451 | ✗ | av_log(ost, AV_LOG_ERROR, "Both -filter and -filter_script set\n"); | |
452 | ✗ | return AVERROR(EINVAL); | |
453 | } | ||
454 | |||
455 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (filters_script) |
456 | ✗ | *dst = file_read(filters_script); | |
457 | else | ||
458 | #endif | ||
459 |
2/2✓ Branch 0 taken 3918 times.
✓ Branch 1 taken 2875 times.
|
6793 | if (filters) |
460 | 3918 | *dst = av_strdup(filters); | |
461 | else | ||
462 |
2/2✓ Branch 0 taken 2291 times.
✓ Branch 1 taken 584 times.
|
2875 | *dst = av_strdup(ost->type == AVMEDIA_TYPE_VIDEO ? "null" : "anull"); |
463 |
1/2✓ Branch 0 taken 6793 times.
✗ Branch 1 not taken.
|
6793 | return *dst ? 0 : AVERROR(ENOMEM); |
464 | } | ||
465 | |||
466 | ✗ | static int parse_matrix_coeffs(void *logctx, uint16_t *dest, const char *str) | |
467 | { | ||
468 | ✗ | const char *p = str; | |
469 | ✗ | for (int i = 0;; i++) { | |
470 | ✗ | dest[i] = atoi(p); | |
471 | ✗ | if (i == 63) | |
472 | ✗ | break; | |
473 | ✗ | p = strchr(p, ','); | |
474 | ✗ | if (!p) { | |
475 | ✗ | av_log(logctx, AV_LOG_FATAL, | |
476 | "Syntax error in matrix \"%s\" at coeff %d\n", str, i); | ||
477 | ✗ | return AVERROR(EINVAL); | |
478 | } | ||
479 | ✗ | p++; | |
480 | } | ||
481 | |||
482 | ✗ | return 0; | |
483 | } | ||
484 | |||
485 | 646 | static int fmt_in_list(const int *formats, int format) | |
486 | { | ||
487 |
1/2✓ Branch 0 taken 3706 times.
✗ Branch 1 not taken.
|
3706 | for (; *formats != -1; formats++) |
488 |
2/2✓ Branch 0 taken 646 times.
✓ Branch 1 taken 3060 times.
|
3706 | if (*formats == format) |
489 | 646 | return 1; | |
490 | ✗ | return 0; | |
491 | } | ||
492 | |||
493 | static enum AVPixelFormat | ||
494 | ✗ | choose_pixel_fmt(const AVCodecContext *avctx, enum AVPixelFormat target) | |
495 | { | ||
496 | const enum AVPixelFormat *p; | ||
497 | ✗ | const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(target); | |
498 | //FIXME: This should check for AV_PIX_FMT_FLAG_ALPHA after PAL8 pixel format without alpha is implemented | ||
499 | ✗ | int has_alpha = desc ? desc->nb_components % 2 == 0 : 0; | |
500 | ✗ | enum AVPixelFormat best= AV_PIX_FMT_NONE; | |
501 | int ret; | ||
502 | |||
503 | ✗ | ret = avcodec_get_supported_config(avctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, | |
504 | 0, (const void **) &p, NULL); | ||
505 | ✗ | if (ret < 0) | |
506 | ✗ | return AV_PIX_FMT_NONE; | |
507 | |||
508 | ✗ | for (; *p != AV_PIX_FMT_NONE; p++) { | |
509 | ✗ | best = av_find_best_pix_fmt_of_2(best, *p, target, has_alpha, NULL); | |
510 | ✗ | if (*p == target) | |
511 | ✗ | break; | |
512 | } | ||
513 | ✗ | if (*p == AV_PIX_FMT_NONE) { | |
514 | ✗ | if (target != AV_PIX_FMT_NONE) | |
515 | ✗ | av_log(NULL, AV_LOG_WARNING, | |
516 | "Incompatible pixel format '%s' for codec '%s', auto-selecting format '%s'\n", | ||
517 | av_get_pix_fmt_name(target), | ||
518 | ✗ | avctx->codec->name, | |
519 | av_get_pix_fmt_name(best)); | ||
520 | ✗ | return best; | |
521 | } | ||
522 | ✗ | return target; | |
523 | } | ||
524 | |||
525 | 5302 | static enum AVPixelFormat pix_fmt_parse(OutputStream *ost, const char *name) | |
526 | { | ||
527 | const enum AVPixelFormat *fmts; | ||
528 | enum AVPixelFormat fmt; | ||
529 | int ret; | ||
530 | |||
531 | 5302 | fmt = av_get_pix_fmt(name); | |
532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5302 times.
|
5302 | if (fmt == AV_PIX_FMT_NONE) { |
533 | ✗ | av_log(ost, AV_LOG_FATAL, "Unknown pixel format requested: %s.\n", name); | |
534 | ✗ | return AV_PIX_FMT_NONE; | |
535 | } | ||
536 | |||
537 | 5302 | ret = avcodec_get_supported_config(ost->enc->enc_ctx, NULL, AV_CODEC_CONFIG_PIX_FORMAT, | |
538 | 0, (const void **) &fmts, NULL); | ||
539 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5302 times.
|
5302 | if (ret < 0) |
540 | ✗ | return AV_PIX_FMT_NONE; | |
541 | |||
542 | /* when the user specified-format is an alias for an endianness-specific | ||
543 | * one (e.g. rgb48 -> rgb48be/le), it gets translated into the native | ||
544 | * endianness by av_get_pix_fmt(); | ||
545 | * the following code handles the case when the native endianness is not | ||
546 | * supported by the encoder, but the other one is */ | ||
547 |
3/4✓ Branch 0 taken 323 times.
✓ Branch 1 taken 4979 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 323 times.
|
5302 | if (fmts && !fmt_in_list(fmts, fmt)) { |
548 | ✗ | const char *name_canonical = av_get_pix_fmt_name(fmt); | |
549 | ✗ | int len = strlen(name_canonical); | |
550 | |||
551 | ✗ | if (strcmp(name, name_canonical) && | |
552 | ✗ | (!strcmp(name_canonical + len - 2, "le") || | |
553 | ✗ | !strcmp(name_canonical + len - 2, "be"))) { | |
554 | char name_other[64]; | ||
555 | enum AVPixelFormat fmt_other; | ||
556 | |||
557 | ✗ | snprintf(name_other, sizeof(name_other), "%s%ce", | |
558 | ✗ | name, name_canonical[len - 2] == 'l' ? 'b' : 'l'); | |
559 | ✗ | fmt_other = av_get_pix_fmt(name_other); | |
560 | ✗ | if (fmt_other != AV_PIX_FMT_NONE && fmt_in_list(fmts, fmt_other)) { | |
561 | ✗ | av_log(ost, AV_LOG_VERBOSE, "Mapping pixel format %s->%s\n", | |
562 | name, name_other); | ||
563 | ✗ | fmt = fmt_other; | |
564 | } | ||
565 | } | ||
566 | } | ||
567 | |||
568 |
3/4✓ Branch 0 taken 323 times.
✓ Branch 1 taken 4979 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 323 times.
|
5302 | if (fmts && !fmt_in_list(fmts, fmt)) |
569 | ✗ | fmt = choose_pixel_fmt(ost->enc->enc_ctx, fmt); | |
570 | |||
571 | 5302 | return fmt; | |
572 | } | ||
573 | |||
574 | 7168 | static int new_stream_video(Muxer *mux, const OptionsContext *o, | |
575 | OutputStream *ost, int *keep_pix_fmt, | ||
576 | enum VideoSyncMethod *vsync_method) | ||
577 | { | ||
578 | 7168 | MuxStream *ms = ms_from_ost(ost); | |
579 | 7168 | AVFormatContext *oc = mux->fc; | |
580 | AVStream *st; | ||
581 | 7168 | const char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL; | |
582 | 7168 | int ret = 0; | |
583 | |||
584 | 7168 | st = ost->st; | |
585 | |||
586 | 7168 | opt_match_per_stream_str(ost, &o->frame_rates, oc, st, &frame_rate); | |
587 |
3/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 7146 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
|
7168 | if (frame_rate && av_parse_video_rate(&ms->frame_rate, frame_rate) < 0) { |
588 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate); | |
589 | ✗ | return AVERROR(EINVAL); | |
590 | } | ||
591 | |||
592 | 7168 | opt_match_per_stream_str(ost, &o->max_frame_rates, oc, st, &max_frame_rate); | |
593 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7168 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
7168 | if (max_frame_rate && av_parse_video_rate(&ms->max_frame_rate, max_frame_rate) < 0) { |
594 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid maximum framerate value: %s\n", max_frame_rate); | |
595 | ✗ | return AVERROR(EINVAL); | |
596 | } | ||
597 | |||
598 |
3/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 7146 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
|
7168 | if (frame_rate && max_frame_rate) { |
599 | ✗ | av_log(ost, AV_LOG_ERROR, "Only one of -fpsmax and -r can be set for a stream.\n"); | |
600 | ✗ | return AVERROR(EINVAL); | |
601 | } | ||
602 | |||
603 | 7168 | opt_match_per_stream_str(ost, &o->frame_aspect_ratios, oc, st, &frame_aspect_ratio); | |
604 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7168 times.
|
7168 | if (frame_aspect_ratio) { |
605 | AVRational q; | ||
606 | ✗ | if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 || | |
607 | ✗ | q.num <= 0 || q.den <= 0) { | |
608 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid aspect ratio: %s\n", frame_aspect_ratio); | |
609 | ✗ | return AVERROR(EINVAL); | |
610 | } | ||
611 | ✗ | ost->frame_aspect_ratio = q; | |
612 | } | ||
613 | |||
614 |
2/2✓ Branch 0 taken 6793 times.
✓ Branch 1 taken 375 times.
|
7168 | if (ost->enc) { |
615 | 6793 | AVCodecContext *video_enc = ost->enc->enc_ctx; | |
616 | 6793 | const char *p = NULL, *fps_mode = NULL; | |
617 | 6793 | const char *frame_size = NULL; | |
618 | 6793 | const char *frame_pix_fmt = NULL; | |
619 | 6793 | const char *intra_matrix = NULL, *inter_matrix = NULL; | |
620 | 6793 | const char *chroma_intra_matrix = NULL; | |
621 | 6793 | int do_pass = 0; | |
622 | int i; | ||
623 | |||
624 | 6793 | opt_match_per_stream_str(ost, &o->frame_sizes, oc, st, &frame_size); | |
625 |
2/2✓ Branch 0 taken 1306 times.
✓ Branch 1 taken 5487 times.
|
6793 | if (frame_size) { |
626 | 1306 | ret = av_parse_video_size(&video_enc->width, &video_enc->height, frame_size); | |
627 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1306 times.
|
1306 | if (ret < 0) { |
628 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size); | |
629 | ✗ | return AVERROR(EINVAL); | |
630 | } | ||
631 | } | ||
632 | |||
633 | 6793 | opt_match_per_stream_str(ost, &o->frame_pix_fmts, oc, st, &frame_pix_fmt); | |
634 |
3/4✓ Branch 0 taken 5302 times.
✓ Branch 1 taken 1491 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5302 times.
|
6793 | if (frame_pix_fmt && *frame_pix_fmt == '+') { |
635 | ✗ | *keep_pix_fmt = 1; | |
636 | ✗ | if (!*++frame_pix_fmt) | |
637 | ✗ | frame_pix_fmt = NULL; | |
638 | } | ||
639 |
2/2✓ Branch 0 taken 5302 times.
✓ Branch 1 taken 1491 times.
|
6793 | if (frame_pix_fmt) { |
640 | 5302 | video_enc->pix_fmt = pix_fmt_parse(ost, frame_pix_fmt); | |
641 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5302 times.
|
5302 | if (video_enc->pix_fmt == AV_PIX_FMT_NONE) |
642 | ✗ | return AVERROR(EINVAL); | |
643 | } | ||
644 | |||
645 | 6793 | opt_match_per_stream_str(ost, &o->intra_matrices, oc, st, &intra_matrix); | |
646 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (intra_matrix) { |
647 | ✗ | if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64))) | |
648 | ✗ | return AVERROR(ENOMEM); | |
649 | |||
650 | ✗ | ret = parse_matrix_coeffs(ost, video_enc->intra_matrix, intra_matrix); | |
651 | ✗ | if (ret < 0) | |
652 | ✗ | return ret; | |
653 | } | ||
654 | 6793 | opt_match_per_stream_str(ost, &o->chroma_intra_matrices, oc, st, &chroma_intra_matrix); | |
655 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (chroma_intra_matrix) { |
656 | ✗ | if (!(video_enc->chroma_intra_matrix = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64))) | |
657 | ✗ | return AVERROR(ENOMEM); | |
658 | ✗ | ret = parse_matrix_coeffs(ost, video_enc->chroma_intra_matrix, chroma_intra_matrix); | |
659 | ✗ | if (ret < 0) | |
660 | ✗ | return ret; | |
661 | } | ||
662 | 6793 | opt_match_per_stream_str(ost, &o->inter_matrices, oc, st, &inter_matrix); | |
663 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (inter_matrix) { |
664 | ✗ | if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64))) | |
665 | ✗ | return AVERROR(ENOMEM); | |
666 | ✗ | ret = parse_matrix_coeffs(ost, video_enc->inter_matrix, inter_matrix); | |
667 | ✗ | if (ret < 0) | |
668 | ✗ | return ret; | |
669 | } | ||
670 | |||
671 | 6793 | opt_match_per_stream_str(ost, &o->rc_overrides, oc, st, &p); | |
672 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | for (i = 0; p; i++) { |
673 | int start, end, q; | ||
674 | ✗ | int e = sscanf(p, "%d,%d,%d", &start, &end, &q); | |
675 | ✗ | if (e != 3) { | |
676 | ✗ | av_log(ost, AV_LOG_FATAL, "error parsing rc_override\n"); | |
677 | ✗ | return AVERROR(EINVAL); | |
678 | } | ||
679 | ✗ | video_enc->rc_override = | |
680 | ✗ | av_realloc_array(video_enc->rc_override, | |
681 | ✗ | i + 1, sizeof(RcOverride)); | |
682 | ✗ | if (!video_enc->rc_override) { | |
683 | ✗ | av_log(ost, AV_LOG_FATAL, "Could not (re)allocate memory for rc_override.\n"); | |
684 | ✗ | return AVERROR(ENOMEM); | |
685 | } | ||
686 | ✗ | video_enc->rc_override[i].start_frame = start; | |
687 | ✗ | video_enc->rc_override[i].end_frame = end; | |
688 | ✗ | if (q > 0) { | |
689 | ✗ | video_enc->rc_override[i].qscale = q; | |
690 | ✗ | video_enc->rc_override[i].quality_factor = 1.0; | |
691 | } | ||
692 | else { | ||
693 | ✗ | video_enc->rc_override[i].qscale = 0; | |
694 | ✗ | video_enc->rc_override[i].quality_factor = -q/100.0; | |
695 | } | ||
696 | ✗ | p = strchr(p, '/'); | |
697 | ✗ | if (p) p++; | |
698 | } | ||
699 | 6793 | video_enc->rc_override_count = i; | |
700 | |||
701 | /* two pass mode */ | ||
702 | 6793 | opt_match_per_stream_int(ost, &o->pass, oc, st, &do_pass); | |
703 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 6777 times.
|
6793 | if (do_pass) { |
704 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | if (do_pass & 1) |
705 | 8 | video_enc->flags |= AV_CODEC_FLAG_PASS1; | |
706 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | if (do_pass & 2) |
707 | 8 | video_enc->flags |= AV_CODEC_FLAG_PASS2; | |
708 | } | ||
709 | |||
710 | 6793 | opt_match_per_stream_str(ost, &o->passlogfiles, oc, st, &ost->logfile_prefix); | |
711 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 6777 times.
|
6793 | if (ost->logfile_prefix && |
712 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
|
16 | !(ost->logfile_prefix = av_strdup(ost->logfile_prefix))) |
713 | ✗ | return AVERROR(ENOMEM); | |
714 | |||
715 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 6777 times.
|
6793 | if (do_pass) { |
716 | 16 | int ost_idx = -1; | |
717 | char logfilename[1024]; | ||
718 | FILE *f; | ||
719 | |||
720 | /* compute this stream's global index */ | ||
721 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 16 times.
|
32 | for (int idx = 0; idx <= ost->file->index; idx++) |
722 | 16 | ost_idx += output_files[idx]->nb_streams; | |
723 | |||
724 | 16 | snprintf(logfilename, sizeof(logfilename), "%s-%d.log", | |
725 |
1/2✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
|
16 | ost->logfile_prefix ? ost->logfile_prefix : |
726 | DEFAULT_PASS_LOGFILENAME_PREFIX, | ||
727 | ost_idx); | ||
728 |
2/4✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 16 times.
|
16 | if (!strcmp(video_enc->codec->name, "libx264") || !strcmp(video_enc->codec->name, "libvvenc")) { |
729 | ✗ | if (av_opt_is_set_to_default_by_name(video_enc, "stats", | |
730 | AV_OPT_SEARCH_CHILDREN) > 0) | ||
731 | ✗ | av_opt_set(video_enc, "stats", logfilename, | |
732 | AV_OPT_SEARCH_CHILDREN); | ||
733 | } else { | ||
734 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | if (video_enc->flags & AV_CODEC_FLAG_PASS2) { |
735 | 8 | char *logbuffer = file_read(logfilename); | |
736 | |||
737 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (!logbuffer) { |
738 | ✗ | av_log(ost, AV_LOG_FATAL, "Error reading log file '%s' for pass-2 encoding\n", | |
739 | logfilename); | ||
740 | ✗ | return AVERROR(EIO); | |
741 | } | ||
742 | 8 | video_enc->stats_in = logbuffer; | |
743 | } | ||
744 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | if (video_enc->flags & AV_CODEC_FLAG_PASS1) { |
745 | 8 | f = fopen_utf8(logfilename, "wb"); | |
746 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8 times.
|
8 | if (!f) { |
747 | ✗ | av_log(ost, AV_LOG_FATAL, | |
748 | "Cannot write log file '%s' for pass-1 encoding: %s\n", | ||
749 | ✗ | logfilename, strerror(errno)); | |
750 | ✗ | return AVERROR(errno); | |
751 | } | ||
752 | 8 | ost->logfile = f; | |
753 | } | ||
754 | } | ||
755 | } | ||
756 | |||
757 | 6793 | opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ms->force_fps); | |
758 | |||
759 | #if FFMPEG_OPT_TOP | ||
760 | 6793 | ost->top_field_first = -1; | |
761 | 6793 | opt_match_per_stream_int(ost, &o->top_field_first, oc, st, &ost->top_field_first); | |
762 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (ost->top_field_first >= 0) |
763 | ✗ | av_log(ost, AV_LOG_WARNING, "-top is deprecated, use the setfield filter instead\n"); | |
764 | #endif | ||
765 | |||
766 | #if FFMPEG_OPT_VSYNC | ||
767 | 6793 | *vsync_method = video_sync_method; | |
768 | #else | ||
769 | *vsync_method = VSYNC_AUTO; | ||
770 | #endif | ||
771 | 6793 | opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode); | |
772 |
2/2✓ Branch 0 taken 533 times.
✓ Branch 1 taken 6260 times.
|
6793 | if (fps_mode) { |
773 | 533 | ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index, 0); | |
774 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 533 times.
|
533 | if (ret < 0) |
775 | ✗ | return ret; | |
776 | } | ||
777 | |||
778 |
3/4✓ Branch 0 taken 6772 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6772 times.
|
6793 | if ((ms->frame_rate.num || ms->max_frame_rate.num) && |
779 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 20 times.
|
21 | !(*vsync_method == VSYNC_AUTO || |
780 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
1 | *vsync_method == VSYNC_CFR || *vsync_method == VSYNC_VSCFR)) { |
781 | ✗ | av_log(ost, AV_LOG_FATAL, "One of -r/-fpsmax was specified " | |
782 | "together a non-CFR -vsync/-fps_mode. This is contradictory.\n"); | ||
783 | ✗ | return AVERROR(EINVAL); | |
784 | } | ||
785 | |||
786 |
2/2✓ Branch 0 taken 6260 times.
✓ Branch 1 taken 533 times.
|
6793 | if (*vsync_method == VSYNC_AUTO) { |
787 |
3/4✓ Branch 0 taken 6240 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6240 times.
|
6260 | if (ms->frame_rate.num || ms->max_frame_rate.num) { |
788 | 20 | *vsync_method = VSYNC_CFR; | |
789 |
2/2✓ Branch 0 taken 300 times.
✓ Branch 1 taken 5940 times.
|
6240 | } else if (!strcmp(oc->oformat->name, "avi")) { |
790 | 300 | *vsync_method = VSYNC_VFR; | |
791 | } else { | ||
792 | 5940 | *vsync_method = (oc->oformat->flags & AVFMT_VARIABLE_FPS) ? | |
793 | 4512 | ((oc->oformat->flags & AVFMT_NOTIMESTAMPS) ? | |
794 |
4/4✓ Branch 0 taken 4512 times.
✓ Branch 1 taken 1428 times.
✓ Branch 2 taken 17 times.
✓ Branch 3 taken 4495 times.
|
5940 | VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR; |
795 | } | ||
796 | |||
797 |
4/4✓ Branch 0 taken 5087 times.
✓ Branch 1 taken 1173 times.
✓ Branch 2 taken 387 times.
✓ Branch 3 taken 4700 times.
|
6260 | if (ost->ist && *vsync_method == VSYNC_CFR) { |
798 | 387 | const InputFile *ifile = ost->ist->file; | |
799 | |||
800 |
3/4✓ Branch 0 taken 342 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 342 times.
✗ Branch 3 not taken.
|
387 | if (ifile->nb_streams == 1 && ifile->input_ts_offset == 0) |
801 | 342 | *vsync_method = VSYNC_VSCFR; | |
802 | } | ||
803 | |||
804 |
3/4✓ Branch 0 taken 1106 times.
✓ Branch 1 taken 5154 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1106 times.
|
6260 | if (*vsync_method == VSYNC_CFR && copy_ts) { |
805 | ✗ | *vsync_method = VSYNC_VSCFR; | |
806 | } | ||
807 | } | ||
808 | #if FFMPEG_OPT_VSYNC_DROP | ||
809 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (*vsync_method == VSYNC_DROP) |
810 | ✗ | ms->ts_drop = 1; | |
811 | #endif | ||
812 | } | ||
813 | |||
814 | 7168 | return 0; | |
815 | } | ||
816 | |||
817 | 1635 | static int new_stream_audio(Muxer *mux, const OptionsContext *o, | |
818 | OutputStream *ost) | ||
819 | { | ||
820 | 1635 | MuxStream *ms = ms_from_ost(ost); | |
821 | 1635 | AVFormatContext *oc = mux->fc; | |
822 | 1635 | AVStream *st = ost->st; | |
823 | |||
824 |
2/2✓ Branch 0 taken 1337 times.
✓ Branch 1 taken 298 times.
|
1635 | if (ost->enc) { |
825 | 1337 | AVCodecContext *audio_enc = ost->enc->enc_ctx; | |
826 | 1337 | int channels = 0; | |
827 | 1337 | const char *layout = NULL; | |
828 | 1337 | const char *sample_fmt = NULL; | |
829 | |||
830 | 1337 | opt_match_per_stream_int(ost, &o->audio_channels, oc, st, &channels); | |
831 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1327 times.
|
1337 | if (channels) { |
832 | 10 | audio_enc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; | |
833 | 10 | audio_enc->ch_layout.nb_channels = channels; | |
834 | } | ||
835 | |||
836 | 1337 | opt_match_per_stream_str(ost, &o->audio_ch_layouts, oc, st, &layout); | |
837 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1336 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1337 | if (layout && av_channel_layout_from_string(&audio_enc->ch_layout, layout) < 0) { |
838 | ✗ | av_log(ost, AV_LOG_FATAL, "Unknown channel layout: %s\n", layout); | |
839 | ✗ | return AVERROR(EINVAL); | |
840 | } | ||
841 | |||
842 | 1337 | opt_match_per_stream_str(ost, &o->sample_fmts, oc, st, &sample_fmt); | |
843 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1337 times.
|
1337 | if (sample_fmt && |
844 | ✗ | (audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) { | |
845 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt); | |
846 | ✗ | return AVERROR(EINVAL); | |
847 | } | ||
848 | |||
849 | 1337 | opt_match_per_stream_int(ost, &o->audio_sample_rate, oc, st, &audio_enc->sample_rate); | |
850 | 1337 | opt_match_per_stream_str(ost, &o->apad, oc, st, &ms->apad); | |
851 | } | ||
852 | |||
853 | 1635 | return 0; | |
854 | } | ||
855 | |||
856 | 80 | static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, | |
857 | OutputStream *ost) | ||
858 | { | ||
859 | AVStream *st; | ||
860 | |||
861 | 80 | st = ost->st; | |
862 | |||
863 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 38 times.
|
80 | if (ost->enc) { |
864 | 42 | AVCodecContext *subtitle_enc = ost->enc->enc_ctx; | |
865 | |||
866 | AVCodecDescriptor const *input_descriptor = | ||
867 | 42 | avcodec_descriptor_get(ost->ist->par->codec_id); | |
868 | AVCodecDescriptor const *output_descriptor = | ||
869 | 42 | avcodec_descriptor_get(subtitle_enc->codec_id); | |
870 | 42 | int input_props = 0, output_props = 0; | |
871 | |||
872 | 42 | const char *frame_size = NULL; | |
873 | |||
874 | 42 | opt_match_per_stream_str(ost, &o->frame_sizes, mux->fc, st, &frame_size); | |
875 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (frame_size) { |
876 | ✗ | int ret = av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size); | |
877 | ✗ | if (ret < 0) { | |
878 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid frame size: %s.\n", frame_size); | |
879 | ✗ | return ret; | |
880 | } | ||
881 | } | ||
882 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | if (input_descriptor) |
883 | 42 | input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); | |
884 |
1/2✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
|
42 | if (output_descriptor) |
885 | 42 | output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); | |
886 |
3/6✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
|
42 | if (input_props && output_props && input_props != output_props) { |
887 | ✗ | av_log(ost, AV_LOG_ERROR, | |
888 | "Subtitle encoding currently only possible from text to text " | ||
889 | "or bitmap to bitmap\n"); | ||
890 | ✗ | return AVERROR(EINVAL); | |
891 | } | ||
892 | } | ||
893 | |||
894 | 80 | return 0; | |
895 | } | ||
896 | |||
897 | static int | ||
898 | 8130 | ost_bind_filter(const Muxer *mux, MuxStream *ms, OutputFilter *ofilter, | |
899 | const OptionsContext *o, | ||
900 | AVRational enc_tb, enum VideoSyncMethod vsync_method, | ||
901 | int keep_pix_fmt, int autoscale, int threads_manual, | ||
902 | const ViewSpecifier *vs, | ||
903 | SchedulerNode *src) | ||
904 | { | ||
905 | 8130 | OutputStream *ost = &ms->ost; | |
906 | 8130 | AVCodecContext *enc_ctx = ost->enc->enc_ctx; | |
907 | char name[16]; | ||
908 | 8130 | char *filters = NULL; | |
909 | int ret; | ||
910 | |||
911 | 32520 | OutputFilterOptions opts = { | |
912 | 8130 | .enc = enc_ctx->codec, | |
913 | .name = name, | ||
914 | 8130 | .format = (ost->type == AVMEDIA_TYPE_VIDEO) ? | |
915 | 8130 | enc_ctx->pix_fmt : enc_ctx->sample_fmt, | |
916 | 8130 | .width = enc_ctx->width, | |
917 | 8130 | .height = enc_ctx->height, | |
918 | 8130 | .color_space = enc_ctx->colorspace, | |
919 | 8130 | .color_range = enc_ctx->color_range, | |
920 | 8130 | .alpha_mode = enc_ctx->alpha_mode, | |
921 | .vsync_method = vsync_method, | ||
922 | .frame_rate = ms->frame_rate, | ||
923 | .max_frame_rate = ms->max_frame_rate, | ||
924 | 8130 | .sample_rate = enc_ctx->sample_rate, | |
925 | .ch_layout = enc_ctx->ch_layout, | ||
926 | 8130 | .sws_opts = o->g->sws_dict, | |
927 | 8130 | .swr_opts = o->g->swr_opts, | |
928 | .output_tb = enc_tb, | ||
929 | 8130 | .trim_start_us = mux->of.start_time, | |
930 | 8130 | .trim_duration_us = mux->of.recording_time, | |
931 | 8130 | .ts_offset = mux->of.start_time == AV_NOPTS_VALUE ? | |
932 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8129 times.
|
8130 | 0 : mux->of.start_time, |
933 | .vs = vs, | ||
934 | .nb_threads = -1, | ||
935 | |||
936 | 16260 | .flags = OFILTER_FLAG_DISABLE_CONVERT * !!keep_pix_fmt | | |
937 |
3/4✓ Branch 0 taken 8130 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6793 times.
✓ Branch 3 taken 1337 times.
|
16260 | OFILTER_FLAG_AUTOSCALE * !!autoscale | |
938 |
2/2✓ Branch 1 taken 59 times.
✓ Branch 2 taken 8071 times.
|
8130 | OFILTER_FLAG_AUDIO_24BIT * !!(av_get_exact_bits_per_sample(enc_ctx->codec_id) == 24), |
939 | }; | ||
940 | |||
941 | 8130 | snprintf(name, sizeof(name), "#%d:%d", mux->of.index, ost->index); | |
942 | |||
943 |
2/2✓ Branch 0 taken 6793 times.
✓ Branch 1 taken 1337 times.
|
8130 | if (ost->type == AVMEDIA_TYPE_VIDEO) { |
944 |
1/2✓ Branch 0 taken 6793 times.
✗ Branch 1 not taken.
|
6793 | if (!keep_pix_fmt) { |
945 | 6793 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
946 | AV_CODEC_CONFIG_PIX_FORMAT, 0, | ||
947 | (const void **) &opts.formats, NULL); | ||
948 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (ret < 0) |
949 | ✗ | return ret; | |
950 | } | ||
951 |
2/2✓ Branch 0 taken 6792 times.
✓ Branch 1 taken 1 times.
|
6793 | if (!ms->force_fps) { |
952 | 6792 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
953 | AV_CODEC_CONFIG_FRAME_RATE, 0, | ||
954 | (const void **) &opts.frame_rates, NULL); | ||
955 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6792 times.
|
6792 | if (ret < 0) |
956 | ✗ | return ret; | |
957 | } | ||
958 | 6793 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
959 | AV_CODEC_CONFIG_COLOR_SPACE, 0, | ||
960 | (const void **) &opts.color_spaces, NULL); | ||
961 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (ret < 0) |
962 | ✗ | return ret; | |
963 | 6793 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
964 | AV_CODEC_CONFIG_COLOR_RANGE, 0, | ||
965 | (const void **) &opts.color_ranges, NULL); | ||
966 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (ret < 0) |
967 | ✗ | return ret; | |
968 | 6793 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
969 | AV_CODEC_CONFIG_ALPHA_MODE, 0, | ||
970 | (const void **) &opts.alpha_modes, NULL); | ||
971 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6793 times.
|
6793 | if (ret < 0) |
972 | ✗ | return ret; | |
973 | } else { | ||
974 | 1337 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
975 | AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, | ||
976 | (const void **) &opts.formats, NULL); | ||
977 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1337 times.
|
1337 | if (ret < 0) |
978 | ✗ | return ret; | |
979 | 1337 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
980 | AV_CODEC_CONFIG_SAMPLE_RATE, 0, | ||
981 | (const void **) &opts.sample_rates, NULL); | ||
982 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1337 times.
|
1337 | if (ret < 0) |
983 | ✗ | return ret; | |
984 | 1337 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
985 | AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0, | ||
986 | (const void **) &opts.ch_layouts, NULL); | ||
987 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1337 times.
|
1337 | if (ret < 0) |
988 | ✗ | return ret; | |
989 | } | ||
990 | |||
991 |
2/2✓ Branch 0 taken 5389 times.
✓ Branch 1 taken 2741 times.
|
8130 | if (threads_manual) { |
992 | 5389 | ret = av_opt_get_int(enc_ctx, "threads", 0, &opts.nb_threads); | |
993 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5389 times.
|
5389 | if (ret < 0) |
994 | ✗ | return ret; | |
995 | } | ||
996 | |||
997 | 8130 | ret = ost_get_filters(o, mux->fc, ost, &filters); | |
998 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8130 times.
|
8130 | if (ret < 0) |
999 | ✗ | return ret; | |
1000 | |||
1001 |
2/2✓ Branch 0 taken 1337 times.
✓ Branch 1 taken 6793 times.
|
8130 | if (ofilter) { |
1002 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1337 times.
|
1337 | av_assert0(!filters); |
1003 | 1337 | ost->filter = ofilter; | |
1004 | 1337 | ret = ofilter_bind_enc(ofilter, ms->sch_idx_enc, &opts); | |
1005 | } else { | ||
1006 | 6793 | ret = fg_create_simple(&ost->fg_simple, ost->ist, filters, | |
1007 | 6793 | mux->sch, ms->sch_idx_enc, &opts); | |
1008 |
1/2✓ Branch 0 taken 6793 times.
✗ Branch 1 not taken.
|
6793 | if (ret >= 0) |
1009 | 6793 | ost->filter = ost->fg_simple->outputs[0]; | |
1010 | |||
1011 | } | ||
1012 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8130 times.
|
8130 | if (ret < 0) |
1013 | ✗ | return ret; | |
1014 | |||
1015 | 8130 | *src = SCH_ENC(ms->sch_idx_enc); | |
1016 | |||
1017 | 8130 | return 0; | |
1018 | } | ||
1019 | |||
1020 | 723 | static int streamcopy_init(const OptionsContext *o, const Muxer *mux, | |
1021 | OutputStream *ost, AVDictionary **encoder_opts) | ||
1022 | { | ||
1023 | 723 | MuxStream *ms = ms_from_ost(ost); | |
1024 | |||
1025 | 723 | const InputStream *ist = ost->ist; | |
1026 | 723 | const InputFile *ifile = ist->file; | |
1027 | |||
1028 | 723 | AVCodecParameters *par = ms->par_in; | |
1029 | 723 | uint32_t codec_tag = par->codec_tag; | |
1030 | |||
1031 | 723 | AVCodecContext *codec_ctx = NULL; | |
1032 | |||
1033 | 723 | AVRational fr = ms->frame_rate; | |
1034 | |||
1035 | 723 | int ret = 0; | |
1036 | |||
1037 | 723 | const char *filters = NULL; | |
1038 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
1039 | 723 | const char *filters_script = NULL; | |
1040 | |||
1041 | 723 | opt_match_per_stream_str(ost, &o->filter_scripts, mux->fc, ost->st, &filters_script); | |
1042 | #endif | ||
1043 | 723 | opt_match_per_stream_str(ost, &o->filters, mux->fc, ost->st, &filters); | |
1044 | |||
1045 | 723 | if ( | |
1046 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
1047 |
2/4✓ Branch 0 taken 723 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 723 times.
|
723 | filters_script || |
1048 | #endif | ||
1049 | filters) { | ||
1050 | ✗ | av_log(ost, AV_LOG_ERROR, | |
1051 | "%s '%s' was specified, but codec copy was selected. " | ||
1052 | "Filtering and streamcopy cannot be used together.\n", | ||
1053 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
1054 | ✗ | filters ? "Filtergraph" : "Filtergraph script", | |
1055 | ✗ | filters ? filters : filters_script | |
1056 | #else | ||
1057 | "Filtergraph", filters | ||
1058 | #endif | ||
1059 | ); | ||
1060 | ✗ | return AVERROR(EINVAL); | |
1061 | } | ||
1062 | |||
1063 | 723 | codec_ctx = avcodec_alloc_context3(NULL); | |
1064 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 723 times.
|
723 | if (!codec_ctx) |
1065 | ✗ | return AVERROR(ENOMEM); | |
1066 | |||
1067 | 723 | ret = avcodec_parameters_to_context(codec_ctx, ist->par); | |
1068 |
1/2✓ Branch 0 taken 723 times.
✗ Branch 1 not taken.
|
723 | if (ret >= 0) |
1069 | 723 | ret = av_opt_set_dict(codec_ctx, encoder_opts); | |
1070 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 723 times.
|
723 | if (ret < 0) { |
1071 | ✗ | av_log(ost, AV_LOG_FATAL, | |
1072 | "Error setting up codec context options.\n"); | ||
1073 | ✗ | goto fail; | |
1074 | } | ||
1075 | |||
1076 | 723 | ret = avcodec_parameters_from_context(par, codec_ctx); | |
1077 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 723 times.
|
723 | if (ret < 0) { |
1078 | ✗ | av_log(ost, AV_LOG_FATAL, | |
1079 | "Error getting reference codec parameters.\n"); | ||
1080 | ✗ | goto fail; | |
1081 | } | ||
1082 | |||
1083 |
2/2✓ Branch 0 taken 716 times.
✓ Branch 1 taken 7 times.
|
723 | if (!codec_tag) { |
1084 | 716 | const struct AVCodecTag * const *ct = mux->fc->oformat->codec_tag; | |
1085 | unsigned int codec_tag_tmp; | ||
1086 |
6/6✓ Branch 0 taken 137 times.
✓ Branch 1 taken 579 times.
✓ Branch 3 taken 102 times.
✓ Branch 4 taken 35 times.
✓ Branch 5 taken 14 times.
✓ Branch 6 taken 88 times.
|
818 | if (!ct || av_codec_get_id (ct, par->codec_tag) == par->codec_id || |
1087 | 102 | !av_codec_get_tag2(ct, par->codec_id, &codec_tag_tmp)) | |
1088 | 628 | codec_tag = par->codec_tag; | |
1089 | } | ||
1090 | |||
1091 | 723 | par->codec_tag = codec_tag; | |
1092 | |||
1093 |
2/2✓ Branch 0 taken 722 times.
✓ Branch 1 taken 1 times.
|
723 | if (!fr.num) |
1094 | 722 | fr = ist->framerate; | |
1095 | |||
1096 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 721 times.
|
723 | if (fr.num) |
1097 | 2 | ost->st->avg_frame_rate = fr; | |
1098 | else | ||
1099 | 721 | ost->st->avg_frame_rate = ist->st->avg_frame_rate; | |
1100 | |||
1101 | // copy timebase while removing common factors | ||
1102 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 723 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
723 | if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) { |
1103 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 721 times.
|
723 | if (fr.num) |
1104 | 2 | ost->st->time_base = av_inv_q(fr); | |
1105 | else | ||
1106 | 721 | ost->st->time_base = av_add_q(ist->st->time_base, (AVRational){0, 1}); | |
1107 | } | ||
1108 | |||
1109 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 723 times.
|
723 | if (!ms->copy_prior_start) { |
1110 | ✗ | ms->ts_copy_start = (mux->of.start_time == AV_NOPTS_VALUE) ? | |
1111 | ✗ | 0 : mux->of.start_time; | |
1112 | ✗ | if (copy_ts && ifile->start_time != AV_NOPTS_VALUE) { | |
1113 | ✗ | ms->ts_copy_start = FFMAX(ms->ts_copy_start, | |
1114 | ifile->start_time + ifile->ts_offset); | ||
1115 | } | ||
1116 | } | ||
1117 | |||
1118 |
2/2✓ Branch 0 taken 83 times.
✓ Branch 1 taken 723 times.
|
806 | for (int i = 0; i < ist->st->codecpar->nb_coded_side_data; i++) { |
1119 | 83 | const AVPacketSideData *sd_src = &ist->st->codecpar->coded_side_data[i]; | |
1120 | AVPacketSideData *sd_dst; | ||
1121 | |||
1122 | 83 | sd_dst = av_packet_side_data_new(&ost->st->codecpar->coded_side_data, | |
1123 | 83 | &ost->st->codecpar->nb_coded_side_data, | |
1124 | 83 | sd_src->type, sd_src->size, 0); | |
1125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 83 times.
|
83 | if (!sd_dst) { |
1126 | ✗ | ret = AVERROR(ENOMEM); | |
1127 | ✗ | goto fail; | |
1128 | } | ||
1129 | 83 | memcpy(sd_dst->data, sd_src->data, sd_src->size); | |
1130 | } | ||
1131 | |||
1132 |
3/3✓ Branch 0 taken 298 times.
✓ Branch 1 taken 375 times.
✓ Branch 2 taken 50 times.
|
723 | switch (par->codec_type) { |
1133 | 298 | case AVMEDIA_TYPE_AUDIO: | |
1134 |
4/6✓ Branch 0 taken 293 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 293 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 293 times.
|
298 | if ((par->block_align == 1 || par->block_align == 1152 || par->block_align == 576) && |
1135 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | par->codec_id == AV_CODEC_ID_MP3) |
1136 | ✗ | par->block_align = 0; | |
1137 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 282 times.
|
298 | if (par->codec_id == AV_CODEC_ID_AC3) |
1138 | 16 | par->block_align = 0; | |
1139 | 298 | break; | |
1140 | 375 | case AVMEDIA_TYPE_VIDEO: { | |
1141 | AVRational sar; | ||
1142 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 375 times.
|
375 | if (ost->frame_aspect_ratio.num) { // overridden by the -aspect cli option |
1143 | sar = | ||
1144 | ✗ | av_mul_q(ost->frame_aspect_ratio, | |
1145 | ✗ | (AVRational){ par->height, par->width }); | |
1146 | ✗ | av_log(ost, AV_LOG_WARNING, "Overriding aspect ratio " | |
1147 | "with stream copy may produce invalid files\n"); | ||
1148 | } | ||
1149 |
2/2✓ Branch 0 taken 94 times.
✓ Branch 1 taken 281 times.
|
375 | else if (ist->st->sample_aspect_ratio.num) |
1150 | 94 | sar = ist->st->sample_aspect_ratio; | |
1151 | else | ||
1152 | 281 | sar = par->sample_aspect_ratio; | |
1153 | 375 | ost->st->sample_aspect_ratio = par->sample_aspect_ratio = sar; | |
1154 | 375 | ost->st->r_frame_rate = ist->st->r_frame_rate; | |
1155 | 375 | break; | |
1156 | } | ||
1157 | } | ||
1158 | |||
1159 | 723 | fail: | |
1160 | 723 | avcodec_free_context(&codec_ctx); | |
1161 | 723 | return ret; | |
1162 | } | ||
1163 | |||
1164 | 8172 | static int set_encoder_id(OutputStream *ost, const AVCodec *codec) | |
1165 | { | ||
1166 | 8172 | const char *cname = codec->name; | |
1167 | uint8_t *encoder_string; | ||
1168 | int encoder_string_len; | ||
1169 | |||
1170 | 8172 | encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2; | |
1171 | 8172 | encoder_string = av_mallocz(encoder_string_len); | |
1172 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
|
8172 | if (!encoder_string) |
1173 | ✗ | return AVERROR(ENOMEM); | |
1174 | |||
1175 |
4/4✓ Branch 0 taken 849 times.
✓ Branch 1 taken 7323 times.
✓ Branch 2 taken 842 times.
✓ Branch 3 taken 7 times.
|
8172 | if (!ost->file->bitexact && !ost->bitexact) |
1176 | 842 | av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len); | |
1177 | else | ||
1178 | 7330 | av_strlcpy(encoder_string, "Lavc ", encoder_string_len); | |
1179 | 8172 | av_strlcat(encoder_string, cname, encoder_string_len); | |
1180 | 8172 | av_dict_set(&ost->st->metadata, "encoder", encoder_string, | |
1181 | AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE); | ||
1182 | |||
1183 | 8172 | return 0; | |
1184 | } | ||
1185 | |||
1186 | 8896 | static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, | |
1187 | InputStream *ist, OutputFilter *ofilter, const ViewSpecifier *vs, | ||
1188 | OutputStream **post) | ||
1189 | { | ||
1190 | 8896 | AVFormatContext *oc = mux->fc; | |
1191 | MuxStream *ms; | ||
1192 | OutputStream *ost; | ||
1193 | const AVCodec *enc; | ||
1194 | AVStream *st; | ||
1195 | 8896 | SchedulerNode src = { .type = SCH_NODE_TYPE_NONE }; | |
1196 | 8896 | AVDictionary *encoder_opts = NULL; | |
1197 | 8896 | int ret = 0, keep_pix_fmt = 0, autoscale = 1; | |
1198 | 8896 | int threads_manual = 0; | |
1199 | 8896 | AVRational enc_tb = { 0, 0 }; | |
1200 | 8896 | enum VideoSyncMethod vsync_method = VSYNC_AUTO; | |
1201 | 8896 | const char *bsfs = NULL, *time_base = NULL, *codec_tag = NULL; | |
1202 | char *next; | ||
1203 | 8896 | double qscale = -1; | |
1204 | |||
1205 | 8896 | st = avformat_new_stream(oc, NULL); | |
1206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8896 times.
|
8896 | if (!st) |
1207 | ✗ | return AVERROR(ENOMEM); | |
1208 | |||
1209 | 8896 | ms = mux_stream_alloc(mux, type); | |
1210 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8896 times.
|
8896 | if (!ms) |
1211 | ✗ | return AVERROR(ENOMEM); | |
1212 | |||
1213 | // only streams with sources (i.e. not attachments) | ||
1214 | // are handled by the scheduler | ||
1215 |
4/4✓ Branch 0 taken 1338 times.
✓ Branch 1 taken 7558 times.
✓ Branch 2 taken 1337 times.
✓ Branch 3 taken 1 times.
|
8896 | if (ist || ofilter) { |
1216 | 8895 | ret = GROW_ARRAY(mux->sch_stream_idx, mux->nb_sch_stream_idx); | |
1217 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8895 times.
|
8895 | if (ret < 0) |
1218 | ✗ | return ret; | |
1219 | |||
1220 | 8895 | ret = sch_add_mux_stream(mux->sch, mux->sch_idx); | |
1221 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8895 times.
|
8895 | if (ret < 0) |
1222 | ✗ | return ret; | |
1223 | |||
1224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8895 times.
|
8895 | av_assert0(ret == mux->nb_sch_stream_idx - 1); |
1225 | 8895 | mux->sch_stream_idx[ret] = ms->ost.index; | |
1226 | 8895 | ms->sch_idx = ret; | |
1227 | } | ||
1228 | |||
1229 | 8896 | ost = &ms->ost; | |
1230 | |||
1231 |
2/2✓ Branch 0 taken 59 times.
✓ Branch 1 taken 8837 times.
|
8896 | if (o->streamid) { |
1232 | AVDictionaryEntry *e; | ||
1233 | char idx[16], *p; | ||
1234 | 59 | snprintf(idx, sizeof(idx), "%d", ost->index); | |
1235 | |||
1236 | 59 | e = av_dict_get(o->streamid, idx, NULL, 0); | |
1237 |
1/2✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
|
59 | if (e) { |
1238 | 59 | st->id = strtol(e->value, &p, 0); | |
1239 |
2/4✓ Branch 0 taken 59 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 59 times.
|
59 | if (!e->value[0] || *p) { |
1240 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid stream id: %s\n", e->value); | |
1241 | ✗ | return AVERROR(EINVAL); | |
1242 | } | ||
1243 | } | ||
1244 | } | ||
1245 | |||
1246 | 8896 | ms->par_in = avcodec_parameters_alloc(); | |
1247 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8896 times.
|
8896 | if (!ms->par_in) |
1248 | ✗ | return AVERROR(ENOMEM); | |
1249 | |||
1250 | 8896 | ms->last_mux_dts = AV_NOPTS_VALUE; | |
1251 | |||
1252 | 8896 | ost->st = st; | |
1253 | 8896 | ost->ist = ist; | |
1254 | 8896 | ost->kf.ref_pts = AV_NOPTS_VALUE; | |
1255 | 8896 | ms->par_in->codec_type = type; | |
1256 | 8896 | st->codecpar->codec_type = type; | |
1257 | |||
1258 | 8896 | ret = choose_encoder(o, oc, ms, &enc); | |
1259 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8896 times.
|
8896 | if (ret < 0) { |
1260 | ✗ | av_log(ost, AV_LOG_FATAL, "Error selecting an encoder\n"); | |
1261 | ✗ | return ret; | |
1262 | } | ||
1263 | |||
1264 |
2/2✓ Branch 0 taken 8172 times.
✓ Branch 1 taken 724 times.
|
8896 | if (enc) { |
1265 | 8172 | ret = sch_add_enc(mux->sch, encoder_thread, ost, | |
1266 |
2/2✓ Branch 0 taken 8130 times.
✓ Branch 1 taken 42 times.
|
8172 | ost->type == AVMEDIA_TYPE_SUBTITLE ? NULL : enc_open); |
1267 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
|
8172 | if (ret < 0) |
1268 | ✗ | return ret; | |
1269 | 8172 | ms->sch_idx_enc = ret; | |
1270 | |||
1271 | 8172 | ret = enc_alloc(&ost->enc, enc, mux->sch, ms->sch_idx_enc, ost); | |
1272 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
|
8172 | if (ret < 0) |
1273 | ✗ | return ret; | |
1274 | |||
1275 | 8172 | av_strlcat(ms->log_name, "/", sizeof(ms->log_name)); | |
1276 | 8172 | av_strlcat(ms->log_name, enc->name, sizeof(ms->log_name)); | |
1277 | } else { | ||
1278 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 724 times.
|
724 | if (ofilter) { |
1279 | ✗ | av_log(ost, AV_LOG_ERROR, | |
1280 | "Streamcopy requested for output stream fed " | ||
1281 | "from a complex filtergraph. Filtering and streamcopy " | ||
1282 | "cannot be used together.\n"); | ||
1283 | ✗ | return AVERROR(EINVAL); | |
1284 | } | ||
1285 | |||
1286 | 724 | av_strlcat(ms->log_name, "/copy", sizeof(ms->log_name)); | |
1287 | } | ||
1288 | |||
1289 | 8896 | av_log(ost, AV_LOG_VERBOSE, "Created %s stream from ", | |
1290 | av_get_media_type_string(type)); | ||
1291 |
2/2✓ Branch 0 taken 7558 times.
✓ Branch 1 taken 1338 times.
|
8896 | if (ist) |
1292 | 7558 | av_log(ost, AV_LOG_VERBOSE, "input stream %d:%d", | |
1293 | 7558 | ist->file->index, ist->index); | |
1294 |
2/2✓ Branch 0 taken 1337 times.
✓ Branch 1 taken 1 times.
|
1338 | else if (ofilter) |
1295 | 1337 | av_log(ost, AV_LOG_VERBOSE, "complex filtergraph %d:[%s]\n", | |
1296 | 1337 | ofilter->graph->index, ofilter->name); | |
1297 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | else if (type == AVMEDIA_TYPE_ATTACHMENT) |
1298 | 1 | av_log(ost, AV_LOG_VERBOSE, "attached file"); | |
1299 | ✗ | else av_assert0(0); | |
1300 | 8896 | av_log(ost, AV_LOG_VERBOSE, "\n"); | |
1301 | |||
1302 | 8896 | ms->pkt = av_packet_alloc(); | |
1303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8896 times.
|
8896 | if (!ms->pkt) |
1304 | ✗ | return AVERROR(ENOMEM); | |
1305 | |||
1306 |
2/2✓ Branch 0 taken 8172 times.
✓ Branch 1 taken 724 times.
|
8896 | if (ost->enc) { |
1307 | 8172 | AVIOContext *s = NULL; | |
1308 | 8172 | char *buf = NULL, *arg = NULL; | |
1309 | 8172 | const char *enc_stats_pre = NULL, *enc_stats_post = NULL, *mux_stats = NULL; | |
1310 | 8172 | const char *enc_time_base = NULL, *preset = NULL; | |
1311 | |||
1312 | 8172 | ret = filter_codec_opts(o->g->codec_opts, enc->id, | |
1313 | oc, st, enc, &encoder_opts, | ||
1314 | &mux->enc_opts_used); | ||
1315 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
|
8172 | if (ret < 0) |
1316 | ✗ | goto fail; | |
1317 | |||
1318 | 8172 | opt_match_per_stream_str(ost, &o->presets, oc, st, &preset); | |
1319 | 8172 | opt_match_per_stream_int(ost, &o->autoscale, oc, st, &autoscale); | |
1320 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
8172 | if (preset && (!(ret = get_preset_file_2(preset, enc->name, &s)))) { |
1321 | AVBPrint bprint; | ||
1322 | ✗ | av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); | |
1323 | do { | ||
1324 | ✗ | av_bprint_clear(&bprint); | |
1325 | ✗ | buf = get_line(s, &bprint); | |
1326 | ✗ | if (!buf) { | |
1327 | ✗ | ret = AVERROR(ENOMEM); | |
1328 | ✗ | break; | |
1329 | } | ||
1330 | |||
1331 | ✗ | if (!buf[0] || buf[0] == '#') | |
1332 | ✗ | continue; | |
1333 | ✗ | if (!(arg = strchr(buf, '='))) { | |
1334 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid line found in the preset file.\n"); | |
1335 | ✗ | ret = AVERROR(EINVAL); | |
1336 | ✗ | break; | |
1337 | } | ||
1338 | ✗ | *arg++ = 0; | |
1339 | ✗ | av_dict_set(&encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE); | |
1340 | ✗ | } while (!s->eof_reached); | |
1341 | ✗ | av_bprint_finalize(&bprint, NULL); | |
1342 | ✗ | avio_closep(&s); | |
1343 | } | ||
1344 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
|
8172 | if (ret) { |
1345 | ✗ | av_log(ost, AV_LOG_FATAL, | |
1346 | "Preset %s specified, but could not be opened.\n", preset); | ||
1347 | ✗ | goto fail; | |
1348 | } | ||
1349 | |||
1350 | 8172 | opt_match_per_stream_str(ost, &o->enc_stats_pre, oc, st, &enc_stats_pre); | |
1351 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
8172 | if (enc_stats_pre && |
1352 | ✗ | (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { | |
1353 | ✗ | const char *format = "{fidx} {sidx} {n} {t}"; | |
1354 | |||
1355 | ✗ | opt_match_per_stream_str(ost, &o->enc_stats_pre_fmt, oc, st, &format); | |
1356 | |||
1357 | ✗ | ret = enc_stats_init(ost, &ost->enc_stats_pre, 1, enc_stats_pre, format); | |
1358 | ✗ | if (ret < 0) | |
1359 | ✗ | goto fail; | |
1360 | } | ||
1361 | |||
1362 | 8172 | opt_match_per_stream_str(ost, &o->enc_stats_post, oc, st, &enc_stats_post); | |
1363 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
8172 | if (enc_stats_post && |
1364 | ✗ | (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { | |
1365 | ✗ | const char *format = "{fidx} {sidx} {n} {t}"; | |
1366 | |||
1367 | ✗ | opt_match_per_stream_str(ost, &o->enc_stats_post_fmt, oc, st, &format); | |
1368 | |||
1369 | ✗ | ret = enc_stats_init(ost, &ost->enc_stats_post, 0, enc_stats_post, format); | |
1370 | ✗ | if (ret < 0) | |
1371 | ✗ | goto fail; | |
1372 | } | ||
1373 | |||
1374 | 8172 | opt_match_per_stream_str(ost, &o->mux_stats, oc, st, &mux_stats); | |
1375 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
8172 | if (mux_stats && |
1376 | ✗ | (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { | |
1377 | ✗ | const char *format = "{fidx} {sidx} {n} {t}"; | |
1378 | |||
1379 | ✗ | opt_match_per_stream_str(ost, &o->mux_stats_fmt, oc, st, &format); | |
1380 | |||
1381 | ✗ | ret = enc_stats_init(ost, &ms->stats, 0, mux_stats, format); | |
1382 | ✗ | if (ret < 0) | |
1383 | ✗ | goto fail; | |
1384 | } | ||
1385 | |||
1386 | 8172 | opt_match_per_stream_str(ost, &o->enc_time_bases, oc, st, &enc_time_base); | |
1387 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8171 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
8172 | if (enc_time_base && type == AVMEDIA_TYPE_SUBTITLE) |
1388 | ✗ | av_log(ost, AV_LOG_WARNING, | |
1389 | "-enc_time_base not supported for subtitles, ignoring\n"); | ||
1390 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8171 times.
|
8172 | else if (enc_time_base) { |
1391 | AVRational q; | ||
1392 | |||
1393 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!strcmp(enc_time_base, "demux")) { |
1394 | 1 | q = (AVRational){ ENC_TIME_BASE_DEMUX, 0 }; | |
1395 | ✗ | } else if (!strcmp(enc_time_base, "filter")) { | |
1396 | ✗ | q = (AVRational){ ENC_TIME_BASE_FILTER, 0 }; | |
1397 | } else { | ||
1398 | ✗ | ret = av_parse_ratio(&q, enc_time_base, INT_MAX, 0, NULL); | |
1399 | ✗ | if (ret < 0 || q.den <= 0 | |
1400 | #if !FFMPEG_OPT_ENC_TIME_BASE_NUM | ||
1401 | || q.num < 0 | ||
1402 | #endif | ||
1403 | ) { | ||
1404 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", enc_time_base); | |
1405 | ✗ | ret = ret < 0 ? ret : AVERROR(EINVAL); | |
1406 | ✗ | goto fail; | |
1407 | } | ||
1408 | #if FFMPEG_OPT_ENC_TIME_BASE_NUM | ||
1409 | ✗ | if (q.num < 0) | |
1410 | ✗ | av_log(ost, AV_LOG_WARNING, "-enc_time_base -1 is deprecated," | |
1411 | " use -enc_time_base demux\n"); | ||
1412 | #endif | ||
1413 | } | ||
1414 | |||
1415 | 1 | enc_tb = q; | |
1416 | } | ||
1417 | |||
1418 | 8172 | threads_manual = !!av_dict_get(encoder_opts, "threads", NULL, 0); | |
1419 | |||
1420 | 8172 | ret = av_opt_set_dict2(ost->enc->enc_ctx, &encoder_opts, AV_OPT_SEARCH_CHILDREN); | |
1421 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
|
8172 | if (ret < 0) { |
1422 | ✗ | av_log(ost, AV_LOG_ERROR, "Error applying encoder options: %s\n", | |
1423 | ✗ | av_err2str(ret)); | |
1424 | ✗ | goto fail; | |
1425 | } | ||
1426 | |||
1427 | 8172 | ret = check_avoptions(encoder_opts); | |
1428 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
|
8172 | if (ret < 0) |
1429 | ✗ | goto fail; | |
1430 | |||
1431 | // default to automatic thread count | ||
1432 |
2/2✓ Branch 0 taken 2783 times.
✓ Branch 1 taken 5389 times.
|
8172 | if (!threads_manual) |
1433 | 2783 | ost->enc->enc_ctx->thread_count = 0; | |
1434 | } else { | ||
1435 | 724 | ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, | |
1436 | NULL, &encoder_opts, | ||
1437 | &mux->enc_opts_used); | ||
1438 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 724 times.
|
724 | if (ret < 0) |
1439 | ✗ | goto fail; | |
1440 | } | ||
1441 | |||
1442 | |||
1443 |
2/2✓ Branch 0 taken 2002 times.
✓ Branch 1 taken 6894 times.
|
8896 | if (o->bitexact) { |
1444 | 2002 | ost->bitexact = 1; | |
1445 |
2/2✓ Branch 0 taken 6290 times.
✓ Branch 1 taken 604 times.
|
6894 | } else if (ost->enc) { |
1446 | 6290 | ost->bitexact = !!(ost->enc->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT); | |
1447 | } | ||
1448 | |||
1449 |
2/2✓ Branch 0 taken 8172 times.
✓ Branch 1 taken 724 times.
|
8896 | if (enc) { |
1450 | 8172 | ret = set_encoder_id(ost, enc); | |
1451 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8172 times.
|
8172 | if (ret < 0) |
1452 | ✗ | return ret; | |
1453 | } | ||
1454 | |||
1455 | 8896 | opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base); | |
1456 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8892 times.
|
8896 | if (time_base) { |
1457 | AVRational q; | ||
1458 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 || |
1459 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | q.num <= 0 || q.den <= 0) { |
1460 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", time_base); | |
1461 | ✗ | ret = AVERROR(EINVAL); | |
1462 | ✗ | goto fail; | |
1463 | } | ||
1464 | 4 | st->time_base = q; | |
1465 | } | ||
1466 | |||
1467 | 8896 | ms->max_frames = INT64_MAX; | |
1468 | 8896 | opt_match_per_stream_int64(ost, &o->max_frames, oc, st, &ms->max_frames); | |
1469 |
2/2✓ Branch 0 taken 5426 times.
✓ Branch 1 taken 8890 times.
|
14316 | for (int i = 0; i < o->max_frames.nb_opt; i++) { |
1470 | 5426 | char *p = o->max_frames.opt[i].specifier; | |
1471 |
4/4✓ Branch 0 taken 169 times.
✓ Branch 1 taken 5257 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 163 times.
|
5426 | if (!*p && type != AVMEDIA_TYPE_VIDEO) { |
1472 | 6 | av_log(ost, AV_LOG_WARNING, "Applying unspecific -frames to non video streams, maybe you meant -vframes ?\n"); | |
1473 | 6 | break; | |
1474 | } | ||
1475 | } | ||
1476 | |||
1477 | 8896 | ms->copy_prior_start = -1; | |
1478 | 8896 | opt_match_per_stream_int(ost, &o->copy_prior_start, oc, st, &ms->copy_prior_start); | |
1479 | 8896 | opt_match_per_stream_str(ost, &o->bitstream_filters, oc, st, &bsfs); | |
1480 |
3/4✓ Branch 0 taken 141 times.
✓ Branch 1 taken 8755 times.
✓ Branch 2 taken 141 times.
✗ Branch 3 not taken.
|
8896 | if (bsfs && *bsfs) { |
1481 | 141 | ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx); | |
1482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 141 times.
|
141 | if (ret < 0) { |
1483 | ✗ | av_log(ost, AV_LOG_ERROR, "Error parsing bitstream filter sequence '%s': %s\n", bsfs, av_err2str(ret)); | |
1484 | ✗ | goto fail; | |
1485 | } | ||
1486 | } | ||
1487 | |||
1488 | 8896 | opt_match_per_stream_str(ost, &o->codec_tags, oc, st, &codec_tag); | |
1489 |
2/2✓ Branch 0 taken 9 times.
✓ Branch 1 taken 8887 times.
|
8896 | if (codec_tag) { |
1490 | 9 | uint32_t tag = strtol(codec_tag, &next, 0); | |
1491 |
1/2✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
|
9 | if (*next) { |
1492 | 9 | uint8_t buf[4] = { 0 }; | |
1493 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
|
9 | memcpy(buf, codec_tag, FFMIN(sizeof(buf), strlen(codec_tag))); |
1494 | 9 | tag = AV_RL32(buf); | |
1495 | } | ||
1496 | 9 | ost->st->codecpar->codec_tag = tag; | |
1497 | 9 | ms->par_in->codec_tag = tag; | |
1498 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 7 times.
|
9 | if (ost->enc) |
1499 | 2 | ost->enc->enc_ctx->codec_tag = tag; | |
1500 | } | ||
1501 | |||
1502 | 8896 | opt_match_per_stream_dbl(ost, &o->qscale, oc, st, &qscale); | |
1503 |
4/4✓ Branch 0 taken 8172 times.
✓ Branch 1 taken 724 times.
✓ Branch 2 taken 266 times.
✓ Branch 3 taken 7906 times.
|
8896 | if (ost->enc && qscale >= 0) { |
1504 | 266 | ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE; | |
1505 | 266 | ost->enc->enc_ctx->global_quality = FF_QP2LAMBDA * qscale; | |
1506 | } | ||
1507 | |||
1508 |
2/2✓ Branch 0 taken 8895 times.
✓ Branch 1 taken 1 times.
|
8896 | if (ms->sch_idx >= 0) { |
1509 | 8895 | int max_muxing_queue_size = 128; | |
1510 | 8895 | int muxing_queue_data_threshold = 50 * 1024 * 1024; | |
1511 | |||
1512 | 8895 | opt_match_per_stream_int(ost, &o->max_muxing_queue_size, oc, st, | |
1513 | &max_muxing_queue_size); | ||
1514 | 8895 | opt_match_per_stream_int(ost, &o->muxing_queue_data_threshold, | |
1515 | oc, st, &muxing_queue_data_threshold); | ||
1516 | |||
1517 | 8895 | sch_mux_stream_buffering(mux->sch, mux->sch_idx, ms->sch_idx, | |
1518 | max_muxing_queue_size, muxing_queue_data_threshold); | ||
1519 | } | ||
1520 | |||
1521 | 8896 | opt_match_per_stream_int(ost, &o->bits_per_raw_sample, oc, st, | |
1522 | &ost->bits_per_raw_sample); | ||
1523 | |||
1524 | 8896 | opt_match_per_stream_int(ost, &o->fix_sub_duration_heartbeat, | |
1525 | 8896 | oc, st, &ost->fix_sub_duration_heartbeat); | |
1526 | |||
1527 |
4/4✓ Branch 0 taken 3221 times.
✓ Branch 1 taken 5675 times.
✓ Branch 2 taken 3093 times.
✓ Branch 3 taken 128 times.
|
8896 | if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc) |
1528 | 3093 | ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | |
1529 | |||
1530 | 8896 | opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes, | |
1531 | oc, st, &ms->copy_initial_nonkeyframes); | ||
1532 |
4/4✓ Branch 0 taken 7168 times.
✓ Branch 1 taken 1635 times.
✓ Branch 2 taken 80 times.
✓ Branch 3 taken 13 times.
|
8896 | switch (type) { |
1533 | 7168 | case AVMEDIA_TYPE_VIDEO: ret = new_stream_video (mux, o, ost, &keep_pix_fmt, &vsync_method); break; | |
1534 | 1635 | case AVMEDIA_TYPE_AUDIO: ret = new_stream_audio (mux, o, ost); break; | |
1535 | 80 | case AVMEDIA_TYPE_SUBTITLE: ret = new_stream_subtitle (mux, o, ost); break; | |
1536 | } | ||
1537 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8896 times.
|
8896 | if (ret < 0) |
1538 | ✗ | goto fail; | |
1539 | |||
1540 |
4/4✓ Branch 0 taken 8172 times.
✓ Branch 1 taken 724 times.
✓ Branch 2 taken 1379 times.
✓ Branch 3 taken 6793 times.
|
8896 | if (ost->enc && |
1541 |
2/2✓ Branch 0 taken 1337 times.
✓ Branch 1 taken 42 times.
|
1379 | (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { |
1542 | 8130 | ret = ost_bind_filter(mux, ms, ofilter, o, enc_tb, vsync_method, | |
1543 | keep_pix_fmt, autoscale, threads_manual, vs, &src); | ||
1544 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8130 times.
|
8130 | if (ret < 0) |
1545 | ✗ | goto fail; | |
1546 |
2/2✓ Branch 0 taken 765 times.
✓ Branch 1 taken 1 times.
|
766 | } else if (ost->ist) { |
1547 | 765 | ret = ist_use(ost->ist, !!ost->enc, NULL, &src); | |
1548 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 765 times.
|
765 | if (ret < 0) { |
1549 | ✗ | av_log(ost, AV_LOG_ERROR, | |
1550 | "Error binding an input stream\n"); | ||
1551 | ✗ | goto fail; | |
1552 | } | ||
1553 | 765 | ms->sch_idx_src = src.idx; | |
1554 | |||
1555 | // src refers to a decoder for transcoding, demux stream otherwise | ||
1556 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 723 times.
|
765 | if (ost->enc) { |
1557 | 42 | ret = sch_connect(mux->sch, | |
1558 | 42 | src, SCH_ENC(ms->sch_idx_enc)); | |
1559 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (ret < 0) |
1560 | ✗ | goto fail; | |
1561 | 42 | src = SCH_ENC(ms->sch_idx_enc); | |
1562 | } | ||
1563 | } | ||
1564 | |||
1565 |
2/2✓ Branch 0 taken 8895 times.
✓ Branch 1 taken 1 times.
|
8896 | if (src.type != SCH_NODE_TYPE_NONE) { |
1566 | 8895 | ret = sch_connect(mux->sch, | |
1567 | 8895 | src, SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); | |
1568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8895 times.
|
8895 | if (ret < 0) |
1569 | ✗ | goto fail; | |
1570 | } else { | ||
1571 | // only attachment streams don't have a source | ||
1572 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | av_assert0(type == AVMEDIA_TYPE_ATTACHMENT && ms->sch_idx < 0); |
1573 | } | ||
1574 | |||
1575 |
4/4✓ Branch 0 taken 7558 times.
✓ Branch 1 taken 1338 times.
✓ Branch 2 taken 723 times.
✓ Branch 3 taken 6835 times.
|
8896 | if (ost->ist && !ost->enc) { |
1576 | 723 | ret = streamcopy_init(o, mux, ost, &encoder_opts); | |
1577 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 723 times.
|
723 | if (ret < 0) |
1578 | ✗ | goto fail; | |
1579 | } | ||
1580 | |||
1581 | // copy estimated duration as a hint to the muxer | ||
1582 |
4/4✓ Branch 0 taken 7558 times.
✓ Branch 1 taken 1338 times.
✓ Branch 2 taken 5943 times.
✓ Branch 3 taken 1615 times.
|
8896 | if (ost->ist && ost->ist->st->duration > 0) { |
1583 | 5943 | ms->stream_duration = ist->st->duration; | |
1584 | 5943 | ms->stream_duration_tb = ist->st->time_base; | |
1585 | } | ||
1586 | |||
1587 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8895 times.
|
8896 | if (post) |
1588 | 1 | *post = ost; | |
1589 | |||
1590 | 8896 | ret = 0; | |
1591 | |||
1592 | 8896 | fail: | |
1593 | 8896 | av_dict_free(&encoder_opts); | |
1594 | |||
1595 | 8896 | return ret; | |
1596 | } | ||
1597 | |||
1598 | 6889 | static int map_auto_video(Muxer *mux, const OptionsContext *o) | |
1599 | { | ||
1600 | 6889 | AVFormatContext *oc = mux->fc; | |
1601 | 6889 | InputStream *best_ist = NULL; | |
1602 | 6889 | int64_t best_score = 0; | |
1603 | int qcr; | ||
1604 | |||
1605 | /* video: highest resolution */ | ||
1606 |
2/2✓ Branch 1 taken 732 times.
✓ Branch 2 taken 6157 times.
|
6889 | if (av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_VIDEO) == AV_CODEC_ID_NONE) |
1607 | 732 | return 0; | |
1608 | |||
1609 | 6157 | qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0); | |
1610 |
2/2✓ Branch 0 taken 6198 times.
✓ Branch 1 taken 6157 times.
|
12355 | for (int j = 0; j < nb_input_files; j++) { |
1611 | 6198 | InputFile *ifile = input_files[j]; | |
1612 | 6198 | InputStream *file_best_ist = NULL; | |
1613 | 6198 | int64_t file_best_score = 0; | |
1614 |
2/2✓ Branch 0 taken 6480 times.
✓ Branch 1 taken 6198 times.
|
12678 | for (int i = 0; i < ifile->nb_streams; i++) { |
1615 | 6480 | InputStream *ist = ifile->streams[i]; | |
1616 | int64_t score; | ||
1617 | |||
1618 |
2/2✓ Branch 0 taken 6479 times.
✓ Branch 1 taken 1 times.
|
6480 | if (ist->user_set_discard == AVDISCARD_ALL || |
1619 |
2/2✓ Branch 0 taken 644 times.
✓ Branch 1 taken 5835 times.
|
6479 | ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) |
1620 | 645 | continue; | |
1621 | |||
1622 | 11670 | score = ist->st->codecpar->width * (int64_t)ist->st->codecpar->height | |
1623 |
2/2✓ Branch 0 taken 5833 times.
✓ Branch 1 taken 2 times.
|
5835 | + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) |
1624 |
2/2✓ Branch 0 taken 524 times.
✓ Branch 1 taken 5311 times.
|
5835 | + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); |
1625 |
3/4✓ Branch 0 taken 5835 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 5826 times.
|
5835 | if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) |
1626 | 9 | score = 1; | |
1627 | |||
1628 |
2/2✓ Branch 0 taken 5834 times.
✓ Branch 1 taken 1 times.
|
5835 | if (score > file_best_score) { |
1629 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 5834 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
5834 | if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) |
1630 | ✗ | continue; | |
1631 | 5834 | file_best_score = score; | |
1632 | 5834 | file_best_ist = ist; | |
1633 | } | ||
1634 | } | ||
1635 |
2/2✓ Branch 0 taken 5834 times.
✓ Branch 1 taken 364 times.
|
6198 | if (file_best_ist) { |
1636 |
1/2✓ Branch 0 taken 5834 times.
✗ Branch 1 not taken.
|
5834 | if((qcr == MKTAG('A', 'P', 'I', 'C')) || |
1637 |
2/2✓ Branch 0 taken 5826 times.
✓ Branch 1 taken 8 times.
|
5834 | !(file_best_ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) |
1638 |
2/2✓ Branch 0 taken 524 times.
✓ Branch 1 taken 5302 times.
|
5826 | file_best_score -= 5000000*!!(file_best_ist->st->disposition & AV_DISPOSITION_DEFAULT); |
1639 |
1/2✓ Branch 0 taken 5834 times.
✗ Branch 1 not taken.
|
5834 | if (file_best_score > best_score) { |
1640 | 5834 | best_score = file_best_score; | |
1641 | 5834 | best_ist = file_best_ist; | |
1642 | } | ||
1643 | } | ||
1644 | } | ||
1645 |
2/2✓ Branch 0 taken 5834 times.
✓ Branch 1 taken 323 times.
|
6157 | if (best_ist) |
1646 | 5834 | return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, best_ist, NULL, NULL, NULL); | |
1647 | |||
1648 | 323 | return 0; | |
1649 | } | ||
1650 | |||
1651 | 8055 | static int map_auto_audio(Muxer *mux, const OptionsContext *o) | |
1652 | { | ||
1653 | 8055 | AVFormatContext *oc = mux->fc; | |
1654 | 8055 | InputStream *best_ist = NULL; | |
1655 | 8055 | int best_score = 0; | |
1656 | |||
1657 | /* audio: most channels */ | ||
1658 |
2/2✓ Branch 1 taken 1942 times.
✓ Branch 2 taken 6113 times.
|
8055 | if (av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_AUDIO) == AV_CODEC_ID_NONE) |
1659 | 1942 | return 0; | |
1660 | |||
1661 |
2/2✓ Branch 0 taken 6093 times.
✓ Branch 1 taken 6113 times.
|
12206 | for (int j = 0; j < nb_input_files; j++) { |
1662 | 6093 | InputFile *ifile = input_files[j]; | |
1663 | 6093 | InputStream *file_best_ist = NULL; | |
1664 | 6093 | int file_best_score = 0; | |
1665 |
2/2✓ Branch 0 taken 6300 times.
✓ Branch 1 taken 6093 times.
|
12393 | for (int i = 0; i < ifile->nb_streams; i++) { |
1666 | 6300 | InputStream *ist = ifile->streams[i]; | |
1667 | int score; | ||
1668 | |||
1669 |
2/2✓ Branch 0 taken 6299 times.
✓ Branch 1 taken 1 times.
|
6300 | if (ist->user_set_discard == AVDISCARD_ALL || |
1670 |
2/2✓ Branch 0 taken 4995 times.
✓ Branch 1 taken 1304 times.
|
6299 | ist->st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) |
1671 | 4996 | continue; | |
1672 | |||
1673 | 2608 | score = ist->st->codecpar->ch_layout.nb_channels | |
1674 |
2/2✓ Branch 0 taken 1303 times.
✓ Branch 1 taken 1 times.
|
1304 | + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) |
1675 |
2/2✓ Branch 0 taken 175 times.
✓ Branch 1 taken 1129 times.
|
1304 | + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); |
1676 |
2/2✓ Branch 0 taken 1294 times.
✓ Branch 1 taken 10 times.
|
1304 | if (score > file_best_score) { |
1677 | 1294 | file_best_score = score; | |
1678 | 1294 | file_best_ist = ist; | |
1679 | } | ||
1680 | } | ||
1681 |
2/2✓ Branch 0 taken 1294 times.
✓ Branch 1 taken 4799 times.
|
6093 | if (file_best_ist) { |
1682 |
2/2✓ Branch 0 taken 175 times.
✓ Branch 1 taken 1119 times.
|
1294 | file_best_score -= 5000000*!!(file_best_ist->st->disposition & AV_DISPOSITION_DEFAULT); |
1683 |
1/2✓ Branch 0 taken 1294 times.
✗ Branch 1 not taken.
|
1294 | if (file_best_score > best_score) { |
1684 | 1294 | best_score = file_best_score; | |
1685 | 1294 | best_ist = file_best_ist; | |
1686 | } | ||
1687 | } | ||
1688 | } | ||
1689 |
2/2✓ Branch 0 taken 1294 times.
✓ Branch 1 taken 4819 times.
|
6113 | if (best_ist) |
1690 | 1294 | return ost_add(mux, o, AVMEDIA_TYPE_AUDIO, best_ist, NULL, NULL, NULL); | |
1691 | |||
1692 | 4819 | return 0; | |
1693 | } | ||
1694 | |||
1695 | 8221 | static int map_auto_subtitle(Muxer *mux, const OptionsContext *o) | |
1696 | { | ||
1697 | 8221 | AVFormatContext *oc = mux->fc; | |
1698 | 8221 | const char *subtitle_codec_name = NULL; | |
1699 | |||
1700 | /* subtitles: pick first */ | ||
1701 | 8221 | subtitle_codec_name = opt_match_per_type_str(&o->codec_names, 's'); | |
1702 |
4/4✓ Branch 1 taken 8158 times.
✓ Branch 2 taken 63 times.
✓ Branch 3 taken 8151 times.
✓ Branch 4 taken 7 times.
|
8221 | if (!avcodec_find_encoder(oc->oformat->subtitle_codec) && !subtitle_codec_name) |
1703 | 8151 | return 0; | |
1704 | |||
1705 |
2/2✓ Branch 2 taken 84 times.
✓ Branch 3 taken 20 times.
|
104 | for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist)) |
1706 |
2/2✓ Branch 0 taken 50 times.
✓ Branch 1 taken 34 times.
|
84 | if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { |
1707 | AVCodecDescriptor const *input_descriptor = | ||
1708 | 50 | avcodec_descriptor_get(ist->st->codecpar->codec_id); | |
1709 | 50 | AVCodecDescriptor const *output_descriptor = NULL; | |
1710 | AVCodec const *output_codec = | ||
1711 | 50 | avcodec_find_encoder(oc->oformat->subtitle_codec); | |
1712 | 50 | int input_props = 0, output_props = 0; | |
1713 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 50 times.
|
50 | if (ist->user_set_discard == AVDISCARD_ALL) |
1714 | ✗ | continue; | |
1715 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 7 times.
|
50 | if (output_codec) |
1716 | 43 | output_descriptor = avcodec_descriptor_get(output_codec->id); | |
1717 |
1/2✓ Branch 0 taken 50 times.
✗ Branch 1 not taken.
|
50 | if (input_descriptor) |
1718 | 50 | input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); | |
1719 |
2/2✓ Branch 0 taken 43 times.
✓ Branch 1 taken 7 times.
|
50 | if (output_descriptor) |
1720 | 43 | output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); | |
1721 |
2/2✓ Branch 0 taken 34 times.
✓ Branch 1 taken 16 times.
|
50 | if (subtitle_codec_name || |
1722 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
34 | input_props & output_props || |
1723 | // Map dvb teletext which has neither property to any output subtitle encoder | ||
1724 | ✗ | input_descriptor && output_descriptor && | |
1725 | ✗ | (!input_descriptor->props || | |
1726 | ✗ | !output_descriptor->props)) { | |
1727 | 50 | return ost_add(mux, o, AVMEDIA_TYPE_SUBTITLE, ist, NULL, NULL, NULL); | |
1728 | } | ||
1729 | } | ||
1730 | |||
1731 | 20 | return 0; | |
1732 | } | ||
1733 | |||
1734 | 8222 | static int map_auto_data(Muxer *mux, const OptionsContext *o) | |
1735 | { | ||
1736 | 8222 | AVFormatContext *oc = mux->fc; | |
1737 | /* Data only if codec id match */ | ||
1738 | 8222 | enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_DATA); | |
1739 | |||
1740 |
1/2✓ Branch 0 taken 8222 times.
✗ Branch 1 not taken.
|
8222 | if (codec_id == AV_CODEC_ID_NONE) |
1741 | 8222 | return 0; | |
1742 | |||
1743 | ✗ | for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist)) { | |
1744 | ✗ | if (ist->user_set_discard == AVDISCARD_ALL) | |
1745 | ✗ | continue; | |
1746 | ✗ | if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA && | |
1747 | ✗ | ist->st->codecpar->codec_id == codec_id) { | |
1748 | ✗ | int ret = ost_add(mux, o, AVMEDIA_TYPE_DATA, ist, NULL, NULL, NULL); | |
1749 | ✗ | if (ret < 0) | |
1750 | ✗ | return ret; | |
1751 | } | ||
1752 | } | ||
1753 | |||
1754 | ✗ | return 0; | |
1755 | } | ||
1756 | |||
1757 | 455 | static int map_manual(Muxer *mux, const OptionsContext *o, const StreamMap *map) | |
1758 | { | ||
1759 | InputStream *ist; | ||
1760 | int ret; | ||
1761 | |||
1762 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 455 times.
|
455 | if (map->disabled) |
1763 | ✗ | return 0; | |
1764 | |||
1765 |
2/2✓ Branch 0 taken 75 times.
✓ Branch 1 taken 380 times.
|
455 | if (map->linklabel) { |
1766 | FilterGraph *fg; | ||
1767 | 75 | OutputFilter *ofilter = NULL; | |
1768 | int j, k; | ||
1769 | |||
1770 |
1/2✓ Branch 0 taken 75 times.
✗ Branch 1 not taken.
|
75 | for (j = 0; j < nb_filtergraphs; j++) { |
1771 | 75 | fg = filtergraphs[j]; | |
1772 |
1/2✓ Branch 0 taken 266 times.
✗ Branch 1 not taken.
|
266 | for (k = 0; k < fg->nb_outputs; k++) { |
1773 | 266 | const char *linklabel = fg->outputs[k]->linklabel; | |
1774 |
4/4✓ Branch 0 taken 109 times.
✓ Branch 1 taken 157 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 34 times.
|
266 | if (linklabel && !strcmp(linklabel, map->linklabel)) { |
1775 | 75 | ofilter = fg->outputs[k]; | |
1776 | 75 | goto loop_end; | |
1777 | } | ||
1778 | } | ||
1779 | } | ||
1780 | ✗ | loop_end: | |
1781 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
|
75 | if (!ofilter) { |
1782 | ✗ | av_log(mux, AV_LOG_FATAL, "Output with label '%s' does not exist " | |
1783 | ✗ | "in any defined filter graph, or was already used elsewhere.\n", map->linklabel); | |
1784 | ✗ | return AVERROR(EINVAL); | |
1785 | } | ||
1786 | |||
1787 | 75 | av_log(mux, AV_LOG_VERBOSE, "Creating output stream from an explicitly " | |
1788 | 75 | "mapped complex filtergraph %d, output [%s]\n", fg->index, map->linklabel); | |
1789 | |||
1790 | 75 | ret = ost_add(mux, o, ofilter->type, NULL, ofilter, NULL, NULL); | |
1791 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 75 times.
|
75 | if (ret < 0) |
1792 | ✗ | return ret; | |
1793 | } else { | ||
1794 | 760 | const ViewSpecifier *vs = map->vs.type == VIEW_SPECIFIER_TYPE_NONE ? | |
1795 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 367 times.
|
380 | NULL : &map->vs; |
1796 | |||
1797 | 380 | ist = input_files[map->file_index]->streams[map->stream_index]; | |
1798 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
|
380 | if (ist->user_set_discard == AVDISCARD_ALL) { |
1799 | ✗ | av_log(mux, AV_LOG_FATAL, "Stream #%d:%d is disabled and cannot be mapped.\n", | |
1800 | ✗ | map->file_index, map->stream_index); | |
1801 | ✗ | return AVERROR(EINVAL); | |
1802 | } | ||
1803 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
380 | if(o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) |
1804 | ✗ | return 0; | |
1805 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
380 | if(o-> audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) |
1806 | ✗ | return 0; | |
1807 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 379 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
380 | if(o-> video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) |
1808 | ✗ | return 0; | |
1809 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
380 | if(o-> data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA) |
1810 | ✗ | return 0; | |
1811 | |||
1812 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
|
380 | if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_UNKNOWN && |
1813 | ✗ | !copy_unknown_streams) { | |
1814 | ✗ | av_log(mux, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL, | |
1815 | "Cannot map stream #%d:%d - unsupported type.\n", | ||
1816 | ✗ | map->file_index, map->stream_index); | |
1817 | ✗ | if (!ignore_unknown_streams) { | |
1818 | ✗ | av_log(mux, AV_LOG_FATAL, | |
1819 | "If you want unsupported types ignored instead " | ||
1820 | "of failing, please use the -ignore_unknown option\n" | ||
1821 | "If you want them copied, please use -copy_unknown\n"); | ||
1822 | ✗ | return AVERROR(EINVAL); | |
1823 | } | ||
1824 | ✗ | return 0; | |
1825 | } | ||
1826 | |||
1827 |
3/4✓ Branch 0 taken 13 times.
✓ Branch 1 taken 367 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
380 | if (vs && ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { |
1828 | ✗ | av_log(mux, AV_LOG_ERROR, | |
1829 | "View specifier given for mapping a %s input stream\n", | ||
1830 | ✗ | av_get_media_type_string(ist->st->codecpar->codec_type)); | |
1831 | ✗ | return AVERROR(EINVAL); | |
1832 | } | ||
1833 | |||
1834 | 380 | ret = ost_add(mux, o, ist->st->codecpar->codec_type, ist, NULL, vs, NULL); | |
1835 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 380 times.
|
380 | if (ret < 0) |
1836 | ✗ | return ret; | |
1837 | } | ||
1838 | |||
1839 | 455 | return 0; | |
1840 | } | ||
1841 | |||
1842 | 8406 | static int of_add_attachments(Muxer *mux, const OptionsContext *o) | |
1843 | { | ||
1844 | MuxStream *ms; | ||
1845 | OutputStream *ost; | ||
1846 | int err; | ||
1847 | |||
1848 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8406 times.
|
8407 | for (int i = 0; i < o->nb_attachments; i++) { |
1849 | AVIOContext *pb; | ||
1850 | uint8_t *attachment; | ||
1851 | char *attachment_filename; | ||
1852 | const char *p; | ||
1853 | int64_t len; | ||
1854 | |||
1855 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if ((err = avio_open2(&pb, o->attachments[i], AVIO_FLAG_READ, &int_cb, NULL)) < 0) { |
1856 | ✗ | av_log(mux, AV_LOG_FATAL, "Could not open attachment file %s.\n", | |
1857 | ✗ | o->attachments[i]); | |
1858 | ✗ | return err; | |
1859 | } | ||
1860 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if ((len = avio_size(pb)) <= 0) { |
1861 | ✗ | av_log(mux, AV_LOG_FATAL, "Could not get size of the attachment %s.\n", | |
1862 | ✗ | o->attachments[i]); | |
1863 | ✗ | err = len ? len : AVERROR_INVALIDDATA; | |
1864 | ✗ | goto read_fail; | |
1865 | } | ||
1866 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (len > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { |
1867 | ✗ | av_log(mux, AV_LOG_FATAL, "Attachment %s too large.\n", | |
1868 | ✗ | o->attachments[i]); | |
1869 | ✗ | err = AVERROR(ERANGE); | |
1870 | ✗ | goto read_fail; | |
1871 | } | ||
1872 | |||
1873 | 1 | attachment = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE); | |
1874 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!attachment) { |
1875 | ✗ | err = AVERROR(ENOMEM); | |
1876 | ✗ | goto read_fail; | |
1877 | } | ||
1878 | |||
1879 | 1 | err = avio_read(pb, attachment, len); | |
1880 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (err < 0) |
1881 | ✗ | av_log(mux, AV_LOG_FATAL, "Error reading attachment file %s: %s\n", | |
1882 | ✗ | o->attachments[i], av_err2str(err)); | |
1883 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | else if (err != len) { |
1884 | ✗ | av_log(mux, AV_LOG_FATAL, "Could not read all %"PRId64" bytes for " | |
1885 | ✗ | "attachment file %s\n", len, o->attachments[i]); | |
1886 | ✗ | err = AVERROR(EIO); | |
1887 | } | ||
1888 | |||
1889 | 1 | read_fail: | |
1890 | 1 | avio_closep(&pb); | |
1891 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (err < 0) |
1892 | ✗ | return err; | |
1893 | |||
1894 | 1 | memset(attachment + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); | |
1895 | |||
1896 | 1 | av_log(mux, AV_LOG_VERBOSE, "Creating attachment stream from file %s\n", | |
1897 | 1 | o->attachments[i]); | |
1898 | |||
1899 | 1 | attachment_filename = av_strdup(o->attachments[i]); | |
1900 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!attachment_filename) { |
1901 | ✗ | av_free(attachment); | |
1902 | ✗ | return AVERROR(ENOMEM); | |
1903 | } | ||
1904 | |||
1905 | 1 | err = ost_add(mux, o, AVMEDIA_TYPE_ATTACHMENT, NULL, NULL, NULL, &ost); | |
1906 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (err < 0) { |
1907 | ✗ | av_free(attachment_filename); | |
1908 | ✗ | av_freep(&attachment); | |
1909 | ✗ | return err; | |
1910 | } | ||
1911 | |||
1912 | 1 | ms = ms_from_ost(ost); | |
1913 | |||
1914 | 1 | ost->attachment_filename = attachment_filename; | |
1915 | 1 | ms->par_in->extradata = attachment; | |
1916 | 1 | ms->par_in->extradata_size = len; | |
1917 | |||
1918 | 1 | p = strrchr(o->attachments[i], '/'); | |
1919 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | av_dict_set(&ost->st->metadata, "filename", (p && *p) ? p + 1 : o->attachments[i], AV_DICT_DONT_OVERWRITE); |
1920 | } | ||
1921 | |||
1922 | 8406 | return 0; | |
1923 | } | ||
1924 | |||
1925 | 8406 | static int create_streams(Muxer *mux, const OptionsContext *o) | |
1926 | { | ||
1927 | static int (* const map_func[])(Muxer *mux, const OptionsContext *o) = { | ||
1928 | [AVMEDIA_TYPE_VIDEO] = map_auto_video, | ||
1929 | [AVMEDIA_TYPE_AUDIO] = map_auto_audio, | ||
1930 | [AVMEDIA_TYPE_SUBTITLE] = map_auto_subtitle, | ||
1931 | [AVMEDIA_TYPE_DATA] = map_auto_data, | ||
1932 | }; | ||
1933 | |||
1934 | 8406 | AVFormatContext *oc = mux->fc; | |
1935 | |||
1936 | 8406 | int auto_disable = | |
1937 | 8406 | o->video_disable * (1 << AVMEDIA_TYPE_VIDEO) | | |
1938 | 8406 | o->audio_disable * (1 << AVMEDIA_TYPE_AUDIO) | | |
1939 | 8406 | o->subtitle_disable * (1 << AVMEDIA_TYPE_SUBTITLE) | | |
1940 | 8406 | o->data_disable * (1 << AVMEDIA_TYPE_DATA); | |
1941 | |||
1942 | int ret; | ||
1943 | |||
1944 | /* create streams for all unlabeled output pads */ | ||
1945 |
2/2✓ Branch 0 taken 1208 times.
✓ Branch 1 taken 8406 times.
|
9614 | for (int i = 0; i < nb_filtergraphs; i++) { |
1946 | 1208 | FilterGraph *fg = filtergraphs[i]; | |
1947 |
2/2✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 1208 times.
|
2552 | for (int j = 0; j < fg->nb_outputs; j++) { |
1948 | 1344 | OutputFilter *ofilter = fg->outputs[j]; | |
1949 | |||
1950 |
4/4✓ Branch 0 taken 1265 times.
✓ Branch 1 taken 79 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1262 times.
|
1344 | if (ofilter->linklabel || ofilter->bound) |
1951 | 82 | continue; | |
1952 | |||
1953 | 1262 | auto_disable |= 1 << ofilter->type; | |
1954 | |||
1955 | 1262 | av_log(mux, AV_LOG_VERBOSE, "Creating output stream from unlabeled " | |
1956 | "output of complex filtergraph %d.", fg->index); | ||
1957 |
1/2✓ Branch 0 taken 1262 times.
✗ Branch 1 not taken.
|
1262 | if (!o->nb_stream_maps) |
1958 | 1262 | av_log(mux, AV_LOG_VERBOSE, " This overrides automatic %s mapping.", | |
1959 | av_get_media_type_string(ofilter->type)); | ||
1960 | 1262 | av_log(mux, AV_LOG_VERBOSE, "\n"); | |
1961 | |||
1962 | 1262 | ret = ost_add(mux, o, ofilter->type, NULL, ofilter, NULL, NULL); | |
1963 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1262 times.
|
1262 | if (ret < 0) |
1964 | ✗ | return ret; | |
1965 | } | ||
1966 | } | ||
1967 | |||
1968 |
2/2✓ Branch 0 taken 8222 times.
✓ Branch 1 taken 184 times.
|
8406 | if (!o->nb_stream_maps) { |
1969 | 8222 | av_log(mux, AV_LOG_VERBOSE, "No explicit maps, mapping streams automatically...\n"); | |
1970 | |||
1971 | /* pick the "best" stream of each type */ | ||
1972 |
2/2✓ Branch 0 taken 32888 times.
✓ Branch 1 taken 8222 times.
|
41110 | for (int i = 0; i < FF_ARRAY_ELEMS(map_func); i++) { |
1973 |
3/4✓ Branch 0 taken 32888 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1501 times.
✓ Branch 3 taken 31387 times.
|
32888 | if (!map_func[i] || auto_disable & (1 << i)) |
1974 | 1501 | continue; | |
1975 | 31387 | ret = map_func[i](mux, o); | |
1976 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 31387 times.
|
31387 | if (ret < 0) |
1977 | ✗ | return ret; | |
1978 | } | ||
1979 | } else { | ||
1980 | 184 | av_log(mux, AV_LOG_VERBOSE, "Adding streams from explicit maps...\n"); | |
1981 | |||
1982 |
2/2✓ Branch 0 taken 455 times.
✓ Branch 1 taken 184 times.
|
639 | for (int i = 0; i < o->nb_stream_maps; i++) { |
1983 | 455 | ret = map_manual(mux, o, &o->stream_maps[i]); | |
1984 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 455 times.
|
455 | if (ret < 0) |
1985 | ✗ | return ret; | |
1986 | } | ||
1987 | } | ||
1988 | |||
1989 | 8406 | ret = of_add_attachments(mux, o); | |
1990 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (ret < 0) |
1991 | ✗ | return ret; | |
1992 | |||
1993 | // setup fix_sub_duration_heartbeat mappings | ||
1994 |
2/2✓ Branch 0 taken 8896 times.
✓ Branch 1 taken 8406 times.
|
17302 | for (unsigned i = 0; i < oc->nb_streams; i++) { |
1995 | 8896 | MuxStream *src = ms_from_ost(mux->of.streams[i]); | |
1996 | |||
1997 |
2/2✓ Branch 0 taken 8895 times.
✓ Branch 1 taken 1 times.
|
8896 | if (!src->ost.fix_sub_duration_heartbeat) |
1998 | 8895 | continue; | |
1999 | |||
2000 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (unsigned j = 0; j < oc->nb_streams; j++) { |
2001 | 2 | MuxStream *dst = ms_from_ost(mux->of.streams[j]); | |
2002 | |||
2003 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
2 | if (src == dst || dst->ost.type != AVMEDIA_TYPE_SUBTITLE || |
2004 |
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 | !dst->ost.enc || !dst->ost.ist || !dst->ost.ist->fix_sub_duration) |
2005 | 1 | continue; | |
2006 | |||
2007 | 1 | ret = sch_mux_sub_heartbeat_add(mux->sch, mux->sch_idx, src->sch_idx, | |
2008 | 1 | dst->sch_idx_src); | |
2009 | |||
2010 | } | ||
2011 | } | ||
2012 | |||
2013 | // handle -apad | ||
2014 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 8402 times.
|
8406 | if (o->shortest) { |
2015 | 4 | int have_video = 0; | |
2016 | |||
2017 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | for (unsigned i = 0; i < mux->of.nb_streams; i++) |
2018 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (mux->of.streams[i]->type == AVMEDIA_TYPE_VIDEO) { |
2019 | 4 | have_video = 1; | |
2020 | 4 | break; | |
2021 | } | ||
2022 | |||
2023 |
3/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 4 times.
|
12 | for (unsigned i = 0; have_video && i < mux->of.nb_streams; i++) { |
2024 | 8 | MuxStream *ms = ms_from_ost(mux->of.streams[i]); | |
2025 | 8 | OutputFilter *ofilter = ms->ost.filter; | |
2026 | |||
2027 |
3/6✓ Branch 0 taken 3 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
|
8 | if (ms->ost.type != AVMEDIA_TYPE_AUDIO || !ms->apad || !ofilter) |
2028 | 8 | continue; | |
2029 | |||
2030 | ✗ | ofilter->apad = av_strdup(ms->apad); | |
2031 | ✗ | if (!ofilter->apad) | |
2032 | ✗ | return AVERROR(ENOMEM); | |
2033 | } | ||
2034 | } | ||
2035 |
2/2✓ Branch 0 taken 8896 times.
✓ Branch 1 taken 8406 times.
|
17302 | for (unsigned i = 0; i < mux->of.nb_streams; i++) { |
2036 | 8896 | MuxStream *ms = ms_from_ost(mux->of.streams[i]); | |
2037 | 8896 | ms->apad = NULL; | |
2038 | } | ||
2039 | |||
2040 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
8406 | if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) { |
2041 | ✗ | av_dump_format(oc, nb_output_files - 1, oc->url, 1); | |
2042 | ✗ | av_log(mux, AV_LOG_ERROR, "Output file does not contain any stream\n"); | |
2043 | ✗ | return AVERROR(EINVAL); | |
2044 | } | ||
2045 | |||
2046 | 8406 | return 0; | |
2047 | } | ||
2048 | |||
2049 | 8406 | static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, | |
2050 | int64_t buf_size_us, int shortest) | ||
2051 | { | ||
2052 | 8406 | OutputFile *of = &mux->of; | |
2053 | 8406 | int nb_av_enc = 0, nb_audio_fs = 0, nb_interleaved = 0; | |
2054 | 8406 | int limit_frames = 0, limit_frames_av_enc = 0; | |
2055 | |||
2056 | #define IS_AV_ENC(ost, type) \ | ||
2057 | (ost->enc && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) | ||
2058 | #define IS_INTERLEAVED(type) (type != AVMEDIA_TYPE_ATTACHMENT) | ||
2059 | |||
2060 |
2/2✓ Branch 0 taken 8896 times.
✓ Branch 1 taken 8406 times.
|
17302 | for (int i = 0; i < oc->nb_streams; i++) { |
2061 | 8896 | OutputStream *ost = of->streams[i]; | |
2062 | 8896 | MuxStream *ms = ms_from_ost(ost); | |
2063 | 8896 | enum AVMediaType type = ost->type; | |
2064 | |||
2065 | 8896 | ms->sq_idx_mux = -1; | |
2066 | |||
2067 | 8896 | nb_interleaved += IS_INTERLEAVED(type); | |
2068 |
6/6✓ Branch 0 taken 8172 times.
✓ Branch 1 taken 724 times.
✓ Branch 2 taken 1379 times.
✓ Branch 3 taken 6793 times.
✓ Branch 4 taken 1337 times.
✓ Branch 5 taken 42 times.
|
8896 | nb_av_enc += IS_AV_ENC(ost, type); |
2069 |
4/4✓ Branch 0 taken 8172 times.
✓ Branch 1 taken 724 times.
✓ Branch 2 taken 1337 times.
✓ Branch 3 taken 6835 times.
|
10233 | nb_audio_fs += (ost->enc && type == AVMEDIA_TYPE_AUDIO && |
2070 |
2/2✓ Branch 0 taken 174 times.
✓ Branch 1 taken 1163 times.
|
1337 | !(ost->enc->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)); |
2071 | |||
2072 | 8896 | limit_frames |= ms->max_frames < INT64_MAX; | |
2073 |
7/8✓ Branch 0 taken 3088 times.
✓ Branch 1 taken 5808 times.
✓ Branch 2 taken 3059 times.
✓ Branch 3 taken 29 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 3030 times.
✓ Branch 6 taken 29 times.
✗ Branch 7 not taken.
|
8896 | limit_frames_av_enc |= (ms->max_frames < INT64_MAX) && IS_AV_ENC(ost, type); |
2074 | } | ||
2075 | |||
2076 |
7/8✓ Branch 0 taken 252 times.
✓ Branch 1 taken 8154 times.
✓ Branch 2 taken 248 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 8402 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 5207 times.
✓ Branch 7 taken 124 times.
|
13737 | if (!((nb_interleaved > 1 && shortest) || |
2077 |
2/2✓ Branch 0 taken 5331 times.
✓ Branch 1 taken 3071 times.
|
8402 | (nb_interleaved > 0 && limit_frames) || |
2078 | nb_audio_fs)) | ||
2079 | 5207 | return 0; | |
2080 | |||
2081 | /* we use a sync queue before encoding when: | ||
2082 | * - 'shortest' is in effect and we have two or more encoded audio/video | ||
2083 | * streams | ||
2084 | * - at least one encoded audio/video stream is frame-limited, since | ||
2085 | * that has similar semantics to 'shortest' | ||
2086 | * - at least one audio encoder requires constant frame sizes | ||
2087 | * | ||
2088 | * Note that encoding sync queues are handled in the scheduler, because | ||
2089 | * different encoders run in different threads and need external | ||
2090 | * synchronization, while muxer sync queues can be handled inside the muxer | ||
2091 | */ | ||
2092 |
8/8✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3195 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 139 times.
✓ Branch 5 taken 3059 times.
✓ Branch 6 taken 126 times.
✓ Branch 7 taken 13 times.
|
3199 | if ((shortest && nb_av_enc > 1) || limit_frames_av_enc || nb_audio_fs) { |
2093 | int sq_idx, ret; | ||
2094 | |||
2095 | 3186 | sq_idx = sch_add_sq_enc(mux->sch, buf_size_us, mux); | |
2096 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3186 times.
|
3186 | if (sq_idx < 0) |
2097 | ✗ | return sq_idx; | |
2098 | |||
2099 |
2/2✓ Branch 0 taken 3255 times.
✓ Branch 1 taken 3186 times.
|
6441 | for (int i = 0; i < oc->nb_streams; i++) { |
2100 | 3255 | OutputStream *ost = of->streams[i]; | |
2101 | 3255 | MuxStream *ms = ms_from_ost(ost); | |
2102 | 3255 | enum AVMediaType type = ost->type; | |
2103 | |||
2104 |
5/6✓ Branch 0 taken 3248 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 201 times.
✓ Branch 3 taken 3047 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 201 times.
|
3255 | if (!IS_AV_ENC(ost, type)) |
2105 | 7 | continue; | |
2106 | |||
2107 | 3248 | ret = sch_sq_add_enc(mux->sch, sq_idx, ms->sch_idx_enc, | |
2108 |
2/2✓ Branch 0 taken 3059 times.
✓ Branch 1 taken 185 times.
|
3244 | shortest || ms->max_frames < INT64_MAX, |
2109 |
2/2✓ Branch 0 taken 3244 times.
✓ Branch 1 taken 4 times.
|
3248 | ms->max_frames); |
2110 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3248 times.
|
3248 | if (ret < 0) |
2111 | ✗ | return ret; | |
2112 | } | ||
2113 | } | ||
2114 | |||
2115 | /* if there are any additional interleaved streams, then ALL the streams | ||
2116 | * are also synchronized before sending them to the muxer */ | ||
2117 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 3182 times.
|
3199 | if (nb_interleaved > nb_av_enc) { |
2118 | 17 | mux->sq_mux = sq_alloc(SYNC_QUEUE_PACKETS, buf_size_us, mux); | |
2119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!mux->sq_mux) |
2120 | ✗ | return AVERROR(ENOMEM); | |
2121 | |||
2122 | 17 | mux->sq_pkt = av_packet_alloc(); | |
2123 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!mux->sq_pkt) |
2124 | ✗ | return AVERROR(ENOMEM); | |
2125 | |||
2126 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 17 times.
|
62 | for (int i = 0; i < oc->nb_streams; i++) { |
2127 | 45 | OutputStream *ost = of->streams[i]; | |
2128 | 45 | MuxStream *ms = ms_from_ost(ost); | |
2129 | 45 | enum AVMediaType type = ost->type; | |
2130 | |||
2131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | if (!IS_INTERLEAVED(type)) |
2132 | ✗ | continue; | |
2133 | |||
2134 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 6 times.
|
84 | ms->sq_idx_mux = sq_add_stream(mux->sq_mux, |
2135 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 10 times.
|
39 | shortest || ms->max_frames < INT64_MAX); |
2136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | if (ms->sq_idx_mux < 0) |
2137 | ✗ | return ms->sq_idx_mux; | |
2138 | |||
2139 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 16 times.
|
45 | if (ms->max_frames != INT64_MAX) |
2140 | 29 | sq_limit_frames(mux->sq_mux, ms->sq_idx_mux, ms->max_frames); | |
2141 | } | ||
2142 | } | ||
2143 | |||
2144 | #undef IS_AV_ENC | ||
2145 | #undef IS_INTERLEAVED | ||
2146 | |||
2147 | 3199 | return 0; | |
2148 | } | ||
2149 | |||
2150 | 12 | static int of_parse_iamf_audio_element_layers(Muxer *mux, AVStreamGroup *stg, char *ptr) | |
2151 | { | ||
2152 | 12 | AVIAMFAudioElement *audio_element = stg->params.iamf_audio_element; | |
2153 | 12 | AVDictionary *dict = NULL; | |
2154 | const char *token; | ||
2155 | 12 | int ret = 0; | |
2156 | |||
2157 | 12 | audio_element->demixing_info = | |
2158 | 12 | av_iamf_param_definition_alloc(AV_IAMF_PARAMETER_DEFINITION_DEMIXING, 1, NULL); | |
2159 | 12 | audio_element->recon_gain_info = | |
2160 | 12 | av_iamf_param_definition_alloc(AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN, 1, NULL); | |
2161 | |||
2162 |
1/2✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
|
12 | if (!audio_element->demixing_info || |
2163 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | !audio_element->recon_gain_info) |
2164 | ✗ | return AVERROR(ENOMEM); | |
2165 | |||
2166 | /* process manually set layers and parameters */ | ||
2167 | 12 | token = av_strtok(NULL, ",", &ptr); | |
2168 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 12 times.
|
60 | while (token) { |
2169 | const AVDictionaryEntry *e; | ||
2170 | 48 | int demixing = 0, recon_gain = 0; | |
2171 | 48 | int layer = 0; | |
2172 | |||
2173 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1 times.
|
48 | if (ptr) |
2174 | 47 | ptr += strspn(ptr, " \n\t\r"); | |
2175 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 20 times.
|
48 | if (av_strstart(token, "layer=", &token)) |
2176 | 28 | layer = 1; | |
2177 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
|
20 | else if (av_strstart(token, "demixing=", &token)) |
2178 | 10 | demixing = 1; | |
2179 |
1/2✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
10 | else if (av_strstart(token, "recon_gain=", &token)) |
2180 | 10 | recon_gain = 1; | |
2181 | |||
2182 | 48 | av_dict_free(&dict); | |
2183 | 48 | ret = av_dict_parse_string(&dict, token, "=", ":", 0); | |
2184 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (ret < 0) { |
2185 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing audio element specification %s\n", token); | |
2186 | ✗ | goto fail; | |
2187 | } | ||
2188 | |||
2189 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 20 times.
|
48 | if (layer) { |
2190 | 28 | AVIAMFLayer *audio_layer = av_iamf_audio_element_add_layer(audio_element); | |
2191 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (!audio_layer) { |
2192 | ✗ | av_log(mux, AV_LOG_ERROR, "Error adding layer to stream group %d\n", stg->index); | |
2193 | ✗ | ret = AVERROR(ENOMEM); | |
2194 | ✗ | goto fail; | |
2195 | } | ||
2196 | 28 | av_opt_set_dict(audio_layer, &dict); | |
2197 |
3/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
20 | } else if (demixing || recon_gain) { |
2198 | 20 | AVIAMFParamDefinition *param = demixing ? audio_element->demixing_info | |
2199 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
|
20 | : audio_element->recon_gain_info; |
2200 | 20 | void *subblock = av_iamf_param_definition_get_subblock(param, 0); | |
2201 | |||
2202 | 20 | av_opt_set_dict(param, &dict); | |
2203 | 20 | av_opt_set_dict(subblock, &dict); | |
2204 | } | ||
2205 | |||
2206 | // make sure that no entries are left in the dict | ||
2207 | 48 | e = NULL; | |
2208 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 48 times.
|
48 | if (e = av_dict_iterate(dict, e)) { |
2209 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown layer key %s.\n", e->key); | |
2210 | ✗ | ret = AVERROR(EINVAL); | |
2211 | ✗ | goto fail; | |
2212 | } | ||
2213 | 48 | token = av_strtok(NULL, ",", &ptr); | |
2214 | } | ||
2215 | |||
2216 | 12 | fail: | |
2217 | 12 | av_dict_free(&dict); | |
2218 |
2/4✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 12 times.
|
12 | if (!ret && !audio_element->nb_layers) { |
2219 | ✗ | av_log(mux, AV_LOG_ERROR, "No layer in audio element specification\n"); | |
2220 | ✗ | ret = AVERROR(EINVAL); | |
2221 | } | ||
2222 | |||
2223 | 12 | return ret; | |
2224 | } | ||
2225 | |||
2226 | 11 | static int of_parse_iamf_submixes(Muxer *mux, AVStreamGroup *stg, char *ptr) | |
2227 | { | ||
2228 | 11 | AVFormatContext *oc = mux->fc; | |
2229 | 11 | AVIAMFMixPresentation *mix = stg->params.iamf_mix_presentation; | |
2230 | 11 | AVDictionary *dict = NULL; | |
2231 | const char *token; | ||
2232 | 11 | char *submix_str = NULL; | |
2233 | 11 | int ret = 0; | |
2234 | |||
2235 | /* process manually set submixes */ | ||
2236 | 11 | token = av_strtok(NULL, ",", &ptr); | |
2237 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 11 times.
|
24 | while (token) { |
2238 | 13 | AVIAMFSubmix *submix = NULL; | |
2239 | const char *subtoken; | ||
2240 | 13 | char *subptr = NULL; | |
2241 | |||
2242 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 1 times.
|
13 | if (ptr) |
2243 | 12 | ptr += strspn(ptr, " \n\t\r"); | |
2244 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 13 times.
|
13 | if (!av_strstart(token, "submix=", &token)) { |
2245 | ✗ | av_log(mux, AV_LOG_ERROR, "No submix in mix presentation specification \"%s\"\n", token); | |
2246 | ✗ | goto fail; | |
2247 | } | ||
2248 | |||
2249 | 13 | submix_str = av_strdup(token); | |
2250 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (!submix_str) |
2251 | ✗ | goto fail; | |
2252 | |||
2253 | 13 | submix = av_iamf_mix_presentation_add_submix(mix); | |
2254 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (!submix) { |
2255 | ✗ | av_log(mux, AV_LOG_ERROR, "Error adding submix to stream group %d\n", stg->index); | |
2256 | ✗ | ret = AVERROR(ENOMEM); | |
2257 | ✗ | goto fail; | |
2258 | } | ||
2259 | 13 | submix->output_mix_config = | |
2260 | 13 | av_iamf_param_definition_alloc(AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN, 0, NULL); | |
2261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (!submix->output_mix_config) { |
2262 | ✗ | ret = AVERROR(ENOMEM); | |
2263 | ✗ | goto fail; | |
2264 | } | ||
2265 | |||
2266 | 13 | subptr = NULL; | |
2267 | 13 | subtoken = av_strtok(submix_str, "|", &subptr); | |
2268 |
2/2✓ Branch 0 taken 57 times.
✓ Branch 1 taken 13 times.
|
70 | while (subtoken) { |
2269 | const AVDictionaryEntry *e; | ||
2270 | 57 | int element = 0, layout = 0; | |
2271 | |||
2272 |
2/2✓ Branch 0 taken 44 times.
✓ Branch 1 taken 13 times.
|
57 | if (subptr) |
2273 | 44 | subptr += strspn(subptr, " \n\t\r"); | |
2274 |
2/2✓ Branch 1 taken 14 times.
✓ Branch 2 taken 43 times.
|
57 | if (av_strstart(subtoken, "element=", &subtoken)) |
2275 | 14 | element = 1; | |
2276 |
2/2✓ Branch 1 taken 30 times.
✓ Branch 2 taken 13 times.
|
43 | else if (av_strstart(subtoken, "layout=", &subtoken)) |
2277 | 30 | layout = 1; | |
2278 | |||
2279 | 57 | av_dict_free(&dict); | |
2280 | 57 | ret = av_dict_parse_string(&dict, subtoken, "=", ":", 0); | |
2281 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
|
57 | if (ret < 0) { |
2282 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing submix specification \"%s\"\n", subtoken); | |
2283 | ✗ | goto fail; | |
2284 | } | ||
2285 | |||
2286 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 43 times.
|
57 | if (element) { |
2287 | AVIAMFSubmixElement *submix_element; | ||
2288 | 14 | char *endptr = NULL; | |
2289 | 14 | int64_t idx = -1; | |
2290 | |||
2291 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | if (e = av_dict_get(dict, "stg", NULL, 0)) |
2292 | 14 | idx = strtoll(e->value, &endptr, 0); | |
2293 |
4/8✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 14 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 14 times.
✗ Branch 7 not taken.
|
14 | if (!endptr || *endptr || idx < 0 || idx >= oc->nb_stream_groups - 1 || |
2294 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | oc->stream_groups[idx]->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT) { |
2295 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid or missing stream group index in " | |
2296 | "submix element specification \"%s\"\n", subtoken); | ||
2297 | ✗ | ret = AVERROR(EINVAL); | |
2298 | ✗ | goto fail; | |
2299 | } | ||
2300 | 14 | submix_element = av_iamf_submix_add_element(submix); | |
2301 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (!submix_element) { |
2302 | ✗ | av_log(mux, AV_LOG_ERROR, "Error adding element to submix\n"); | |
2303 | ✗ | ret = AVERROR(ENOMEM); | |
2304 | ✗ | goto fail; | |
2305 | } | ||
2306 | |||
2307 | 14 | submix_element->audio_element_id = oc->stream_groups[idx]->id; | |
2308 | |||
2309 | 14 | submix_element->element_mix_config = | |
2310 | 14 | av_iamf_param_definition_alloc(AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN, 0, NULL); | |
2311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 14 times.
|
14 | if (!submix_element->element_mix_config) |
2312 | ✗ | ret = AVERROR(ENOMEM); | |
2313 | 14 | av_dict_set(&dict, "stg", NULL, 0); | |
2314 | 14 | av_opt_set_dict2(submix_element, &dict, AV_OPT_SEARCH_CHILDREN); | |
2315 |
2/2✓ Branch 0 taken 30 times.
✓ Branch 1 taken 13 times.
|
43 | } else if (layout) { |
2316 | 30 | AVIAMFSubmixLayout *submix_layout = av_iamf_submix_add_layout(submix); | |
2317 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 30 times.
|
30 | if (!submix_layout) { |
2318 | ✗ | av_log(mux, AV_LOG_ERROR, "Error adding layout to submix\n"); | |
2319 | ✗ | ret = AVERROR(ENOMEM); | |
2320 | ✗ | goto fail; | |
2321 | } | ||
2322 | 30 | av_opt_set_dict(submix_layout, &dict); | |
2323 | } else | ||
2324 | 13 | av_opt_set_dict2(submix, &dict, AV_OPT_SEARCH_CHILDREN); | |
2325 | |||
2326 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
|
57 | if (ret < 0) { |
2327 | ✗ | goto fail; | |
2328 | } | ||
2329 | |||
2330 | // make sure that no entries are left in the dict | ||
2331 | 57 | e = NULL; | |
2332 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
|
57 | while (e = av_dict_iterate(dict, e)) { |
2333 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown submix key %s.\n", e->key); | |
2334 | ✗ | ret = AVERROR(EINVAL); | |
2335 | ✗ | goto fail; | |
2336 | } | ||
2337 | 57 | subtoken = av_strtok(NULL, "|", &subptr); | |
2338 | } | ||
2339 | 13 | av_freep(&submix_str); | |
2340 | |||
2341 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 13 times.
|
13 | if (!submix->nb_elements) { |
2342 | ✗ | av_log(mux, AV_LOG_ERROR, "No audio elements in submix specification \"%s\"\n", token); | |
2343 | ✗ | ret = AVERROR(EINVAL); | |
2344 | } | ||
2345 | 13 | token = av_strtok(NULL, ",", &ptr); | |
2346 | } | ||
2347 | |||
2348 | 11 | fail: | |
2349 | 11 | av_dict_free(&dict); | |
2350 | 11 | av_free(submix_str); | |
2351 | |||
2352 | 11 | return ret; | |
2353 | } | ||
2354 | |||
2355 | 12 | static int of_serialize_options(Muxer *mux, void *obj, AVBPrint *bp) | |
2356 | { | ||
2357 | char *ptr; | ||
2358 | int ret; | ||
2359 | |||
2360 | 12 | ret = av_opt_serialize(obj, 0, AV_OPT_SERIALIZE_SKIP_DEFAULTS | AV_OPT_SERIALIZE_SEARCH_CHILDREN, | |
2361 | &ptr, '=', ':'); | ||
2362 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (ret < 0) { |
2363 | ✗ | av_log(mux, AV_LOG_ERROR, "Failed to serialize group\n"); | |
2364 | ✗ | return ret; | |
2365 | } | ||
2366 | |||
2367 | 12 | av_bprintf(bp, "%s", ptr); | |
2368 | 12 | ret = strlen(ptr); | |
2369 | 12 | av_free(ptr); | |
2370 | |||
2371 | 12 | return ret; | |
2372 | } | ||
2373 | |||
2374 | #define SERIALIZE(parent, child) do { \ | ||
2375 | ret = of_serialize_options(mux, parent->child, bp); \ | ||
2376 | if (ret < 0) \ | ||
2377 | return ret; \ | ||
2378 | } while (0) | ||
2379 | |||
2380 | #define SERIALIZE_LOOP_SUBBLOCK(obj) do { \ | ||
2381 | for (int k = 0; k < obj->nb_subblocks; k++) { \ | ||
2382 | ret = of_serialize_options(mux, \ | ||
2383 | av_iamf_param_definition_get_subblock(obj, k), bp); \ | ||
2384 | if (ret < 0) \ | ||
2385 | return ret; \ | ||
2386 | } \ | ||
2387 | } while (0) | ||
2388 | |||
2389 | #define SERIALIZE_LOOP(parent, child, suffix, separator) do { \ | ||
2390 | for (int j = 0; j < parent->nb_## child ## suffix; j++) { \ | ||
2391 | av_bprintf(bp, separator#child "="); \ | ||
2392 | SERIALIZE(parent, child ## suffix[j]); \ | ||
2393 | } \ | ||
2394 | } while (0) | ||
2395 | |||
2396 | 1 | static int64_t get_stream_group_index_from_id(Muxer *mux, int64_t id) | |
2397 | { | ||
2398 | 1 | AVFormatContext *oc = mux->fc; | |
2399 | |||
2400 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | for (unsigned i = 0; i < oc->nb_stream_groups; i++) |
2401 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (oc->stream_groups[i]->id == id) |
2402 | 1 | return oc->stream_groups[i]->index; | |
2403 | |||
2404 | ✗ | return AVERROR(EINVAL); | |
2405 | } | ||
2406 | |||
2407 | 2 | static int of_map_group(Muxer *mux, AVDictionary **dict, AVBPrint *bp, const char *map) | |
2408 | { | ||
2409 | AVStreamGroup *stg; | ||
2410 | int ret, file_idx, stream_idx; | ||
2411 | char *ptr; | ||
2412 | |||
2413 | 2 | file_idx = strtol(map, &ptr, 0); | |
2414 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | if (file_idx >= nb_input_files || file_idx < 0 || map == ptr) { |
2415 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid input file index: %d.\n", file_idx); | |
2416 | ✗ | return AVERROR(EINVAL); | |
2417 | } | ||
2418 | |||
2419 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | stream_idx = strtol(*ptr == '=' ? ptr + 1 : ptr, &ptr, 0); |
2420 |
3/6✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
|
2 | if (*ptr || stream_idx >= input_files[file_idx]->ctx->nb_stream_groups || stream_idx < 0) { |
2421 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid input stream group index: %d.\n", stream_idx); | |
2422 | ✗ | return AVERROR(EINVAL); | |
2423 | } | ||
2424 | |||
2425 | 2 | stg = input_files[file_idx]->ctx->stream_groups[stream_idx]; | |
2426 | 2 | ret = of_serialize_options(mux, stg, bp); | |
2427 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) |
2428 | ✗ | return ret; | |
2429 | |||
2430 | 2 | ret = av_dict_parse_string(dict, bp->str, "=", ":", 0); | |
2431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) |
2432 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing mapped group specification %s\n", ptr); | |
2433 | 2 | av_dict_set_int(dict, "type", stg->type, 0); | |
2434 | |||
2435 | 2 | av_bprint_clear(bp); | |
2436 |
2/3✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | switch(stg->type) { |
2437 | 1 | case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: { | |
2438 | 1 | AVIAMFAudioElement *audio_element = stg->params.iamf_audio_element; | |
2439 | |||
2440 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (audio_element->demixing_info) { |
2441 | 1 | AVIAMFParamDefinition *demixing_info = audio_element->demixing_info; | |
2442 | 1 | av_bprintf(bp, ",demixing="); | |
2443 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | SERIALIZE(audio_element, demixing_info); |
2444 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if (ret && demixing_info->nb_subblocks) |
2445 | 1 | av_bprintf(bp, ":"); | |
2446 |
3/4✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
|
2 | SERIALIZE_LOOP_SUBBLOCK(demixing_info); |
2447 | } | ||
2448 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (audio_element->recon_gain_info) { |
2449 | 1 | AVIAMFParamDefinition *recon_gain_info = audio_element->recon_gain_info; | |
2450 | 1 | av_bprintf(bp, ",recon_gain="); | |
2451 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | SERIALIZE(audio_element, recon_gain_info); |
2452 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
✗ Branch 3 not taken.
|
1 | if (ret && recon_gain_info->nb_subblocks) |
2453 | 1 | av_bprintf(bp, ":"); | |
2454 |
3/4✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 1 times.
|
2 | SERIALIZE_LOOP_SUBBLOCK(recon_gain_info); |
2455 | } | ||
2456 |
3/4✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
|
3 | SERIALIZE_LOOP(audio_element, layer, s, ","); |
2457 | 1 | break; | |
2458 | } | ||
2459 | 1 | case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: { | |
2460 | 1 | AVIAMFMixPresentation *mix = stg->params.iamf_mix_presentation; | |
2461 | |||
2462 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int i = 0; i < mix->nb_submixes; i++) { |
2463 | 1 | AVIAMFSubmix *submix = mix->submixes[i]; | |
2464 | 1 | AVIAMFParamDefinition *output_mix_config = submix->output_mix_config; | |
2465 | |||
2466 | 1 | av_bprintf(bp, ",submix="); | |
2467 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | SERIALIZE(mix, submixes[i]); |
2468 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (ret && output_mix_config->nb_subblocks) |
2469 | ✗ | av_bprintf(bp, ":"); | |
2470 |
1/4✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | SERIALIZE_LOOP_SUBBLOCK(output_mix_config); |
2471 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int j = 0; j < submix->nb_elements; j++) { |
2472 | 1 | AVIAMFSubmixElement *element = submix->elements[j]; | |
2473 | 1 | AVIAMFParamDefinition *element_mix_config = element->element_mix_config; | |
2474 | 1 | int64_t id = get_stream_group_index_from_id(mux, element->audio_element_id); | |
2475 | |||
2476 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (id < 0) { |
2477 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid or missing stream group index in" | |
2478 | "submix element"); | ||
2479 | ✗ | return id; | |
2480 | } | ||
2481 | |||
2482 | 1 | av_bprintf(bp, "|element="); | |
2483 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | SERIALIZE(submix, elements[j]); |
2484 |
2/4✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
1 | if (ret && element_mix_config->nb_subblocks) |
2485 | ✗ | av_bprintf(bp, ":"); | |
2486 |
1/4✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 1 times.
|
1 | SERIALIZE_LOOP_SUBBLOCK(element_mix_config); |
2487 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (ret) |
2488 | 1 | av_bprintf(bp, ":"); | |
2489 | 1 | av_bprintf(bp, "stg=%"PRId64, id); | |
2490 | } | ||
2491 |
3/4✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 1 times.
|
3 | SERIALIZE_LOOP(submix, layout, s, "|"); |
2492 | } | ||
2493 | 1 | break; | |
2494 | } | ||
2495 | ✗ | default: | |
2496 | ✗ | av_log(mux, AV_LOG_ERROR, "Unsupported mapped group type %d.\n", stg->type); | |
2497 | ✗ | ret = AVERROR(EINVAL); | |
2498 | ✗ | break; | |
2499 | } | ||
2500 | 2 | return 0; | |
2501 | } | ||
2502 | |||
2503 | 23 | static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) | |
2504 | { | ||
2505 | 23 | AVFormatContext *oc = mux->fc; | |
2506 | AVStreamGroup *stg; | ||
2507 | 23 | AVDictionary *dict = NULL, *tmp = NULL; | |
2508 | 23 | char *mapped_string = NULL; | |
2509 | const AVDictionaryEntry *e; | ||
2510 | 23 | const AVOption opts[] = { | |
2511 | { "type", "Set group type", offsetof(AVStreamGroup, type), AV_OPT_TYPE_INT, | ||
2512 | { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "type" }, | ||
2513 | { "iamf_audio_element", NULL, 0, AV_OPT_TYPE_CONST, | ||
2514 | { .i64 = AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT }, .unit = "type" }, | ||
2515 | { "iamf_mix_presentation", NULL, 0, AV_OPT_TYPE_CONST, | ||
2516 | { .i64 = AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION }, .unit = "type" }, | ||
2517 | { NULL }, | ||
2518 | }; | ||
2519 | 23 | const AVClass class = { | |
2520 | .class_name = "StreamGroupType", | ||
2521 | .item_name = av_default_item_name, | ||
2522 | .option = opts, | ||
2523 | .version = LIBAVUTIL_VERSION_INT, | ||
2524 | }; | ||
2525 | 23 | const AVClass *pclass = &class; | |
2526 | int type, ret; | ||
2527 | |||
2528 | 23 | ret = av_dict_parse_string(&dict, token, "=", ":", AV_DICT_MULTIKEY); | |
2529 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (ret < 0) { |
2530 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing group specification %s\n", token); | |
2531 | ✗ | return ret; | |
2532 | } | ||
2533 | |||
2534 | 23 | av_dict_copy(&tmp, dict, 0); | |
2535 | 23 | e = av_dict_get(dict, "map", NULL, 0); | |
2536 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 21 times.
|
23 | if (e) { |
2537 | AVBPrint bp; | ||
2538 | |||
2539 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ptr) { |
2540 | ✗ | av_log(mux, AV_LOG_ERROR, "Unexpected extra parameters when mapping a" | |
2541 | " stream group\n"); | ||
2542 | ✗ | ret = AVERROR(EINVAL); | |
2543 | ✗ | goto end; | |
2544 | } | ||
2545 | |||
2546 | 2 | av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); | |
2547 | 2 | ret = of_map_group(mux, &tmp, &bp, e->value); | |
2548 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) { |
2549 | ✗ | av_bprint_finalize(&bp, NULL); | |
2550 | ✗ | goto end; | |
2551 | } | ||
2552 | |||
2553 | 2 | av_bprint_finalize(&bp, &mapped_string); | |
2554 | 2 | ptr = mapped_string; | |
2555 | } | ||
2556 | |||
2557 | // "type" is not a user settable AVOption in AVStreamGroup, so handle it here | ||
2558 | 23 | e = av_dict_get(tmp, "type", NULL, 0); | |
2559 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!e) { |
2560 | ✗ | av_log(mux, AV_LOG_ERROR, "No type specified for Stream Group in \"%s\"\n", token); | |
2561 | ✗ | ret = AVERROR(EINVAL); | |
2562 | ✗ | goto end; | |
2563 | } | ||
2564 | |||
2565 | 23 | ret = av_opt_eval_int(&pclass, opts, e->value, &type); | |
2566 |
2/4✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 23 times.
|
23 | if (!ret && type == AV_STREAM_GROUP_PARAMS_NONE) |
2567 | ✗ | ret = AVERROR(EINVAL); | |
2568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (ret < 0) { |
2569 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid group type \"%s\"\n", e->value); | |
2570 | ✗ | goto end; | |
2571 | } | ||
2572 | |||
2573 | 23 | stg = avformat_stream_group_create(oc, type, &tmp); | |
2574 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!stg) { |
2575 | ✗ | ret = AVERROR(ENOMEM); | |
2576 | ✗ | goto end; | |
2577 | } | ||
2578 | |||
2579 | 23 | e = NULL; | |
2580 |
2/2✓ Branch 1 taken 57 times.
✓ Branch 2 taken 23 times.
|
80 | while (e = av_dict_get(dict, "st", e, 0)) { |
2581 | char *endptr; | ||
2582 | 57 | int64_t idx = strtoll(e->value, &endptr, 0); | |
2583 |
3/6✓ Branch 0 taken 57 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 57 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 57 times.
|
57 | if (*endptr || idx < 0 || idx >= oc->nb_streams) { |
2584 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid stream index %"PRId64"\n", idx); | |
2585 | ✗ | ret = AVERROR(EINVAL); | |
2586 | ✗ | goto end; | |
2587 | } | ||
2588 | 57 | ret = avformat_stream_group_add_stream(stg, oc->streams[idx]); | |
2589 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 57 times.
|
57 | if (ret < 0) |
2590 | ✗ | goto end; | |
2591 | } | ||
2592 |
2/2✓ Branch 1 taken 11 times.
✓ Branch 2 taken 23 times.
|
34 | while (e = av_dict_get(dict, "stg", e, 0)) { |
2593 | char *endptr; | ||
2594 | 11 | int64_t idx = strtoll(e->value, &endptr, 0); | |
2595 |
3/6✓ Branch 0 taken 11 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 11 times.
|
11 | if (*endptr || idx < 0 || idx >= oc->nb_stream_groups - 1) { |
2596 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid stream group index %"PRId64"\n", idx); | |
2597 | ✗ | ret = AVERROR(EINVAL); | |
2598 | ✗ | goto end; | |
2599 | } | ||
2600 |
2/2✓ Branch 0 taken 56 times.
✓ Branch 1 taken 11 times.
|
67 | for (unsigned i = 0; i < oc->stream_groups[idx]->nb_streams; i++) { |
2601 | 56 | ret = avformat_stream_group_add_stream(stg, oc->stream_groups[idx]->streams[i]); | |
2602 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 56 times.
|
56 | if (ret < 0) |
2603 | ✗ | goto end; | |
2604 | } | ||
2605 | } | ||
2606 | |||
2607 |
2/3✓ Branch 0 taken 12 times.
✓ Branch 1 taken 11 times.
✗ Branch 2 not taken.
|
23 | switch(type) { |
2608 | 12 | case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: | |
2609 | 12 | ret = of_parse_iamf_audio_element_layers(mux, stg, ptr); | |
2610 | 12 | break; | |
2611 | 11 | case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: | |
2612 | 11 | ret = of_parse_iamf_submixes(mux, stg, ptr); | |
2613 | 11 | break; | |
2614 | ✗ | default: | |
2615 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown group type %d.\n", type); | |
2616 | ✗ | ret = AVERROR(EINVAL); | |
2617 | ✗ | break; | |
2618 | } | ||
2619 | |||
2620 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (ret < 0) |
2621 | ✗ | goto end; | |
2622 | |||
2623 | // make sure that nothing but "st" and "stg" entries are left in the dict | ||
2624 | 23 | e = NULL; | |
2625 | 23 | av_dict_set(&tmp, "map", NULL, 0); | |
2626 | 23 | av_dict_set(&tmp, "type", NULL, 0); | |
2627 |
2/2✓ Branch 1 taken 23 times.
✓ Branch 2 taken 23 times.
|
46 | while (e = av_dict_iterate(tmp, e)) { |
2628 |
3/4✓ Branch 0 taken 11 times.
✓ Branch 1 taken 12 times.
✓ Branch 2 taken 11 times.
✗ Branch 3 not taken.
|
23 | if (!strcmp(e->key, "st") || !strcmp(e->key, "stg")) |
2629 | 23 | continue; | |
2630 | |||
2631 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown group key %s.\n", e->key); | |
2632 | ✗ | ret = AVERROR(EINVAL); | |
2633 | ✗ | goto end; | |
2634 | } | ||
2635 | |||
2636 | 23 | ret = 0; | |
2637 | 23 | end: | |
2638 | 23 | av_free(mapped_string); | |
2639 | 23 | av_dict_free(&dict); | |
2640 | 23 | av_dict_free(&tmp); | |
2641 | |||
2642 | 23 | return ret; | |
2643 | } | ||
2644 | |||
2645 | 8406 | static int of_add_groups(Muxer *mux, const OptionsContext *o) | |
2646 | { | ||
2647 | /* process manually set groups */ | ||
2648 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 8406 times.
|
8429 | for (int i = 0; i < o->stream_groups.nb_opt; i++) { |
2649 | const char *token; | ||
2650 | 23 | char *str, *ptr = NULL; | |
2651 | 23 | int ret = 0; | |
2652 | |||
2653 | 23 | str = av_strdup(o->stream_groups.opt[i].u.str); | |
2654 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (!str) |
2655 | ✗ | return ret; | |
2656 | |||
2657 | 23 | token = av_strtok(str, ",", &ptr); | |
2658 |
1/2✓ Branch 0 taken 23 times.
✗ Branch 1 not taken.
|
23 | if (token) { |
2659 |
2/2✓ Branch 0 taken 21 times.
✓ Branch 1 taken 2 times.
|
23 | if (ptr) |
2660 | 21 | ptr += strspn(ptr, " \n\t\r"); | |
2661 | 23 | ret = of_parse_group_token(mux, token, ptr); | |
2662 | } | ||
2663 | |||
2664 | 23 | av_free(str); | |
2665 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 23 times.
|
23 | if (ret < 0) |
2666 | ✗ | return ret; | |
2667 | } | ||
2668 | |||
2669 | 8406 | return 0; | |
2670 | } | ||
2671 | |||
2672 | 8406 | static int of_add_programs(Muxer *mux, const OptionsContext *o) | |
2673 | { | ||
2674 | 8406 | AVFormatContext *oc = mux->fc; | |
2675 | /* process manually set programs */ | ||
2676 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | for (int i = 0; i < o->program.nb_opt; i++) { |
2677 | ✗ | AVDictionary *dict = NULL; | |
2678 | const AVDictionaryEntry *e; | ||
2679 | AVProgram *program; | ||
2680 | ✗ | int ret, progid = i + 1; | |
2681 | |||
2682 | ✗ | ret = av_dict_parse_string(&dict, o->program.opt[i].u.str, "=", ":", | |
2683 | AV_DICT_MULTIKEY); | ||
2684 | ✗ | if (ret < 0) { | |
2685 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing program specification %s\n", | |
2686 | ✗ | o->program.opt[i].u.str); | |
2687 | ✗ | return ret; | |
2688 | } | ||
2689 | |||
2690 | ✗ | e = av_dict_get(dict, "program_num", NULL, 0); | |
2691 | ✗ | if (e) { | |
2692 | ✗ | progid = strtol(e->value, NULL, 0); | |
2693 | ✗ | av_dict_set(&dict, e->key, NULL, 0); | |
2694 | } | ||
2695 | |||
2696 | ✗ | program = av_new_program(oc, progid); | |
2697 | ✗ | if (!program) { | |
2698 | ✗ | ret = AVERROR(ENOMEM); | |
2699 | ✗ | goto fail; | |
2700 | } | ||
2701 | |||
2702 | ✗ | e = av_dict_get(dict, "title", NULL, 0); | |
2703 | ✗ | if (e) { | |
2704 | ✗ | av_dict_set(&program->metadata, e->key, e->value, 0); | |
2705 | ✗ | av_dict_set(&dict, e->key, NULL, 0); | |
2706 | } | ||
2707 | |||
2708 | ✗ | e = NULL; | |
2709 | ✗ | while (e = av_dict_get(dict, "st", e, 0)) { | |
2710 | ✗ | int st_num = strtol(e->value, NULL, 0); | |
2711 | ✗ | av_program_add_stream_index(oc, progid, st_num); | |
2712 | } | ||
2713 | |||
2714 | // make sure that nothing but "st" entries are left in the dict | ||
2715 | ✗ | e = NULL; | |
2716 | ✗ | while (e = av_dict_iterate(dict, e)) { | |
2717 | ✗ | if (!strcmp(e->key, "st")) | |
2718 | ✗ | continue; | |
2719 | |||
2720 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown program key %s.\n", e->key); | |
2721 | ✗ | ret = AVERROR(EINVAL); | |
2722 | ✗ | goto fail; | |
2723 | } | ||
2724 | |||
2725 | ✗ | fail: | |
2726 | ✗ | av_dict_free(&dict); | |
2727 | ✗ | if (ret < 0) | |
2728 | ✗ | return ret; | |
2729 | } | ||
2730 | |||
2731 | 8406 | return 0; | |
2732 | } | ||
2733 | |||
2734 | /** | ||
2735 | * Parse a metadata specifier passed as 'arg' parameter. | ||
2736 | * @param arg metadata string to parse | ||
2737 | * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram) | ||
2738 | * @param index for type c/p, chapter/program index is written here | ||
2739 | * @param stream_spec for type s, the stream specifier is written here | ||
2740 | */ | ||
2741 | 236 | static int parse_meta_type(void *logctx, const char *arg, | |
2742 | char *type, int *index, const char **stream_spec) | ||
2743 | { | ||
2744 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 165 times.
|
236 | if (*arg) { |
2745 | 71 | *type = *arg; | |
2746 |
3/4✓ Branch 0 taken 21 times.
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
71 | switch (*arg) { |
2747 | 21 | case 'g': | |
2748 | 21 | break; | |
2749 | 46 | case 's': | |
2750 |
2/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
|
46 | if (*(++arg) && *arg != ':') { |
2751 | ✗ | av_log(logctx, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg); | |
2752 | ✗ | return AVERROR(EINVAL); | |
2753 | } | ||
2754 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | *stream_spec = *arg == ':' ? arg + 1 : ""; |
2755 | 46 | break; | |
2756 | 4 | case 'c': | |
2757 | case 'p': | ||
2758 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if (*(++arg) == ':') |
2759 | 3 | *index = strtol(++arg, NULL, 0); | |
2760 | 4 | break; | |
2761 | ✗ | default: | |
2762 | ✗ | av_log(logctx, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg); | |
2763 | ✗ | return AVERROR(EINVAL); | |
2764 | } | ||
2765 | } else | ||
2766 | 165 | *type = 'g'; | |
2767 | |||
2768 | 236 | return 0; | |
2769 | } | ||
2770 | |||
2771 | 8406 | static int of_add_metadata(OutputFile *of, AVFormatContext *oc, | |
2772 | const OptionsContext *o) | ||
2773 | { | ||
2774 |
2/2✓ Branch 0 taken 222 times.
✓ Branch 1 taken 8406 times.
|
8628 | for (int i = 0; i < o->metadata.nb_opt; i++) { |
2775 | AVDictionary **m; | ||
2776 | char type, *val; | ||
2777 | const char *stream_spec; | ||
2778 | 222 | int index = 0, ret = 0; | |
2779 | |||
2780 | 222 | val = strchr(o->metadata.opt[i].u.str, '='); | |
2781 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 222 times.
|
222 | if (!val) { |
2782 | ✗ | av_log(of, AV_LOG_FATAL, "No '=' character in metadata string %s.\n", | |
2783 | ✗ | o->metadata.opt[i].u.str); | |
2784 | ✗ | return AVERROR(EINVAL); | |
2785 | } | ||
2786 | 222 | *val++ = 0; | |
2787 | |||
2788 | 222 | ret = parse_meta_type(of, o->metadata.opt[i].specifier, &type, &index, &stream_spec); | |
2789 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 222 times.
|
222 | if (ret < 0) |
2790 | ✗ | return ret; | |
2791 | |||
2792 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 181 times.
|
222 | if (type == 's') { |
2793 |
2/2✓ Branch 0 taken 219 times.
✓ Branch 1 taken 41 times.
|
260 | for (int j = 0; j < oc->nb_streams; j++) { |
2794 |
2/2✓ Branch 1 taken 41 times.
✓ Branch 2 taken 178 times.
|
219 | if ((ret = check_stream_specifier(oc, oc->streams[j], stream_spec)) > 0) { |
2795 |
1/2✓ Branch 0 taken 41 times.
✗ Branch 1 not taken.
|
41 | av_dict_set(&oc->streams[j]->metadata, o->metadata.opt[i].u.str, *val ? val : NULL, 0); |
2796 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 178 times.
|
178 | } else if (ret < 0) |
2797 | ✗ | return ret; | |
2798 | } | ||
2799 | } else { | ||
2800 |
2/4✓ Branch 0 taken 177 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
181 | switch (type) { |
2801 | 177 | case 'g': | |
2802 | 177 | m = &oc->metadata; | |
2803 | 177 | break; | |
2804 | 4 | case 'c': | |
2805 |
2/4✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
4 | if (index < 0 || index >= oc->nb_chapters) { |
2806 | ✗ | av_log(of, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index); | |
2807 | ✗ | return AVERROR(EINVAL); | |
2808 | } | ||
2809 | 4 | m = &oc->chapters[index]->metadata; | |
2810 | 4 | break; | |
2811 | ✗ | case 'p': | |
2812 | ✗ | if (index < 0 || index >= oc->nb_programs) { | |
2813 | ✗ | av_log(of, AV_LOG_FATAL, "Invalid program index %d in metadata specifier.\n", index); | |
2814 | ✗ | return AVERROR(EINVAL); | |
2815 | } | ||
2816 | ✗ | m = &oc->programs[index]->metadata; | |
2817 | ✗ | break; | |
2818 | ✗ | default: | |
2819 | ✗ | av_log(of, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata.opt[i].specifier); | |
2820 | ✗ | return AVERROR(EINVAL); | |
2821 | } | ||
2822 |
2/2✓ Branch 0 taken 180 times.
✓ Branch 1 taken 1 times.
|
181 | av_dict_set(m, o->metadata.opt[i].u.str, *val ? val : NULL, 0); |
2823 | } | ||
2824 | } | ||
2825 | |||
2826 | 8406 | return 0; | |
2827 | } | ||
2828 | |||
2829 | 19 | static int copy_chapters(InputFile *ifile, OutputFile *ofile, AVFormatContext *os, | |
2830 | int copy_metadata) | ||
2831 | { | ||
2832 | 19 | AVFormatContext *is = ifile->ctx; | |
2833 | AVChapter **tmp; | ||
2834 | |||
2835 | 19 | tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters)); | |
2836 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
|
19 | if (!tmp) |
2837 | ✗ | return AVERROR(ENOMEM); | |
2838 | 19 | os->chapters = tmp; | |
2839 | |||
2840 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 16 times.
|
53 | for (int i = 0; i < is->nb_chapters; i++) { |
2841 | 37 | AVChapter *in_ch = is->chapters[i], *out_ch; | |
2842 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | int64_t start_time = (ofile->start_time == AV_NOPTS_VALUE) ? 0 : ofile->start_time; |
2843 | 37 | int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset, | |
2844 | 37 | AV_TIME_BASE_Q, in_ch->time_base); | |
2845 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 32 times.
|
37 | int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX : |
2846 | 5 | av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base); | |
2847 | |||
2848 | |||
2849 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (in_ch->end < ts_off) |
2850 | ✗ | continue; | |
2851 |
4/4✓ Branch 0 taken 5 times.
✓ Branch 1 taken 32 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 2 times.
|
37 | if (rt != INT64_MAX && in_ch->start > rt + ts_off) |
2852 | 3 | break; | |
2853 | |||
2854 | 34 | out_ch = av_mallocz(sizeof(AVChapter)); | |
2855 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (!out_ch) |
2856 | ✗ | return AVERROR(ENOMEM); | |
2857 | |||
2858 | 34 | out_ch->id = in_ch->id; | |
2859 | 34 | out_ch->time_base = in_ch->time_base; | |
2860 | 34 | out_ch->start = FFMAX(0, in_ch->start - ts_off); | |
2861 | 34 | out_ch->end = FFMIN(rt, in_ch->end - ts_off); | |
2862 | |||
2863 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if (copy_metadata) |
2864 | 34 | av_dict_copy(&out_ch->metadata, in_ch->metadata, 0); | |
2865 | |||
2866 | 34 | os->chapters[os->nb_chapters++] = out_ch; | |
2867 | } | ||
2868 | 19 | return 0; | |
2869 | } | ||
2870 | |||
2871 | 7 | static int copy_metadata(Muxer *mux, AVFormatContext *ic, | |
2872 | const char *outspec, const char *inspec, | ||
2873 | int *metadata_global_manual, int *metadata_streams_manual, | ||
2874 | int *metadata_chapters_manual) | ||
2875 | { | ||
2876 | 7 | AVFormatContext *oc = mux->fc; | |
2877 | 7 | AVDictionary **meta_in = NULL; | |
2878 | 7 | AVDictionary **meta_out = NULL; | |
2879 | 7 | int i, ret = 0; | |
2880 | char type_in, type_out; | ||
2881 | 7 | const char *istream_spec = NULL, *ostream_spec = NULL; | |
2882 | 7 | int idx_in = 0, idx_out = 0; | |
2883 | |||
2884 | 7 | ret = parse_meta_type(mux, inspec, &type_in, &idx_in, &istream_spec); | |
2885 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (ret >= 0) |
2886 | 7 | ret = parse_meta_type(mux, outspec, &type_out, &idx_out, &ostream_spec); | |
2887 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (ret < 0) |
2888 | ✗ | return ret; | |
2889 | |||
2890 |
4/8✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 2 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
7 | if (type_in == 'g' || type_out == 'g' || (!*outspec && !ic)) |
2891 | 5 | *metadata_global_manual = 1; | |
2892 |
7/8✓ Branch 0 taken 5 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 3 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
7 | if (type_in == 's' || type_out == 's' || (!*outspec && !ic)) |
2893 | 3 | *metadata_streams_manual = 1; | |
2894 |
5/8✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 7 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 6 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1 times.
|
7 | if (type_in == 'c' || type_out == 'c' || (!*outspec && !ic)) |
2895 | ✗ | *metadata_chapters_manual = 1; | |
2896 | |||
2897 | /* ic is NULL when just disabling automatic mappings */ | ||
2898 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
|
7 | if (!ic) |
2899 | 2 | return 0; | |
2900 | |||
2901 | #define METADATA_CHECK_INDEX(index, nb_elems, desc)\ | ||
2902 | if ((index) < 0 || (index) >= (nb_elems)) {\ | ||
2903 | av_log(mux, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\ | ||
2904 | (desc), (index));\ | ||
2905 | return AVERROR(EINVAL);\ | ||
2906 | } | ||
2907 | |||
2908 | #define SET_DICT(type, meta, context, index)\ | ||
2909 | switch (type) {\ | ||
2910 | case 'g':\ | ||
2911 | meta = &context->metadata;\ | ||
2912 | break;\ | ||
2913 | case 'c':\ | ||
2914 | METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\ | ||
2915 | meta = &context->chapters[index]->metadata;\ | ||
2916 | break;\ | ||
2917 | case 'p':\ | ||
2918 | METADATA_CHECK_INDEX(index, context->nb_programs, "program")\ | ||
2919 | meta = &context->programs[index]->metadata;\ | ||
2920 | break;\ | ||
2921 | case 's':\ | ||
2922 | break; /* handled separately below */ \ | ||
2923 | default: av_assert0(0);\ | ||
2924 | }\ | ||
2925 | |||
2926 |
2/13✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
5 | SET_DICT(type_in, meta_in, ic, idx_in); |
2927 |
2/13✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✗ Branch 10 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
✗ Branch 13 not taken.
|
5 | SET_DICT(type_out, meta_out, oc, idx_out); |
2928 | |||
2929 | /* for input streams choose first matching stream */ | ||
2930 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5 | if (type_in == 's') { |
2931 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | for (i = 0; i < ic->nb_streams; i++) { |
2932 |
2/2✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1 times.
|
3 | if ((ret = check_stream_specifier(ic, ic->streams[i], istream_spec)) > 0) { |
2933 | 2 | meta_in = &ic->streams[i]->metadata; | |
2934 | 2 | break; | |
2935 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if (ret < 0) |
2936 | ✗ | return ret; | |
2937 | } | ||
2938 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!meta_in) { |
2939 | ✗ | av_log(mux, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec); | |
2940 | ✗ | return AVERROR(EINVAL); | |
2941 | } | ||
2942 | } | ||
2943 | |||
2944 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
5 | if (type_out == 's') { |
2945 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
|
11 | for (i = 0; i < oc->nb_streams; i++) { |
2946 |
2/2✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
|
8 | if ((ret = check_stream_specifier(oc, oc->streams[i], ostream_spec)) > 0) { |
2947 | 3 | meta_out = &oc->streams[i]->metadata; | |
2948 | 3 | av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE); | |
2949 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | } else if (ret < 0) |
2950 | ✗ | return ret; | |
2951 | } | ||
2952 | } else | ||
2953 | 2 | av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE); | |
2954 | |||
2955 | 5 | return 0; | |
2956 | } | ||
2957 | |||
2958 | 8406 | static int copy_meta(Muxer *mux, const OptionsContext *o) | |
2959 | { | ||
2960 | 8406 | OutputFile *of = &mux->of; | |
2961 | 8406 | AVFormatContext *oc = mux->fc; | |
2962 | 8406 | int chapters_input_file = o->chapters_input_file; | |
2963 | 8406 | int metadata_global_manual = 0; | |
2964 | 8406 | int metadata_streams_manual = 0; | |
2965 | 8406 | int metadata_chapters_manual = 0; | |
2966 | int ret; | ||
2967 | |||
2968 | /* copy metadata */ | ||
2969 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8406 times.
|
8413 | for (int i = 0; i < o->metadata_map.nb_opt; i++) { |
2970 | char *p; | ||
2971 | 7 | int in_file_index = strtol(o->metadata_map.opt[i].u.str, &p, 0); | |
2972 | |||
2973 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (in_file_index >= nb_input_files) { |
2974 | ✗ | av_log(mux, AV_LOG_FATAL, "Invalid input file index %d while " | |
2975 | "processing metadata maps\n", in_file_index); | ||
2976 | ✗ | return AVERROR(EINVAL); | |
2977 | } | ||
2978 | 10 | ret = copy_metadata(mux, | |
2979 | 5 | in_file_index >= 0 ? input_files[in_file_index]->ctx : NULL, | |
2980 |
4/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 5 times.
✓ Branch 3 taken 2 times.
|
10 | o->metadata_map.opt[i].specifier, *p ? p + 1 : p, |
2981 | &metadata_global_manual, &metadata_streams_manual, | ||
2982 | &metadata_chapters_manual); | ||
2983 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (ret < 0) |
2984 | ✗ | return ret; | |
2985 | } | ||
2986 | |||
2987 | /* copy chapters */ | ||
2988 |
1/2✓ Branch 0 taken 8406 times.
✗ Branch 1 not taken.
|
8406 | if (chapters_input_file >= nb_input_files) { |
2989 |
1/2✓ Branch 0 taken 8406 times.
✗ Branch 1 not taken.
|
8406 | if (chapters_input_file == INT_MAX) { |
2990 | /* copy chapters from the first input file that has them*/ | ||
2991 | 8406 | chapters_input_file = -1; | |
2992 |
2/2✓ Branch 0 taken 7360 times.
✓ Branch 1 taken 8387 times.
|
15747 | for (int i = 0; i < nb_input_files; i++) |
2993 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 7341 times.
|
7360 | if (input_files[i]->ctx->nb_chapters) { |
2994 | 19 | chapters_input_file = i; | |
2995 | 19 | break; | |
2996 | } | ||
2997 | } else { | ||
2998 | ✗ | av_log(mux, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n", | |
2999 | chapters_input_file); | ||
3000 | ✗ | return AVERROR(EINVAL); | |
3001 | } | ||
3002 | } | ||
3003 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 8387 times.
|
8406 | if (chapters_input_file >= 0) |
3004 | 19 | copy_chapters(input_files[chapters_input_file], of, oc, | |
3005 | !metadata_chapters_manual); | ||
3006 | |||
3007 | /* copy global metadata by default */ | ||
3008 |
4/4✓ Branch 0 taken 8402 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 7264 times.
✓ Branch 3 taken 1138 times.
|
8406 | if (!metadata_global_manual && nb_input_files){ |
3009 | 7264 | av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata, | |
3010 | AV_DICT_DONT_OVERWRITE); | ||
3011 |
2/2✓ Branch 0 taken 191 times.
✓ Branch 1 taken 7073 times.
|
7264 | if (of->recording_time != INT64_MAX) |
3012 | 191 | av_dict_set(&oc->metadata, "duration", NULL, 0); | |
3013 | 7264 | av_dict_set(&oc->metadata, "creation_time", NULL, 0); | |
3014 | 7264 | av_dict_set(&oc->metadata, "company_name", NULL, 0); | |
3015 | 7264 | av_dict_set(&oc->metadata, "product_name", NULL, 0); | |
3016 | 7264 | av_dict_set(&oc->metadata, "product_version", NULL, 0); | |
3017 | } | ||
3018 |
2/2✓ Branch 0 taken 8404 times.
✓ Branch 1 taken 2 times.
|
8406 | if (!metadata_streams_manual) |
3019 |
2/2✓ Branch 0 taken 8891 times.
✓ Branch 1 taken 8404 times.
|
17295 | for (int i = 0; i < of->nb_streams; i++) { |
3020 | 8891 | OutputStream *ost = of->streams[i]; | |
3021 | |||
3022 |
2/2✓ Branch 0 taken 1338 times.
✓ Branch 1 taken 7553 times.
|
8891 | if (!ost->ist) /* this is true e.g. for attached files */ |
3023 | 1338 | continue; | |
3024 | 7553 | av_dict_copy(&ost->st->metadata, ost->ist->st->metadata, AV_DICT_DONT_OVERWRITE); | |
3025 | } | ||
3026 | |||
3027 | 8406 | return 0; | |
3028 | } | ||
3029 | |||
3030 | 8406 | static int set_dispositions(Muxer *mux, const OptionsContext *o) | |
3031 | { | ||
3032 | 8406 | OutputFile *of = &mux->of; | |
3033 | 8406 | AVFormatContext *ctx = mux->fc; | |
3034 | |||
3035 | // indexed by type+1, because AVMEDIA_TYPE_UNKNOWN=-1 | ||
3036 | 8406 | int nb_streams[AVMEDIA_TYPE_NB + 1] = { 0 }; | |
3037 | 8406 | int have_default[AVMEDIA_TYPE_NB + 1] = { 0 }; | |
3038 | 8406 | int have_manual = 0; | |
3039 | 8406 | int ret = 0; | |
3040 | |||
3041 | const char **dispositions; | ||
3042 | |||
3043 | 8406 | dispositions = av_calloc(ctx->nb_streams, sizeof(*dispositions)); | |
3044 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (!dispositions) |
3045 | ✗ | return AVERROR(ENOMEM); | |
3046 | |||
3047 | // first, copy the input dispositions | ||
3048 |
2/2✓ Branch 0 taken 8896 times.
✓ Branch 1 taken 8406 times.
|
17302 | for (int i = 0; i < ctx->nb_streams; i++) { |
3049 | 8896 | OutputStream *ost = of->streams[i]; | |
3050 | |||
3051 | 8896 | nb_streams[ost->type + 1]++; | |
3052 | |||
3053 | 8896 | opt_match_per_stream_str(ost, &o->disposition, ctx, ost->st, &dispositions[i]); | |
3054 | |||
3055 | 8896 | have_manual |= !!dispositions[i]; | |
3056 | |||
3057 |
2/2✓ Branch 0 taken 7558 times.
✓ Branch 1 taken 1338 times.
|
8896 | if (ost->ist) { |
3058 | 7558 | ost->st->disposition = ost->ist->st->disposition; | |
3059 | |||
3060 |
2/2✓ Branch 0 taken 809 times.
✓ Branch 1 taken 6749 times.
|
7558 | if (ost->st->disposition & AV_DISPOSITION_DEFAULT) |
3061 | 809 | have_default[ost->type + 1] = 1; | |
3062 | } | ||
3063 | } | ||
3064 | |||
3065 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8398 times.
|
8406 | if (have_manual) { |
3066 | // process manually set dispositions - they override the above copy | ||
3067 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 8 times.
|
31 | for (int i = 0; i < ctx->nb_streams; i++) { |
3068 | 23 | OutputStream *ost = of->streams[i]; | |
3069 | 23 | const char *disp = dispositions[i]; | |
3070 | |||
3071 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 16 times.
|
23 | if (!disp) |
3072 | 7 | continue; | |
3073 | |||
3074 | 16 | ret = av_opt_set(ost->st, "disposition", disp, 0); | |
3075 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (ret < 0) |
3076 | ✗ | goto finish; | |
3077 | } | ||
3078 | } else { | ||
3079 | // For each media type with more than one stream, find a suitable stream to | ||
3080 | // mark as default, unless one is already marked default. | ||
3081 | // "Suitable" means the first of that type, skipping attached pictures. | ||
3082 |
2/2✓ Branch 0 taken 8873 times.
✓ Branch 1 taken 8398 times.
|
17271 | for (int i = 0; i < ctx->nb_streams; i++) { |
3083 | 8873 | OutputStream *ost = of->streams[i]; | |
3084 | 8873 | enum AVMediaType type = ost->type; | |
3085 | |||
3086 |
4/4✓ Branch 0 taken 385 times.
✓ Branch 1 taken 8488 times.
✓ Branch 2 taken 75 times.
✓ Branch 3 taken 310 times.
|
8873 | if (nb_streams[type + 1] < 2 || have_default[type + 1] || |
3087 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 43 times.
|
75 | ost->st->disposition & AV_DISPOSITION_ATTACHED_PIC) |
3088 | 8830 | continue; | |
3089 | |||
3090 | 43 | ost->st->disposition |= AV_DISPOSITION_DEFAULT; | |
3091 | 43 | have_default[type + 1] = 1; | |
3092 | } | ||
3093 | } | ||
3094 | |||
3095 | 8398 | finish: | |
3096 | 8406 | av_freep(&dispositions); | |
3097 | |||
3098 | 8406 | return ret; | |
3099 | } | ||
3100 | |||
3101 | static const char *const forced_keyframes_const_names[] = { | ||
3102 | "n", | ||
3103 | "n_forced", | ||
3104 | "prev_forced_n", | ||
3105 | "prev_forced_t", | ||
3106 | "t", | ||
3107 | NULL | ||
3108 | }; | ||
3109 | |||
3110 | 1 | static int compare_int64(const void *a, const void *b) | |
3111 | { | ||
3112 | 1 | return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b); | |
3113 | } | ||
3114 | |||
3115 | 1 | static int parse_forced_key_frames(void *log, KeyframeForceCtx *kf, | |
3116 | const Muxer *mux, const char *spec) | ||
3117 | { | ||
3118 | const char *p; | ||
3119 | 1 | int n = 1, i, ret, size, index = 0; | |
3120 | int64_t t, *pts; | ||
3121 | |||
3122 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
|
14 | for (p = spec; *p; p++) |
3123 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
|
13 | if (*p == ',') |
3124 | 1 | n++; | |
3125 | 1 | size = n; | |
3126 | 1 | pts = av_malloc_array(size, sizeof(*pts)); | |
3127 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!pts) |
3128 | ✗ | return AVERROR(ENOMEM); | |
3129 | |||
3130 | 1 | p = spec; | |
3131 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (i = 0; i < n; i++) { |
3132 | 2 | char *next = strchr(p, ','); | |
3133 | |||
3134 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (next) |
3135 | 1 | *next++ = 0; | |
3136 | |||
3137 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (strstr(p, "chapters") == p) { |
3138 | ✗ | AVChapter * const *ch = mux->fc->chapters; | |
3139 | ✗ | unsigned int nb_ch = mux->fc->nb_chapters; | |
3140 | int j; | ||
3141 | |||
3142 | ✗ | if (nb_ch > INT_MAX - size) { | |
3143 | ✗ | ret = AVERROR(ERANGE); | |
3144 | ✗ | goto fail; | |
3145 | } | ||
3146 | ✗ | size += nb_ch - 1; | |
3147 | ✗ | pts = av_realloc_f(pts, size, sizeof(*pts)); | |
3148 | ✗ | if (!pts) | |
3149 | ✗ | return AVERROR(ENOMEM); | |
3150 | |||
3151 | ✗ | if (p[8]) { | |
3152 | ✗ | ret = av_parse_time(&t, p + 8, 1); | |
3153 | ✗ | if (ret < 0) { | |
3154 | ✗ | av_log(log, AV_LOG_ERROR, | |
3155 | "Invalid chapter time offset: %s\n", p + 8); | ||
3156 | ✗ | goto fail; | |
3157 | } | ||
3158 | } else | ||
3159 | ✗ | t = 0; | |
3160 | |||
3161 | ✗ | for (j = 0; j < nb_ch; j++) { | |
3162 | ✗ | const AVChapter *c = ch[j]; | |
3163 | av_assert1(index < size); | ||
3164 | ✗ | pts[index++] = av_rescale_q(c->start, c->time_base, | |
3165 | ✗ | AV_TIME_BASE_Q) + t; | |
3166 | } | ||
3167 | |||
3168 | } else { | ||
3169 | av_assert1(index < size); | ||
3170 | 2 | ret = av_parse_time(&t, p, 1); | |
3171 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) { |
3172 | ✗ | av_log(log, AV_LOG_ERROR, "Invalid keyframe time: %s\n", p); | |
3173 | ✗ | goto fail; | |
3174 | } | ||
3175 | |||
3176 | 2 | pts[index++] = t; | |
3177 | } | ||
3178 | |||
3179 | 2 | p = next; | |
3180 | } | ||
3181 | |||
3182 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | av_assert0(index == size); |
3183 | 1 | qsort(pts, size, sizeof(*pts), compare_int64); | |
3184 | 1 | kf->nb_pts = size; | |
3185 | 1 | kf->pts = pts; | |
3186 | |||
3187 | 1 | return 0; | |
3188 | ✗ | fail: | |
3189 | ✗ | av_freep(&pts); | |
3190 | ✗ | return ret; | |
3191 | } | ||
3192 | |||
3193 | 8406 | static int process_forced_keyframes(Muxer *mux, const OptionsContext *o) | |
3194 | { | ||
3195 |
2/2✓ Branch 0 taken 8896 times.
✓ Branch 1 taken 8406 times.
|
17302 | for (int i = 0; i < mux->of.nb_streams; i++) { |
3196 | 8896 | OutputStream *ost = mux->of.streams[i]; | |
3197 | 8896 | const char *forced_keyframes = NULL; | |
3198 | |||
3199 | 8896 | opt_match_per_stream_str(ost, &o->forced_key_frames, | |
3200 | mux->fc, ost->st, &forced_keyframes); | ||
3201 | |||
3202 |
2/2✓ Branch 0 taken 7168 times.
✓ Branch 1 taken 1728 times.
|
8896 | if (!(ost->type == AVMEDIA_TYPE_VIDEO && |
3203 |
4/4✓ Branch 0 taken 6793 times.
✓ Branch 1 taken 375 times.
✓ Branch 2 taken 6789 times.
✓ Branch 3 taken 4 times.
|
7168 | ost->enc && forced_keyframes)) |
3204 | 8892 | continue; | |
3205 | |||
3206 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!strncmp(forced_keyframes, "expr:", 5)) { |
3207 | ✗ | int ret = av_expr_parse(&ost->kf.pexpr, forced_keyframes + 5, | |
3208 | forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL); | ||
3209 | ✗ | if (ret < 0) { | |
3210 | ✗ | av_log(ost, AV_LOG_ERROR, | |
3211 | "Invalid force_key_frames expression '%s'\n", forced_keyframes + 5); | ||
3212 | ✗ | return ret; | |
3213 | } | ||
3214 | ✗ | ost->kf.expr_const_values[FKF_N] = 0; | |
3215 | ✗ | ost->kf.expr_const_values[FKF_N_FORCED] = 0; | |
3216 | ✗ | ost->kf.expr_const_values[FKF_PREV_FORCED_N] = NAN; | |
3217 | ✗ | ost->kf.expr_const_values[FKF_PREV_FORCED_T] = NAN; | |
3218 | |||
3219 | // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes', | ||
3220 | // parse it only for static kf timings | ||
3221 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | } else if (!strcmp(forced_keyframes, "source")) { |
3222 | 3 | ost->kf.type = KF_FORCE_SOURCE; | |
3223 | #if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP | ||
3224 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if (!strcmp(forced_keyframes, "source_no_drop")) { |
3225 | ✗ | av_log(ost, AV_LOG_WARNING, "The 'source_no_drop' value for " | |
3226 | "-force_key_frames is deprecated, use just 'source'\n"); | ||
3227 | ✗ | ost->kf.type = KF_FORCE_SOURCE; | |
3228 | #endif | ||
3229 | } else { | ||
3230 | 1 | int ret = parse_forced_key_frames(ost, &ost->kf, mux, forced_keyframes); | |
3231 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) |
3232 | ✗ | return ret; | |
3233 | } | ||
3234 | } | ||
3235 | |||
3236 | 8406 | return 0; | |
3237 | } | ||
3238 | |||
3239 | 8784 | static const char *output_file_item_name(void *obj) | |
3240 | { | ||
3241 | 8784 | const Muxer *mux = obj; | |
3242 | |||
3243 | 8784 | return mux->log_name; | |
3244 | } | ||
3245 | |||
3246 | static const AVClass output_file_class = { | ||
3247 | .class_name = "OutputFile", | ||
3248 | .version = LIBAVUTIL_VERSION_INT, | ||
3249 | .item_name = output_file_item_name, | ||
3250 | .category = AV_CLASS_CATEGORY_MUXER, | ||
3251 | }; | ||
3252 | |||
3253 | 8406 | static Muxer *mux_alloc(void) | |
3254 | { | ||
3255 | 8406 | Muxer *mux = allocate_array_elem(&output_files, sizeof(*mux), &nb_output_files); | |
3256 | |||
3257 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (!mux) |
3258 | ✗ | return NULL; | |
3259 | |||
3260 | 8406 | mux->of.class = &output_file_class; | |
3261 | 8406 | mux->of.index = nb_output_files - 1; | |
3262 | |||
3263 | 8406 | snprintf(mux->log_name, sizeof(mux->log_name), "out#%d", mux->of.index); | |
3264 | |||
3265 | 8406 | return mux; | |
3266 | } | ||
3267 | |||
3268 | 8406 | int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) | |
3269 | { | ||
3270 | Muxer *mux; | ||
3271 | AVFormatContext *oc; | ||
3272 | int err; | ||
3273 | OutputFile *of; | ||
3274 | |||
3275 | 8406 | int64_t recording_time = o->recording_time; | |
3276 | 8406 | int64_t stop_time = o->stop_time; | |
3277 | |||
3278 | 8406 | mux = mux_alloc(); | |
3279 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (!mux) |
3280 | ✗ | return AVERROR(ENOMEM); | |
3281 | |||
3282 | 8406 | of = &mux->of; | |
3283 | |||
3284 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
8406 | if (stop_time != INT64_MAX && recording_time != INT64_MAX) { |
3285 | ✗ | stop_time = INT64_MAX; | |
3286 | ✗ | av_log(mux, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n"); | |
3287 | } | ||
3288 | |||
3289 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
8406 | if (stop_time != INT64_MAX && recording_time == INT64_MAX) { |
3290 | ✗ | int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time; | |
3291 | ✗ | if (stop_time <= start_time) { | |
3292 | ✗ | av_log(mux, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n"); | |
3293 | ✗ | return AVERROR(EINVAL); | |
3294 | } else { | ||
3295 | ✗ | recording_time = stop_time - start_time; | |
3296 | } | ||
3297 | } | ||
3298 | |||
3299 | 8406 | of->recording_time = recording_time; | |
3300 | 8406 | of->start_time = o->start_time; | |
3301 | |||
3302 | 8406 | mux->limit_filesize = o->limit_filesize; | |
3303 | 8406 | av_dict_copy(&mux->opts, o->g->format_opts, 0); | |
3304 | |||
3305 |
2/2✓ Branch 0 taken 2688 times.
✓ Branch 1 taken 5718 times.
|
8406 | if (!strcmp(filename, "-")) |
3306 | 2688 | filename = "pipe:"; | |
3307 | |||
3308 | 8406 | err = avformat_alloc_output_context2(&oc, NULL, o->format, filename); | |
3309 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (!oc) { |
3310 | ✗ | av_log(mux, AV_LOG_FATAL, "Error initializing the muxer for %s: %s\n", | |
3311 | ✗ | filename, av_err2str(err)); | |
3312 | ✗ | return err; | |
3313 | } | ||
3314 | 8406 | mux->fc = oc; | |
3315 | |||
3316 | 8406 | av_strlcat(mux->log_name, "/", sizeof(mux->log_name)); | |
3317 | 8406 | av_strlcat(mux->log_name, oc->oformat->name, sizeof(mux->log_name)); | |
3318 | |||
3319 | |||
3320 |
2/2✓ Branch 0 taken 1258 times.
✓ Branch 1 taken 7148 times.
|
8406 | if (recording_time != INT64_MAX) |
3321 | 1258 | oc->duration = recording_time; | |
3322 | |||
3323 | 8406 | oc->interrupt_callback = int_cb; | |
3324 | |||
3325 |
2/2✓ Branch 0 taken 1864 times.
✓ Branch 1 taken 6542 times.
|
8406 | if (o->bitexact) { |
3326 | 1864 | oc->flags |= AVFMT_FLAG_BITEXACT; | |
3327 | 1864 | of->bitexact = 1; | |
3328 | } else { | ||
3329 | 6542 | of->bitexact = check_opt_bitexact(oc, mux->opts, "fflags", | |
3330 | AVFMT_FLAG_BITEXACT); | ||
3331 | } | ||
3332 | |||
3333 | 8406 | err = sch_add_mux(sch, muxer_thread, mux_check_init, mux, | |
3334 | 8406 | !strcmp(oc->oformat->name, "rtp"), o->thread_queue_size); | |
3335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) |
3336 | ✗ | return err; | |
3337 | 8406 | mux->sch = sch; | |
3338 | 8406 | mux->sch_idx = err; | |
3339 | |||
3340 | /* create all output streams for this file */ | ||
3341 | 8406 | err = create_streams(mux, o); | |
3342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) |
3343 | ✗ | return err; | |
3344 | |||
3345 | /* check if all codec options have been used */ | ||
3346 | 8406 | err = check_avoptions_used(o->g->codec_opts, mux->enc_opts_used, mux, 0); | |
3347 | 8406 | av_dict_free(&mux->enc_opts_used); | |
3348 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) |
3349 | ✗ | return err; | |
3350 | |||
3351 | /* check filename in case of an image number is expected */ | ||
3352 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
8406 | if (oc->oformat->flags & AVFMT_NEEDNUMBER && !av_filename_number_test(oc->url)) { |
3353 | ✗ | av_log(mux, AV_LOG_FATAL, | |
3354 | "Output filename '%s' does not contain a numeric pattern like " | ||
3355 | "'%%d', which is required by output format '%s'.\n", | ||
3356 | ✗ | oc->url, oc->oformat->name); | |
3357 | ✗ | return AVERROR(EINVAL); | |
3358 | } | ||
3359 | |||
3360 |
2/2✓ Branch 0 taken 8307 times.
✓ Branch 1 taken 99 times.
|
8406 | if (!(oc->oformat->flags & AVFMT_NOFILE)) { |
3361 | /* test if it already exists to avoid losing precious files */ | ||
3362 | 8307 | err = assert_file_overwrite(filename); | |
3363 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8307 times.
|
8307 | if (err < 0) |
3364 | ✗ | return err; | |
3365 | |||
3366 | /* open the file */ | ||
3367 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8307 times.
|
8307 | if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, |
3368 | 8307 | &oc->interrupt_callback, | |
3369 | &mux->opts)) < 0) { | ||
3370 | ✗ | av_log(mux, AV_LOG_FATAL, "Error opening output %s: %s\n", | |
3371 | ✗ | filename, av_err2str(err)); | |
3372 | ✗ | return err; | |
3373 | } | ||
3374 |
4/4✓ Branch 0 taken 61 times.
✓ Branch 1 taken 38 times.
✓ Branch 3 taken 10 times.
✓ Branch 4 taken 51 times.
|
99 | } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename)) { |
3375 | 10 | err = assert_file_overwrite(filename); | |
3376 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | if (err < 0) |
3377 | ✗ | return err; | |
3378 | } | ||
3379 | |||
3380 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (o->mux_preload) { |
3381 | ✗ | av_dict_set_int(&mux->opts, "preload", o->mux_preload*AV_TIME_BASE, 0); | |
3382 | } | ||
3383 | 8406 | oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE); | |
3384 | |||
3385 | /* copy metadata and chapters from input files */ | ||
3386 | 8406 | err = copy_meta(mux, o); | |
3387 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) |
3388 | ✗ | return err; | |
3389 | |||
3390 | 8406 | err = of_add_groups(mux, o); | |
3391 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) |
3392 | ✗ | return err; | |
3393 | |||
3394 | 8406 | err = of_add_programs(mux, o); | |
3395 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) |
3396 | ✗ | return err; | |
3397 | |||
3398 | 8406 | err = of_add_metadata(of, oc, o); | |
3399 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) |
3400 | ✗ | return err; | |
3401 | |||
3402 | 8406 | err = set_dispositions(mux, o); | |
3403 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) { |
3404 | ✗ | av_log(mux, AV_LOG_FATAL, "Error setting output stream dispositions\n"); | |
3405 | ✗ | return err; | |
3406 | } | ||
3407 | |||
3408 | // parse forced keyframe specifications; | ||
3409 | // must be done after chapters are created | ||
3410 | 8406 | err = process_forced_keyframes(mux, o); | |
3411 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) { |
3412 | ✗ | av_log(mux, AV_LOG_FATAL, "Error processing forced keyframes\n"); | |
3413 | ✗ | return err; | |
3414 | } | ||
3415 | |||
3416 | 8406 | err = setup_sync_queues(mux, oc, o->shortest_buf_duration * AV_TIME_BASE, | |
3417 | 8406 | o->shortest); | |
3418 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8406 times.
|
8406 | if (err < 0) { |
3419 | ✗ | av_log(mux, AV_LOG_FATAL, "Error setting up output sync queues\n"); | |
3420 | ✗ | return err; | |
3421 | } | ||
3422 | |||
3423 | 8406 | of->url = filename; | |
3424 | |||
3425 | /* initialize streamcopy streams. */ | ||
3426 |
2/2✓ Branch 0 taken 8896 times.
✓ Branch 1 taken 8406 times.
|
17302 | for (int i = 0; i < of->nb_streams; i++) { |
3427 | 8896 | OutputStream *ost = of->streams[i]; | |
3428 | |||
3429 |
2/2✓ Branch 0 taken 724 times.
✓ Branch 1 taken 8172 times.
|
8896 | if (!ost->enc) { |
3430 | 724 | err = of_stream_init(of, ost, NULL); | |
3431 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 724 times.
|
724 | if (err < 0) |
3432 | ✗ | return err; | |
3433 | } | ||
3434 | } | ||
3435 | |||
3436 | 8406 | return 0; | |
3437 | } | ||
3438 |