@@ -246,6 +246,8 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
(uint8_t *)optctx + po->u.off : po->u.dst_ptr;
char *arg_allocated = NULL;
+ enum OptionType so_type = po->type;
+
SpecifierOptList *sol = NULL;
double num;
int ret = 0;
@@ -310,6 +312,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
goto finish;
*(int *)dst = num;
+ so_type = OPT_TYPE_INT;
} else if (po->type == OPT_TYPE_INT64) {
ret = parse_number(opt, arg, OPT_TYPE_INT64, INT64_MIN, (double)INT64_MAX, &num);
if (ret < 0)
@@ -323,6 +326,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
opt, arg);
goto finish;
}
+ so_type = OPT_TYPE_INT64;
} else if (po->type == OPT_TYPE_FLOAT) {
ret = parse_number(opt, arg, OPT_TYPE_FLOAT, -INFINITY, INFINITY, &num);
if (ret < 0)
@@ -352,7 +356,7 @@ static int write_option(void *optctx, const OptionDef *po, const char *opt,
}
if (sol) {
- sol->type = po->type;
+ sol->type = so_type;
sol->opt_canon = (po->flags & OPT_HAS_CANON) ?
find_option(defs, po->u1.name_canon) : po;
}
@@ -120,6 +120,9 @@ typedef struct SpecifierOptList {
/* Canonical option definition that was parsed into this list. */
const struct OptionDef *opt_canon;
+ /* Type corresponding to the field that should be used from SpecifierOpt.u.
+ * May not match the option type, e.g. OPT_TYPE_BOOL options are stored as
+ * int, so this field would be OPT_TYPE_INT for them */
enum OptionType type;
} SpecifierOptList;
@@ -593,7 +593,7 @@ typedef struct OutputStream {
KeyframeForceCtx kf;
- char *logfile_prefix;
+ const char *logfile_prefix;
FILE *logfile;
// simple filtergraph feeding this stream, if any
@@ -902,6 +902,8 @@ void update_benchmark(const char *fmt, ...);
const char *opt_match_per_type_str(const SpecifierOptList *sol,
char mediatype);
+int opt_match_per_stream_str(void *logctx, const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st, const char **out);
int muxer_thread(void *arg);
int encoder_thread(void *arg);
@@ -1077,14 +1077,19 @@ int ist_filter_add(InputStream *ist, InputFilter *ifilter, int is_simple,
return ds->sch_idx_dec;
}
-static int choose_decoder(const OptionsContext *o, AVFormatContext *s, AVStream *st,
+static int choose_decoder(const OptionsContext *o, void *logctx,
+ AVFormatContext *s, AVStream *st,
enum HWAccelID hwaccel_id, enum AVHWDeviceType hwaccel_device_type,
const AVCodec **pcodec)
{
- char *codec_name = NULL;
+ const char *codec_name = NULL;
+ int ret;
+
+ ret = opt_match_per_stream_str(logctx, &o->codec_names, s, st, &codec_name);
+ if (ret < 0)
+ return ret;
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, st);
if (codec_name) {
int ret = find_codec(NULL, codec_name, st->codecpar->codec_type, 0, pcodec);
if (ret < 0)
@@ -1226,14 +1231,14 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
AVCodecParameters *par = st->codecpar;
DemuxStream *ds;
InputStream *ist;
- char *framerate = NULL, *hwaccel_device = NULL;
+ const char *framerate = NULL, *hwaccel_device = NULL;
const char *hwaccel = NULL;
const char *apply_cropping = NULL;
- char *hwaccel_output_format = NULL;
- char *codec_tag = NULL;
- char *bsfs = NULL;
+ const char *hwaccel_output_format = NULL;
+ const char *codec_tag = NULL;
+ const char *bsfs = NULL;
char *next;
- char *discard_str = NULL;
+ const char *discard_str = NULL;
int ret;
ds = demux_stream_alloc(d, st);
@@ -1256,7 +1261,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
MATCH_PER_STREAM_OPT(autorotate, i, ds->autorotate, ic, st);
ds->apply_cropping = CROP_ALL;
- MATCH_PER_STREAM_OPT(apply_cropping, str, apply_cropping, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->apply_cropping, ic, st, &apply_cropping);
+ if (ret < 0)
+ return ret;
if (apply_cropping) {
const AVOption opts[] = {
{ "apply_cropping", NULL, 0, AV_OPT_TYPE_INT,
@@ -1282,7 +1289,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
}
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->codec_tags, ic, st, &codec_tag);
+ if (ret < 0)
+ return ret;
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next) {
@@ -1299,9 +1308,14 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
if (ret < 0)
return ret;
- MATCH_PER_STREAM_OPT(hwaccels, str, hwaccel, ic, st);
- MATCH_PER_STREAM_OPT(hwaccel_output_formats, str,
- hwaccel_output_format, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->hwaccels, ic, st, &hwaccel);
+ if (ret < 0)
+ return ret;
+
+ ret = opt_match_per_stream_str(ist, &o->hwaccel_output_formats, ic, st,
+ &hwaccel_output_format);
+ if (ret < 0)
+ return ret;
if (!hwaccel_output_format && hwaccel && !strcmp(hwaccel, "cuvid")) {
av_log(ist, AV_LOG_WARNING,
@@ -1360,7 +1374,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
}
- MATCH_PER_STREAM_OPT(hwaccel_devices, str, hwaccel_device, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->hwaccel_devices, ic, st, &hwaccel_device);
+ if (ret < 0)
+ return ret;
if (hwaccel_device) {
ds->dec_opts.hwaccel_device = av_strdup(hwaccel_device);
if (!ds->dec_opts.hwaccel_device)
@@ -1368,7 +1384,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
}
- ret = choose_decoder(o, ic, st, ds->dec_opts.hwaccel_id,
+ ret = choose_decoder(o, ist, ic, st, ds->dec_opts.hwaccel_id,
ds->dec_opts.hwaccel_device_type, &ist->dec);
if (ret < 0)
return ret;
@@ -1391,7 +1407,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
(o->data_disable && ist->st->codecpar->codec_type == AVMEDIA_TYPE_DATA))
ist->user_set_discard = AVDISCARD_ALL;
- MATCH_PER_STREAM_OPT(discard, str, discard_str, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->discard, ic, st, &discard_str);
+ if (ret < 0)
+ return ret;
if (discard_str) {
ret = av_opt_set(ist->st, "discard", discard_str, 0);
if (ret < 0) {
@@ -1413,7 +1431,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
switch (par->codec_type) {
case AVMEDIA_TYPE_VIDEO:
- MATCH_PER_STREAM_OPT(frame_rates, str, framerate, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->frame_rates, ic, st, &framerate);
+ if (ret < 0)
+ return ret;
if (framerate) {
ret = av_parse_video_rate(&ist->framerate, framerate);
if (ret < 0) {
@@ -1430,8 +1450,11 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
break;
case AVMEDIA_TYPE_AUDIO: {
- char *ch_layout_str = NULL;
- MATCH_PER_STREAM_OPT(audio_ch_layouts, str, ch_layout_str, ic, st);
+ const char *ch_layout_str = NULL;
+
+ ret = opt_match_per_stream_str(ist, &o->audio_ch_layouts, ic, st, &ch_layout_str);
+ if (ret < 0)
+ return ret;
if (ch_layout_str) {
AVChannelLayout ch_layout;
ret = av_channel_layout_from_string(&ch_layout, ch_layout_str);
@@ -1458,9 +1481,12 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
}
case AVMEDIA_TYPE_DATA:
case AVMEDIA_TYPE_SUBTITLE: {
- char *canvas_size = NULL;
+ const char *canvas_size = NULL;
MATCH_PER_STREAM_OPT(fix_sub_duration, i, ist->fix_sub_duration, ic, st);
- MATCH_PER_STREAM_OPT(canvas_sizes, str, canvas_size, ic, st);
+
+ ret = opt_match_per_stream_str(ist, &o->canvas_sizes, ic, st, &canvas_size);
+ if (ret < 0)
+ return ret;
if (canvas_size) {
ret = av_parse_video_size(&par->width, &par->height,
canvas_size);
@@ -1490,7 +1516,9 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictiona
if (ist->st->sample_aspect_ratio.num)
ist->par->sample_aspect_ratio = ist->st->sample_aspect_ratio;
- MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, ic, st);
+ ret = opt_match_per_stream_str(ist, &o->bitstream_filters, ic, st, &bsfs);
+ if (ret < 0)
+ return ret;
if (bsfs) {
ret = av_bsf_list_parse_str(bsfs, &ds->bsf);
if (ret < 0) {
@@ -1752,7 +1780,7 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch)
/* apply forced codec ids */
for (i = 0; i < ic->nb_streams; i++) {
const AVCodec *dummy;
- ret = choose_decoder(o, ic, ic->streams[i], HWACCEL_NONE, AV_HWDEVICE_TYPE_NONE,
+ ret = choose_decoder(o, f, ic, ic->streams[i], HWACCEL_NONE, AV_HWDEVICE_TYPE_NONE,
&dummy);
if (ret < 0)
return ret;
@@ -79,7 +79,7 @@ typedef struct MuxStream {
int ts_drop;
#endif
- char *apad;
+ const char *apad;
} MuxStream;
typedef struct Muxer {
@@ -70,11 +70,14 @@ static int choose_encoder(const OptionsContext *o, AVFormatContext *s,
OutputStream *ost, const AVCodec **enc)
{
enum AVMediaType type = ost->type;
- char *codec_name = NULL;
+ const char *codec_name = NULL;
+ int ret;
*enc = NULL;
- MATCH_PER_STREAM_OPT(codec_names, str, codec_name, s, ost->st);
+ ret = opt_match_per_stream_str(ost, &o->codec_names, s, ost->st, &codec_name);
+ if (ret < 0)
+ return ret;
if (type != AVMEDIA_TYPE_VIDEO &&
type != AVMEDIA_TYPE_AUDIO &&
@@ -416,12 +419,17 @@ static int ost_get_filters(const OptionsContext *o, AVFormatContext *oc,
OutputStream *ost, char **dst)
{
const char *filters = NULL;
+ int ret;
#if FFMPEG_OPT_FILTER_SCRIPT
const char *filters_script = NULL;
- MATCH_PER_STREAM_OPT(filter_scripts, str, filters_script, oc, ost->st);
+ ret = opt_match_per_stream_str(ost, &o->filter_scripts, oc, ost->st, &filters_script);
+ if (ret < 0)
+ return ret;
#endif
- MATCH_PER_STREAM_OPT(filters, str, filters, oc, ost->st);
+ ret = opt_match_per_stream_str(ost, &o->filters, oc, ost->st, &filters);
+ if (ret < 0)
+ return ret;
if (!ost->enc) {
if (
@@ -586,18 +594,22 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
MuxStream *ms = ms_from_ost(ost);
AVFormatContext *oc = mux->fc;
AVStream *st;
- char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL;
+ const char *frame_rate = NULL, *max_frame_rate = NULL, *frame_aspect_ratio = NULL;
int ret = 0;
st = ost->st;
- MATCH_PER_STREAM_OPT(frame_rates, str, frame_rate, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_rates, oc, st, &frame_rate);
+ if (ret < 0)
+ return ret;
if (frame_rate && av_parse_video_rate(&ost->frame_rate, frame_rate) < 0) {
av_log(ost, AV_LOG_FATAL, "Invalid framerate value: %s\n", frame_rate);
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(max_frame_rates, str, max_frame_rate, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->max_frame_rates, oc, st, &max_frame_rate);
+ if (ret < 0)
+ return ret;
if (max_frame_rate && av_parse_video_rate(&ost->max_frame_rate, max_frame_rate) < 0) {
av_log(ost, AV_LOG_FATAL, "Invalid maximum framerate value: %s\n", max_frame_rate);
return AVERROR(EINVAL);
@@ -608,7 +620,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(frame_aspect_ratios, str, frame_aspect_ratio, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_aspect_ratios, oc, st, &frame_aspect_ratio);
+ if (ret < 0)
+ return ret;
if (frame_aspect_ratio) {
AVRational q;
if (av_parse_ratio(&q, frame_aspect_ratio, 255, 0, NULL) < 0 ||
@@ -622,14 +636,16 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
if (ost->enc_ctx) {
AVCodecContext *video_enc = ost->enc_ctx;
const char *p = NULL, *fps_mode = NULL;
- char *frame_size = NULL;
- char *frame_pix_fmt = NULL;
- char *intra_matrix = NULL, *inter_matrix = NULL;
- char *chroma_intra_matrix = NULL;
+ const char *frame_size = NULL;
+ const char *frame_pix_fmt = NULL;
+ const char *intra_matrix = NULL, *inter_matrix = NULL;
+ const char *chroma_intra_matrix = NULL;
int do_pass = 0;
int i;
- MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_sizes, oc, st, &frame_size);
+ if (ret < 0)
+ return ret;
if (frame_size) {
ret = av_parse_video_size(&video_enc->width, &video_enc->height, frame_size);
if (ret < 0) {
@@ -638,7 +654,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
}
}
- MATCH_PER_STREAM_OPT(frame_pix_fmts, str, frame_pix_fmt, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_pix_fmts, oc, st, &frame_pix_fmt);
+ if (ret < 0)
+ return ret;
if (frame_pix_fmt && *frame_pix_fmt == '+') {
*keep_pix_fmt = 1;
if (!*++frame_pix_fmt)
@@ -650,7 +668,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(intra_matrices, str, intra_matrix, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->intra_matrices, oc, st, &intra_matrix);
+ if (ret < 0)
+ return ret;
if (intra_matrix) {
if (!(video_enc->intra_matrix = av_mallocz(sizeof(*video_enc->intra_matrix) * 64)))
return AVERROR(ENOMEM);
@@ -659,7 +679,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
if (ret < 0)
return ret;
}
- MATCH_PER_STREAM_OPT(chroma_intra_matrices, str, chroma_intra_matrix, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->chroma_intra_matrices, oc, st, &chroma_intra_matrix);
+ if (ret < 0)
+ return ret;
if (chroma_intra_matrix) {
uint16_t *p = av_mallocz(sizeof(*video_enc->chroma_intra_matrix) * 64);
if (!p)
@@ -669,7 +691,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
if (ret < 0)
return ret;
}
- MATCH_PER_STREAM_OPT(inter_matrices, str, inter_matrix, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->inter_matrices, oc, st, &inter_matrix);
+ if (ret < 0)
+ return ret;
if (inter_matrix) {
if (!(video_enc->inter_matrix = av_mallocz(sizeof(*video_enc->inter_matrix) * 64)))
return AVERROR(ENOMEM);
@@ -678,7 +702,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
return ret;
}
- MATCH_PER_STREAM_OPT(rc_overrides, str, p, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->rc_overrides, oc, st, &p);
+ if (ret < 0)
+ return ret;
for (i = 0; p; i++) {
int start, end, q;
int e = sscanf(p, "%d,%d,%d", &start, &end, &q);
@@ -717,7 +743,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
video_enc->flags |= AV_CODEC_FLAG_PASS2;
}
- MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->passlogfiles, oc, st, &ost->logfile_prefix);
+ if (ret < 0)
+ return ret;
if (ost->logfile_prefix &&
!(ost->logfile_prefix = av_strdup(ost->logfile_prefix)))
return AVERROR(ENOMEM);
@@ -778,7 +806,9 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o,
#else
*vsync_method = VSYNC_AUTO;
#endif
- MATCH_PER_STREAM_OPT(fps_mode, str, fps_mode, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->fps_mode, oc, st, &fps_mode);
+ if (ret < 0)
+ return ret;
if (fps_mode) {
ret = parse_and_set_vsync(fps_mode, vsync_method, ost->file->index, ost->index, 0);
if (ret < 0)
@@ -834,8 +864,9 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
if (ost->enc_ctx) {
AVCodecContext *audio_enc = ost->enc_ctx;
int channels = 0;
- char *layout = NULL;
- char *sample_fmt = NULL;
+ const char *layout = NULL;
+ const char *sample_fmt = NULL;
+ int ret;
MATCH_PER_STREAM_OPT(audio_channels, i, channels, oc, st);
if (channels) {
@@ -843,13 +874,17 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
audio_enc->ch_layout.nb_channels = channels;
}
- MATCH_PER_STREAM_OPT(audio_ch_layouts, str, layout, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->audio_ch_layouts, oc, st, &layout);
+ if (ret < 0)
+ return ret;
if (layout && av_channel_layout_from_string(&audio_enc->ch_layout, layout) < 0) {
av_log(ost, AV_LOG_FATAL, "Unknown channel layout: %s\n", layout);
return AVERROR(EINVAL);
}
- MATCH_PER_STREAM_OPT(sample_fmts, str, sample_fmt, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->sample_fmts, oc, st, &sample_fmt);
+ if (ret < 0)
+ return ret;
if (sample_fmt &&
(audio_enc->sample_fmt = av_get_sample_fmt(sample_fmt)) == AV_SAMPLE_FMT_NONE) {
av_log(ost, AV_LOG_FATAL, "Invalid sample format '%s'\n", sample_fmt);
@@ -858,7 +893,9 @@ static int new_stream_audio(Muxer *mux, const OptionsContext *o,
MATCH_PER_STREAM_OPT(audio_sample_rate, i, audio_enc->sample_rate, oc, st);
- MATCH_PER_STREAM_OPT(apad, str, ms->apad, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->apad, oc, st, &ms->apad);
+ if (ret < 0)
+ return ret;
}
return 0;
@@ -880,9 +917,12 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o,
avcodec_descriptor_get(subtitle_enc->codec_id);
int input_props = 0, output_props = 0;
- char *frame_size = NULL;
+ const char *frame_size = NULL;
+ int ret;
- MATCH_PER_STREAM_OPT(frame_sizes, str, frame_size, mux->fc, st);
+ ret = opt_match_per_stream_str(ost, &o->frame_sizes, mux->fc, st, &frame_size);
+ if (ret < 0)
+ return ret;
if (frame_size) {
int ret = av_parse_video_size(&subtitle_enc->width, &subtitle_enc->height, frame_size);
if (ret < 0) {
@@ -1039,8 +1079,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
int threads_manual = 0;
AVRational enc_tb = { 0, 0 };
enum VideoSyncMethod vsync_method = VSYNC_AUTO;
- const char *bsfs = NULL, *time_base = NULL;
- char *filters = NULL, *next, *codec_tag = NULL;
+ const char *bsfs = NULL, *time_base = NULL, *codec_tag = NULL;
+ char *filters = NULL, *next;
double qscale = -1;
st = avformat_new_stream(oc, NULL);
@@ -1151,9 +1191,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (ost->enc_ctx) {
AVCodecContext *enc = ost->enc_ctx;
AVIOContext *s = NULL;
- char *buf = NULL, *arg = NULL, *preset = NULL;
+ char *buf = NULL, *arg = NULL;
const char *enc_stats_pre = NULL, *enc_stats_post = NULL, *mux_stats = NULL;
- const char *enc_time_base = NULL;
+ const char *enc_time_base = NULL, *preset = NULL;
ret = filter_codec_opts(o->g->codec_opts, enc->codec_id,
oc, st, enc->codec, &encoder_opts,
@@ -1161,7 +1201,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
if (ret < 0)
goto fail;
- MATCH_PER_STREAM_OPT(presets, str, preset, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->presets, oc, st, &preset);
+ if (ret < 0)
+ goto fail;
MATCH_PER_STREAM_OPT(autoscale, i, autoscale, oc, st);
if (preset && (!(ret = get_preset_file_2(preset, enc->codec->name, &s)))) {
@@ -1194,43 +1236,57 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
goto fail;
}
- MATCH_PER_STREAM_OPT(enc_stats_pre, str, enc_stats_pre, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_stats_pre, oc, st, &enc_stats_pre);
+ if (ret < 0)
+ goto fail;
if (enc_stats_pre &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- MATCH_PER_STREAM_OPT(enc_stats_pre_fmt, str, format, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_stats_pre_fmt, oc, st, &format);
+ if (ret < 0)
+ goto fail;
ret = enc_stats_init(ost, &ost->enc_stats_pre, 1, enc_stats_pre, format);
if (ret < 0)
goto fail;
}
- MATCH_PER_STREAM_OPT(enc_stats_post, str, enc_stats_post, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_stats_post, oc, st, &enc_stats_post);
+ if (ret < 0)
+ goto fail;
if (enc_stats_post &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- MATCH_PER_STREAM_OPT(enc_stats_post_fmt, str, format, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_stats_post_fmt, oc, st, &format);
+ if (ret < 0)
+ goto fail;
ret = enc_stats_init(ost, &ost->enc_stats_post, 0, enc_stats_post, format);
if (ret < 0)
goto fail;
}
- MATCH_PER_STREAM_OPT(mux_stats, str, mux_stats, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->mux_stats, oc, st, &mux_stats);
+ if (ret < 0)
+ goto fail;
if (mux_stats &&
(type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) {
const char *format = "{fidx} {sidx} {n} {t}";
- MATCH_PER_STREAM_OPT(mux_stats_fmt, str, format, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->mux_stats_fmt, oc, st, &format);
+ if (ret < 0)
+ goto fail;
ret = enc_stats_init(ost, &ms->stats, 0, mux_stats, format);
if (ret < 0)
goto fail;
}
- MATCH_PER_STREAM_OPT(enc_time_bases, str, enc_time_base, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->enc_time_bases, oc, st, &enc_time_base);
+ if (ret < 0)
+ goto fail;
if (enc_time_base && type == AVMEDIA_TYPE_SUBTITLE)
av_log(ost, AV_LOG_WARNING,
"-enc_time_base not supported for subtitles, ignoring\n");
@@ -1293,7 +1349,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ost->bitexact = !!(ost->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT);
}
- MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->time_bases, oc, st, &time_base);
+ if (ret < 0)
+ return ret;
if (time_base) {
AVRational q;
if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 ||
@@ -1318,7 +1376,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
ms->copy_prior_start = -1;
MATCH_PER_STREAM_OPT(copy_prior_start, i, ms->copy_prior_start, oc ,st);
- MATCH_PER_STREAM_OPT(bitstream_filters, str, bsfs, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->bitstream_filters, oc, st, &bsfs);
+ if (ret < 0)
+ return ret;
if (bsfs && *bsfs) {
ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx);
if (ret < 0) {
@@ -1327,7 +1387,9 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type,
}
}
- MATCH_PER_STREAM_OPT(codec_tags, str, codec_tag, oc, st);
+ ret = opt_match_per_stream_str(ost, &o->codec_tags, oc, st, &codec_tag);
+ if (ret < 0)
+ return ret;
if (codec_tag) {
uint32_t tag = strtol(codec_tag, &next, 0);
if (*next) {
@@ -2943,7 +3005,9 @@ static int set_dispositions(Muxer *mux, const OptionsContext *o)
nb_streams[ost->type + 1]++;
- MATCH_PER_STREAM_OPT_CLEAN(disposition, str, dispositions[i], ctx, ost->st, goto finish);
+ ret = opt_match_per_stream_str(ost, &o->disposition, ctx, ost->st, &dispositions[i]);
+ if (ret < 0)
+ goto finish;
have_manual |= !!dispositions[i];
@@ -3088,8 +3152,12 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o)
for (int i = 0; i < mux->of.nb_streams; i++) {
OutputStream *ost = mux->of.streams[i];
const char *forced_keyframes = NULL;
+ int ret;
- MATCH_PER_STREAM_OPT(forced_key_frames, str, forced_keyframes, mux->fc, ost->st);
+ ret = opt_match_per_stream_str(ost, &o->forced_key_frames,
+ mux->fc, ost->st, &forced_keyframes);
+ if (ret < 0)
+ return ret;
if (!(ost->type == AVMEDIA_TYPE_VIDEO &&
ost->enc_ctx && forced_keyframes))
@@ -164,6 +164,73 @@ const char *opt_match_per_type_str(const SpecifierOptList *sol,
return NULL;
}
+static int opt_match_per_stream(void *logctx, enum OptionType type,
+ const SpecifierOptList *sol,
+ AVFormatContext *fc, AVStream *st)
+{
+ int matches = 0, match_idx = -1;
+
+ av_assert0((type == sol->type) || !sol->nb_opt);
+
+ for (int i = 0; i < sol->nb_opt; i++) {
+ const char *spec = sol->opt[i].specifier;
+ int ret = check_stream_specifier(fc, st, spec);
+ if (ret > 0) {
+ match_idx = i;
+ matches++;
+ } else if (ret < 0)
+ return ret;
+ }
+
+ if (matches > 1 && sol->opt_canon) {
+ const SpecifierOpt *so = &sol->opt[match_idx];
+ const char *spec = so->specifier && so->specifier[0] ? so->specifier : "";
+
+ char namestr[128] = "";
+ char optval_buf[32];
+ const char *optval = optval_buf;
+
+ snprintf(namestr, sizeof(namestr), "-%s", sol->opt_canon->name);
+ if (sol->opt_canon->flags & OPT_HAS_ALT) {
+ const char * const *names_alt = sol->opt_canon->u1.names_alt;
+ for (int i = 0; names_alt[i]; i++)
+ av_strlcatf(namestr, sizeof(namestr), "/-%s", names_alt[i]);
+ }
+
+ switch (sol->type) {
+ case OPT_TYPE_STRING: optval = so->u.str; break;
+ case OPT_TYPE_INT: snprintf(optval_buf, sizeof(optval_buf), "%d", so->u.i); break;
+ case OPT_TYPE_INT64: snprintf(optval_buf, sizeof(optval_buf), "%"PRId64, so->u.i64); break;
+ case OPT_TYPE_FLOAT: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.f); break;
+ case OPT_TYPE_DOUBLE: snprintf(optval_buf, sizeof(optval_buf), "%f", so->u.dbl); break;
+ default: av_assert0(0);
+ }
+
+ av_log(logctx, AV_LOG_WARNING, "Multiple %s options specified for "
+ "stream %d, only the last option '-%s%s%s %s' will be used.\n",
+ namestr, st->index, sol->opt_canon->name, spec[0] ? ":" : "",
+ spec, optval);
+ }
+
+ return match_idx + 1;
+}
+
+#define OPT_MATCH_PER_STREAM(name, type, opt_type, m) \
+int opt_match_per_stream_ ## name(void *logctx, const SpecifierOptList *sol, \
+ AVFormatContext *fc, AVStream *st, type *out) \
+{ \
+ int ret = opt_match_per_stream(logctx, opt_type, sol, fc, st); \
+ \
+ if (ret <= 0) \
+ return ret; \
+ \
+ *out = sol->opt[ret - 1].u.m; \
+ \
+ return 0; \
+}
+
+OPT_MATCH_PER_STREAM(str, const char *, OPT_TYPE_STRING, str);
+
int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global)
{
if (!av_strcasecmp(arg, "cfr")) *vsync_var = VSYNC_CFR;