From 52380a055b358b8611d88fc02b3a477cac2e4f0c Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Mon, 14 Nov 2022 11:18:26 +0100 Subject: [PATCH] fftools/ffmpeg_mux_init: move validating codec avoptions to a separate function --- fftools/ffmpeg.h | 2 +- fftools/ffmpeg_mux_init.c | 91 +++++++++++++++++++++------------------ fftools/ffmpeg_opt.c | 2 +- 3 files changed, 51 insertions(+), 44 deletions(-) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index ad53ad4ce8..b9262b373f 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -694,7 +694,7 @@ void assert_avoptions(AVDictionary *m); void assert_file_overwrite(const char *filename); char *file_read(const char *filename); -AVDictionary *strip_specifiers(AVDictionary *dict); +AVDictionary *strip_specifiers(const AVDictionary *dict); const AVCodec *find_codec_or_die(const char *name, enum AVMediaType type, int encoder); int parse_and_set_vsync(const char *arg, int *vsync_var, int file_idx, int st_idx, int is_global); diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index 150eb77ee2..7ccaf9da78 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -1725,14 +1725,60 @@ static int set_dispositions(OutputFile *of, AVFormatContext *ctx) return 0; } +static void validate_enc_avopt(const Muxer *mux, const AVDictionary *codec_avopt) +{ + const OutputFile *of = &mux->of; + + AVDictionary *unused_opts; + const AVDictionaryEntry *e; + + unused_opts = strip_specifiers(codec_avopt); + for (int i = 0; i < of->nb_streams; i++) { + e = NULL; + while ((e = av_dict_get(of->streams[i]->encoder_opts, "", e, + AV_DICT_IGNORE_SUFFIX))) + av_dict_set(&unused_opts, e->key, NULL, 0); + } + + e = NULL; + while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) { + const AVClass *class = avcodec_get_class(); + const AVOption *option = av_opt_find(&class, e->key, NULL, 0, + AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); + const AVClass *fclass = avformat_get_class(); + const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0, + AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); + if (!option || foption) + continue; + + if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) { + av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for " + "output file #%d (%s) is not an encoding option.\n", e->key, + option->help ? option->help : "", nb_output_files - 1, + mux->fc->url); + exit_program(1); + } + + // gop_timecode is injected by generic code but not always used + if (!strcmp(e->key, "gop_timecode")) + continue; + + av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for " + "output file #%d (%s) has not been used for any stream. The most " + "likely reason is either wrong type (e.g. a video option with " + "no video streams) or that it is a private option of some encoder " + "which was not actually used for any stream.\n", e->key, + option->help ? option->help : "", nb_output_files - 1, mux->fc->url); + } + av_dict_free(&unused_opts); +} + int of_open(const OptionsContext *o, const char *filename) { Muxer *mux; AVFormatContext *oc; int err; OutputFile *of; - AVDictionary *unused_opts = NULL; - const AVDictionaryEntry *e = NULL; int64_t recording_time = o->recording_time; int64_t stop_time = o->stop_time; @@ -1795,46 +1841,7 @@ int of_open(const OptionsContext *o, const char *filename) create_streams(mux, o); /* check if all codec options have been used */ - unused_opts = strip_specifiers(o->g->codec_opts); - for (int i = 0; i < of->nb_streams; i++) { - e = NULL; - while ((e = av_dict_get(of->streams[i]->encoder_opts, "", e, - AV_DICT_IGNORE_SUFFIX))) - av_dict_set(&unused_opts, e->key, NULL, 0); - } - - e = NULL; - while ((e = av_dict_get(unused_opts, "", e, AV_DICT_IGNORE_SUFFIX))) { - const AVClass *class = avcodec_get_class(); - const AVOption *option = av_opt_find(&class, e->key, NULL, 0, - AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); - const AVClass *fclass = avformat_get_class(); - const AVOption *foption = av_opt_find(&fclass, e->key, NULL, 0, - AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); - if (!option || foption) - continue; - - - if (!(option->flags & AV_OPT_FLAG_ENCODING_PARAM)) { - av_log(NULL, AV_LOG_ERROR, "Codec AVOption %s (%s) specified for " - "output file #%d (%s) is not an encoding option.\n", e->key, - option->help ? option->help : "", nb_output_files - 1, - filename); - exit_program(1); - } - - // gop_timecode is injected by generic code but not always used - if (!strcmp(e->key, "gop_timecode")) - continue; - - av_log(NULL, AV_LOG_WARNING, "Codec AVOption %s (%s) specified for " - "output file #%d (%s) has not been used for any stream. The most " - "likely reason is either wrong type (e.g. a video option with " - "no video streams) or that it is a private option of some encoder " - "which was not actually used for any stream.\n", e->key, - option->help ? option->help : "", nb_output_files - 1, filename); - } - av_dict_free(&unused_opts); + validate_enc_avopt(mux, o->g->codec_opts); /* set the decoding_needed flags and create simple filtergraphs */ for (int i = 0; i < of->nb_streams; i++) { diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 0fd9d98f0f..5ab296828b 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -165,7 +165,7 @@ static int show_hwaccels(void *optctx, const char *opt, const char *arg) } /* return a copy of the input with the stream specifiers removed from the keys */ -AVDictionary *strip_specifiers(AVDictionary *dict) +AVDictionary *strip_specifiers(const AVDictionary *dict) { const AVDictionaryEntry *e = NULL; AVDictionary *ret = NULL;