From patchwork Mon Nov 14 15:13:47 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 39276 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a21:999a:b0:a4:2148:650a with SMTP id ve26csp2488546pzb; Mon, 14 Nov 2022 07:15:15 -0800 (PST) X-Google-Smtp-Source: AA0mqf6AfVbj6eLy6EZEgZYDGQFkXajkC2q3LLsD+ozHx2ULIxiFJ7HEdsp5+PadZsuP/cR3Kuqt X-Received: by 2002:a50:d4d1:0:b0:467:6ffe:e94c with SMTP id e17-20020a50d4d1000000b004676ffee94cmr9994986edj.417.1668438915242; Mon, 14 Nov 2022 07:15:15 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668438915; cv=none; d=google.com; s=arc-20160816; b=toHGbxV5Q8Lr31bulytxZAw97kfQR+k20rugSDkykftWx23Tuapr0XlJL+TpgvAu+X NG4m1SXDaWAsHv3V9zTi4DRcPMQOo0w0E7lBIsZx7LAlu0CbrV7kTBtVpm1kqC3BX6X6 90yvaAEaqW8otbqbz/X2TKrL4xUkGf8KPtie3ajiCvRmHubyMQk791dyL/856W+IJWjU mJaSdDKx60mnoRTmtOhn5PYD3ArFCTum6pDP8jJtvABtkNVJZkNQlGAj/FNkGCFzbAr7 b6e4tn8quhupsDFR10JBfC8LecdPH1YpFv/IdYmBiBmwOV1TpDbg0zYc0qjLY7OwELCJ B82g== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:reply-to:list-subscribe :list-help:list-post:list-archive:list-unsubscribe:list-id :precedence:subject:mime-version:references:in-reply-to:message-id :date:to:from:delivered-to; bh=g0MsofV8Gu9BGTvybyBTjPmlA5jHAV1mBaPu+qhYmhw=; b=DQkE/zmKSsuOmMBnUSnDafo9N7PPlIwFOB0KFDIKJ1zo0yzh3ZDTBh/RgbcsmYNi6v dypTxruoPg3TvbS1HbXExOFy0P5gqTlzUpM9VYVrA2jDXo3nYsn7GAHDnSK95S/y+jnU 6JgszbFScQKKL4Uzp9tX1qCBwEfsyCtU1nP5BhXncIOofjAMG9RC2vkHzxbGe6G3Sr99 P+CjWAfLp/dlyQ87G9pCq26leQT6GI0sHL+ErDyH66SK6p934CzDAPrIHONFBkW26hec K7Vnbb6RxiOOE7ujVYnoxlF9GoipHmgPjSo1JE1htZivNFYSbg4kCFz42waw4DjgcqQA Lg7g== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id k1-20020a170906970100b007ad7e81a30csi7148421ejx.167.2022.11.14.07.15.06; Mon, 14 Nov 2022 07:15:15 -0800 (PST) Received-SPF: pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) client-ip=79.124.17.100; Authentication-Results: mx.google.com; spf=pass (google.com: domain of ffmpeg-devel-bounces@ffmpeg.org designates 79.124.17.100 as permitted sender) smtp.mailfrom=ffmpeg-devel-bounces@ffmpeg.org Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id B15D768BE35; Mon, 14 Nov 2022 17:14:31 +0200 (EET) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail0.khirnov.net (red.khirnov.net [176.97.15.12]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 8866E68BE1A for ; Mon, 14 Nov 2022 17:14:22 +0200 (EET) Received: from localhost (localhost [IPv6:::1]) by mail0.khirnov.net (Postfix) with ESMTP id 3126A2405EC for ; Mon, 14 Nov 2022 16:14:22 +0100 (CET) Received: from mail0.khirnov.net ([IPv6:::1]) by localhost (mail0.khirnov.net [IPv6:::1]) (amavisd-new, port 10024) with ESMTP id w9PwdQsXX6wi for ; Mon, 14 Nov 2022 16:14:21 +0100 (CET) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:2a00:c500:561:201::7]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "libav.khirnov.net", Issuer "smtp.khirnov.net SMTP CA" (verified OK)) by mail0.khirnov.net (Postfix) with ESMTPS id 1C623240591 for ; Mon, 14 Nov 2022 16:14:19 +0100 (CET) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id BFB483A058F for ; Mon, 14 Nov 2022 16:14:18 +0100 (CET) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Mon, 14 Nov 2022 16:13:47 +0100 Message-Id: <20221114151350.5134-5-anton@khirnov.net> X-Mailer: git-send-email 2.35.1 In-Reply-To: <20221114151350.5134-1-anton@khirnov.net> References: <20221114151350.5134-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 5/8] fftools/ffmpeg_mux_init: move validating codec avoptions to a separate function X-BeenThere: ffmpeg-devel@ffmpeg.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: FFmpeg development discussions and patches List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: FFmpeg development discussions and patches Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: Kx6tP25e1DjM --- 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;