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 | 6091 | static int check_opt_bitexact(void *ctx, const AVDictionary *opts, | |
54 | const char *opt_name, int flag) | ||
55 | { | ||
56 | 6091 | const AVDictionaryEntry *e = av_dict_get(opts, opt_name, NULL, 0); | |
57 | |||
58 |
2/2✓ Branch 0 taken 5118 times.
✓ Branch 1 taken 973 times.
|
6091 | if (e) { |
59 | 5118 | const AVOption *o = av_opt_find(ctx, opt_name, NULL, 0, 0); | |
60 | 5118 | int val = 0; | |
61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5118 times.
|
5118 | if (!o) |
62 | ✗ | return 0; | |
63 | 5118 | av_opt_eval_flags(ctx, o, e->value, &val); | |
64 | 5118 | return !!(val & flag); | |
65 | } | ||
66 | 973 | return 0; | |
67 | } | ||
68 | |||
69 | 8357 | static int choose_encoder(const OptionsContext *o, AVFormatContext *s, | |
70 | MuxStream *ms, const AVCodec **enc) | ||
71 | { | ||
72 | 8357 | OutputStream *ost = &ms->ost; | |
73 | 8357 | enum AVMediaType type = ost->type; | |
74 | 8357 | const char *codec_name = NULL; | |
75 | |||
76 | 8357 | *enc = NULL; | |
77 | |||
78 | 8357 | opt_match_per_stream_str(ost, &o->codec_names, s, ost->st, &codec_name); | |
79 | |||
80 |
4/4✓ Branch 0 taken 1676 times.
✓ Branch 1 taken 6681 times.
✓ Branch 2 taken 82 times.
✓ Branch 3 taken 1594 times.
|
8357 | if (type != AVMEDIA_TYPE_VIDEO && |
81 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 71 times.
|
82 | type != AVMEDIA_TYPE_AUDIO && |
82 | type != AVMEDIA_TYPE_SUBTITLE) { | ||
83 |
3/4✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4 times.
|
11 | 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 | 11 | return 0; | |
91 | } | ||
92 | |||
93 |
2/2✓ Branch 0 taken 3776 times.
✓ Branch 1 taken 4570 times.
|
8346 | if (!codec_name) { |
94 | 3776 | ms->par_in->codec_id = av_guess_codec(s->oformat, NULL, s->url, NULL, ost->type); | |
95 | 3776 | *enc = avcodec_find_encoder(ms->par_in->codec_id); | |
96 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3776 times.
|
3776 | 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 3920 times.
✓ Branch 1 taken 650 times.
|
4570 | } else if (strcmp(codec_name, "copy")) { |
104 | 3920 | int ret = find_codec(ost, codec_name, ost->type, 1, enc); | |
105 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3920 times.
|
3920 | if (ret < 0) |
106 | ✗ | return ret; | |
107 | 3920 | ms->par_in->codec_id = (*enc)->id; | |
108 | } | ||
109 | |||
110 | 8346 | 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 | 7915 | void of_enc_stats_close(void) | |
198 | { | ||
199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7915 times.
|
7915 | 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 | 7915 | av_freep(&enc_stats_files); | |
204 | 7915 | nb_enc_stats_files = 0; | |
205 | 7915 | } | |
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 | 2322 | static const char *output_stream_item_name(void *obj) | |
379 | { | ||
380 | 2322 | const MuxStream *ms = obj; | |
381 | |||
382 | 2322 | 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 | 8357 | static MuxStream *mux_stream_alloc(Muxer *mux, enum AVMediaType type) | |
393 | { | ||
394 | 8357 | const char *type_str = av_get_media_type_string(type); | |
395 | MuxStream *ms; | ||
396 | |||
397 | 8357 | ms = allocate_array_elem(&mux->of.streams, sizeof(*ms), &mux->of.nb_streams); | |
398 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8357 times.
|
8357 | if (!ms) |
399 | ✗ | return NULL; | |
400 | |||
401 | 8357 | ms->ost.file = &mux->of; | |
402 | 8357 | ms->ost.index = mux->of.nb_streams - 1; | |
403 | 8357 | ms->ost.type = type; | |
404 | |||
405 | 8357 | ms->ost.class = &output_stream_class; | |
406 | |||
407 | 8357 | ms->sch_idx = -1; | |
408 | 8357 | ms->sch_idx_enc = -1; | |
409 | |||
410 |
1/2✓ Branch 0 taken 8357 times.
✗ Branch 1 not taken.
|
8357 | snprintf(ms->log_name, sizeof(ms->log_name), "%cost#%d:%d", |
411 | 8357 | type_str ? *type_str : '?', mux->of.index, ms->ost.index); | |
412 | |||
413 | 8357 | return ms; | |
414 | } | ||
415 | |||
416 | 7658 | static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc, | |
417 | OutputStream *ost, char **dst) | ||
418 | { | ||
419 | 7658 | const char *filters = NULL; | |
420 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
421 | 7658 | const char *filters_script = NULL; | |
422 | |||
423 | 7658 | opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script); | |
424 | #endif | ||
425 | 7658 | opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters); | |
426 | |||
427 |
2/2✓ Branch 0 taken 1023 times.
✓ Branch 1 taken 6635 times.
|
7658 | if (!ost->ist) { |
428 | 1023 | if ( | |
429 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
430 |
2/4✓ Branch 0 taken 1023 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 1023 times.
|
1023 | 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 | 1023 | return 0; | |
447 | } | ||
448 | |||
449 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
450 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 6635 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
6635 | 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 6635 times.
|
6635 | if (filters_script) |
456 | ✗ | *dst = file_read(filters_script); | |
457 | else | ||
458 | #endif | ||
459 |
2/2✓ Branch 0 taken 3787 times.
✓ Branch 1 taken 2848 times.
|
6635 | if (filters) |
460 | 3787 | *dst = av_strdup(filters); | |
461 | else | ||
462 |
2/2✓ Branch 0 taken 2264 times.
✓ Branch 1 taken 584 times.
|
2848 | *dst = av_strdup(ost->type == AVMEDIA_TYPE_VIDEO ? "null" : "anull"); |
463 |
1/2✓ Branch 0 taken 6635 times.
✗ Branch 1 not taken.
|
6635 | 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 | 640 | static int fmt_in_list(const int *formats, int format) | |
486 | { | ||
487 |
1/2✓ Branch 0 taken 3680 times.
✗ Branch 1 not taken.
|
3680 | for (; *formats != -1; formats++) |
488 |
2/2✓ Branch 0 taken 640 times.
✓ Branch 1 taken 3040 times.
|
3680 | if (*formats == format) |
489 | 640 | 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 | 4866 | 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 | 4866 | fmt = av_get_pix_fmt(name); | |
532 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4866 times.
|
4866 | 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 | 4866 | 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 4866 times.
|
4866 | 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 320 times.
✓ Branch 1 taken 4546 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 320 times.
|
4866 | 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 320 times.
✓ Branch 1 taken 4546 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 320 times.
|
4866 | if (fmts && !fmt_in_list(fmts, fmt)) |
569 | ✗ | fmt = choose_pixel_fmt(ost->enc->enc_ctx, fmt); | |
570 | |||
571 | 4866 | return fmt; | |
572 | } | ||
573 | |||
574 | 6681 | static int new_stream_video(Muxer *mux, const OptionsContext *o, | |
575 | OutputStream *ost, int *keep_pix_fmt, | ||
576 | enum VideoSyncMethod *vsync_method) | ||
577 | { | ||
578 | 6681 | MuxStream *ms = ms_from_ost(ost); | |
579 | 6681 | AVFormatContext *oc = mux->fc; | |
580 | AVStream *st; | ||
581 | 6681 | const char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL; | |
582 | 6681 | int ret = 0; | |
583 | |||
584 | 6681 | st = ost->st; | |
585 | |||
586 | 6681 | opt_match_per_stream_str(ost, &o->frame_rates, oc, st, &frame_rate); | |
587 |
3/4✓ Branch 0 taken 22 times.
✓ Branch 1 taken 6659 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 22 times.
|
6681 | 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 | 6681 | 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 6681 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
6681 | 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 6659 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 22 times.
|
6681 | 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 | 6681 | 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 6681 times.
|
6681 | 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 6338 times.
✓ Branch 1 taken 343 times.
|
6681 | if (ost->enc) { |
615 | 6338 | AVCodecContext *video_enc = ost->enc->enc_ctx; | |
616 | 6338 | const char *p = NULL, *fps_mode = NULL; | |
617 | 6338 | const char *frame_size = NULL; | |
618 | 6338 | const char *frame_pix_fmt = NULL; | |
619 | 6338 | const char *intra_matrix = NULL, *inter_matrix = NULL; | |
620 | 6338 | const char *chroma_intra_matrix = NULL; | |
621 | 6338 | int do_pass = 0; | |
622 | int i; | ||
623 | |||
624 | 6338 | opt_match_per_stream_str(ost, &o->frame_sizes, oc, st, &frame_size); | |
625 |
2/2✓ Branch 0 taken 1013 times.
✓ Branch 1 taken 5325 times.
|
6338 | if (frame_size) { |
626 | 1013 | ret = av_parse_video_size(&video_enc->width, &video_enc->height, frame_size); | |
627 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1013 times.
|
1013 | 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 | 6338 | opt_match_per_stream_str(ost, &o->frame_pix_fmts, oc, st, &frame_pix_fmt); | |
634 |
3/4✓ Branch 0 taken 4866 times.
✓ Branch 1 taken 1472 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 4866 times.
|
6338 | 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 4866 times.
✓ Branch 1 taken 1472 times.
|
6338 | if (frame_pix_fmt) { |
640 | 4866 | video_enc->pix_fmt = pix_fmt_parse(ost, frame_pix_fmt); | |
641 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4866 times.
|
4866 | if (video_enc->pix_fmt == AV_PIX_FMT_NONE) |
642 | ✗ | return AVERROR(EINVAL); | |
643 | } | ||
644 | |||
645 | 6338 | opt_match_per_stream_str(ost, &o->intra_matrices, oc, st, &intra_matrix); | |
646 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6338 times.
|
6338 | 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 | 6338 | 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 6338 times.
|
6338 | 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 | 6338 | opt_match_per_stream_str(ost, &o->inter_matrices, oc, st, &inter_matrix); | |
663 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6338 times.
|
6338 | 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 | 6338 | opt_match_per_stream_str(ost, &o->rc_overrides, oc, st, &p); | |
672 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6338 times.
|
6338 | 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 | 6338 | video_enc->rc_override_count = i; | |
700 | |||
701 | /* two pass mode */ | ||
702 | 6338 | opt_match_per_stream_int(ost, &o->pass, oc, st, &do_pass); | |
703 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 6322 times.
|
6338 | 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 | 6338 | opt_match_per_stream_str(ost, &o->passlogfiles, oc, st, &ost->logfile_prefix); | |
711 |
2/2✓ Branch 0 taken 16 times.
✓ Branch 1 taken 6322 times.
|
6338 | 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 6322 times.
|
6338 | 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 | 6338 | opt_match_per_stream_int(ost, &o->force_fps, oc, st, &ms->force_fps); | |
758 | |||
759 | #if FFMPEG_OPT_TOP | ||
760 | 6338 | ost->top_field_first = -1; | |
761 | 6338 | 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 6338 times.
|
6338 | 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 | 6338 | *vsync_method = video_sync_method; | |
768 | #else | ||
769 | *vsync_method = VSYNC_AUTO; | ||
770 | #endif | ||
771 | 6338 | opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode); | |
772 |
2/2✓ Branch 0 taken 528 times.
✓ Branch 1 taken 5810 times.
|
6338 | if (fps_mode) { |
773 | 528 | 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 528 times.
|
528 | if (ret < 0) |
775 | ✗ | return ret; | |
776 | } | ||
777 | |||
778 |
3/4✓ Branch 0 taken 6317 times.
✓ Branch 1 taken 21 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6317 times.
|
6338 | 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 5810 times.
✓ Branch 1 taken 528 times.
|
6338 | if (*vsync_method == VSYNC_AUTO) { |
787 |
3/4✓ Branch 0 taken 5790 times.
✓ Branch 1 taken 20 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 5790 times.
|
5810 | if (ms->frame_rate.num || ms->max_frame_rate.num) { |
788 | 20 | *vsync_method = VSYNC_CFR; | |
789 |
2/2✓ Branch 0 taken 296 times.
✓ Branch 1 taken 5494 times.
|
5790 | } else if (!strcmp(oc->oformat->name, "avi")) { |
790 | 296 | *vsync_method = VSYNC_VFR; | |
791 | } else { | ||
792 | 5494 | *vsync_method = (oc->oformat->flags & AVFMT_VARIABLE_FPS) ? | |
793 | 4363 | ((oc->oformat->flags & AVFMT_NOTIMESTAMPS) ? | |
794 |
4/4✓ Branch 0 taken 4363 times.
✓ Branch 1 taken 1131 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 4348 times.
|
5494 | VSYNC_PASSTHROUGH : VSYNC_VFR) : VSYNC_CFR; |
795 | } | ||
796 | |||
797 |
4/4✓ Branch 0 taken 4939 times.
✓ Branch 1 taken 871 times.
✓ Branch 2 taken 383 times.
✓ Branch 3 taken 4556 times.
|
5810 | if (ost->ist && *vsync_method == VSYNC_CFR) { |
798 | 383 | const InputFile *ifile = ost->ist->file; | |
799 | |||
800 |
3/4✓ Branch 0 taken 338 times.
✓ Branch 1 taken 45 times.
✓ Branch 2 taken 338 times.
✗ Branch 3 not taken.
|
383 | if (ifile->nb_streams == 1 && ifile->input_ts_offset == 0) |
801 | 338 | *vsync_method = VSYNC_VSCFR; | |
802 | } | ||
803 | |||
804 |
3/4✓ Branch 0 taken 813 times.
✓ Branch 1 taken 4997 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 813 times.
|
5810 | 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 6338 times.
|
6338 | if (*vsync_method == VSYNC_DROP) |
810 | ✗ | ms->ts_drop = 1; | |
811 | #endif | ||
812 | } | ||
813 | |||
814 | 6681 | return 0; | |
815 | } | ||
816 | |||
817 | 1594 | static int new_stream_audio(Muxer *mux, const OptionsContext *o, | |
818 | OutputStream *ost) | ||
819 | { | ||
820 | 1594 | MuxStream *ms = ms_from_ost(ost); | |
821 | 1594 | AVFormatContext *oc = mux->fc; | |
822 | 1594 | AVStream *st = ost->st; | |
823 | |||
824 |
2/2✓ Branch 0 taken 1320 times.
✓ Branch 1 taken 274 times.
|
1594 | if (ost->enc) { |
825 | 1320 | AVCodecContext *audio_enc = ost->enc->enc_ctx; | |
826 | 1320 | int channels = 0; | |
827 | 1320 | const char *layout = NULL; | |
828 | 1320 | const char *sample_fmt = NULL; | |
829 | |||
830 | 1320 | opt_match_per_stream_int(ost, &o->audio_channels, oc, st, &channels); | |
831 |
2/2✓ Branch 0 taken 10 times.
✓ Branch 1 taken 1310 times.
|
1320 | 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 | 1320 | opt_match_per_stream_str(ost, &o->audio_ch_layouts, oc, st, &layout); | |
837 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1319 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1 times.
|
1320 | 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 | 1320 | opt_match_per_stream_str(ost, &o->sample_fmts, oc, st, &sample_fmt); | |
843 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1320 times.
|
1320 | 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 | 1320 | opt_match_per_stream_int(ost, &o->audio_sample_rate, oc, st, &audio_enc->sample_rate); | |
850 | 1320 | opt_match_per_stream_str(ost, &o->apad, oc, st, &ms->apad); | |
851 | } | ||
852 | |||
853 | 1594 | return 0; | |
854 | } | ||
855 | |||
856 | 71 | static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, | |
857 | OutputStream *ost) | ||
858 | { | ||
859 | AVStream *st; | ||
860 | |||
861 | 71 | st = ost->st; | |
862 | |||
863 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 33 times.
|
71 | if (ost->enc) { |
864 | 38 | AVCodecContext *subtitle_enc = ost->enc->enc_ctx; | |
865 | |||
866 | AVCodecDescriptor const *input_descriptor = | ||
867 | 38 | avcodec_descriptor_get(ost->ist->par->codec_id); | |
868 | AVCodecDescriptor const *output_descriptor = | ||
869 | 38 | avcodec_descriptor_get(subtitle_enc->codec_id); | |
870 | 38 | int input_props = 0, output_props = 0; | |
871 | |||
872 | 38 | const char *frame_size = NULL; | |
873 | |||
874 | 38 | opt_match_per_stream_str(ost, &o->frame_sizes, mux->fc, st, &frame_size); | |
875 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | 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 38 times.
✗ Branch 1 not taken.
|
38 | if (input_descriptor) |
883 | 38 | input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); | |
884 |
1/2✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
|
38 | if (output_descriptor) |
885 | 38 | output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); | |
886 |
3/6✓ Branch 0 taken 38 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 38 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 38 times.
|
38 | 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 | 71 | return 0; | |
895 | } | ||
896 | |||
897 | static int | ||
898 | 7658 | 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 | 7658 | OutputStream *ost = &ms->ost; | |
906 | 7658 | AVCodecContext *enc_ctx = ost->enc->enc_ctx; | |
907 | char name[16]; | ||
908 | 7658 | char *filters = NULL; | |
909 | int ret; | ||
910 | |||
911 | 30632 | OutputFilterOptions opts = { | |
912 | 7658 | .enc = enc_ctx->codec, | |
913 | .name = name, | ||
914 | 7658 | .format = (ost->type == AVMEDIA_TYPE_VIDEO) ? | |
915 | 7658 | enc_ctx->pix_fmt : enc_ctx->sample_fmt, | |
916 | 7658 | .width = enc_ctx->width, | |
917 | 7658 | .height = enc_ctx->height, | |
918 | 7658 | .color_space = enc_ctx->colorspace, | |
919 | 7658 | .color_range = enc_ctx->color_range, | |
920 | .vsync_method = vsync_method, | ||
921 | .frame_rate = ms->frame_rate, | ||
922 | .max_frame_rate = ms->max_frame_rate, | ||
923 | 7658 | .sample_rate = enc_ctx->sample_rate, | |
924 | .ch_layout = enc_ctx->ch_layout, | ||
925 | 7658 | .sws_opts = o->g->sws_dict, | |
926 | 7658 | .swr_opts = o->g->swr_opts, | |
927 | .output_tb = enc_tb, | ||
928 | 7658 | .trim_start_us = mux->of.start_time, | |
929 | 7658 | .trim_duration_us = mux->of.recording_time, | |
930 | 7658 | .ts_offset = mux->of.start_time == AV_NOPTS_VALUE ? | |
931 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7657 times.
|
7658 | 0 : mux->of.start_time, |
932 | .vs = vs, | ||
933 | |||
934 | 15316 | .flags = OFILTER_FLAG_DISABLE_CONVERT * !!keep_pix_fmt | | |
935 |
3/4✓ Branch 0 taken 7658 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6338 times.
✓ Branch 3 taken 1320 times.
|
15316 | OFILTER_FLAG_AUTOSCALE * !!autoscale | |
936 |
2/2✓ Branch 1 taken 59 times.
✓ Branch 2 taken 7599 times.
|
7658 | OFILTER_FLAG_AUDIO_24BIT * !!(av_get_exact_bits_per_sample(enc_ctx->codec_id) == 24), |
937 | }; | ||
938 | |||
939 | 7658 | snprintf(name, sizeof(name), "#%d:%d", mux->of.index, ost->index); | |
940 | |||
941 |
2/2✓ Branch 0 taken 6338 times.
✓ Branch 1 taken 1320 times.
|
7658 | if (ost->type == AVMEDIA_TYPE_VIDEO) { |
942 |
1/2✓ Branch 0 taken 6338 times.
✗ Branch 1 not taken.
|
6338 | if (!keep_pix_fmt) { |
943 | 6338 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
944 | AV_CODEC_CONFIG_PIX_FORMAT, 0, | ||
945 | (const void **) &opts.formats, NULL); | ||
946 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6338 times.
|
6338 | if (ret < 0) |
947 | ✗ | return ret; | |
948 | } | ||
949 |
2/2✓ Branch 0 taken 6337 times.
✓ Branch 1 taken 1 times.
|
6338 | if (!ms->force_fps) { |
950 | 6337 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
951 | AV_CODEC_CONFIG_FRAME_RATE, 0, | ||
952 | (const void **) &opts.frame_rates, NULL); | ||
953 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6337 times.
|
6337 | if (ret < 0) |
954 | ✗ | return ret; | |
955 | } | ||
956 | 6338 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
957 | AV_CODEC_CONFIG_COLOR_SPACE, 0, | ||
958 | (const void **) &opts.color_spaces, NULL); | ||
959 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6338 times.
|
6338 | if (ret < 0) |
960 | ✗ | return ret; | |
961 | 6338 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
962 | AV_CODEC_CONFIG_COLOR_RANGE, 0, | ||
963 | (const void **) &opts.color_ranges, NULL); | ||
964 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6338 times.
|
6338 | if (ret < 0) |
965 | ✗ | return ret; | |
966 | } else { | ||
967 | 1320 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
968 | AV_CODEC_CONFIG_SAMPLE_FORMAT, 0, | ||
969 | (const void **) &opts.formats, NULL); | ||
970 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1320 times.
|
1320 | if (ret < 0) |
971 | ✗ | return ret; | |
972 | 1320 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
973 | AV_CODEC_CONFIG_SAMPLE_RATE, 0, | ||
974 | (const void **) &opts.sample_rates, NULL); | ||
975 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1320 times.
|
1320 | if (ret < 0) |
976 | ✗ | return ret; | |
977 | 1320 | ret = avcodec_get_supported_config(enc_ctx, NULL, | |
978 | AV_CODEC_CONFIG_CHANNEL_LAYOUT, 0, | ||
979 | (const void **) &opts.ch_layouts, NULL); | ||
980 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1320 times.
|
1320 | if (ret < 0) |
981 | ✗ | return ret; | |
982 | } | ||
983 | |||
984 |
2/2✓ Branch 0 taken 4948 times.
✓ Branch 1 taken 2710 times.
|
7658 | if (threads_manual) { |
985 | 4948 | ret = av_opt_get(enc_ctx, "threads", 0, (uint8_t**)&opts.nb_threads); | |
986 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4948 times.
|
4948 | if (ret < 0) |
987 | ✗ | return ret; | |
988 | } | ||
989 | |||
990 | 7658 | ret = ost_get_filters(o, mux->fc, ost, &filters); | |
991 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7658 times.
|
7658 | if (ret < 0) |
992 | ✗ | return ret; | |
993 | |||
994 |
2/2✓ Branch 0 taken 1023 times.
✓ Branch 1 taken 6635 times.
|
7658 | if (ofilter) { |
995 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1023 times.
|
1023 | av_assert0(!filters); |
996 | 1023 | ost->filter = ofilter; | |
997 | 1023 | ret = ofilter_bind_enc(ofilter, ms->sch_idx_enc, &opts); | |
998 | } else { | ||
999 | 6635 | ret = fg_create_simple(&ost->fg_simple, ost->ist, filters, | |
1000 | 6635 | mux->sch, ms->sch_idx_enc, &opts); | |
1001 |
1/2✓ Branch 0 taken 6635 times.
✗ Branch 1 not taken.
|
6635 | if (ret >= 0) |
1002 | 6635 | ost->filter = ost->fg_simple->outputs[0]; | |
1003 | |||
1004 | } | ||
1005 | 7658 | av_freep(&opts.nb_threads); | |
1006 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7658 times.
|
7658 | if (ret < 0) |
1007 | ✗ | return ret; | |
1008 | |||
1009 | 7658 | *src = SCH_ENC(ms->sch_idx_enc); | |
1010 | |||
1011 | 7658 | return 0; | |
1012 | } | ||
1013 | |||
1014 | 660 | static int streamcopy_init(const OptionsContext *o, const Muxer *mux, | |
1015 | OutputStream *ost, AVDictionary **encoder_opts) | ||
1016 | { | ||
1017 | 660 | MuxStream *ms = ms_from_ost(ost); | |
1018 | |||
1019 | 660 | const InputStream *ist = ost->ist; | |
1020 | 660 | const InputFile *ifile = ist->file; | |
1021 | |||
1022 | 660 | AVCodecParameters *par = ms->par_in; | |
1023 | 660 | uint32_t codec_tag = par->codec_tag; | |
1024 | |||
1025 | 660 | AVCodecContext *codec_ctx = NULL; | |
1026 | |||
1027 | 660 | AVRational fr = ms->frame_rate; | |
1028 | |||
1029 | 660 | int ret = 0; | |
1030 | |||
1031 | 660 | const char *filters = NULL; | |
1032 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
1033 | 660 | const char *filters_script = NULL; | |
1034 | |||
1035 | 660 | opt_match_per_stream_str(ost, &o->filter_scripts, mux->fc, ost->st, &filters_script); | |
1036 | #endif | ||
1037 | 660 | opt_match_per_stream_str(ost, &o->filters, mux->fc, ost->st, &filters); | |
1038 | |||
1039 | 660 | if ( | |
1040 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
1041 |
2/4✓ Branch 0 taken 660 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 660 times.
|
660 | filters_script || |
1042 | #endif | ||
1043 | filters) { | ||
1044 | ✗ | av_log(ost, AV_LOG_ERROR, | |
1045 | "%s '%s' was specified, but codec copy was selected. " | ||
1046 | "Filtering and streamcopy cannot be used together.\n", | ||
1047 | #if FFMPEG_OPT_FILTER_SCRIPT | ||
1048 | ✗ | filters ? "Filtergraph" : "Filtergraph script", | |
1049 | ✗ | filters ? filters : filters_script | |
1050 | #else | ||
1051 | "Filtergraph", filters | ||
1052 | #endif | ||
1053 | ); | ||
1054 | ✗ | return AVERROR(EINVAL); | |
1055 | } | ||
1056 | |||
1057 | 660 | codec_ctx = avcodec_alloc_context3(NULL); | |
1058 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
|
660 | if (!codec_ctx) |
1059 | ✗ | return AVERROR(ENOMEM); | |
1060 | |||
1061 | 660 | ret = avcodec_parameters_to_context(codec_ctx, ist->par); | |
1062 |
1/2✓ Branch 0 taken 660 times.
✗ Branch 1 not taken.
|
660 | if (ret >= 0) |
1063 | 660 | ret = av_opt_set_dict(codec_ctx, encoder_opts); | |
1064 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
|
660 | if (ret < 0) { |
1065 | ✗ | av_log(ost, AV_LOG_FATAL, | |
1066 | "Error setting up codec context options.\n"); | ||
1067 | ✗ | goto fail; | |
1068 | } | ||
1069 | |||
1070 | 660 | ret = avcodec_parameters_from_context(par, codec_ctx); | |
1071 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
|
660 | if (ret < 0) { |
1072 | ✗ | av_log(ost, AV_LOG_FATAL, | |
1073 | "Error getting reference codec parameters.\n"); | ||
1074 | ✗ | goto fail; | |
1075 | } | ||
1076 | |||
1077 |
2/2✓ Branch 0 taken 654 times.
✓ Branch 1 taken 6 times.
|
660 | if (!codec_tag) { |
1078 | 654 | const struct AVCodecTag * const *ct = mux->fc->oformat->codec_tag; | |
1079 | unsigned int codec_tag_tmp; | ||
1080 |
6/6✓ Branch 0 taken 120 times.
✓ Branch 1 taken 534 times.
✓ Branch 3 taken 87 times.
✓ Branch 4 taken 33 times.
✓ Branch 5 taken 11 times.
✓ Branch 6 taken 76 times.
|
741 | if (!ct || av_codec_get_id (ct, par->codec_tag) == par->codec_id || |
1081 | 87 | !av_codec_get_tag2(ct, par->codec_id, &codec_tag_tmp)) | |
1082 | 578 | codec_tag = par->codec_tag; | |
1083 | } | ||
1084 | |||
1085 | 660 | par->codec_tag = codec_tag; | |
1086 | |||
1087 |
2/2✓ Branch 0 taken 659 times.
✓ Branch 1 taken 1 times.
|
660 | if (!fr.num) |
1088 | 659 | fr = ist->framerate; | |
1089 | |||
1090 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 658 times.
|
660 | if (fr.num) |
1091 | 2 | ost->st->avg_frame_rate = fr; | |
1092 | else | ||
1093 | 658 | ost->st->avg_frame_rate = ist->st->avg_frame_rate; | |
1094 | |||
1095 | // copy timebase while removing common factors | ||
1096 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
660 | if (ost->st->time_base.num <= 0 || ost->st->time_base.den <= 0) { |
1097 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 658 times.
|
660 | if (fr.num) |
1098 | 2 | ost->st->time_base = av_inv_q(fr); | |
1099 | else | ||
1100 | 658 | ost->st->time_base = av_add_q(ist->st->time_base, (AVRational){0, 1}); | |
1101 | } | ||
1102 | |||
1103 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
|
660 | if (!ms->copy_prior_start) { |
1104 | ✗ | ms->ts_copy_start = (mux->of.start_time == AV_NOPTS_VALUE) ? | |
1105 | ✗ | 0 : mux->of.start_time; | |
1106 | ✗ | if (copy_ts && ifile->start_time != AV_NOPTS_VALUE) { | |
1107 | ✗ | ms->ts_copy_start = FFMAX(ms->ts_copy_start, | |
1108 | ifile->start_time + ifile->ts_offset); | ||
1109 | } | ||
1110 | } | ||
1111 | |||
1112 |
2/2✓ Branch 0 taken 78 times.
✓ Branch 1 taken 660 times.
|
738 | for (int i = 0; i < ist->st->codecpar->nb_coded_side_data; i++) { |
1113 | 78 | const AVPacketSideData *sd_src = &ist->st->codecpar->coded_side_data[i]; | |
1114 | AVPacketSideData *sd_dst; | ||
1115 | |||
1116 | 78 | sd_dst = av_packet_side_data_new(&ost->st->codecpar->coded_side_data, | |
1117 | 78 | &ost->st->codecpar->nb_coded_side_data, | |
1118 | 78 | sd_src->type, sd_src->size, 0); | |
1119 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 78 times.
|
78 | if (!sd_dst) { |
1120 | ✗ | ret = AVERROR(ENOMEM); | |
1121 | ✗ | goto fail; | |
1122 | } | ||
1123 | 78 | memcpy(sd_dst->data, sd_src->data, sd_src->size); | |
1124 | } | ||
1125 | |||
1126 |
3/3✓ Branch 0 taken 274 times.
✓ Branch 1 taken 343 times.
✓ Branch 2 taken 43 times.
|
660 | switch (par->codec_type) { |
1127 | 274 | case AVMEDIA_TYPE_AUDIO: | |
1128 |
4/6✓ Branch 0 taken 269 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 269 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 269 times.
|
274 | if ((par->block_align == 1 || par->block_align == 1152 || par->block_align == 576) && |
1129 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | par->codec_id == AV_CODEC_ID_MP3) |
1130 | ✗ | par->block_align = 0; | |
1131 |
2/2✓ Branch 0 taken 14 times.
✓ Branch 1 taken 260 times.
|
274 | if (par->codec_id == AV_CODEC_ID_AC3) |
1132 | 14 | par->block_align = 0; | |
1133 | 274 | break; | |
1134 | 343 | case AVMEDIA_TYPE_VIDEO: { | |
1135 | AVRational sar; | ||
1136 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 343 times.
|
343 | if (ost->frame_aspect_ratio.num) { // overridden by the -aspect cli option |
1137 | sar = | ||
1138 | ✗ | av_mul_q(ost->frame_aspect_ratio, | |
1139 | ✗ | (AVRational){ par->height, par->width }); | |
1140 | ✗ | av_log(ost, AV_LOG_WARNING, "Overriding aspect ratio " | |
1141 | "with stream copy may produce invalid files\n"); | ||
1142 | } | ||
1143 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 253 times.
|
343 | else if (ist->st->sample_aspect_ratio.num) |
1144 | 90 | sar = ist->st->sample_aspect_ratio; | |
1145 | else | ||
1146 | 253 | sar = par->sample_aspect_ratio; | |
1147 | 343 | ost->st->sample_aspect_ratio = par->sample_aspect_ratio = sar; | |
1148 | 343 | ost->st->r_frame_rate = ist->st->r_frame_rate; | |
1149 | 343 | break; | |
1150 | } | ||
1151 | } | ||
1152 | |||
1153 | 660 | fail: | |
1154 | 660 | avcodec_free_context(&codec_ctx); | |
1155 | 660 | return ret; | |
1156 | } | ||
1157 | |||
1158 | 7696 | static int set_encoder_id(OutputStream *ost, const AVCodec *codec) | |
1159 | { | ||
1160 | 7696 | const char *cname = codec->name; | |
1161 | uint8_t *encoder_string; | ||
1162 | int encoder_string_len; | ||
1163 | |||
1164 | 7696 | encoder_string_len = sizeof(LIBAVCODEC_IDENT) + strlen(cname) + 2; | |
1165 | 7696 | encoder_string = av_mallocz(encoder_string_len); | |
1166 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
|
7696 | if (!encoder_string) |
1167 | ✗ | return AVERROR(ENOMEM); | |
1168 | |||
1169 |
4/4✓ Branch 0 taken 845 times.
✓ Branch 1 taken 6851 times.
✓ Branch 2 taken 838 times.
✓ Branch 3 taken 7 times.
|
7696 | if (!ost->file->bitexact && !ost->bitexact) |
1170 | 838 | av_strlcpy(encoder_string, LIBAVCODEC_IDENT " ", encoder_string_len); | |
1171 | else | ||
1172 | 6858 | av_strlcpy(encoder_string, "Lavc ", encoder_string_len); | |
1173 | 7696 | av_strlcat(encoder_string, cname, encoder_string_len); | |
1174 | 7696 | av_dict_set(&ost->st->metadata, "encoder", encoder_string, | |
1175 | AV_DICT_DONT_STRDUP_VAL | AV_DICT_DONT_OVERWRITE); | ||
1176 | |||
1177 | 7696 | return 0; | |
1178 | } | ||
1179 | |||
1180 | 8357 | static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, | |
1181 | InputStream *ist, OutputFilter *ofilter, const ViewSpecifier *vs, | ||
1182 | OutputStream **post) | ||
1183 | { | ||
1184 | 8357 | AVFormatContext *oc = mux->fc; | |
1185 | MuxStream *ms; | ||
1186 | OutputStream *ost; | ||
1187 | const AVCodec *enc; | ||
1188 | AVStream *st; | ||
1189 | 8357 | SchedulerNode src = { .type = SCH_NODE_TYPE_NONE }; | |
1190 | 8357 | AVDictionary *encoder_opts = NULL; | |
1191 | 8357 | int ret = 0, keep_pix_fmt = 0, autoscale = 1; | |
1192 | 8357 | int threads_manual = 0; | |
1193 | 8357 | AVRational enc_tb = { 0, 0 }; | |
1194 | 8357 | enum VideoSyncMethod vsync_method = VSYNC_AUTO; | |
1195 | 8357 | const char *bsfs = NULL, *time_base = NULL, *codec_tag = NULL; | |
1196 | char *next; | ||
1197 | 8357 | double qscale = -1; | |
1198 | |||
1199 | 8357 | st = avformat_new_stream(oc, NULL); | |
1200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8357 times.
|
8357 | if (!st) |
1201 | ✗ | return AVERROR(ENOMEM); | |
1202 | |||
1203 | 8357 | ms = mux_stream_alloc(mux, type); | |
1204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8357 times.
|
8357 | if (!ms) |
1205 | ✗ | return AVERROR(ENOMEM); | |
1206 | |||
1207 | // only streams with sources (i.e. not attachments) | ||
1208 | // are handled by the scheduler | ||
1209 |
4/4✓ Branch 0 taken 1024 times.
✓ Branch 1 taken 7333 times.
✓ Branch 2 taken 1023 times.
✓ Branch 3 taken 1 times.
|
8357 | if (ist || ofilter) { |
1210 | 8356 | ret = GROW_ARRAY(mux->sch_stream_idx, mux->nb_sch_stream_idx); | |
1211 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8356 times.
|
8356 | if (ret < 0) |
1212 | ✗ | return ret; | |
1213 | |||
1214 | 8356 | ret = sch_add_mux_stream(mux->sch, mux->sch_idx); | |
1215 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8356 times.
|
8356 | if (ret < 0) |
1216 | ✗ | return ret; | |
1217 | |||
1218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8356 times.
|
8356 | av_assert0(ret == mux->nb_sch_stream_idx - 1); |
1219 | 8356 | mux->sch_stream_idx[ret] = ms->ost.index; | |
1220 | 8356 | ms->sch_idx = ret; | |
1221 | } | ||
1222 | |||
1223 | 8357 | ost = &ms->ost; | |
1224 | |||
1225 |
2/2✓ Branch 0 taken 49 times.
✓ Branch 1 taken 8308 times.
|
8357 | if (o->streamid) { |
1226 | AVDictionaryEntry *e; | ||
1227 | char idx[16], *p; | ||
1228 | 49 | snprintf(idx, sizeof(idx), "%d", ost->index); | |
1229 | |||
1230 | 49 | e = av_dict_get(o->streamid, idx, NULL, 0); | |
1231 |
1/2✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
|
49 | if (e) { |
1232 | 49 | st->id = strtol(e->value, &p, 0); | |
1233 |
2/4✓ Branch 0 taken 49 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 49 times.
|
49 | if (!e->value[0] || *p) { |
1234 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid stream id: %s\n", e->value); | |
1235 | ✗ | return AVERROR(EINVAL); | |
1236 | } | ||
1237 | } | ||
1238 | } | ||
1239 | |||
1240 | 8357 | ms->par_in = avcodec_parameters_alloc(); | |
1241 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8357 times.
|
8357 | if (!ms->par_in) |
1242 | ✗ | return AVERROR(ENOMEM); | |
1243 | |||
1244 | 8357 | ms->last_mux_dts = AV_NOPTS_VALUE; | |
1245 | |||
1246 | 8357 | ost->st = st; | |
1247 | 8357 | ost->ist = ist; | |
1248 | 8357 | ost->kf.ref_pts = AV_NOPTS_VALUE; | |
1249 | 8357 | ms->par_in->codec_type = type; | |
1250 | 8357 | st->codecpar->codec_type = type; | |
1251 | |||
1252 | 8357 | ret = choose_encoder(o, oc, ms, &enc); | |
1253 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8357 times.
|
8357 | if (ret < 0) { |
1254 | ✗ | av_log(ost, AV_LOG_FATAL, "Error selecting an encoder\n"); | |
1255 | ✗ | return ret; | |
1256 | } | ||
1257 | |||
1258 |
2/2✓ Branch 0 taken 7696 times.
✓ Branch 1 taken 661 times.
|
8357 | if (enc) { |
1259 | 7696 | ret = sch_add_enc(mux->sch, encoder_thread, ost, | |
1260 |
2/2✓ Branch 0 taken 7658 times.
✓ Branch 1 taken 38 times.
|
7696 | ost->type == AVMEDIA_TYPE_SUBTITLE ? NULL : enc_open); |
1261 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
|
7696 | if (ret < 0) |
1262 | ✗ | return ret; | |
1263 | 7696 | ms->sch_idx_enc = ret; | |
1264 | |||
1265 | 7696 | ret = enc_alloc(&ost->enc, enc, mux->sch, ms->sch_idx_enc, ost); | |
1266 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
|
7696 | if (ret < 0) |
1267 | ✗ | return ret; | |
1268 | |||
1269 | 7696 | av_strlcat(ms->log_name, "/", sizeof(ms->log_name)); | |
1270 | 7696 | av_strlcat(ms->log_name, enc->name, sizeof(ms->log_name)); | |
1271 | } else { | ||
1272 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 661 times.
|
661 | if (ofilter) { |
1273 | ✗ | av_log(ost, AV_LOG_ERROR, | |
1274 | "Streamcopy requested for output stream fed " | ||
1275 | "from a complex filtergraph. Filtering and streamcopy " | ||
1276 | "cannot be used together.\n"); | ||
1277 | ✗ | return AVERROR(EINVAL); | |
1278 | } | ||
1279 | |||
1280 | 661 | av_strlcat(ms->log_name, "/copy", sizeof(ms->log_name)); | |
1281 | } | ||
1282 | |||
1283 | 8357 | av_log(ost, AV_LOG_VERBOSE, "Created %s stream from ", | |
1284 | av_get_media_type_string(type)); | ||
1285 |
2/2✓ Branch 0 taken 7333 times.
✓ Branch 1 taken 1024 times.
|
8357 | if (ist) |
1286 | 7333 | av_log(ost, AV_LOG_VERBOSE, "input stream %d:%d", | |
1287 | 7333 | ist->file->index, ist->index); | |
1288 |
2/2✓ Branch 0 taken 1023 times.
✓ Branch 1 taken 1 times.
|
1024 | else if (ofilter) |
1289 | 1023 | av_log(ost, AV_LOG_VERBOSE, "complex filtergraph %d:[%s]\n", | |
1290 | 1023 | ofilter->graph->index, ofilter->name); | |
1291 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | else if (type == AVMEDIA_TYPE_ATTACHMENT) |
1292 | 1 | av_log(ost, AV_LOG_VERBOSE, "attached file"); | |
1293 | ✗ | else av_assert0(0); | |
1294 | 8357 | av_log(ost, AV_LOG_VERBOSE, "\n"); | |
1295 | |||
1296 | 8357 | ms->pkt = av_packet_alloc(); | |
1297 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8357 times.
|
8357 | if (!ms->pkt) |
1298 | ✗ | return AVERROR(ENOMEM); | |
1299 | |||
1300 |
2/2✓ Branch 0 taken 7696 times.
✓ Branch 1 taken 661 times.
|
8357 | if (ost->enc) { |
1301 | 7696 | AVIOContext *s = NULL; | |
1302 | 7696 | char *buf = NULL, *arg = NULL; | |
1303 | 7696 | const char *enc_stats_pre = NULL, *enc_stats_post = NULL, *mux_stats = NULL; | |
1304 | 7696 | const char *enc_time_base = NULL, *preset = NULL; | |
1305 | |||
1306 | 7696 | ret = filter_codec_opts(o->g->codec_opts, enc->id, | |
1307 | oc, st, enc, &encoder_opts, | ||
1308 | &mux->enc_opts_used); | ||
1309 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
|
7696 | if (ret < 0) |
1310 | ✗ | goto fail; | |
1311 | |||
1312 | 7696 | opt_match_per_stream_str(ost, &o->presets, oc, st, &preset); | |
1313 | 7696 | opt_match_per_stream_int(ost, &o->autoscale, oc, st, &autoscale); | |
1314 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
7696 | if (preset && (!(ret = get_preset_file_2(preset, enc->name, &s)))) { |
1315 | AVBPrint bprint; | ||
1316 | ✗ | av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); | |
1317 | do { | ||
1318 | ✗ | av_bprint_clear(&bprint); | |
1319 | ✗ | buf = get_line(s, &bprint); | |
1320 | ✗ | if (!buf) { | |
1321 | ✗ | ret = AVERROR(ENOMEM); | |
1322 | ✗ | break; | |
1323 | } | ||
1324 | |||
1325 | ✗ | if (!buf[0] || buf[0] == '#') | |
1326 | ✗ | continue; | |
1327 | ✗ | if (!(arg = strchr(buf, '='))) { | |
1328 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid line found in the preset file.\n"); | |
1329 | ✗ | ret = AVERROR(EINVAL); | |
1330 | ✗ | break; | |
1331 | } | ||
1332 | ✗ | *arg++ = 0; | |
1333 | ✗ | av_dict_set(&encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE); | |
1334 | ✗ | } while (!s->eof_reached); | |
1335 | ✗ | av_bprint_finalize(&bprint, NULL); | |
1336 | ✗ | avio_closep(&s); | |
1337 | } | ||
1338 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
|
7696 | if (ret) { |
1339 | ✗ | av_log(ost, AV_LOG_FATAL, | |
1340 | "Preset %s specified, but could not be opened.\n", preset); | ||
1341 | ✗ | goto fail; | |
1342 | } | ||
1343 | |||
1344 | 7696 | opt_match_per_stream_str(ost, &o->enc_stats_pre, oc, st, &enc_stats_pre); | |
1345 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7696 | if (enc_stats_pre && |
1346 | ✗ | (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { | |
1347 | ✗ | const char *format = "{fidx} {sidx} {n} {t}"; | |
1348 | |||
1349 | ✗ | opt_match_per_stream_str(ost, &o->enc_stats_pre_fmt, oc, st, &format); | |
1350 | |||
1351 | ✗ | ret = enc_stats_init(ost, &ost->enc_stats_pre, 1, enc_stats_pre, format); | |
1352 | ✗ | if (ret < 0) | |
1353 | ✗ | goto fail; | |
1354 | } | ||
1355 | |||
1356 | 7696 | opt_match_per_stream_str(ost, &o->enc_stats_post, oc, st, &enc_stats_post); | |
1357 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7696 | if (enc_stats_post && |
1358 | ✗ | (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { | |
1359 | ✗ | const char *format = "{fidx} {sidx} {n} {t}"; | |
1360 | |||
1361 | ✗ | opt_match_per_stream_str(ost, &o->enc_stats_post_fmt, oc, st, &format); | |
1362 | |||
1363 | ✗ | ret = enc_stats_init(ost, &ost->enc_stats_post, 0, enc_stats_post, format); | |
1364 | ✗ | if (ret < 0) | |
1365 | ✗ | goto fail; | |
1366 | } | ||
1367 | |||
1368 | 7696 | opt_match_per_stream_str(ost, &o->mux_stats, oc, st, &mux_stats); | |
1369 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7696 | if (mux_stats && |
1370 | ✗ | (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { | |
1371 | ✗ | const char *format = "{fidx} {sidx} {n} {t}"; | |
1372 | |||
1373 | ✗ | opt_match_per_stream_str(ost, &o->mux_stats_fmt, oc, st, &format); | |
1374 | |||
1375 | ✗ | ret = enc_stats_init(ost, &ms->stats, 0, mux_stats, format); | |
1376 | ✗ | if (ret < 0) | |
1377 | ✗ | goto fail; | |
1378 | } | ||
1379 | |||
1380 | 7696 | opt_match_per_stream_str(ost, &o->enc_time_bases, oc, st, &enc_time_base); | |
1381 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7695 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
7696 | if (enc_time_base && type == AVMEDIA_TYPE_SUBTITLE) |
1382 | ✗ | av_log(ost, AV_LOG_WARNING, | |
1383 | "-enc_time_base not supported for subtitles, ignoring\n"); | ||
1384 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7695 times.
|
7696 | else if (enc_time_base) { |
1385 | AVRational q; | ||
1386 | |||
1387 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (!strcmp(enc_time_base, "demux")) { |
1388 | 1 | q = (AVRational){ ENC_TIME_BASE_DEMUX, 0 }; | |
1389 | ✗ | } else if (!strcmp(enc_time_base, "filter")) { | |
1390 | ✗ | q = (AVRational){ ENC_TIME_BASE_FILTER, 0 }; | |
1391 | } else { | ||
1392 | ✗ | ret = av_parse_ratio(&q, enc_time_base, INT_MAX, 0, NULL); | |
1393 | ✗ | if (ret < 0 || q.den <= 0 | |
1394 | #if !FFMPEG_OPT_ENC_TIME_BASE_NUM | ||
1395 | || q.num < 0 | ||
1396 | #endif | ||
1397 | ) { | ||
1398 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", enc_time_base); | |
1399 | ✗ | ret = ret < 0 ? ret : AVERROR(EINVAL); | |
1400 | ✗ | goto fail; | |
1401 | } | ||
1402 | #if FFMPEG_OPT_ENC_TIME_BASE_NUM | ||
1403 | ✗ | if (q.num < 0) | |
1404 | ✗ | av_log(ost, AV_LOG_WARNING, "-enc_time_base -1 is deprecated," | |
1405 | " use -enc_time_base demux\n"); | ||
1406 | #endif | ||
1407 | } | ||
1408 | |||
1409 | 1 | enc_tb = q; | |
1410 | } | ||
1411 | |||
1412 | 7696 | threads_manual = !!av_dict_get(encoder_opts, "threads", NULL, 0); | |
1413 | |||
1414 | 7696 | ret = av_opt_set_dict2(ost->enc->enc_ctx, &encoder_opts, AV_OPT_SEARCH_CHILDREN); | |
1415 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
|
7696 | if (ret < 0) { |
1416 | ✗ | av_log(ost, AV_LOG_ERROR, "Error applying encoder options: %s\n", | |
1417 | ✗ | av_err2str(ret)); | |
1418 | ✗ | goto fail; | |
1419 | } | ||
1420 | |||
1421 | 7696 | ret = check_avoptions(encoder_opts); | |
1422 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
|
7696 | if (ret < 0) |
1423 | ✗ | goto fail; | |
1424 | |||
1425 | // default to automatic thread count | ||
1426 |
2/2✓ Branch 0 taken 2748 times.
✓ Branch 1 taken 4948 times.
|
7696 | if (!threads_manual) |
1427 | 2748 | ost->enc->enc_ctx->thread_count = 0; | |
1428 | } else { | ||
1429 | 661 | ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, | |
1430 | NULL, &encoder_opts, | ||
1431 | &mux->enc_opts_used); | ||
1432 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 661 times.
|
661 | if (ret < 0) |
1433 | ✗ | goto fail; | |
1434 | } | ||
1435 | |||
1436 | |||
1437 |
2/2✓ Branch 0 taken 1960 times.
✓ Branch 1 taken 6397 times.
|
8357 | if (o->bitexact) { |
1438 | 1960 | ost->bitexact = 1; | |
1439 |
2/2✓ Branch 0 taken 5845 times.
✓ Branch 1 taken 552 times.
|
6397 | } else if (ost->enc) { |
1440 | 5845 | ost->bitexact = !!(ost->enc->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT); | |
1441 | } | ||
1442 | |||
1443 |
2/2✓ Branch 0 taken 7696 times.
✓ Branch 1 taken 661 times.
|
8357 | if (enc) { |
1444 | 7696 | ret = set_encoder_id(ost, enc); | |
1445 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7696 times.
|
7696 | if (ret < 0) |
1446 | ✗ | return ret; | |
1447 | } | ||
1448 | |||
1449 | 8357 | opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base); | |
1450 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 8355 times.
|
8357 | if (time_base) { |
1451 | AVRational q; | ||
1452 |
1/2✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
|
2 | if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 || |
1453 |
2/4✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 2 times.
|
2 | q.num <= 0 || q.den <= 0) { |
1454 | ✗ | av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", time_base); | |
1455 | ✗ | ret = AVERROR(EINVAL); | |
1456 | ✗ | goto fail; | |
1457 | } | ||
1458 | 2 | st->time_base = q; | |
1459 | } | ||
1460 | |||
1461 | 8357 | ms->max_frames = INT64_MAX; | |
1462 | 8357 | opt_match_per_stream_int64(ost, &o->max_frames, oc, st, &ms->max_frames); | |
1463 |
2/2✓ Branch 0 taken 5206 times.
✓ Branch 1 taken 8351 times.
|
13557 | for (int i = 0; i < o->max_frames.nb_opt; i++) { |
1464 | 5206 | char *p = o->max_frames.opt[i].specifier; | |
1465 |
4/4✓ Branch 0 taken 169 times.
✓ Branch 1 taken 5037 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 163 times.
|
5206 | if (!*p && type != AVMEDIA_TYPE_VIDEO) { |
1466 | 6 | av_log(ost, AV_LOG_WARNING, "Applying unspecific -frames to non video streams, maybe you meant -vframes ?\n"); | |
1467 | 6 | break; | |
1468 | } | ||
1469 | } | ||
1470 | |||
1471 | 8357 | ms->copy_prior_start = -1; | |
1472 | 8357 | opt_match_per_stream_int(ost, &o->copy_prior_start, oc, st, &ms->copy_prior_start); | |
1473 | 8357 | opt_match_per_stream_str(ost, &o->bitstream_filters, oc, st, &bsfs); | |
1474 |
3/4✓ Branch 0 taken 133 times.
✓ Branch 1 taken 8224 times.
✓ Branch 2 taken 133 times.
✗ Branch 3 not taken.
|
8357 | if (bsfs && *bsfs) { |
1475 | 133 | ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx); | |
1476 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 133 times.
|
133 | if (ret < 0) { |
1477 | ✗ | av_log(ost, AV_LOG_ERROR, "Error parsing bitstream filter sequence '%s': %s\n", bsfs, av_err2str(ret)); | |
1478 | ✗ | goto fail; | |
1479 | } | ||
1480 | } | ||
1481 | |||
1482 | 8357 | opt_match_per_stream_str(ost, &o->codec_tags, oc, st, &codec_tag); | |
1483 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 8350 times.
|
8357 | if (codec_tag) { |
1484 | 7 | uint32_t tag = strtol(codec_tag, &next, 0); | |
1485 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (*next) { |
1486 | 7 | uint8_t buf[4] = { 0 }; | |
1487 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | memcpy(buf, codec_tag, FFMIN(sizeof(buf), strlen(codec_tag))); |
1488 | 7 | tag = AV_RL32(buf); | |
1489 | } | ||
1490 | 7 | ost->st->codecpar->codec_tag = tag; | |
1491 | 7 | ms->par_in->codec_tag = tag; | |
1492 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 6 times.
|
7 | if (ost->enc) |
1493 | 1 | ost->enc->enc_ctx->codec_tag = tag; | |
1494 | } | ||
1495 | |||
1496 | 8357 | opt_match_per_stream_dbl(ost, &o->qscale, oc, st, &qscale); | |
1497 |
4/4✓ Branch 0 taken 7696 times.
✓ Branch 1 taken 661 times.
✓ Branch 2 taken 266 times.
✓ Branch 3 taken 7430 times.
|
8357 | if (ost->enc && qscale >= 0) { |
1498 | 266 | ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_QSCALE; | |
1499 | 266 | ost->enc->enc_ctx->global_quality = FF_QP2LAMBDA * qscale; | |
1500 | } | ||
1501 | |||
1502 |
2/2✓ Branch 0 taken 8356 times.
✓ Branch 1 taken 1 times.
|
8357 | if (ms->sch_idx >= 0) { |
1503 | 8356 | int max_muxing_queue_size = 128; | |
1504 | 8356 | int muxing_queue_data_threshold = 50 * 1024 * 1024; | |
1505 | |||
1506 | 8356 | opt_match_per_stream_int(ost, &o->max_muxing_queue_size, oc, st, | |
1507 | &max_muxing_queue_size); | ||
1508 | 8356 | opt_match_per_stream_int(ost, &o->muxing_queue_data_threshold, | |
1509 | oc, st, &muxing_queue_data_threshold); | ||
1510 | |||
1511 | 8356 | sch_mux_stream_buffering(mux->sch, mux->sch_idx, ms->sch_idx, | |
1512 | max_muxing_queue_size, muxing_queue_data_threshold); | ||
1513 | } | ||
1514 | |||
1515 | 8357 | opt_match_per_stream_int(ost, &o->bits_per_raw_sample, oc, st, | |
1516 | &ost->bits_per_raw_sample); | ||
1517 | |||
1518 | 8357 | opt_match_per_stream_int(ost, &o->fix_sub_duration_heartbeat, | |
1519 | 8357 | oc, st, &ost->fix_sub_duration_heartbeat); | |
1520 | |||
1521 |
4/4✓ Branch 0 taken 3062 times.
✓ Branch 1 taken 5295 times.
✓ Branch 2 taken 2958 times.
✓ Branch 3 taken 104 times.
|
8357 | if (oc->oformat->flags & AVFMT_GLOBALHEADER && ost->enc) |
1522 | 2958 | ost->enc->enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; | |
1523 | |||
1524 | 8357 | opt_match_per_stream_int(ost, &o->copy_initial_nonkeyframes, | |
1525 | oc, st, &ms->copy_initial_nonkeyframes); | ||
1526 |
4/4✓ Branch 0 taken 6681 times.
✓ Branch 1 taken 1594 times.
✓ Branch 2 taken 71 times.
✓ Branch 3 taken 11 times.
|
8357 | switch (type) { |
1527 | 6681 | case AVMEDIA_TYPE_VIDEO: ret = new_stream_video (mux, o, ost, &keep_pix_fmt, &vsync_method); break; | |
1528 | 1594 | case AVMEDIA_TYPE_AUDIO: ret = new_stream_audio (mux, o, ost); break; | |
1529 | 71 | case AVMEDIA_TYPE_SUBTITLE: ret = new_stream_subtitle (mux, o, ost); break; | |
1530 | } | ||
1531 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8357 times.
|
8357 | if (ret < 0) |
1532 | ✗ | goto fail; | |
1533 | |||
1534 |
4/4✓ Branch 0 taken 7696 times.
✓ Branch 1 taken 661 times.
✓ Branch 2 taken 1358 times.
✓ Branch 3 taken 6338 times.
|
8357 | if (ost->enc && |
1535 |
2/2✓ Branch 0 taken 1320 times.
✓ Branch 1 taken 38 times.
|
1358 | (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { |
1536 | 7658 | ret = ost_bind_filter(mux, ms, ofilter, o, enc_tb, vsync_method, | |
1537 | keep_pix_fmt, autoscale, threads_manual, vs, &src); | ||
1538 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7658 times.
|
7658 | if (ret < 0) |
1539 | ✗ | goto fail; | |
1540 |
2/2✓ Branch 0 taken 698 times.
✓ Branch 1 taken 1 times.
|
699 | } else if (ost->ist) { |
1541 | 698 | ret = ist_use(ost->ist, !!ost->enc, NULL, &src); | |
1542 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 698 times.
|
698 | if (ret < 0) { |
1543 | ✗ | av_log(ost, AV_LOG_ERROR, | |
1544 | "Error binding an input stream\n"); | ||
1545 | ✗ | goto fail; | |
1546 | } | ||
1547 | 698 | ms->sch_idx_src = src.idx; | |
1548 | |||
1549 | // src refers to a decoder for transcoding, demux stream otherwise | ||
1550 |
2/2✓ Branch 0 taken 38 times.
✓ Branch 1 taken 660 times.
|
698 | if (ost->enc) { |
1551 | 38 | ret = sch_connect(mux->sch, | |
1552 | 38 | src, SCH_ENC(ms->sch_idx_enc)); | |
1553 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 38 times.
|
38 | if (ret < 0) |
1554 | ✗ | goto fail; | |
1555 | 38 | src = SCH_ENC(ms->sch_idx_enc); | |
1556 | } | ||
1557 | } | ||
1558 | |||
1559 |
2/2✓ Branch 0 taken 8356 times.
✓ Branch 1 taken 1 times.
|
8357 | if (src.type != SCH_NODE_TYPE_NONE) { |
1560 | 8356 | ret = sch_connect(mux->sch, | |
1561 | 8356 | src, SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); | |
1562 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8356 times.
|
8356 | if (ret < 0) |
1563 | ✗ | goto fail; | |
1564 | } else { | ||
1565 | // only attachment streams don't have a source | ||
1566 |
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); |
1567 | } | ||
1568 | |||
1569 |
4/4✓ Branch 0 taken 7333 times.
✓ Branch 1 taken 1024 times.
✓ Branch 2 taken 660 times.
✓ Branch 3 taken 6673 times.
|
8357 | if (ost->ist && !ost->enc) { |
1570 | 660 | ret = streamcopy_init(o, mux, ost, &encoder_opts); | |
1571 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 660 times.
|
660 | if (ret < 0) |
1572 | ✗ | goto fail; | |
1573 | } | ||
1574 | |||
1575 | // copy estimated duration as a hint to the muxer | ||
1576 |
4/4✓ Branch 0 taken 7333 times.
✓ Branch 1 taken 1024 times.
✓ Branch 2 taken 5798 times.
✓ Branch 3 taken 1535 times.
|
8357 | if (ost->ist && ost->ist->st->duration > 0) { |
1577 | 5798 | ms->stream_duration = ist->st->duration; | |
1578 | 5798 | ms->stream_duration_tb = ist->st->time_base; | |
1579 | } | ||
1580 | |||
1581 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 8356 times.
|
8357 | if (post) |
1582 | 1 | *post = ost; | |
1583 | |||
1584 | 8357 | ret = 0; | |
1585 | |||
1586 | 8357 | fail: | |
1587 | 8357 | av_dict_free(&encoder_opts); | |
1588 | |||
1589 | 8357 | return ret; | |
1590 | } | ||
1591 | |||
1592 | 6722 | static int map_auto_video(Muxer *mux, const OptionsContext *o) | |
1593 | { | ||
1594 | 6722 | AVFormatContext *oc = mux->fc; | |
1595 | 6722 | InputStream *best_ist = NULL; | |
1596 | 6722 | int best_score = 0; | |
1597 | int qcr; | ||
1598 | |||
1599 | /* video: highest resolution */ | ||
1600 |
2/2✓ Branch 1 taken 732 times.
✓ Branch 2 taken 5990 times.
|
6722 | if (av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_VIDEO) == AV_CODEC_ID_NONE) |
1601 | 732 | return 0; | |
1602 | |||
1603 | 5990 | qcr = avformat_query_codec(oc->oformat, oc->oformat->video_codec, 0); | |
1604 |
2/2✓ Branch 0 taken 6030 times.
✓ Branch 1 taken 5990 times.
|
12020 | for (int j = 0; j < nb_input_files; j++) { |
1605 | 6030 | InputFile *ifile = input_files[j]; | |
1606 | 6030 | InputStream *file_best_ist = NULL; | |
1607 | 6030 | int file_best_score = 0; | |
1608 |
2/2✓ Branch 0 taken 6309 times.
✓ Branch 1 taken 6030 times.
|
12339 | for (int i = 0; i < ifile->nb_streams; i++) { |
1609 | 6309 | InputStream *ist = ifile->streams[i]; | |
1610 | int score; | ||
1611 | |||
1612 |
2/2✓ Branch 0 taken 6308 times.
✓ Branch 1 taken 1 times.
|
6309 | if (ist->user_set_discard == AVDISCARD_ALL || |
1613 |
2/2✓ Branch 0 taken 633 times.
✓ Branch 1 taken 5675 times.
|
6308 | ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) |
1614 | 634 | continue; | |
1615 | |||
1616 | 11350 | score = ist->st->codecpar->width * ist->st->codecpar->height | |
1617 |
2/2✓ Branch 0 taken 5673 times.
✓ Branch 1 taken 2 times.
|
5675 | + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) |
1618 |
2/2✓ Branch 0 taken 519 times.
✓ Branch 1 taken 5156 times.
|
5675 | + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); |
1619 |
3/4✓ Branch 0 taken 5675 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 9 times.
✓ Branch 3 taken 5666 times.
|
5675 | if((qcr!=MKTAG('A', 'P', 'I', 'C')) && (ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) |
1620 | 9 | score = 1; | |
1621 | |||
1622 |
2/2✓ Branch 0 taken 5674 times.
✓ Branch 1 taken 1 times.
|
5675 | if (score > file_best_score) { |
1623 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 5674 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
5674 | if((qcr==MKTAG('A', 'P', 'I', 'C')) && !(ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) |
1624 | ✗ | continue; | |
1625 | 5674 | file_best_score = score; | |
1626 | 5674 | file_best_ist = ist; | |
1627 | } | ||
1628 | } | ||
1629 |
2/2✓ Branch 0 taken 5674 times.
✓ Branch 1 taken 356 times.
|
6030 | if (file_best_ist) { |
1630 |
1/2✓ Branch 0 taken 5674 times.
✗ Branch 1 not taken.
|
5674 | if((qcr == MKTAG('A', 'P', 'I', 'C')) || |
1631 |
2/2✓ Branch 0 taken 5666 times.
✓ Branch 1 taken 8 times.
|
5674 | !(file_best_ist->st->disposition & AV_DISPOSITION_ATTACHED_PIC)) |
1632 |
2/2✓ Branch 0 taken 519 times.
✓ Branch 1 taken 5147 times.
|
5666 | file_best_score -= 5000000*!!(file_best_ist->st->disposition & AV_DISPOSITION_DEFAULT); |
1633 |
1/2✓ Branch 0 taken 5674 times.
✗ Branch 1 not taken.
|
5674 | if (file_best_score > best_score) { |
1634 | 5674 | best_score = file_best_score; | |
1635 | 5674 | best_ist = file_best_ist; | |
1636 | } | ||
1637 | } | ||
1638 | } | ||
1639 |
2/2✓ Branch 0 taken 5674 times.
✓ Branch 1 taken 316 times.
|
5990 | if (best_ist) |
1640 | 5674 | return ost_add(mux, o, AVMEDIA_TYPE_VIDEO, best_ist, NULL, NULL, NULL); | |
1641 | |||
1642 | 316 | return 0; | |
1643 | } | ||
1644 | |||
1645 | 7594 | static int map_auto_audio(Muxer *mux, const OptionsContext *o) | |
1646 | { | ||
1647 | 7594 | AVFormatContext *oc = mux->fc; | |
1648 | 7594 | InputStream *best_ist = NULL; | |
1649 | 7594 | int best_score = 0; | |
1650 | |||
1651 | /* audio: most channels */ | ||
1652 |
2/2✓ Branch 1 taken 1637 times.
✓ Branch 2 taken 5957 times.
|
7594 | if (av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_AUDIO) == AV_CODEC_ID_NONE) |
1653 | 1637 | return 0; | |
1654 | |||
1655 |
2/2✓ Branch 0 taken 5942 times.
✓ Branch 1 taken 5957 times.
|
11899 | for (int j = 0; j < nb_input_files; j++) { |
1656 | 5942 | InputFile *ifile = input_files[j]; | |
1657 | 5942 | InputStream *file_best_ist = NULL; | |
1658 | 5942 | int file_best_score = 0; | |
1659 |
2/2✓ Branch 0 taken 6147 times.
✓ Branch 1 taken 5942 times.
|
12089 | for (int i = 0; i < ifile->nb_streams; i++) { |
1660 | 6147 | InputStream *ist = ifile->streams[i]; | |
1661 | int score; | ||
1662 | |||
1663 |
2/2✓ Branch 0 taken 6146 times.
✓ Branch 1 taken 1 times.
|
6147 | if (ist->user_set_discard == AVDISCARD_ALL || |
1664 |
2/2✓ Branch 0 taken 4850 times.
✓ Branch 1 taken 1296 times.
|
6146 | ist->st->codecpar->codec_type != AVMEDIA_TYPE_AUDIO) |
1665 | 4851 | continue; | |
1666 | |||
1667 | 2592 | score = ist->st->codecpar->ch_layout.nb_channels | |
1668 |
2/2✓ Branch 0 taken 1295 times.
✓ Branch 1 taken 1 times.
|
1296 | + 100000000 * !!(ist->st->event_flags & AVSTREAM_EVENT_FLAG_NEW_PACKETS) |
1669 |
2/2✓ Branch 0 taken 174 times.
✓ Branch 1 taken 1122 times.
|
1296 | + 5000000*!!(ist->st->disposition & AV_DISPOSITION_DEFAULT); |
1670 |
2/2✓ Branch 0 taken 1286 times.
✓ Branch 1 taken 10 times.
|
1296 | if (score > file_best_score) { |
1671 | 1286 | file_best_score = score; | |
1672 | 1286 | file_best_ist = ist; | |
1673 | } | ||
1674 | } | ||
1675 |
2/2✓ Branch 0 taken 1286 times.
✓ Branch 1 taken 4656 times.
|
5942 | if (file_best_ist) { |
1676 |
2/2✓ Branch 0 taken 174 times.
✓ Branch 1 taken 1112 times.
|
1286 | file_best_score -= 5000000*!!(file_best_ist->st->disposition & AV_DISPOSITION_DEFAULT); |
1677 |
1/2✓ Branch 0 taken 1286 times.
✗ Branch 1 not taken.
|
1286 | if (file_best_score > best_score) { |
1678 | 1286 | best_score = file_best_score; | |
1679 | 1286 | best_ist = file_best_ist; | |
1680 | } | ||
1681 | } | ||
1682 | } | ||
1683 |
2/2✓ Branch 0 taken 1286 times.
✓ Branch 1 taken 4671 times.
|
5957 | if (best_ist) |
1684 | 1286 | return ost_add(mux, o, AVMEDIA_TYPE_AUDIO, best_ist, NULL, NULL, NULL); | |
1685 | |||
1686 | 4671 | return 0; | |
1687 | } | ||
1688 | |||
1689 | 7754 | static int map_auto_subtitle(Muxer *mux, const OptionsContext *o) | |
1690 | { | ||
1691 | 7754 | AVFormatContext *oc = mux->fc; | |
1692 | 7754 | const char *subtitle_codec_name = NULL; | |
1693 | |||
1694 | /* subtitles: pick first */ | ||
1695 | 7754 | subtitle_codec_name = opt_match_per_type_str(&o->codec_names, 's'); | |
1696 |
4/4✓ Branch 1 taken 7694 times.
✓ Branch 2 taken 60 times.
✓ Branch 3 taken 7687 times.
✓ Branch 4 taken 7 times.
|
7754 | if (!avcodec_find_encoder(oc->oformat->subtitle_codec) && !subtitle_codec_name) |
1697 | 7687 | return 0; | |
1698 | |||
1699 |
2/2✓ Branch 2 taken 81 times.
✓ Branch 3 taken 19 times.
|
100 | for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist)) |
1700 |
2/2✓ Branch 0 taken 48 times.
✓ Branch 1 taken 33 times.
|
81 | if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) { |
1701 | AVCodecDescriptor const *input_descriptor = | ||
1702 | 48 | avcodec_descriptor_get(ist->st->codecpar->codec_id); | |
1703 | 48 | AVCodecDescriptor const *output_descriptor = NULL; | |
1704 | AVCodec const *output_codec = | ||
1705 | 48 | avcodec_find_encoder(oc->oformat->subtitle_codec); | |
1706 | 48 | int input_props = 0, output_props = 0; | |
1707 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 48 times.
|
48 | if (ist->user_set_discard == AVDISCARD_ALL) |
1708 | ✗ | continue; | |
1709 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 7 times.
|
48 | if (output_codec) |
1710 | 41 | output_descriptor = avcodec_descriptor_get(output_codec->id); | |
1711 |
1/2✓ Branch 0 taken 48 times.
✗ Branch 1 not taken.
|
48 | if (input_descriptor) |
1712 | 48 | input_props = input_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); | |
1713 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 7 times.
|
48 | if (output_descriptor) |
1714 | 41 | output_props = output_descriptor->props & (AV_CODEC_PROP_TEXT_SUB | AV_CODEC_PROP_BITMAP_SUB); | |
1715 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 16 times.
|
48 | if (subtitle_codec_name || |
1716 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 32 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
32 | input_props & output_props || |
1717 | // Map dvb teletext which has neither property to any output subtitle encoder | ||
1718 | ✗ | input_descriptor && output_descriptor && | |
1719 | ✗ | (!input_descriptor->props || | |
1720 | ✗ | !output_descriptor->props)) { | |
1721 | 48 | return ost_add(mux, o, AVMEDIA_TYPE_SUBTITLE, ist, NULL, NULL, NULL); | |
1722 | } | ||
1723 | } | ||
1724 | |||
1725 | 19 | return 0; | |
1726 | } | ||
1727 | |||
1728 | 7755 | static int map_auto_data(Muxer *mux, const OptionsContext *o) | |
1729 | { | ||
1730 | 7755 | AVFormatContext *oc = mux->fc; | |
1731 | /* Data only if codec id match */ | ||
1732 | 7755 | enum AVCodecID codec_id = av_guess_codec(oc->oformat, NULL, oc->url, NULL, AVMEDIA_TYPE_DATA); | |
1733 | |||
1734 |
1/2✓ Branch 0 taken 7755 times.
✗ Branch 1 not taken.
|
7755 | if (codec_id == AV_CODEC_ID_NONE) |
1735 | 7755 | return 0; | |
1736 | |||
1737 | ✗ | for (InputStream *ist = ist_iter(NULL); ist; ist = ist_iter(ist)) { | |
1738 | ✗ | if (ist->user_set_discard == AVDISCARD_ALL) | |
1739 | ✗ | continue; | |
1740 | ✗ | if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA && | |
1741 | ✗ | ist->st->codecpar->codec_id == codec_id) { | |
1742 | ✗ | int ret = ost_add(mux, o, AVMEDIA_TYPE_DATA, ist, NULL, NULL, NULL); | |
1743 | ✗ | if (ret < 0) | |
1744 | ✗ | return ret; | |
1745 | } | ||
1746 | } | ||
1747 | |||
1748 | ✗ | return 0; | |
1749 | } | ||
1750 | |||
1751 | 386 | static int map_manual(Muxer *mux, const OptionsContext *o, const StreamMap *map) | |
1752 | { | ||
1753 | InputStream *ist; | ||
1754 | int ret; | ||
1755 | |||
1756 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 386 times.
|
386 | if (map->disabled) |
1757 | ✗ | return 0; | |
1758 | |||
1759 |
2/2✓ Branch 0 taken 61 times.
✓ Branch 1 taken 325 times.
|
386 | if (map->linklabel) { |
1760 | FilterGraph *fg; | ||
1761 | 61 | OutputFilter *ofilter = NULL; | |
1762 | int j, k; | ||
1763 | |||
1764 |
1/2✓ Branch 0 taken 61 times.
✗ Branch 1 not taken.
|
61 | for (j = 0; j < nb_filtergraphs; j++) { |
1765 | 61 | fg = filtergraphs[j]; | |
1766 |
1/2✓ Branch 0 taken 204 times.
✗ Branch 1 not taken.
|
204 | for (k = 0; k < fg->nb_outputs; k++) { |
1767 | 204 | const char *linklabel = fg->outputs[k]->linklabel; | |
1768 |
3/4✓ Branch 0 taken 61 times.
✓ Branch 1 taken 143 times.
✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
|
204 | if (linklabel && !strcmp(linklabel, map->linklabel)) { |
1769 | 61 | ofilter = fg->outputs[k]; | |
1770 | 61 | goto loop_end; | |
1771 | } | ||
1772 | } | ||
1773 | } | ||
1774 | ✗ | loop_end: | |
1775 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
|
61 | if (!ofilter) { |
1776 | ✗ | av_log(mux, AV_LOG_FATAL, "Output with label '%s' does not exist " | |
1777 | ✗ | "in any defined filter graph, or was already used elsewhere.\n", map->linklabel); | |
1778 | ✗ | return AVERROR(EINVAL); | |
1779 | } | ||
1780 | |||
1781 | 61 | av_log(mux, AV_LOG_VERBOSE, "Creating output stream from an explicitly " | |
1782 | 61 | "mapped complex filtergraph %d, output [%s]\n", fg->index, map->linklabel); | |
1783 | |||
1784 | 61 | ret = ost_add(mux, o, ofilter->type, NULL, ofilter, NULL, NULL); | |
1785 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 61 times.
|
61 | if (ret < 0) |
1786 | ✗ | return ret; | |
1787 | } else { | ||
1788 | 650 | const ViewSpecifier *vs = map->vs.type == VIEW_SPECIFIER_TYPE_NONE ? | |
1789 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 312 times.
|
325 | NULL : &map->vs; |
1790 | |||
1791 | 325 | ist = input_files[map->file_index]->streams[map->stream_index]; | |
1792 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | if (ist->user_set_discard == AVDISCARD_ALL) { |
1793 | ✗ | av_log(mux, AV_LOG_FATAL, "Stream #%d:%d is disabled and cannot be mapped.\n", | |
1794 | ✗ | map->file_index, map->stream_index); | |
1795 | ✗ | return AVERROR(EINVAL); | |
1796 | } | ||
1797 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
325 | if(o->subtitle_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_SUBTITLE) |
1798 | ✗ | return 0; | |
1799 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
325 | if(o-> audio_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) |
1800 | ✗ | return 0; | |
1801 |
3/4✓ Branch 0 taken 1 times.
✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 1 times.
|
325 | if(o-> video_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) |
1802 | ✗ | return 0; | |
1803 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
325 | if(o-> data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA) |
1804 | ✗ | return 0; | |
1805 | |||
1806 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | if (ist->st->codecpar->codec_type == AVMEDIA_TYPE_UNKNOWN && |
1807 | ✗ | !copy_unknown_streams) { | |
1808 | ✗ | av_log(mux, ignore_unknown_streams ? AV_LOG_WARNING : AV_LOG_FATAL, | |
1809 | "Cannot map stream #%d:%d - unsupported type.\n", | ||
1810 | ✗ | map->file_index, map->stream_index); | |
1811 | ✗ | if (!ignore_unknown_streams) { | |
1812 | ✗ | av_log(mux, AV_LOG_FATAL, | |
1813 | "If you want unsupported types ignored instead " | ||
1814 | "of failing, please use the -ignore_unknown option\n" | ||
1815 | "If you want them copied, please use -copy_unknown\n"); | ||
1816 | ✗ | return AVERROR(EINVAL); | |
1817 | } | ||
1818 | ✗ | return 0; | |
1819 | } | ||
1820 | |||
1821 |
3/4✓ Branch 0 taken 13 times.
✓ Branch 1 taken 312 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 13 times.
|
325 | if (vs && ist->st->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) { |
1822 | ✗ | av_log(mux, AV_LOG_ERROR, | |
1823 | "View specifier given for mapping a %s input stream\n", | ||
1824 | ✗ | av_get_media_type_string(ist->st->codecpar->codec_type)); | |
1825 | ✗ | return AVERROR(EINVAL); | |
1826 | } | ||
1827 | |||
1828 | 325 | ret = ost_add(mux, o, ist->st->codecpar->codec_type, ist, NULL, vs, NULL); | |
1829 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 325 times.
|
325 | if (ret < 0) |
1830 | ✗ | return ret; | |
1831 | } | ||
1832 | |||
1833 | 386 | return 0; | |
1834 | } | ||
1835 | |||
1836 | 7916 | static int of_add_attachments(Muxer *mux, const OptionsContext *o) | |
1837 | { | ||
1838 | MuxStream *ms; | ||
1839 | OutputStream *ost; | ||
1840 | int err; | ||
1841 | |||
1842 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 7916 times.
|
7917 | for (int i = 0; i < o->nb_attachments; i++) { |
1843 | AVIOContext *pb; | ||
1844 | uint8_t *attachment; | ||
1845 | char *attachment_filename; | ||
1846 | const char *p; | ||
1847 | int64_t len; | ||
1848 | |||
1849 |
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) { |
1850 | ✗ | av_log(mux, AV_LOG_FATAL, "Could not open attachment file %s.\n", | |
1851 | ✗ | o->attachments[i]); | |
1852 | ✗ | return err; | |
1853 | } | ||
1854 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | if ((len = avio_size(pb)) <= 0) { |
1855 | ✗ | av_log(mux, AV_LOG_FATAL, "Could not get size of the attachment %s.\n", | |
1856 | ✗ | o->attachments[i]); | |
1857 | ✗ | err = len ? len : AVERROR_INVALIDDATA; | |
1858 | ✗ | goto read_fail; | |
1859 | } | ||
1860 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (len > INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { |
1861 | ✗ | av_log(mux, AV_LOG_FATAL, "Attachment %s too large.\n", | |
1862 | ✗ | o->attachments[i]); | |
1863 | ✗ | err = AVERROR(ERANGE); | |
1864 | ✗ | goto read_fail; | |
1865 | } | ||
1866 | |||
1867 | 1 | attachment = av_malloc(len + AV_INPUT_BUFFER_PADDING_SIZE); | |
1868 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!attachment) { |
1869 | ✗ | err = AVERROR(ENOMEM); | |
1870 | ✗ | goto read_fail; | |
1871 | } | ||
1872 | |||
1873 | 1 | err = avio_read(pb, attachment, len); | |
1874 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (err < 0) |
1875 | ✗ | av_log(mux, AV_LOG_FATAL, "Error reading attachment file %s: %s\n", | |
1876 | ✗ | o->attachments[i], av_err2str(err)); | |
1877 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | else if (err != len) { |
1878 | ✗ | av_log(mux, AV_LOG_FATAL, "Could not read all %"PRId64" bytes for " | |
1879 | ✗ | "attachment file %s\n", len, o->attachments[i]); | |
1880 | ✗ | err = AVERROR(EIO); | |
1881 | } | ||
1882 | |||
1883 | 1 | read_fail: | |
1884 | 1 | avio_closep(&pb); | |
1885 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (err < 0) |
1886 | ✗ | return err; | |
1887 | |||
1888 | 1 | memset(attachment + len, 0, AV_INPUT_BUFFER_PADDING_SIZE); | |
1889 | |||
1890 | 1 | av_log(mux, AV_LOG_VERBOSE, "Creating attachment stream from file %s\n", | |
1891 | 1 | o->attachments[i]); | |
1892 | |||
1893 | 1 | attachment_filename = av_strdup(o->attachments[i]); | |
1894 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!attachment_filename) { |
1895 | ✗ | av_free(attachment); | |
1896 | ✗ | return AVERROR(ENOMEM); | |
1897 | } | ||
1898 | |||
1899 | 1 | err = ost_add(mux, o, AVMEDIA_TYPE_ATTACHMENT, NULL, NULL, NULL, &ost); | |
1900 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (err < 0) { |
1901 | ✗ | av_free(attachment_filename); | |
1902 | ✗ | av_freep(&attachment); | |
1903 | ✗ | return err; | |
1904 | } | ||
1905 | |||
1906 | 1 | ms = ms_from_ost(ost); | |
1907 | |||
1908 | 1 | ost->attachment_filename = attachment_filename; | |
1909 | 1 | ms->par_in->extradata = attachment; | |
1910 | 1 | ms->par_in->extradata_size = len; | |
1911 | |||
1912 | 1 | p = strrchr(o->attachments[i], '/'); | |
1913 |
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); |
1914 | } | ||
1915 | |||
1916 | 7916 | return 0; | |
1917 | } | ||
1918 | |||
1919 | 7916 | static int create_streams(Muxer *mux, const OptionsContext *o) | |
1920 | { | ||
1921 | static int (* const map_func[])(Muxer *mux, const OptionsContext *o) = { | ||
1922 | [AVMEDIA_TYPE_VIDEO] = map_auto_video, | ||
1923 | [AVMEDIA_TYPE_AUDIO] = map_auto_audio, | ||
1924 | [AVMEDIA_TYPE_SUBTITLE] = map_auto_subtitle, | ||
1925 | [AVMEDIA_TYPE_DATA] = map_auto_data, | ||
1926 | }; | ||
1927 | |||
1928 | 7916 | AVFormatContext *oc = mux->fc; | |
1929 | |||
1930 | 7916 | int auto_disable = | |
1931 | 7916 | o->video_disable * (1 << AVMEDIA_TYPE_VIDEO) | | |
1932 | 7916 | o->audio_disable * (1 << AVMEDIA_TYPE_AUDIO) | | |
1933 | 7916 | o->subtitle_disable * (1 << AVMEDIA_TYPE_SUBTITLE) | | |
1934 | 7916 | o->data_disable * (1 << AVMEDIA_TYPE_DATA); | |
1935 | |||
1936 | int ret; | ||
1937 | |||
1938 | /* create streams for all unlabeled output pads */ | ||
1939 |
2/2✓ Branch 0 taken 903 times.
✓ Branch 1 taken 7916 times.
|
8819 | for (int i = 0; i < nb_filtergraphs; i++) { |
1940 | 903 | FilterGraph *fg = filtergraphs[i]; | |
1941 |
2/2✓ Branch 0 taken 1024 times.
✓ Branch 1 taken 903 times.
|
1927 | for (int j = 0; j < fg->nb_outputs; j++) { |
1942 | 1024 | OutputFilter *ofilter = fg->outputs[j]; | |
1943 | |||
1944 |
3/4✓ Branch 0 taken 962 times.
✓ Branch 1 taken 62 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 962 times.
|
1024 | if (ofilter->linklabel || ofilter->bound) |
1945 | 62 | continue; | |
1946 | |||
1947 | 962 | auto_disable |= 1 << ofilter->type; | |
1948 | |||
1949 | 962 | av_log(mux, AV_LOG_VERBOSE, "Creating output stream from unlabeled " | |
1950 | "output of complex filtergraph %d.", fg->index); | ||
1951 |
1/2✓ Branch 0 taken 962 times.
✗ Branch 1 not taken.
|
962 | if (!o->nb_stream_maps) |
1952 | 962 | av_log(mux, AV_LOG_VERBOSE, " This overrides automatic %s mapping.", | |
1953 | av_get_media_type_string(ofilter->type)); | ||
1954 | 962 | av_log(mux, AV_LOG_VERBOSE, "\n"); | |
1955 | |||
1956 | 962 | ret = ost_add(mux, o, ofilter->type, NULL, ofilter, NULL, NULL); | |
1957 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 962 times.
|
962 | if (ret < 0) |
1958 | ✗ | return ret; | |
1959 | } | ||
1960 | } | ||
1961 | |||
1962 |
2/2✓ Branch 0 taken 7755 times.
✓ Branch 1 taken 161 times.
|
7916 | if (!o->nb_stream_maps) { |
1963 | 7755 | av_log(mux, AV_LOG_VERBOSE, "No explicit maps, mapping streams automatically...\n"); | |
1964 | |||
1965 | /* pick the "best" stream of each type */ | ||
1966 |
2/2✓ Branch 0 taken 31020 times.
✓ Branch 1 taken 7755 times.
|
38775 | for (int i = 0; i < FF_ARRAY_ELEMS(map_func); i++) { |
1967 |
3/4✓ Branch 0 taken 31020 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1195 times.
✓ Branch 3 taken 29825 times.
|
31020 | if (!map_func[i] || auto_disable & (1 << i)) |
1968 | 1195 | continue; | |
1969 | 29825 | ret = map_func[i](mux, o); | |
1970 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 29825 times.
|
29825 | if (ret < 0) |
1971 | ✗ | return ret; | |
1972 | } | ||
1973 | } else { | ||
1974 | 161 | av_log(mux, AV_LOG_VERBOSE, "Adding streams from explicit maps...\n"); | |
1975 | |||
1976 |
2/2✓ Branch 0 taken 386 times.
✓ Branch 1 taken 161 times.
|
547 | for (int i = 0; i < o->nb_stream_maps; i++) { |
1977 | 386 | ret = map_manual(mux, o, &o->stream_maps[i]); | |
1978 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 386 times.
|
386 | if (ret < 0) |
1979 | ✗ | return ret; | |
1980 | } | ||
1981 | } | ||
1982 | |||
1983 | 7916 | ret = of_add_attachments(mux, o); | |
1984 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (ret < 0) |
1985 | ✗ | return ret; | |
1986 | |||
1987 | // setup fix_sub_duration_heartbeat mappings | ||
1988 |
2/2✓ Branch 0 taken 8357 times.
✓ Branch 1 taken 7916 times.
|
16273 | for (unsigned i = 0; i < oc->nb_streams; i++) { |
1989 | 8357 | MuxStream *src = ms_from_ost(mux->of.streams[i]); | |
1990 | |||
1991 |
2/2✓ Branch 0 taken 8356 times.
✓ Branch 1 taken 1 times.
|
8357 | if (!src->ost.fix_sub_duration_heartbeat) |
1992 | 8356 | continue; | |
1993 | |||
1994 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (unsigned j = 0; j < oc->nb_streams; j++) { |
1995 | 2 | MuxStream *dst = ms_from_ost(mux->of.streams[j]); | |
1996 | |||
1997 |
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 || |
1998 |
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) |
1999 | 1 | continue; | |
2000 | |||
2001 | 1 | ret = sch_mux_sub_heartbeat_add(mux->sch, mux->sch_idx, src->sch_idx, | |
2002 | 1 | dst->sch_idx_src); | |
2003 | |||
2004 | } | ||
2005 | } | ||
2006 | |||
2007 | // handle -apad | ||
2008 |
2/2✓ Branch 0 taken 4 times.
✓ Branch 1 taken 7912 times.
|
7916 | if (o->shortest) { |
2009 | 4 | int have_video = 0; | |
2010 | |||
2011 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | for (unsigned i = 0; i < mux->of.nb_streams; i++) |
2012 |
1/2✓ Branch 0 taken 4 times.
✗ Branch 1 not taken.
|
4 | if (mux->of.streams[i]->type == AVMEDIA_TYPE_VIDEO) { |
2013 | 4 | have_video = 1; | |
2014 | 4 | break; | |
2015 | } | ||
2016 | |||
2017 |
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++) { |
2018 | 8 | MuxStream *ms = ms_from_ost(mux->of.streams[i]); | |
2019 | 8 | OutputFilter *ofilter = ms->ost.filter; | |
2020 | |||
2021 |
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) |
2022 | 8 | continue; | |
2023 | |||
2024 | ✗ | ofilter->apad = av_strdup(ms->apad); | |
2025 | ✗ | if (!ofilter->apad) | |
2026 | ✗ | return AVERROR(ENOMEM); | |
2027 | } | ||
2028 | } | ||
2029 |
2/2✓ Branch 0 taken 8357 times.
✓ Branch 1 taken 7916 times.
|
16273 | for (unsigned i = 0; i < mux->of.nb_streams; i++) { |
2030 | 8357 | MuxStream *ms = ms_from_ost(mux->of.streams[i]); | |
2031 | 8357 | ms->apad = NULL; | |
2032 | } | ||
2033 | |||
2034 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7916 | if (!oc->nb_streams && !(oc->oformat->flags & AVFMT_NOSTREAMS)) { |
2035 | ✗ | av_dump_format(oc, nb_output_files - 1, oc->url, 1); | |
2036 | ✗ | av_log(mux, AV_LOG_ERROR, "Output file does not contain any stream\n"); | |
2037 | ✗ | return AVERROR(EINVAL); | |
2038 | } | ||
2039 | |||
2040 | 7916 | return 0; | |
2041 | } | ||
2042 | |||
2043 | 7916 | static int setup_sync_queues(Muxer *mux, AVFormatContext *oc, | |
2044 | int64_t buf_size_us, int shortest) | ||
2045 | { | ||
2046 | 7916 | OutputFile *of = &mux->of; | |
2047 | 7916 | int nb_av_enc = 0, nb_audio_fs = 0, nb_interleaved = 0; | |
2048 | 7916 | int limit_frames = 0, limit_frames_av_enc = 0; | |
2049 | |||
2050 | #define IS_AV_ENC(ost, type) \ | ||
2051 | (ost->enc && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) | ||
2052 | #define IS_INTERLEAVED(type) (type != AVMEDIA_TYPE_ATTACHMENT) | ||
2053 | |||
2054 |
2/2✓ Branch 0 taken 8357 times.
✓ Branch 1 taken 7916 times.
|
16273 | for (int i = 0; i < oc->nb_streams; i++) { |
2055 | 8357 | OutputStream *ost = of->streams[i]; | |
2056 | 8357 | MuxStream *ms = ms_from_ost(ost); | |
2057 | 8357 | enum AVMediaType type = ost->type; | |
2058 | |||
2059 | 8357 | ms->sq_idx_mux = -1; | |
2060 | |||
2061 | 8357 | nb_interleaved += IS_INTERLEAVED(type); | |
2062 |
6/6✓ Branch 0 taken 7696 times.
✓ Branch 1 taken 661 times.
✓ Branch 2 taken 1358 times.
✓ Branch 3 taken 6338 times.
✓ Branch 4 taken 1320 times.
✓ Branch 5 taken 38 times.
|
8357 | nb_av_enc += IS_AV_ENC(ost, type); |
2063 |
4/4✓ Branch 0 taken 7696 times.
✓ Branch 1 taken 661 times.
✓ Branch 2 taken 1320 times.
✓ Branch 3 taken 6376 times.
|
9677 | nb_audio_fs += (ost->enc && type == AVMEDIA_TYPE_AUDIO && |
2064 |
2/2✓ Branch 0 taken 163 times.
✓ Branch 1 taken 1157 times.
|
1320 | !(ost->enc->enc_ctx->codec->capabilities & AV_CODEC_CAP_VARIABLE_FRAME_SIZE)); |
2065 | |||
2066 | 8357 | limit_frames |= ms->max_frames < INT64_MAX; | |
2067 |
7/8✓ Branch 0 taken 2971 times.
✓ Branch 1 taken 5386 times.
✓ Branch 2 taken 2942 times.
✓ Branch 3 taken 29 times.
✓ Branch 4 taken 28 times.
✓ Branch 5 taken 2914 times.
✓ Branch 6 taken 28 times.
✗ Branch 7 not taken.
|
8357 | limit_frames_av_enc |= (ms->max_frames < INT64_MAX) && IS_AV_ENC(ost, type); |
2068 | } | ||
2069 | |||
2070 |
7/8✓ Branch 0 taken 238 times.
✓ Branch 1 taken 7678 times.
✓ Branch 2 taken 234 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 7912 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 4835 times.
✓ Branch 7 taken 123 times.
|
12874 | if (!((nb_interleaved > 1 && shortest) || |
2071 |
2/2✓ Branch 0 taken 4958 times.
✓ Branch 1 taken 2954 times.
|
7912 | (nb_interleaved > 0 && limit_frames) || |
2072 | nb_audio_fs)) | ||
2073 | 4835 | return 0; | |
2074 | |||
2075 | /* we use a sync queue before encoding when: | ||
2076 | * - 'shortest' is in effect and we have two or more encoded audio/video | ||
2077 | * streams | ||
2078 | * - at least one encoded audio/video stream is frame-limited, since | ||
2079 | * that has similar semantics to 'shortest' | ||
2080 | * - at least one audio encoder requires constant frame sizes | ||
2081 | * | ||
2082 | * Note that encoding sync queues are handled in the scheduler, because | ||
2083 | * different encoders run in different threads and need external | ||
2084 | * synchronization, while muxer sync queues can be handled inside the muxer | ||
2085 | */ | ||
2086 |
8/8✓ Branch 0 taken 4 times.
✓ Branch 1 taken 3077 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1 times.
✓ Branch 4 taken 138 times.
✓ Branch 5 taken 2942 times.
✓ Branch 6 taken 125 times.
✓ Branch 7 taken 13 times.
|
3081 | if ((shortest && nb_av_enc > 1) || limit_frames_av_enc || nb_audio_fs) { |
2087 | int sq_idx, ret; | ||
2088 | |||
2089 | 3068 | sq_idx = sch_add_sq_enc(mux->sch, buf_size_us, mux); | |
2090 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3068 times.
|
3068 | if (sq_idx < 0) |
2091 | ✗ | return sq_idx; | |
2092 | |||
2093 |
2/2✓ Branch 0 taken 3128 times.
✓ Branch 1 taken 3068 times.
|
6196 | for (int i = 0; i < oc->nb_streams; i++) { |
2094 | 3128 | OutputStream *ost = of->streams[i]; | |
2095 | 3128 | MuxStream *ms = ms_from_ost(ost); | |
2096 | 3128 | enum AVMediaType type = ost->type; | |
2097 | |||
2098 |
5/6✓ Branch 0 taken 3121 times.
✓ Branch 1 taken 7 times.
✓ Branch 2 taken 190 times.
✓ Branch 3 taken 2931 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 190 times.
|
3128 | if (!IS_AV_ENC(ost, type)) |
2099 | 7 | continue; | |
2100 | |||
2101 | 3121 | ret = sch_sq_add_enc(mux->sch, sq_idx, ms->sch_idx_enc, | |
2102 |
2/2✓ Branch 0 taken 2942 times.
✓ Branch 1 taken 175 times.
|
3117 | shortest || ms->max_frames < INT64_MAX, |
2103 |
2/2✓ Branch 0 taken 3117 times.
✓ Branch 1 taken 4 times.
|
3121 | ms->max_frames); |
2104 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 3121 times.
|
3121 | if (ret < 0) |
2105 | ✗ | return ret; | |
2106 | } | ||
2107 | } | ||
2108 | |||
2109 | /* if there are any additional interleaved streams, then ALL the streams | ||
2110 | * are also synchronized before sending them to the muxer */ | ||
2111 |
2/2✓ Branch 0 taken 17 times.
✓ Branch 1 taken 3064 times.
|
3081 | if (nb_interleaved > nb_av_enc) { |
2112 | 17 | mux->sq_mux = sq_alloc(SYNC_QUEUE_PACKETS, buf_size_us, mux); | |
2113 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!mux->sq_mux) |
2114 | ✗ | return AVERROR(ENOMEM); | |
2115 | |||
2116 | 17 | mux->sq_pkt = av_packet_alloc(); | |
2117 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 17 times.
|
17 | if (!mux->sq_pkt) |
2118 | ✗ | return AVERROR(ENOMEM); | |
2119 | |||
2120 |
2/2✓ Branch 0 taken 45 times.
✓ Branch 1 taken 17 times.
|
62 | for (int i = 0; i < oc->nb_streams; i++) { |
2121 | 45 | OutputStream *ost = of->streams[i]; | |
2122 | 45 | MuxStream *ms = ms_from_ost(ost); | |
2123 | 45 | enum AVMediaType type = ost->type; | |
2124 | |||
2125 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | if (!IS_INTERLEAVED(type)) |
2126 | ✗ | continue; | |
2127 | |||
2128 |
2/2✓ Branch 0 taken 39 times.
✓ Branch 1 taken 6 times.
|
84 | ms->sq_idx_mux = sq_add_stream(mux->sq_mux, |
2129 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 10 times.
|
39 | shortest || ms->max_frames < INT64_MAX); |
2130 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 45 times.
|
45 | if (ms->sq_idx_mux < 0) |
2131 | ✗ | return ms->sq_idx_mux; | |
2132 | |||
2133 |
2/2✓ Branch 0 taken 29 times.
✓ Branch 1 taken 16 times.
|
45 | if (ms->max_frames != INT64_MAX) |
2134 | 29 | sq_limit_frames(mux->sq_mux, ms->sq_idx_mux, ms->max_frames); | |
2135 | } | ||
2136 | } | ||
2137 | |||
2138 | #undef IS_AV_ENC | ||
2139 | #undef IS_INTERLEAVED | ||
2140 | |||
2141 | 3081 | return 0; | |
2142 | } | ||
2143 | |||
2144 | 10 | static int of_parse_iamf_audio_element_layers(Muxer *mux, AVStreamGroup *stg, char *ptr) | |
2145 | { | ||
2146 | 10 | AVIAMFAudioElement *audio_element = stg->params.iamf_audio_element; | |
2147 | 10 | AVDictionary *dict = NULL; | |
2148 | const char *token; | ||
2149 | 10 | int ret = 0; | |
2150 | |||
2151 | 10 | audio_element->demixing_info = | |
2152 | 10 | av_iamf_param_definition_alloc(AV_IAMF_PARAMETER_DEFINITION_DEMIXING, 1, NULL); | |
2153 | 10 | audio_element->recon_gain_info = | |
2154 | 10 | av_iamf_param_definition_alloc(AV_IAMF_PARAMETER_DEFINITION_RECON_GAIN, 1, NULL); | |
2155 | |||
2156 |
1/2✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
|
10 | if (!audio_element->demixing_info || |
2157 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 10 times.
|
10 | !audio_element->recon_gain_info) |
2158 | ✗ | return AVERROR(ENOMEM); | |
2159 | |||
2160 | /* process manually set layers and parameters */ | ||
2161 | 10 | token = av_strtok(NULL, ",", &ptr); | |
2162 |
2/2✓ Branch 0 taken 42 times.
✓ Branch 1 taken 10 times.
|
52 | while (token) { |
2163 | const AVDictionaryEntry *e; | ||
2164 | 42 | int demixing = 0, recon_gain = 0; | |
2165 | 42 | int layer = 0; | |
2166 | |||
2167 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 1 times.
|
42 | if (ptr) |
2168 | 41 | ptr += strspn(ptr, " \n\t\r"); | |
2169 |
2/2✓ Branch 1 taken 26 times.
✓ Branch 2 taken 16 times.
|
42 | if (av_strstart(token, "layer=", &token)) |
2170 | 26 | layer = 1; | |
2171 |
2/2✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
|
16 | else if (av_strstart(token, "demixing=", &token)) |
2172 | 8 | demixing = 1; | |
2173 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | else if (av_strstart(token, "recon_gain=", &token)) |
2174 | 8 | recon_gain = 1; | |
2175 | |||
2176 | 42 | av_dict_free(&dict); | |
2177 | 42 | ret = av_dict_parse_string(&dict, token, "=", ":", 0); | |
2178 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
|
42 | if (ret < 0) { |
2179 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing audio element specification %s\n", token); | |
2180 | ✗ | goto fail; | |
2181 | } | ||
2182 | |||
2183 |
2/2✓ Branch 0 taken 26 times.
✓ Branch 1 taken 16 times.
|
42 | if (layer) { |
2184 | 26 | AVIAMFLayer *audio_layer = av_iamf_audio_element_add_layer(audio_element); | |
2185 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | if (!audio_layer) { |
2186 | ✗ | av_log(mux, AV_LOG_ERROR, "Error adding layer to stream group %d\n", stg->index); | |
2187 | ✗ | ret = AVERROR(ENOMEM); | |
2188 | ✗ | goto fail; | |
2189 | } | ||
2190 | 26 | av_opt_set_dict(audio_layer, &dict); | |
2191 |
3/4✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
16 | } else if (demixing || recon_gain) { |
2192 | 16 | AVIAMFParamDefinition *param = demixing ? audio_element->demixing_info | |
2193 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 8 times.
|
16 | : audio_element->recon_gain_info; |
2194 | 16 | void *subblock = av_iamf_param_definition_get_subblock(param, 0); | |
2195 | |||
2196 | 16 | av_opt_set_dict(param, &dict); | |
2197 | 16 | av_opt_set_dict(subblock, &dict); | |
2198 | } | ||
2199 | |||
2200 | // make sure that no entries are left in the dict | ||
2201 | 42 | e = NULL; | |
2202 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
|
42 | if (e = av_dict_iterate(dict, e)) { |
2203 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown layer key %s.\n", e->key); | |
2204 | ✗ | ret = AVERROR(EINVAL); | |
2205 | ✗ | goto fail; | |
2206 | } | ||
2207 | 42 | token = av_strtok(NULL, ",", &ptr); | |
2208 | } | ||
2209 | |||
2210 | 10 | fail: | |
2211 | 10 | av_dict_free(&dict); | |
2212 |
2/4✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 10 times.
|
10 | if (!ret && !audio_element->nb_layers) { |
2213 | ✗ | av_log(mux, AV_LOG_ERROR, "No layer in audio element specification\n"); | |
2214 | ✗ | ret = AVERROR(EINVAL); | |
2215 | } | ||
2216 | |||
2217 | 10 | return ret; | |
2218 | } | ||
2219 | |||
2220 | 10 | static int of_parse_iamf_submixes(Muxer *mux, AVStreamGroup *stg, char *ptr) | |
2221 | { | ||
2222 | 10 | AVFormatContext *oc = mux->fc; | |
2223 | 10 | AVIAMFMixPresentation *mix = stg->params.iamf_mix_presentation; | |
2224 | 10 | AVDictionary *dict = NULL; | |
2225 | const char *token; | ||
2226 | 10 | char *submix_str = NULL; | |
2227 | 10 | int ret = 0; | |
2228 | |||
2229 | /* process manually set submixes */ | ||
2230 | 10 | token = av_strtok(NULL, ",", &ptr); | |
2231 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 10 times.
|
22 | while (token) { |
2232 | 12 | AVIAMFSubmix *submix = NULL; | |
2233 | const char *subtoken; | ||
2234 | 12 | char *subptr = NULL; | |
2235 | |||
2236 |
2/2✓ Branch 0 taken 11 times.
✓ Branch 1 taken 1 times.
|
12 | if (ptr) |
2237 | 11 | ptr += strspn(ptr, " \n\t\r"); | |
2238 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
|
12 | if (!av_strstart(token, "submix=", &token)) { |
2239 | ✗ | av_log(mux, AV_LOG_ERROR, "No submix in mix presentation specification \"%s\"\n", token); | |
2240 | ✗ | goto fail; | |
2241 | } | ||
2242 | |||
2243 | 12 | submix_str = av_strdup(token); | |
2244 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (!submix_str) |
2245 | ✗ | goto fail; | |
2246 | |||
2247 | 12 | submix = av_iamf_mix_presentation_add_submix(mix); | |
2248 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (!submix) { |
2249 | ✗ | av_log(mux, AV_LOG_ERROR, "Error adding submix to stream group %d\n", stg->index); | |
2250 | ✗ | ret = AVERROR(ENOMEM); | |
2251 | ✗ | goto fail; | |
2252 | } | ||
2253 | 12 | submix->output_mix_config = | |
2254 | 12 | av_iamf_param_definition_alloc(AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN, 0, NULL); | |
2255 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (!submix->output_mix_config) { |
2256 | ✗ | ret = AVERROR(ENOMEM); | |
2257 | ✗ | goto fail; | |
2258 | } | ||
2259 | |||
2260 | 12 | subptr = NULL; | |
2261 | 12 | subtoken = av_strtok(submix_str, "|", &subptr); | |
2262 |
2/2✓ Branch 0 taken 52 times.
✓ Branch 1 taken 12 times.
|
64 | while (subtoken) { |
2263 | const AVDictionaryEntry *e; | ||
2264 | 52 | int element = 0, layout = 0; | |
2265 | |||
2266 |
2/2✓ Branch 0 taken 40 times.
✓ Branch 1 taken 12 times.
|
52 | if (subptr) |
2267 | 40 | subptr += strspn(subptr, " \n\t\r"); | |
2268 |
2/2✓ Branch 1 taken 12 times.
✓ Branch 2 taken 40 times.
|
52 | if (av_strstart(subtoken, "element=", &subtoken)) |
2269 | 12 | element = 1; | |
2270 |
2/2✓ Branch 1 taken 28 times.
✓ Branch 2 taken 12 times.
|
40 | else if (av_strstart(subtoken, "layout=", &subtoken)) |
2271 | 28 | layout = 1; | |
2272 | |||
2273 | 52 | av_dict_free(&dict); | |
2274 | 52 | ret = av_dict_parse_string(&dict, subtoken, "=", ":", 0); | |
2275 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (ret < 0) { |
2276 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing submix specification \"%s\"\n", subtoken); | |
2277 | ✗ | goto fail; | |
2278 | } | ||
2279 | |||
2280 |
2/2✓ Branch 0 taken 12 times.
✓ Branch 1 taken 40 times.
|
52 | if (element) { |
2281 | AVIAMFSubmixElement *submix_element; | ||
2282 | 12 | char *endptr = NULL; | |
2283 | 12 | int64_t idx = -1; | |
2284 | |||
2285 |
1/2✓ Branch 1 taken 12 times.
✗ Branch 2 not taken.
|
12 | if (e = av_dict_get(dict, "stg", NULL, 0)) |
2286 | 12 | idx = strtoll(e->value, &endptr, 0); | |
2287 |
4/8✓ Branch 0 taken 12 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 12 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 12 times.
✗ Branch 7 not taken.
|
12 | if (!endptr || *endptr || idx < 0 || idx >= oc->nb_stream_groups - 1 || |
2288 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | oc->stream_groups[idx]->type != AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT) { |
2289 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid or missing stream group index in " | |
2290 | "submix element specification \"%s\"\n", subtoken); | ||
2291 | ✗ | ret = AVERROR(EINVAL); | |
2292 | ✗ | goto fail; | |
2293 | } | ||
2294 | 12 | submix_element = av_iamf_submix_add_element(submix); | |
2295 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (!submix_element) { |
2296 | ✗ | av_log(mux, AV_LOG_ERROR, "Error adding element to submix\n"); | |
2297 | ✗ | ret = AVERROR(ENOMEM); | |
2298 | ✗ | goto fail; | |
2299 | } | ||
2300 | |||
2301 | 12 | submix_element->audio_element_id = oc->stream_groups[idx]->id; | |
2302 | |||
2303 | 12 | submix_element->element_mix_config = | |
2304 | 12 | av_iamf_param_definition_alloc(AV_IAMF_PARAMETER_DEFINITION_MIX_GAIN, 0, NULL); | |
2305 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (!submix_element->element_mix_config) |
2306 | ✗ | ret = AVERROR(ENOMEM); | |
2307 | 12 | av_dict_set(&dict, "stg", NULL, 0); | |
2308 | 12 | av_opt_set_dict2(submix_element, &dict, AV_OPT_SEARCH_CHILDREN); | |
2309 |
2/2✓ Branch 0 taken 28 times.
✓ Branch 1 taken 12 times.
|
40 | } else if (layout) { |
2310 | 28 | AVIAMFSubmixLayout *submix_layout = av_iamf_submix_add_layout(submix); | |
2311 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
|
28 | if (!submix_layout) { |
2312 | ✗ | av_log(mux, AV_LOG_ERROR, "Error adding layout to submix\n"); | |
2313 | ✗ | ret = AVERROR(ENOMEM); | |
2314 | ✗ | goto fail; | |
2315 | } | ||
2316 | 28 | av_opt_set_dict(submix_layout, &dict); | |
2317 | } else | ||
2318 | 12 | av_opt_set_dict2(submix, &dict, AV_OPT_SEARCH_CHILDREN); | |
2319 | |||
2320 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 52 times.
|
52 | if (ret < 0) { |
2321 | ✗ | goto fail; | |
2322 | } | ||
2323 | |||
2324 | // make sure that no entries are left in the dict | ||
2325 | 52 | e = NULL; | |
2326 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 52 times.
|
52 | while (e = av_dict_iterate(dict, e)) { |
2327 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown submix key %s.\n", e->key); | |
2328 | ✗ | ret = AVERROR(EINVAL); | |
2329 | ✗ | goto fail; | |
2330 | } | ||
2331 | 52 | subtoken = av_strtok(NULL, "|", &subptr); | |
2332 | } | ||
2333 | 12 | av_freep(&submix_str); | |
2334 | |||
2335 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (!submix->nb_elements) { |
2336 | ✗ | av_log(mux, AV_LOG_ERROR, "No audio elements in submix specification \"%s\"\n", token); | |
2337 | ✗ | ret = AVERROR(EINVAL); | |
2338 | } | ||
2339 | 12 | token = av_strtok(NULL, ",", &ptr); | |
2340 | } | ||
2341 | |||
2342 | 10 | fail: | |
2343 | 10 | av_dict_free(&dict); | |
2344 | 10 | av_free(submix_str); | |
2345 | |||
2346 | 10 | return ret; | |
2347 | } | ||
2348 | |||
2349 | 12 | static int of_serialize_options(Muxer *mux, void *obj, AVBPrint *bp) | |
2350 | { | ||
2351 | char *ptr; | ||
2352 | int ret; | ||
2353 | |||
2354 | 12 | ret = av_opt_serialize(obj, 0, AV_OPT_SERIALIZE_SKIP_DEFAULTS | AV_OPT_SERIALIZE_SEARCH_CHILDREN, | |
2355 | &ptr, '=', ':'); | ||
2356 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 12 times.
|
12 | if (ret < 0) { |
2357 | ✗ | av_log(mux, AV_LOG_ERROR, "Failed to serialize group\n"); | |
2358 | ✗ | return ret; | |
2359 | } | ||
2360 | |||
2361 | 12 | av_bprintf(bp, "%s", ptr); | |
2362 | 12 | ret = strlen(ptr); | |
2363 | 12 | av_free(ptr); | |
2364 | |||
2365 | 12 | return ret; | |
2366 | } | ||
2367 | |||
2368 | #define SERIALIZE(parent, child) do { \ | ||
2369 | ret = of_serialize_options(mux, parent->child, bp); \ | ||
2370 | if (ret < 0) \ | ||
2371 | return ret; \ | ||
2372 | } while (0) | ||
2373 | |||
2374 | #define SERIALIZE_LOOP_SUBBLOCK(obj) do { \ | ||
2375 | for (int k = 0; k < obj->nb_subblocks; k++) { \ | ||
2376 | ret = of_serialize_options(mux, \ | ||
2377 | av_iamf_param_definition_get_subblock(obj, k), bp); \ | ||
2378 | if (ret < 0) \ | ||
2379 | return ret; \ | ||
2380 | } \ | ||
2381 | } while (0) | ||
2382 | |||
2383 | #define SERIALIZE_LOOP(parent, child, suffix, separator) do { \ | ||
2384 | for (int j = 0; j < parent->nb_## child ## suffix; j++) { \ | ||
2385 | av_bprintf(bp, separator#child "="); \ | ||
2386 | SERIALIZE(parent, child ## suffix[j]); \ | ||
2387 | } \ | ||
2388 | } while (0) | ||
2389 | |||
2390 | 1 | static int64_t get_stream_group_index_from_id(Muxer *mux, int64_t id) | |
2391 | { | ||
2392 | 1 | AVFormatContext *oc = mux->fc; | |
2393 | |||
2394 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | for (unsigned i = 0; i < oc->nb_stream_groups; i++) |
2395 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (oc->stream_groups[i]->id == id) |
2396 | 1 | return oc->stream_groups[i]->index; | |
2397 | |||
2398 | ✗ | return AVERROR(EINVAL); | |
2399 | } | ||
2400 | |||
2401 | 2 | static int of_map_group(Muxer *mux, AVDictionary **dict, AVBPrint *bp, const char *map) | |
2402 | { | ||
2403 | AVStreamGroup *stg; | ||
2404 | int ret, file_idx, stream_idx; | ||
2405 | char *ptr; | ||
2406 | |||
2407 | 2 | file_idx = strtol(map, &ptr, 0); | |
2408 |
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) { |
2409 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid input file index: %d.\n", file_idx); | |
2410 | ✗ | return AVERROR(EINVAL); | |
2411 | } | ||
2412 | |||
2413 |
1/2✓ Branch 0 taken 2 times.
✗ Branch 1 not taken.
|
2 | stream_idx = strtol(*ptr == '=' ? ptr + 1 : ptr, &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 (*ptr || stream_idx >= input_files[file_idx]->ctx->nb_stream_groups || stream_idx < 0) { |
2415 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid input stream group index: %d.\n", stream_idx); | |
2416 | ✗ | return AVERROR(EINVAL); | |
2417 | } | ||
2418 | |||
2419 | 2 | stg = input_files[file_idx]->ctx->stream_groups[stream_idx]; | |
2420 | 2 | ret = of_serialize_options(mux, stg, bp); | |
2421 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) |
2422 | ✗ | return ret; | |
2423 | |||
2424 | 2 | ret = av_dict_parse_string(dict, bp->str, "=", ":", 0); | |
2425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) |
2426 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing mapped group specification %s\n", ptr); | |
2427 | 2 | av_dict_set_int(dict, "type", stg->type, 0); | |
2428 | |||
2429 | 2 | av_bprint_clear(bp); | |
2430 |
2/3✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
|
2 | switch(stg->type) { |
2431 | 1 | case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: { | |
2432 | 1 | AVIAMFAudioElement *audio_element = stg->params.iamf_audio_element; | |
2433 | |||
2434 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (audio_element->demixing_info) { |
2435 | 1 | AVIAMFParamDefinition *demixing_info = audio_element->demixing_info; | |
2436 | 1 | av_bprintf(bp, ",demixing="); | |
2437 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | SERIALIZE(audio_element, demixing_info); |
2438 |
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) |
2439 | 1 | av_bprintf(bp, ":"); | |
2440 |
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); |
2441 | } | ||
2442 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (audio_element->recon_gain_info) { |
2443 | 1 | AVIAMFParamDefinition *recon_gain_info = audio_element->recon_gain_info; | |
2444 | 1 | av_bprintf(bp, ",recon_gain="); | |
2445 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | SERIALIZE(audio_element, recon_gain_info); |
2446 |
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) |
2447 | 1 | av_bprintf(bp, ":"); | |
2448 |
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); |
2449 | } | ||
2450 |
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, ","); |
2451 | 1 | break; | |
2452 | } | ||
2453 | 1 | case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: { | |
2454 | 1 | AVIAMFMixPresentation *mix = stg->params.iamf_mix_presentation; | |
2455 | |||
2456 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int i = 0; i < mix->nb_submixes; i++) { |
2457 | 1 | AVIAMFSubmix *submix = mix->submixes[i]; | |
2458 | 1 | AVIAMFParamDefinition *output_mix_config = submix->output_mix_config; | |
2459 | |||
2460 | 1 | av_bprintf(bp, ",submix="); | |
2461 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | SERIALIZE(mix, submixes[i]); |
2462 |
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) |
2463 | ✗ | av_bprintf(bp, ":"); | |
2464 |
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); |
2465 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | for (int j = 0; j < submix->nb_elements; j++) { |
2466 | 1 | AVIAMFSubmixElement *element = submix->elements[j]; | |
2467 | 1 | AVIAMFParamDefinition *element_mix_config = element->element_mix_config; | |
2468 | 1 | int64_t id = get_stream_group_index_from_id(mux, element->audio_element_id); | |
2469 | |||
2470 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (id < 0) { |
2471 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid or missing stream group index in" | |
2472 | "submix element"); | ||
2473 | ✗ | return id; | |
2474 | } | ||
2475 | |||
2476 | 1 | av_bprintf(bp, "|element="); | |
2477 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1 times.
|
1 | SERIALIZE(submix, elements[j]); |
2478 |
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) |
2479 | ✗ | av_bprintf(bp, ":"); | |
2480 |
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); |
2481 |
1/2✓ Branch 0 taken 1 times.
✗ Branch 1 not taken.
|
1 | if (ret) |
2482 | 1 | av_bprintf(bp, ":"); | |
2483 | 1 | av_bprintf(bp, "stg=%"PRId64, id); | |
2484 | } | ||
2485 |
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, "|"); |
2486 | } | ||
2487 | 1 | break; | |
2488 | } | ||
2489 | ✗ | default: | |
2490 | ✗ | av_log(mux, AV_LOG_ERROR, "Unsupported mapped group type %d.\n", stg->type); | |
2491 | ✗ | ret = AVERROR(EINVAL); | |
2492 | ✗ | break; | |
2493 | } | ||
2494 | 2 | return 0; | |
2495 | } | ||
2496 | |||
2497 | 20 | static int of_parse_group_token(Muxer *mux, const char *token, char *ptr) | |
2498 | { | ||
2499 | 20 | AVFormatContext *oc = mux->fc; | |
2500 | AVStreamGroup *stg; | ||
2501 | 20 | AVDictionary *dict = NULL, *tmp = NULL; | |
2502 | 20 | char *mapped_string = NULL; | |
2503 | const AVDictionaryEntry *e; | ||
2504 | 20 | const AVOption opts[] = { | |
2505 | { "type", "Set group type", offsetof(AVStreamGroup, type), AV_OPT_TYPE_INT, | ||
2506 | { .i64 = 0 }, 0, INT_MAX, AV_OPT_FLAG_ENCODING_PARAM, .unit = "type" }, | ||
2507 | { "iamf_audio_element", NULL, 0, AV_OPT_TYPE_CONST, | ||
2508 | { .i64 = AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT }, .unit = "type" }, | ||
2509 | { "iamf_mix_presentation", NULL, 0, AV_OPT_TYPE_CONST, | ||
2510 | { .i64 = AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION }, .unit = "type" }, | ||
2511 | { NULL }, | ||
2512 | }; | ||
2513 | 20 | const AVClass class = { | |
2514 | .class_name = "StreamGroupType", | ||
2515 | .item_name = av_default_item_name, | ||
2516 | .option = opts, | ||
2517 | .version = LIBAVUTIL_VERSION_INT, | ||
2518 | }; | ||
2519 | 20 | const AVClass *pclass = &class; | |
2520 | int type, ret; | ||
2521 | |||
2522 | 20 | ret = av_dict_parse_string(&dict, token, "=", ":", AV_DICT_MULTIKEY); | |
2523 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (ret < 0) { |
2524 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing group specification %s\n", token); | |
2525 | ✗ | return ret; | |
2526 | } | ||
2527 | |||
2528 | 20 | av_dict_copy(&tmp, dict, 0); | |
2529 | 20 | e = av_dict_get(dict, "map", NULL, 0); | |
2530 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 18 times.
|
20 | if (e) { |
2531 | AVBPrint bp; | ||
2532 | |||
2533 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ptr) { |
2534 | ✗ | av_log(mux, AV_LOG_ERROR, "Unexpected extra parameters when mapping a" | |
2535 | " stream group\n"); | ||
2536 | ✗ | ret = AVERROR(EINVAL); | |
2537 | ✗ | goto end; | |
2538 | } | ||
2539 | |||
2540 | 2 | av_bprint_init(&bp, 0, AV_BPRINT_SIZE_AUTOMATIC); | |
2541 | 2 | ret = of_map_group(mux, &tmp, &bp, e->value); | |
2542 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) { |
2543 | ✗ | av_bprint_finalize(&bp, NULL); | |
2544 | ✗ | goto end; | |
2545 | } | ||
2546 | |||
2547 | 2 | av_bprint_finalize(&bp, &mapped_string); | |
2548 | 2 | ptr = mapped_string; | |
2549 | } | ||
2550 | |||
2551 | // "type" is not a user settable AVOption in AVStreamGroup, so handle it here | ||
2552 | 20 | e = av_dict_get(tmp, "type", NULL, 0); | |
2553 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (!e) { |
2554 | ✗ | av_log(mux, AV_LOG_ERROR, "No type specified for Stream Group in \"%s\"\n", token); | |
2555 | ✗ | ret = AVERROR(EINVAL); | |
2556 | ✗ | goto end; | |
2557 | } | ||
2558 | |||
2559 | 20 | ret = av_opt_eval_int(&pclass, opts, e->value, &type); | |
2560 |
2/4✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 20 times.
|
20 | if (!ret && type == AV_STREAM_GROUP_PARAMS_NONE) |
2561 | ✗ | ret = AVERROR(EINVAL); | |
2562 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (ret < 0) { |
2563 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid group type \"%s\"\n", e->value); | |
2564 | ✗ | goto end; | |
2565 | } | ||
2566 | |||
2567 | 20 | stg = avformat_stream_group_create(oc, type, &tmp); | |
2568 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (!stg) { |
2569 | ✗ | ret = AVERROR(ENOMEM); | |
2570 | ✗ | goto end; | |
2571 | } | ||
2572 | |||
2573 | 20 | e = NULL; | |
2574 |
2/2✓ Branch 1 taken 47 times.
✓ Branch 2 taken 20 times.
|
67 | while (e = av_dict_get(dict, "st", e, 0)) { |
2575 | char *endptr; | ||
2576 | 47 | int64_t idx = strtoll(e->value, &endptr, 0); | |
2577 |
3/6✓ Branch 0 taken 47 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 47 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 47 times.
|
47 | if (*endptr || idx < 0 || idx >= oc->nb_streams) { |
2578 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid stream index %"PRId64"\n", idx); | |
2579 | ✗ | ret = AVERROR(EINVAL); | |
2580 | ✗ | goto end; | |
2581 | } | ||
2582 | 47 | ret = avformat_stream_group_add_stream(stg, oc->streams[idx]); | |
2583 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
|
47 | if (ret < 0) |
2584 | ✗ | goto end; | |
2585 | } | ||
2586 |
2/2✓ Branch 1 taken 10 times.
✓ Branch 2 taken 20 times.
|
30 | while (e = av_dict_get(dict, "stg", e, 0)) { |
2587 | char *endptr; | ||
2588 | 10 | int64_t idx = strtoll(e->value, &endptr, 0); | |
2589 |
3/6✓ Branch 0 taken 10 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 10 times.
|
10 | if (*endptr || idx < 0 || idx >= oc->nb_stream_groups - 1) { |
2590 | ✗ | av_log(mux, AV_LOG_ERROR, "Invalid stream group index %"PRId64"\n", idx); | |
2591 | ✗ | ret = AVERROR(EINVAL); | |
2592 | ✗ | goto end; | |
2593 | } | ||
2594 |
2/2✓ Branch 0 taken 47 times.
✓ Branch 1 taken 10 times.
|
57 | for (unsigned i = 0; i < oc->stream_groups[idx]->nb_streams; i++) { |
2595 | 47 | ret = avformat_stream_group_add_stream(stg, oc->stream_groups[idx]->streams[i]); | |
2596 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 47 times.
|
47 | if (ret < 0) |
2597 | ✗ | goto end; | |
2598 | } | ||
2599 | } | ||
2600 | |||
2601 |
2/3✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
|
20 | switch(type) { |
2602 | 10 | case AV_STREAM_GROUP_PARAMS_IAMF_AUDIO_ELEMENT: | |
2603 | 10 | ret = of_parse_iamf_audio_element_layers(mux, stg, ptr); | |
2604 | 10 | break; | |
2605 | 10 | case AV_STREAM_GROUP_PARAMS_IAMF_MIX_PRESENTATION: | |
2606 | 10 | ret = of_parse_iamf_submixes(mux, stg, ptr); | |
2607 | 10 | break; | |
2608 | ✗ | default: | |
2609 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown group type %d.\n", type); | |
2610 | ✗ | ret = AVERROR(EINVAL); | |
2611 | ✗ | break; | |
2612 | } | ||
2613 | |||
2614 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (ret < 0) |
2615 | ✗ | goto end; | |
2616 | |||
2617 | // make sure that nothing but "st" and "stg" entries are left in the dict | ||
2618 | 20 | e = NULL; | |
2619 | 20 | av_dict_set(&tmp, "map", NULL, 0); | |
2620 | 20 | av_dict_set(&tmp, "type", NULL, 0); | |
2621 |
2/2✓ Branch 1 taken 20 times.
✓ Branch 2 taken 20 times.
|
40 | while (e = av_dict_iterate(tmp, e)) { |
2622 |
3/4✓ Branch 0 taken 10 times.
✓ Branch 1 taken 10 times.
✓ Branch 2 taken 10 times.
✗ Branch 3 not taken.
|
20 | if (!strcmp(e->key, "st") || !strcmp(e->key, "stg")) |
2623 | 20 | continue; | |
2624 | |||
2625 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown group key %s.\n", e->key); | |
2626 | ✗ | ret = AVERROR(EINVAL); | |
2627 | ✗ | goto end; | |
2628 | } | ||
2629 | |||
2630 | 20 | ret = 0; | |
2631 | 20 | end: | |
2632 | 20 | av_free(mapped_string); | |
2633 | 20 | av_dict_free(&dict); | |
2634 | 20 | av_dict_free(&tmp); | |
2635 | |||
2636 | 20 | return ret; | |
2637 | } | ||
2638 | |||
2639 | 7916 | static int of_add_groups(Muxer *mux, const OptionsContext *o) | |
2640 | { | ||
2641 | /* process manually set groups */ | ||
2642 |
2/2✓ Branch 0 taken 20 times.
✓ Branch 1 taken 7916 times.
|
7936 | for (int i = 0; i < o->stream_groups.nb_opt; i++) { |
2643 | const char *token; | ||
2644 | 20 | char *str, *ptr = NULL; | |
2645 | 20 | int ret = 0; | |
2646 | |||
2647 | 20 | str = av_strdup(o->stream_groups.opt[i].u.str); | |
2648 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (!str) |
2649 | ✗ | return ret; | |
2650 | |||
2651 | 20 | token = av_strtok(str, ",", &ptr); | |
2652 |
1/2✓ Branch 0 taken 20 times.
✗ Branch 1 not taken.
|
20 | if (token) { |
2653 |
2/2✓ Branch 0 taken 18 times.
✓ Branch 1 taken 2 times.
|
20 | if (ptr) |
2654 | 18 | ptr += strspn(ptr, " \n\t\r"); | |
2655 | 20 | ret = of_parse_group_token(mux, token, ptr); | |
2656 | } | ||
2657 | |||
2658 | 20 | av_free(str); | |
2659 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 20 times.
|
20 | if (ret < 0) |
2660 | ✗ | return ret; | |
2661 | } | ||
2662 | |||
2663 | 7916 | return 0; | |
2664 | } | ||
2665 | |||
2666 | 7916 | static int of_add_programs(Muxer *mux, const OptionsContext *o) | |
2667 | { | ||
2668 | 7916 | AVFormatContext *oc = mux->fc; | |
2669 | /* process manually set programs */ | ||
2670 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | for (int i = 0; i < o->program.nb_opt; i++) { |
2671 | ✗ | AVDictionary *dict = NULL; | |
2672 | const AVDictionaryEntry *e; | ||
2673 | AVProgram *program; | ||
2674 | ✗ | int ret, progid = i + 1; | |
2675 | |||
2676 | ✗ | ret = av_dict_parse_string(&dict, o->program.opt[i].u.str, "=", ":", | |
2677 | AV_DICT_MULTIKEY); | ||
2678 | ✗ | if (ret < 0) { | |
2679 | ✗ | av_log(mux, AV_LOG_ERROR, "Error parsing program specification %s\n", | |
2680 | ✗ | o->program.opt[i].u.str); | |
2681 | ✗ | return ret; | |
2682 | } | ||
2683 | |||
2684 | ✗ | e = av_dict_get(dict, "program_num", NULL, 0); | |
2685 | ✗ | if (e) { | |
2686 | ✗ | progid = strtol(e->value, NULL, 0); | |
2687 | ✗ | av_dict_set(&dict, e->key, NULL, 0); | |
2688 | } | ||
2689 | |||
2690 | ✗ | program = av_new_program(oc, progid); | |
2691 | ✗ | if (!program) { | |
2692 | ✗ | ret = AVERROR(ENOMEM); | |
2693 | ✗ | goto fail; | |
2694 | } | ||
2695 | |||
2696 | ✗ | e = av_dict_get(dict, "title", NULL, 0); | |
2697 | ✗ | if (e) { | |
2698 | ✗ | av_dict_set(&program->metadata, e->key, e->value, 0); | |
2699 | ✗ | av_dict_set(&dict, e->key, NULL, 0); | |
2700 | } | ||
2701 | |||
2702 | ✗ | e = NULL; | |
2703 | ✗ | while (e = av_dict_get(dict, "st", e, 0)) { | |
2704 | ✗ | int st_num = strtol(e->value, NULL, 0); | |
2705 | ✗ | av_program_add_stream_index(oc, progid, st_num); | |
2706 | } | ||
2707 | |||
2708 | // make sure that nothing but "st" entries are left in the dict | ||
2709 | ✗ | e = NULL; | |
2710 | ✗ | while (e = av_dict_iterate(dict, e)) { | |
2711 | ✗ | if (!strcmp(e->key, "st")) | |
2712 | ✗ | continue; | |
2713 | |||
2714 | ✗ | av_log(mux, AV_LOG_FATAL, "Unknown program key %s.\n", e->key); | |
2715 | ✗ | ret = AVERROR(EINVAL); | |
2716 | ✗ | goto fail; | |
2717 | } | ||
2718 | |||
2719 | ✗ | fail: | |
2720 | ✗ | av_dict_free(&dict); | |
2721 | ✗ | if (ret < 0) | |
2722 | ✗ | return ret; | |
2723 | } | ||
2724 | |||
2725 | 7916 | return 0; | |
2726 | } | ||
2727 | |||
2728 | /** | ||
2729 | * Parse a metadata specifier passed as 'arg' parameter. | ||
2730 | * @param arg metadata string to parse | ||
2731 | * @param type metadata type is written here -- g(lobal)/s(tream)/c(hapter)/p(rogram) | ||
2732 | * @param index for type c/p, chapter/program index is written here | ||
2733 | * @param stream_spec for type s, the stream specifier is written here | ||
2734 | */ | ||
2735 | 234 | static int parse_meta_type(void *logctx, const char *arg, | |
2736 | char *type, int *index, const char **stream_spec) | ||
2737 | { | ||
2738 |
2/2✓ Branch 0 taken 71 times.
✓ Branch 1 taken 163 times.
|
234 | if (*arg) { |
2739 | 71 | *type = *arg; | |
2740 |
3/4✓ Branch 0 taken 21 times.
✓ Branch 1 taken 46 times.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
71 | switch (*arg) { |
2741 | 21 | case 'g': | |
2742 | 21 | break; | |
2743 | 46 | case 's': | |
2744 |
2/4✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 46 times.
|
46 | if (*(++arg) && *arg != ':') { |
2745 | ✗ | av_log(logctx, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", arg); | |
2746 | ✗ | return AVERROR(EINVAL); | |
2747 | } | ||
2748 |
1/2✓ Branch 0 taken 46 times.
✗ Branch 1 not taken.
|
46 | *stream_spec = *arg == ':' ? arg + 1 : ""; |
2749 | 46 | break; | |
2750 | 4 | case 'c': | |
2751 | case 'p': | ||
2752 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | if (*(++arg) == ':') |
2753 | 3 | *index = strtol(++arg, NULL, 0); | |
2754 | 4 | break; | |
2755 | ✗ | default: | |
2756 | ✗ | av_log(logctx, AV_LOG_FATAL, "Invalid metadata type %c.\n", *arg); | |
2757 | ✗ | return AVERROR(EINVAL); | |
2758 | } | ||
2759 | } else | ||
2760 | 163 | *type = 'g'; | |
2761 | |||
2762 | 234 | return 0; | |
2763 | } | ||
2764 | |||
2765 | 7916 | static int of_add_metadata(OutputFile *of, AVFormatContext *oc, | |
2766 | const OptionsContext *o) | ||
2767 | { | ||
2768 |
2/2✓ Branch 0 taken 220 times.
✓ Branch 1 taken 7916 times.
|
8136 | for (int i = 0; i < o->metadata.nb_opt; i++) { |
2769 | AVDictionary **m; | ||
2770 | char type, *val; | ||
2771 | const char *stream_spec; | ||
2772 | 220 | int index = 0, ret = 0; | |
2773 | |||
2774 | 220 | val = strchr(o->metadata.opt[i].u.str, '='); | |
2775 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | if (!val) { |
2776 | ✗ | av_log(of, AV_LOG_FATAL, "No '=' character in metadata string %s.\n", | |
2777 | ✗ | o->metadata.opt[i].u.str); | |
2778 | ✗ | return AVERROR(EINVAL); | |
2779 | } | ||
2780 | 220 | *val++ = 0; | |
2781 | |||
2782 | 220 | ret = parse_meta_type(of, o->metadata.opt[i].specifier, &type, &index, &stream_spec); | |
2783 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 220 times.
|
220 | if (ret < 0) |
2784 | ✗ | return ret; | |
2785 | |||
2786 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 179 times.
|
220 | if (type == 's') { |
2787 |
2/2✓ Branch 0 taken 219 times.
✓ Branch 1 taken 41 times.
|
260 | for (int j = 0; j < oc->nb_streams; j++) { |
2788 |
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) { |
2789 |
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); |
2790 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 178 times.
|
178 | } else if (ret < 0) |
2791 | ✗ | return ret; | |
2792 | } | ||
2793 | } else { | ||
2794 |
2/4✓ Branch 0 taken 175 times.
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
179 | switch (type) { |
2795 | 175 | case 'g': | |
2796 | 175 | m = &oc->metadata; | |
2797 | 175 | break; | |
2798 | 4 | case 'c': | |
2799 |
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) { |
2800 | ✗ | av_log(of, AV_LOG_FATAL, "Invalid chapter index %d in metadata specifier.\n", index); | |
2801 | ✗ | return AVERROR(EINVAL); | |
2802 | } | ||
2803 | 4 | m = &oc->chapters[index]->metadata; | |
2804 | 4 | break; | |
2805 | ✗ | case 'p': | |
2806 | ✗ | if (index < 0 || index >= oc->nb_programs) { | |
2807 | ✗ | av_log(of, AV_LOG_FATAL, "Invalid program index %d in metadata specifier.\n", index); | |
2808 | ✗ | return AVERROR(EINVAL); | |
2809 | } | ||
2810 | ✗ | m = &oc->programs[index]->metadata; | |
2811 | ✗ | break; | |
2812 | ✗ | default: | |
2813 | ✗ | av_log(of, AV_LOG_FATAL, "Invalid metadata specifier %s.\n", o->metadata.opt[i].specifier); | |
2814 | ✗ | return AVERROR(EINVAL); | |
2815 | } | ||
2816 |
2/2✓ Branch 0 taken 178 times.
✓ Branch 1 taken 1 times.
|
179 | av_dict_set(m, o->metadata.opt[i].u.str, *val ? val : NULL, 0); |
2817 | } | ||
2818 | } | ||
2819 | |||
2820 | 7916 | return 0; | |
2821 | } | ||
2822 | |||
2823 | 19 | static int copy_chapters(InputFile *ifile, OutputFile *ofile, AVFormatContext *os, | |
2824 | int copy_metadata) | ||
2825 | { | ||
2826 | 19 | AVFormatContext *is = ifile->ctx; | |
2827 | AVChapter **tmp; | ||
2828 | |||
2829 | 19 | tmp = av_realloc_f(os->chapters, is->nb_chapters + os->nb_chapters, sizeof(*os->chapters)); | |
2830 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 19 times.
|
19 | if (!tmp) |
2831 | ✗ | return AVERROR(ENOMEM); | |
2832 | 19 | os->chapters = tmp; | |
2833 | |||
2834 |
2/2✓ Branch 0 taken 37 times.
✓ Branch 1 taken 16 times.
|
53 | for (int i = 0; i < is->nb_chapters; i++) { |
2835 | 37 | AVChapter *in_ch = is->chapters[i], *out_ch; | |
2836 |
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; |
2837 | 37 | int64_t ts_off = av_rescale_q(start_time - ifile->ts_offset, | |
2838 | 37 | AV_TIME_BASE_Q, in_ch->time_base); | |
2839 |
2/2✓ Branch 0 taken 5 times.
✓ Branch 1 taken 32 times.
|
37 | int64_t rt = (ofile->recording_time == INT64_MAX) ? INT64_MAX : |
2840 | 5 | av_rescale_q(ofile->recording_time, AV_TIME_BASE_Q, in_ch->time_base); | |
2841 | |||
2842 | |||
2843 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 37 times.
|
37 | if (in_ch->end < ts_off) |
2844 | ✗ | continue; | |
2845 |
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) |
2846 | 3 | break; | |
2847 | |||
2848 | 34 | out_ch = av_mallocz(sizeof(AVChapter)); | |
2849 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 34 times.
|
34 | if (!out_ch) |
2850 | ✗ | return AVERROR(ENOMEM); | |
2851 | |||
2852 | 34 | out_ch->id = in_ch->id; | |
2853 | 34 | out_ch->time_base = in_ch->time_base; | |
2854 | 34 | out_ch->start = FFMAX(0, in_ch->start - ts_off); | |
2855 | 34 | out_ch->end = FFMIN(rt, in_ch->end - ts_off); | |
2856 | |||
2857 |
1/2✓ Branch 0 taken 34 times.
✗ Branch 1 not taken.
|
34 | if (copy_metadata) |
2858 | 34 | av_dict_copy(&out_ch->metadata, in_ch->metadata, 0); | |
2859 | |||
2860 | 34 | os->chapters[os->nb_chapters++] = out_ch; | |
2861 | } | ||
2862 | 19 | return 0; | |
2863 | } | ||
2864 | |||
2865 | 7 | static int copy_metadata(Muxer *mux, AVFormatContext *ic, | |
2866 | const char *outspec, const char *inspec, | ||
2867 | int *metadata_global_manual, int *metadata_streams_manual, | ||
2868 | int *metadata_chapters_manual) | ||
2869 | { | ||
2870 | 7 | AVFormatContext *oc = mux->fc; | |
2871 | 7 | AVDictionary **meta_in = NULL; | |
2872 | 7 | AVDictionary **meta_out = NULL; | |
2873 | 7 | int i, ret = 0; | |
2874 | char type_in, type_out; | ||
2875 | 7 | const char *istream_spec = NULL, *ostream_spec = NULL; | |
2876 | 7 | int idx_in = 0, idx_out = 0; | |
2877 | |||
2878 | 7 | ret = parse_meta_type(mux, inspec, &type_in, &idx_in, &istream_spec); | |
2879 |
1/2✓ Branch 0 taken 7 times.
✗ Branch 1 not taken.
|
7 | if (ret >= 0) |
2880 | 7 | ret = parse_meta_type(mux, outspec, &type_out, &idx_out, &ostream_spec); | |
2881 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (ret < 0) |
2882 | ✗ | return ret; | |
2883 | |||
2884 |
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)) |
2885 | 5 | *metadata_global_manual = 1; | |
2886 |
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)) |
2887 | 3 | *metadata_streams_manual = 1; | |
2888 |
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)) |
2889 | ✗ | *metadata_chapters_manual = 1; | |
2890 | |||
2891 | /* ic is NULL when just disabling automatic mappings */ | ||
2892 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
|
7 | if (!ic) |
2893 | 2 | return 0; | |
2894 | |||
2895 | #define METADATA_CHECK_INDEX(index, nb_elems, desc)\ | ||
2896 | if ((index) < 0 || (index) >= (nb_elems)) {\ | ||
2897 | av_log(mux, AV_LOG_FATAL, "Invalid %s index %d while processing metadata maps.\n",\ | ||
2898 | (desc), (index));\ | ||
2899 | return AVERROR(EINVAL);\ | ||
2900 | } | ||
2901 | |||
2902 | #define SET_DICT(type, meta, context, index)\ | ||
2903 | switch (type) {\ | ||
2904 | case 'g':\ | ||
2905 | meta = &context->metadata;\ | ||
2906 | break;\ | ||
2907 | case 'c':\ | ||
2908 | METADATA_CHECK_INDEX(index, context->nb_chapters, "chapter")\ | ||
2909 | meta = &context->chapters[index]->metadata;\ | ||
2910 | break;\ | ||
2911 | case 'p':\ | ||
2912 | METADATA_CHECK_INDEX(index, context->nb_programs, "program")\ | ||
2913 | meta = &context->programs[index]->metadata;\ | ||
2914 | break;\ | ||
2915 | case 's':\ | ||
2916 | break; /* handled separately below */ \ | ||
2917 | default: av_assert0(0);\ | ||
2918 | }\ | ||
2919 | |||
2920 |
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); |
2921 |
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); |
2922 | |||
2923 | /* for input streams choose first matching stream */ | ||
2924 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 3 times.
|
5 | if (type_in == 's') { |
2925 |
1/2✓ Branch 0 taken 3 times.
✗ Branch 1 not taken.
|
3 | for (i = 0; i < ic->nb_streams; i++) { |
2926 |
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) { |
2927 | 2 | meta_in = &ic->streams[i]->metadata; | |
2928 | 2 | break; | |
2929 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if (ret < 0) |
2930 | ✗ | return ret; | |
2931 | } | ||
2932 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (!meta_in) { |
2933 | ✗ | av_log(mux, AV_LOG_FATAL, "Stream specifier %s does not match any streams.\n", istream_spec); | |
2934 | ✗ | return AVERROR(EINVAL); | |
2935 | } | ||
2936 | } | ||
2937 | |||
2938 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 2 times.
|
5 | if (type_out == 's') { |
2939 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 3 times.
|
11 | for (i = 0; i < oc->nb_streams; i++) { |
2940 |
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) { |
2941 | 3 | meta_out = &oc->streams[i]->metadata; | |
2942 | 3 | av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE); | |
2943 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5 times.
|
5 | } else if (ret < 0) |
2944 | ✗ | return ret; | |
2945 | } | ||
2946 | } else | ||
2947 | 2 | av_dict_copy(meta_out, *meta_in, AV_DICT_DONT_OVERWRITE); | |
2948 | |||
2949 | 5 | return 0; | |
2950 | } | ||
2951 | |||
2952 | 7916 | static int copy_meta(Muxer *mux, const OptionsContext *o) | |
2953 | { | ||
2954 | 7916 | OutputFile *of = &mux->of; | |
2955 | 7916 | AVFormatContext *oc = mux->fc; | |
2956 | 7916 | int chapters_input_file = o->chapters_input_file; | |
2957 | 7916 | int metadata_global_manual = 0; | |
2958 | 7916 | int metadata_streams_manual = 0; | |
2959 | 7916 | int metadata_chapters_manual = 0; | |
2960 | int ret; | ||
2961 | |||
2962 | /* copy metadata */ | ||
2963 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 7916 times.
|
7923 | for (int i = 0; i < o->metadata_map.nb_opt; i++) { |
2964 | char *p; | ||
2965 | 7 | int in_file_index = strtol(o->metadata_map.opt[i].u.str, &p, 0); | |
2966 | |||
2967 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (in_file_index >= nb_input_files) { |
2968 | ✗ | av_log(mux, AV_LOG_FATAL, "Invalid input file index %d while " | |
2969 | "processing metadata maps\n", in_file_index); | ||
2970 | ✗ | return AVERROR(EINVAL); | |
2971 | } | ||
2972 | 10 | ret = copy_metadata(mux, | |
2973 | 5 | in_file_index >= 0 ? input_files[in_file_index]->ctx : NULL, | |
2974 |
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, |
2975 | &metadata_global_manual, &metadata_streams_manual, | ||
2976 | &metadata_chapters_manual); | ||
2977 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (ret < 0) |
2978 | ✗ | return ret; | |
2979 | } | ||
2980 | |||
2981 | /* copy chapters */ | ||
2982 |
1/2✓ Branch 0 taken 7916 times.
✗ Branch 1 not taken.
|
7916 | if (chapters_input_file >= nb_input_files) { |
2983 |
1/2✓ Branch 0 taken 7916 times.
✗ Branch 1 not taken.
|
7916 | if (chapters_input_file == INT_MAX) { |
2984 | /* copy chapters from the first input file that has them*/ | ||
2985 | 7916 | chapters_input_file = -1; | |
2986 |
2/2✓ Branch 0 taken 7166 times.
✓ Branch 1 taken 7897 times.
|
15063 | for (int i = 0; i < nb_input_files; i++) |
2987 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 7147 times.
|
7166 | if (input_files[i]->ctx->nb_chapters) { |
2988 | 19 | chapters_input_file = i; | |
2989 | 19 | break; | |
2990 | } | ||
2991 | } else { | ||
2992 | ✗ | av_log(mux, AV_LOG_FATAL, "Invalid input file index %d in chapter mapping.\n", | |
2993 | chapters_input_file); | ||
2994 | ✗ | return AVERROR(EINVAL); | |
2995 | } | ||
2996 | } | ||
2997 |
2/2✓ Branch 0 taken 19 times.
✓ Branch 1 taken 7897 times.
|
7916 | if (chapters_input_file >= 0) |
2998 | 19 | copy_chapters(input_files[chapters_input_file], of, oc, | |
2999 | !metadata_chapters_manual); | ||
3000 | |||
3001 | /* copy global metadata by default */ | ||
3002 |
4/4✓ Branch 0 taken 7912 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 7074 times.
✓ Branch 3 taken 838 times.
|
7916 | if (!metadata_global_manual && nb_input_files){ |
3003 | 7074 | av_dict_copy(&oc->metadata, input_files[0]->ctx->metadata, | |
3004 | AV_DICT_DONT_OVERWRITE); | ||
3005 |
2/2✓ Branch 0 taken 188 times.
✓ Branch 1 taken 6886 times.
|
7074 | if (of->recording_time != INT64_MAX) |
3006 | 188 | av_dict_set(&oc->metadata, "duration", NULL, 0); | |
3007 | 7074 | av_dict_set(&oc->metadata, "creation_time", NULL, 0); | |
3008 | 7074 | av_dict_set(&oc->metadata, "company_name", NULL, 0); | |
3009 | 7074 | av_dict_set(&oc->metadata, "product_name", NULL, 0); | |
3010 | 7074 | av_dict_set(&oc->metadata, "product_version", NULL, 0); | |
3011 | } | ||
3012 |
2/2✓ Branch 0 taken 7914 times.
✓ Branch 1 taken 2 times.
|
7916 | if (!metadata_streams_manual) |
3013 |
2/2✓ Branch 0 taken 8352 times.
✓ Branch 1 taken 7914 times.
|
16266 | for (int i = 0; i < of->nb_streams; i++) { |
3014 | 8352 | OutputStream *ost = of->streams[i]; | |
3015 | |||
3016 |
2/2✓ Branch 0 taken 1024 times.
✓ Branch 1 taken 7328 times.
|
8352 | if (!ost->ist) /* this is true e.g. for attached files */ |
3017 | 1024 | continue; | |
3018 | 7328 | av_dict_copy(&ost->st->metadata, ost->ist->st->metadata, AV_DICT_DONT_OVERWRITE); | |
3019 | } | ||
3020 | |||
3021 | 7916 | return 0; | |
3022 | } | ||
3023 | |||
3024 | 7916 | static int set_dispositions(Muxer *mux, const OptionsContext *o) | |
3025 | { | ||
3026 | 7916 | OutputFile *of = &mux->of; | |
3027 | 7916 | AVFormatContext *ctx = mux->fc; | |
3028 | |||
3029 | // indexed by type+1, because AVMEDIA_TYPE_UNKNOWN=-1 | ||
3030 | 7916 | int nb_streams[AVMEDIA_TYPE_NB + 1] = { 0 }; | |
3031 | 7916 | int have_default[AVMEDIA_TYPE_NB + 1] = { 0 }; | |
3032 | 7916 | int have_manual = 0; | |
3033 | 7916 | int ret = 0; | |
3034 | |||
3035 | const char **dispositions; | ||
3036 | |||
3037 | 7916 | dispositions = av_calloc(ctx->nb_streams, sizeof(*dispositions)); | |
3038 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (!dispositions) |
3039 | ✗ | return AVERROR(ENOMEM); | |
3040 | |||
3041 | // first, copy the input dispositions | ||
3042 |
2/2✓ Branch 0 taken 8357 times.
✓ Branch 1 taken 7916 times.
|
16273 | for (int i = 0; i < ctx->nb_streams; i++) { |
3043 | 8357 | OutputStream *ost = of->streams[i]; | |
3044 | |||
3045 | 8357 | nb_streams[ost->type + 1]++; | |
3046 | |||
3047 | 8357 | opt_match_per_stream_str(ost, &o->disposition, ctx, ost->st, &dispositions[i]); | |
3048 | |||
3049 | 8357 | have_manual |= !!dispositions[i]; | |
3050 | |||
3051 |
2/2✓ Branch 0 taken 7333 times.
✓ Branch 1 taken 1024 times.
|
8357 | if (ost->ist) { |
3052 | 7333 | ost->st->disposition = ost->ist->st->disposition; | |
3053 | |||
3054 |
2/2✓ Branch 0 taken 789 times.
✓ Branch 1 taken 6544 times.
|
7333 | if (ost->st->disposition & AV_DISPOSITION_DEFAULT) |
3055 | 789 | have_default[ost->type + 1] = 1; | |
3056 | } | ||
3057 | } | ||
3058 | |||
3059 |
2/2✓ Branch 0 taken 8 times.
✓ Branch 1 taken 7908 times.
|
7916 | if (have_manual) { |
3060 | // process manually set dispositions - they override the above copy | ||
3061 |
2/2✓ Branch 0 taken 23 times.
✓ Branch 1 taken 8 times.
|
31 | for (int i = 0; i < ctx->nb_streams; i++) { |
3062 | 23 | OutputStream *ost = of->streams[i]; | |
3063 | 23 | const char *disp = dispositions[i]; | |
3064 | |||
3065 |
2/2✓ Branch 0 taken 7 times.
✓ Branch 1 taken 16 times.
|
23 | if (!disp) |
3066 | 7 | continue; | |
3067 | |||
3068 | 16 | ret = av_opt_set(ost->st, "disposition", disp, 0); | |
3069 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 16 times.
|
16 | if (ret < 0) |
3070 | ✗ | goto finish; | |
3071 | } | ||
3072 | } else { | ||
3073 | // For each media type with more than one stream, find a suitable stream to | ||
3074 | // mark as default, unless one is already marked default. | ||
3075 | // "Suitable" means the first of that type, skipping attached pictures. | ||
3076 |
2/2✓ Branch 0 taken 8334 times.
✓ Branch 1 taken 7908 times.
|
16242 | for (int i = 0; i < ctx->nb_streams; i++) { |
3077 | 8334 | OutputStream *ost = of->streams[i]; | |
3078 | 8334 | enum AVMediaType type = ost->type; | |
3079 | |||
3080 |
4/4✓ Branch 0 taken 332 times.
✓ Branch 1 taken 8002 times.
✓ Branch 2 taken 69 times.
✓ Branch 3 taken 263 times.
|
8334 | if (nb_streams[type + 1] < 2 || have_default[type + 1] || |
3081 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 37 times.
|
69 | ost->st->disposition & AV_DISPOSITION_ATTACHED_PIC) |
3082 | 8297 | continue; | |
3083 | |||
3084 | 37 | ost->st->disposition |= AV_DISPOSITION_DEFAULT; | |
3085 | 37 | have_default[type + 1] = 1; | |
3086 | } | ||
3087 | } | ||
3088 | |||
3089 | 7908 | finish: | |
3090 | 7916 | av_freep(&dispositions); | |
3091 | |||
3092 | 7916 | return ret; | |
3093 | } | ||
3094 | |||
3095 | static const char *const forced_keyframes_const_names[] = { | ||
3096 | "n", | ||
3097 | "n_forced", | ||
3098 | "prev_forced_n", | ||
3099 | "prev_forced_t", | ||
3100 | "t", | ||
3101 | NULL | ||
3102 | }; | ||
3103 | |||
3104 | 1 | static int compare_int64(const void *a, const void *b) | |
3105 | { | ||
3106 | 1 | return FFDIFFSIGN(*(const int64_t *)a, *(const int64_t *)b); | |
3107 | } | ||
3108 | |||
3109 | 1 | static int parse_forced_key_frames(void *log, KeyframeForceCtx *kf, | |
3110 | const Muxer *mux, const char *spec) | ||
3111 | { | ||
3112 | const char *p; | ||
3113 | 1 | int n = 1, i, ret, size, index = 0; | |
3114 | int64_t t, *pts; | ||
3115 | |||
3116 |
2/2✓ Branch 0 taken 13 times.
✓ Branch 1 taken 1 times.
|
14 | for (p = spec; *p; p++) |
3117 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 12 times.
|
13 | if (*p == ',') |
3118 | 1 | n++; | |
3119 | 1 | size = n; | |
3120 | 1 | pts = av_malloc_array(size, sizeof(*pts)); | |
3121 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (!pts) |
3122 | ✗ | return AVERROR(ENOMEM); | |
3123 | |||
3124 | 1 | p = spec; | |
3125 |
2/2✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
|
3 | for (i = 0; i < n; i++) { |
3126 | 2 | char *next = strchr(p, ','); | |
3127 | |||
3128 |
2/2✓ Branch 0 taken 1 times.
✓ Branch 1 taken 1 times.
|
2 | if (next) |
3129 | 1 | *next++ = 0; | |
3130 | |||
3131 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (strstr(p, "chapters") == p) { |
3132 | ✗ | AVChapter * const *ch = mux->fc->chapters; | |
3133 | ✗ | unsigned int nb_ch = mux->fc->nb_chapters; | |
3134 | int j; | ||
3135 | |||
3136 | ✗ | if (nb_ch > INT_MAX - size) { | |
3137 | ✗ | ret = AVERROR(ERANGE); | |
3138 | ✗ | goto fail; | |
3139 | } | ||
3140 | ✗ | size += nb_ch - 1; | |
3141 | ✗ | pts = av_realloc_f(pts, size, sizeof(*pts)); | |
3142 | ✗ | if (!pts) | |
3143 | ✗ | return AVERROR(ENOMEM); | |
3144 | |||
3145 | ✗ | if (p[8]) { | |
3146 | ✗ | ret = av_parse_time(&t, p + 8, 1); | |
3147 | ✗ | if (ret < 0) { | |
3148 | ✗ | av_log(log, AV_LOG_ERROR, | |
3149 | "Invalid chapter time offset: %s\n", p + 8); | ||
3150 | ✗ | goto fail; | |
3151 | } | ||
3152 | } else | ||
3153 | ✗ | t = 0; | |
3154 | |||
3155 | ✗ | for (j = 0; j < nb_ch; j++) { | |
3156 | ✗ | const AVChapter *c = ch[j]; | |
3157 | av_assert1(index < size); | ||
3158 | ✗ | pts[index++] = av_rescale_q(c->start, c->time_base, | |
3159 | ✗ | AV_TIME_BASE_Q) + t; | |
3160 | } | ||
3161 | |||
3162 | } else { | ||
3163 | av_assert1(index < size); | ||
3164 | 2 | ret = av_parse_time(&t, p, 1); | |
3165 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
|
2 | if (ret < 0) { |
3166 | ✗ | av_log(log, AV_LOG_ERROR, "Invalid keyframe time: %s\n", p); | |
3167 | ✗ | goto fail; | |
3168 | } | ||
3169 | |||
3170 | 2 | pts[index++] = t; | |
3171 | } | ||
3172 | |||
3173 | 2 | p = next; | |
3174 | } | ||
3175 | |||
3176 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | av_assert0(index == size); |
3177 | 1 | qsort(pts, size, sizeof(*pts), compare_int64); | |
3178 | 1 | kf->nb_pts = size; | |
3179 | 1 | kf->pts = pts; | |
3180 | |||
3181 | 1 | return 0; | |
3182 | ✗ | fail: | |
3183 | ✗ | av_freep(&pts); | |
3184 | ✗ | return ret; | |
3185 | } | ||
3186 | |||
3187 | 7916 | static int process_forced_keyframes(Muxer *mux, const OptionsContext *o) | |
3188 | { | ||
3189 |
2/2✓ Branch 0 taken 8357 times.
✓ Branch 1 taken 7916 times.
|
16273 | for (int i = 0; i < mux->of.nb_streams; i++) { |
3190 | 8357 | OutputStream *ost = mux->of.streams[i]; | |
3191 | 8357 | const char *forced_keyframes = NULL; | |
3192 | |||
3193 | 8357 | opt_match_per_stream_str(ost, &o->forced_key_frames, | |
3194 | mux->fc, ost->st, &forced_keyframes); | ||
3195 | |||
3196 |
2/2✓ Branch 0 taken 6681 times.
✓ Branch 1 taken 1676 times.
|
8357 | if (!(ost->type == AVMEDIA_TYPE_VIDEO && |
3197 |
4/4✓ Branch 0 taken 6338 times.
✓ Branch 1 taken 343 times.
✓ Branch 2 taken 6334 times.
✓ Branch 3 taken 4 times.
|
6681 | ost->enc && forced_keyframes)) |
3198 | 8353 | continue; | |
3199 | |||
3200 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
|
4 | if (!strncmp(forced_keyframes, "expr:", 5)) { |
3201 | ✗ | int ret = av_expr_parse(&ost->kf.pexpr, forced_keyframes + 5, | |
3202 | forced_keyframes_const_names, NULL, NULL, NULL, NULL, 0, NULL); | ||
3203 | ✗ | if (ret < 0) { | |
3204 | ✗ | av_log(ost, AV_LOG_ERROR, | |
3205 | "Invalid force_key_frames expression '%s'\n", forced_keyframes + 5); | ||
3206 | ✗ | return ret; | |
3207 | } | ||
3208 | ✗ | ost->kf.expr_const_values[FKF_N] = 0; | |
3209 | ✗ | ost->kf.expr_const_values[FKF_N_FORCED] = 0; | |
3210 | ✗ | ost->kf.expr_const_values[FKF_PREV_FORCED_N] = NAN; | |
3211 | ✗ | ost->kf.expr_const_values[FKF_PREV_FORCED_T] = NAN; | |
3212 | |||
3213 | // Don't parse the 'forced_keyframes' in case of 'keep-source-keyframes', | ||
3214 | // parse it only for static kf timings | ||
3215 |
2/2✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
|
4 | } else if (!strcmp(forced_keyframes, "source")) { |
3216 | 3 | ost->kf.type = KF_FORCE_SOURCE; | |
3217 | #if FFMPEG_OPT_FORCE_KF_SOURCE_NO_DROP | ||
3218 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | } else if (!strcmp(forced_keyframes, "source_no_drop")) { |
3219 | ✗ | av_log(ost, AV_LOG_WARNING, "The 'source_no_drop' value for " | |
3220 | "-force_key_frames is deprecated, use just 'source'\n"); | ||
3221 | ✗ | ost->kf.type = KF_FORCE_SOURCE; | |
3222 | #endif | ||
3223 | } else { | ||
3224 | 1 | int ret = parse_forced_key_frames(ost, &ost->kf, mux, forced_keyframes); | |
3225 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
|
1 | if (ret < 0) |
3226 | ✗ | return ret; | |
3227 | } | ||
3228 | } | ||
3229 | |||
3230 | 7916 | return 0; | |
3231 | } | ||
3232 | |||
3233 | 8292 | static const char *output_file_item_name(void *obj) | |
3234 | { | ||
3235 | 8292 | const Muxer *mux = obj; | |
3236 | |||
3237 | 8292 | return mux->log_name; | |
3238 | } | ||
3239 | |||
3240 | static const AVClass output_file_class = { | ||
3241 | .class_name = "OutputFile", | ||
3242 | .version = LIBAVUTIL_VERSION_INT, | ||
3243 | .item_name = output_file_item_name, | ||
3244 | .category = AV_CLASS_CATEGORY_MUXER, | ||
3245 | }; | ||
3246 | |||
3247 | 7916 | static Muxer *mux_alloc(void) | |
3248 | { | ||
3249 | 7916 | Muxer *mux = allocate_array_elem(&output_files, sizeof(*mux), &nb_output_files); | |
3250 | |||
3251 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (!mux) |
3252 | ✗ | return NULL; | |
3253 | |||
3254 | 7916 | mux->of.class = &output_file_class; | |
3255 | 7916 | mux->of.index = nb_output_files - 1; | |
3256 | |||
3257 | 7916 | snprintf(mux->log_name, sizeof(mux->log_name), "out#%d", mux->of.index); | |
3258 | |||
3259 | 7916 | return mux; | |
3260 | } | ||
3261 | |||
3262 | 7916 | int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) | |
3263 | { | ||
3264 | Muxer *mux; | ||
3265 | AVFormatContext *oc; | ||
3266 | int err; | ||
3267 | OutputFile *of; | ||
3268 | |||
3269 | 7916 | int64_t recording_time = o->recording_time; | |
3270 | 7916 | int64_t stop_time = o->stop_time; | |
3271 | |||
3272 | 7916 | mux = mux_alloc(); | |
3273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (!mux) |
3274 | ✗ | return AVERROR(ENOMEM); | |
3275 | |||
3276 | 7916 | of = &mux->of; | |
3277 | |||
3278 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7916 | if (stop_time != INT64_MAX && recording_time != INT64_MAX) { |
3279 | ✗ | stop_time = INT64_MAX; | |
3280 | ✗ | av_log(mux, AV_LOG_WARNING, "-t and -to cannot be used together; using -t.\n"); | |
3281 | } | ||
3282 | |||
3283 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
7916 | if (stop_time != INT64_MAX && recording_time == INT64_MAX) { |
3284 | ✗ | int64_t start_time = o->start_time == AV_NOPTS_VALUE ? 0 : o->start_time; | |
3285 | ✗ | if (stop_time <= start_time) { | |
3286 | ✗ | av_log(mux, AV_LOG_ERROR, "-to value smaller than -ss; aborting.\n"); | |
3287 | ✗ | return AVERROR(EINVAL); | |
3288 | } else { | ||
3289 | ✗ | recording_time = stop_time - start_time; | |
3290 | } | ||
3291 | } | ||
3292 | |||
3293 | 7916 | of->recording_time = recording_time; | |
3294 | 7916 | of->start_time = o->start_time; | |
3295 | |||
3296 | 7916 | mux->limit_filesize = o->limit_filesize; | |
3297 | 7916 | av_dict_copy(&mux->opts, o->g->format_opts, 0); | |
3298 | |||
3299 |
2/2✓ Branch 0 taken 2636 times.
✓ Branch 1 taken 5280 times.
|
7916 | if (!strcmp(filename, "-")) |
3300 | 2636 | filename = "pipe:"; | |
3301 | |||
3302 | 7916 | err = avformat_alloc_output_context2(&oc, NULL, o->format, filename); | |
3303 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (!oc) { |
3304 | ✗ | av_log(mux, AV_LOG_FATAL, "Error initializing the muxer for %s: %s\n", | |
3305 | ✗ | filename, av_err2str(err)); | |
3306 | ✗ | return err; | |
3307 | } | ||
3308 | 7916 | mux->fc = oc; | |
3309 | |||
3310 | 7916 | av_strlcat(mux->log_name, "/", sizeof(mux->log_name)); | |
3311 | 7916 | av_strlcat(mux->log_name, oc->oformat->name, sizeof(mux->log_name)); | |
3312 | |||
3313 | |||
3314 |
2/2✓ Branch 0 taken 962 times.
✓ Branch 1 taken 6954 times.
|
7916 | if (recording_time != INT64_MAX) |
3315 | 962 | oc->duration = recording_time; | |
3316 | |||
3317 | 7916 | oc->interrupt_callback = int_cb; | |
3318 | |||
3319 |
2/2✓ Branch 0 taken 1825 times.
✓ Branch 1 taken 6091 times.
|
7916 | if (o->bitexact) { |
3320 | 1825 | oc->flags |= AVFMT_FLAG_BITEXACT; | |
3321 | 1825 | of->bitexact = 1; | |
3322 | } else { | ||
3323 | 6091 | of->bitexact = check_opt_bitexact(oc, mux->opts, "fflags", | |
3324 | AVFMT_FLAG_BITEXACT); | ||
3325 | } | ||
3326 | |||
3327 | 7916 | err = sch_add_mux(sch, muxer_thread, mux_check_init, mux, | |
3328 | 7916 | !strcmp(oc->oformat->name, "rtp"), o->thread_queue_size); | |
3329 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) |
3330 | ✗ | return err; | |
3331 | 7916 | mux->sch = sch; | |
3332 | 7916 | mux->sch_idx = err; | |
3333 | |||
3334 | /* create all output streams for this file */ | ||
3335 | 7916 | err = create_streams(mux, o); | |
3336 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) |
3337 | ✗ | return err; | |
3338 | |||
3339 | /* check if all codec options have been used */ | ||
3340 | 7916 | err = check_avoptions_used(o->g->codec_opts, mux->enc_opts_used, mux, 0); | |
3341 | 7916 | av_dict_free(&mux->enc_opts_used); | |
3342 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) |
3343 | ✗ | return err; | |
3344 | |||
3345 | /* check filename in case of an image number is expected */ | ||
3346 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
7916 | if (oc->oformat->flags & AVFMT_NEEDNUMBER && !av_filename_number_test(oc->url)) { |
3347 | ✗ | av_log(mux, AV_LOG_FATAL, | |
3348 | "Output filename '%s' does not contain a numeric pattern like " | ||
3349 | "'%%d', which is required by output format '%s'.\n", | ||
3350 | ✗ | oc->url, oc->oformat->name); | |
3351 | ✗ | return AVERROR(EINVAL); | |
3352 | } | ||
3353 | |||
3354 |
2/2✓ Branch 0 taken 7823 times.
✓ Branch 1 taken 93 times.
|
7916 | if (!(oc->oformat->flags & AVFMT_NOFILE)) { |
3355 | /* test if it already exists to avoid losing precious files */ | ||
3356 | 7823 | err = assert_file_overwrite(filename); | |
3357 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7823 times.
|
7823 | if (err < 0) |
3358 | ✗ | return err; | |
3359 | |||
3360 | /* open the file */ | ||
3361 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7823 times.
|
7823 | if ((err = avio_open2(&oc->pb, filename, AVIO_FLAG_WRITE, |
3362 | 7823 | &oc->interrupt_callback, | |
3363 | &mux->opts)) < 0) { | ||
3364 | ✗ | av_log(mux, AV_LOG_FATAL, "Error opening output %s: %s\n", | |
3365 | ✗ | filename, av_err2str(err)); | |
3366 | ✗ | return err; | |
3367 | } | ||
3368 |
4/4✓ Branch 0 taken 58 times.
✓ Branch 1 taken 35 times.
✓ Branch 3 taken 7 times.
✓ Branch 4 taken 51 times.
|
93 | } else if (strcmp(oc->oformat->name, "image2")==0 && !av_filename_number_test(filename)) { |
3369 | 7 | err = assert_file_overwrite(filename); | |
3370 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7 times.
|
7 | if (err < 0) |
3371 | ✗ | return err; | |
3372 | } | ||
3373 | |||
3374 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (o->mux_preload) { |
3375 | ✗ | av_dict_set_int(&mux->opts, "preload", o->mux_preload*AV_TIME_BASE, 0); | |
3376 | } | ||
3377 | 7916 | oc->max_delay = (int)(o->mux_max_delay * AV_TIME_BASE); | |
3378 | |||
3379 | /* copy metadata and chapters from input files */ | ||
3380 | 7916 | err = copy_meta(mux, o); | |
3381 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) |
3382 | ✗ | return err; | |
3383 | |||
3384 | 7916 | err = of_add_groups(mux, o); | |
3385 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) |
3386 | ✗ | return err; | |
3387 | |||
3388 | 7916 | err = of_add_programs(mux, o); | |
3389 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) |
3390 | ✗ | return err; | |
3391 | |||
3392 | 7916 | err = of_add_metadata(of, oc, o); | |
3393 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) |
3394 | ✗ | return err; | |
3395 | |||
3396 | 7916 | err = set_dispositions(mux, o); | |
3397 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) { |
3398 | ✗ | av_log(mux, AV_LOG_FATAL, "Error setting output stream dispositions\n"); | |
3399 | ✗ | return err; | |
3400 | } | ||
3401 | |||
3402 | // parse forced keyframe specifications; | ||
3403 | // must be done after chapters are created | ||
3404 | 7916 | err = process_forced_keyframes(mux, o); | |
3405 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) { |
3406 | ✗ | av_log(mux, AV_LOG_FATAL, "Error processing forced keyframes\n"); | |
3407 | ✗ | return err; | |
3408 | } | ||
3409 | |||
3410 | 7916 | err = setup_sync_queues(mux, oc, o->shortest_buf_duration * AV_TIME_BASE, | |
3411 | 7916 | o->shortest); | |
3412 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 7916 times.
|
7916 | if (err < 0) { |
3413 | ✗ | av_log(mux, AV_LOG_FATAL, "Error setting up output sync queues\n"); | |
3414 | ✗ | return err; | |
3415 | } | ||
3416 | |||
3417 | 7916 | of->url = filename; | |
3418 | |||
3419 | /* initialize streamcopy streams. */ | ||
3420 |
2/2✓ Branch 0 taken 8357 times.
✓ Branch 1 taken 7916 times.
|
16273 | for (int i = 0; i < of->nb_streams; i++) { |
3421 | 8357 | OutputStream *ost = of->streams[i]; | |
3422 | |||
3423 |
2/2✓ Branch 0 taken 661 times.
✓ Branch 1 taken 7696 times.
|
8357 | if (!ost->enc) { |
3424 | 661 | err = of_stream_init(of, ost, NULL); | |
3425 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 661 times.
|
661 | if (err < 0) |
3426 | ✗ | return err; | |
3427 | } | ||
3428 | } | ||
3429 | |||
3430 | 7916 | return 0; | |
3431 | } | ||
3432 |