From patchwork Thu Jun 27 08:44:00 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 50191 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:bc92:0:b0:482:c625:d099 with SMTP id p18csp316869vqy; Thu, 27 Jun 2024 01:44:25 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXHPvVUqiSdDbqrN6Q64I4KgNY9nqwoGlTZt1/N7ZZw0rDcSrgSUv7jo12DpVOXLrfrN+j8JH42mLatgm8HCm1BDFYjLEridLFgCQ== X-Google-Smtp-Source: AGHT+IGLNs+Rdp/P4dH7nsCTRV459GhzUSj1SdKxHaJDt/HDvj0yjuYSGf94kpdOu39M/LZ1U8i0 X-Received: by 2002:a50:ab5b:0:b0:57d:2659:9143 with SMTP id 4fb4d7f45d1cf-57d4bde078cmr10532377a12.37.1719477864954; Thu, 27 Jun 2024 01:44:24 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1719477864; cv=none; d=google.com; s=arc-20160816; b=HuR5Sx2WvcF9zqfVffpLXfOVOWaBBR/TqFXoJP8CJVtWDDDJnMh0Qvi+cLvXADjQdv 92FiimMsnyw1/l+rOSznuzrV8qjOGtpIHXD6uBtZjJLB66O86N9K71B6t6q98BHd9rZa S7lN5g9/UiBrD1FkhN34o8rniivbhyuMAKKuDbRHQ104gHGr9woIM84jp1oXhlbJ2O6a b0riTvBNxhve9xIHDNZMPCZ5ryLtuFuyetR5I4Np6AdZxwjzaAKyj8Fs5k7ILtTfXLir VGqmoTndPBGybeKA5NXymgwYwLeYbWy8J/Nvqge+8iRroegh89K+IeMce/2Xc5qU1VaX 1fsg== 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:message-id:date:to:from :dkim-signature:delivered-to; bh=BRQlyGzX0bXoj49n5aQ9Of3WfZR2JobouPLkll/WVjg=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=dO3/EIVBT58nwNZhyV73trlROCuFrsByc8OGAF6xyy9dQd0gJt6XEiWMZstcsb5BjA ufi/X9sQxQ7vb49M4ByCpcUXxLXslAnRELIXFSF9eM33RHSkwYPOJ12Cn37x22rVyfwM iOc/9hL6a3pds5T0k+oQjX/wL3hpSioPdlo5ZsDr4H3gb+QU90apdh5wAHWu94b7QPv0 94E5GJCccx3wFYxO+XXfM0G7/uxg6EOeTUKePVgImTI15M31hhgkdmLtcllTkDIh6QvV TqP7lfnTpYbWKccY4WCUUtEpDGxVRfMBdJYqK7oczrvRdxOm5xgSZapPzaQhbZvtWoiw revA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=DrRzrNMM; 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 4fb4d7f45d1cf-584d108ea54si483773a12.188.2024.06.27.01.44.24; Thu, 27 Jun 2024 01:44:24 -0700 (PDT) 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; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=DrRzrNMM; 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 ACAE468C5BB; Thu, 27 Jun 2024 11:44:20 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail1.khirnov.net (quelana.khirnov.net [94.230.150.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2E6DA68D2F5 for ; Thu, 27 Jun 2024 11:44:13 +0300 (EEST) Authentication-Results: mail1.khirnov.net; dkim=pass (2048-bit key; unprotected) header.d=khirnov.net header.i=@khirnov.net header.a=rsa-sha256 header.s=mail header.b=DrRzrNMM; dkim-atps=neutral Received: from localhost (mail1.khirnov.net [IPv6:::1]) by mail1.khirnov.net (Postfix) with ESMTP id 7C0044D9D for ; Thu, 27 Jun 2024 10:44:12 +0200 (CEST) Received: from mail1.khirnov.net ([IPv6:::1]) by localhost (mail1.khirnov.net [IPv6:::1]) (amavis, port 10024) with ESMTP id J4ZNU57PRtlH for ; Thu, 27 Jun 2024 10:44:11 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=khirnov.net; s=mail; t=1719477850; bh=bXfeSbEgz6SrdInm+Zyk4V7yPaOV0JOpyrY7y87U4jM=; h=From:To:Subject:Date:From; b=DrRzrNMMVMh5L622mlYbYqGYUJnEl9NS8aXdNm4BI5XaFSLEcYxWrQnCjE2nqgOYL Tm/N/FanpuQCtEGQ3DMAoPkZPd8//eIioX1DgUG7oUstt2jbXaaaq6Flvqwgn+P3VE 2gR2N4MGrP28dnCDm3GiK7SNeLZJuAmzi5dxhefhz5B2SzaRj6BXUZdPRSwjzmguWf FbAT0Tipq4CxIsWPAmSubTs9KHZ0+rprKzDtFg0Qhq7vgBmQAFBowfbSZ2x/eXEYQQ 1ijgLwpXiOlCmpCzx3Ay0tVXUcYpvfzO5TFSqanqz6fa2rMGVaM9UvzB+0sL5Loy1m JQu5fTIjrcDCg== 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 mail1.khirnov.net (Postfix) with ESMTPS id 98FAD4DA2 for ; Thu, 27 Jun 2024 10:44:10 +0200 (CEST) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id 4725F3A02CA for ; Thu, 27 Jun 2024 10:44:04 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Thu, 27 Jun 2024 10:44:00 +0200 Message-ID: <20240627084402.32474-1-anton@khirnov.net> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 1/3] fftools/ffmpeg: rewrite checking whether codec AVOptions have been used 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: q6YJPzjZuF+Q Share the code between encoding and decoding. Instead of checking every stream's options dictionary (which is also used for other purposes), track all used options in a dedicated dictionary. --- fftools/cmdutils.c | 17 ++++++++---- fftools/cmdutils.h | 4 ++- fftools/ffmpeg.c | 50 ++++++++++++++++++++++++++++++++++ fftools/ffmpeg.h | 4 ++- fftools/ffmpeg_demux.c | 50 ++++++++-------------------------- fftools/ffmpeg_mux.c | 1 + fftools/ffmpeg_mux.h | 3 +++ fftools/ffmpeg_mux_init.c | 56 +++++---------------------------------- fftools/ffmpeg_opt.c | 18 ------------- fftools/ffplay.c | 2 +- fftools/ffprobe.c | 2 +- 11 files changed, 91 insertions(+), 116 deletions(-) diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index a504acb3e4..9b18cf5e4d 100644 --- a/fftools/cmdutils.c +++ b/fftools/cmdutils.c @@ -986,7 +986,7 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec) int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, const AVCodec *codec, - AVDictionary **dst) + AVDictionary **dst, AVDictionary **opts_used) { AVDictionary *ret = NULL; const AVDictionaryEntry *t = NULL; @@ -1013,6 +1013,7 @@ int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, while (t = av_dict_iterate(opts, t)) { const AVClass *priv_class; char *p = strchr(t->key, ':'); + int used = 0; /* check stream specification in opt name */ if (p) { @@ -1030,15 +1031,21 @@ int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, !codec || ((priv_class = codec->priv_class) && av_opt_find(&priv_class, t->key, NULL, flags, - AV_OPT_SEARCH_FAKE_OBJ))) + AV_OPT_SEARCH_FAKE_OBJ))) { av_dict_set(&ret, t->key, t->value, 0); - else if (t->key[0] == prefix && + used = 1; + } else if (t->key[0] == prefix && av_opt_find(&cc, t->key + 1, NULL, flags, - AV_OPT_SEARCH_FAKE_OBJ)) + AV_OPT_SEARCH_FAKE_OBJ)) { av_dict_set(&ret, t->key + 1, t->value, 0); + used = 1; + } if (p) *p = ':'; + + if (used && opts_used) + av_dict_set(opts_used, t->key, "", 0); } *dst = ret; @@ -1063,7 +1070,7 @@ int setup_find_stream_info_opts(AVFormatContext *s, for (int i = 0; i < s->nb_streams; i++) { ret = filter_codec_opts(codec_opts, s->streams[i]->codecpar->codec_id, - s, s->streams[i], NULL, &opts[i]); + s, s->streams[i], NULL, &opts[i], NULL); if (ret < 0) goto fail; } diff --git a/fftools/cmdutils.h b/fftools/cmdutils.h index 2125f791d0..14340dff7d 100644 --- a/fftools/cmdutils.h +++ b/fftools/cmdutils.h @@ -371,11 +371,13 @@ int check_stream_specifier(AVFormatContext *s, AVStream *st, const char *spec); * @param codec The particular codec for which the options should be filtered. * If null, the default one is looked up according to the codec id. * @param dst a pointer to the created dictionary + * @param opts_used if non-NULL, every option stored in dst is also stored here, + * with specifiers preserved * @return a non-negative number on success, a negative error code on failure */ int filter_codec_opts(const AVDictionary *opts, enum AVCodecID codec_id, AVFormatContext *s, AVStream *st, const AVCodec *codec, - AVDictionary **dst); + AVDictionary **dst, AVDictionary **opts_used); /** * Setup AVCodecContext options for avformat_find_stream_info(). diff --git a/fftools/ffmpeg.c b/fftools/ffmpeg.c index 88ce3007e8..61593c842f 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -473,6 +473,56 @@ const FrameData *packet_data_c(AVPacket *pkt) return ret < 0 ? NULL : (const FrameData*)pkt->opaque_ref->data; } +int check_avoptions_used(const AVDictionary *opts, const AVDictionary *opts_used, + void *logctx, int decode) +{ + const AVClass *class = avcodec_get_class(); + const AVClass *fclass = avformat_get_class(); + + const int flag = decode ? AV_OPT_FLAG_DECODING_PARAM : + AV_OPT_FLAG_ENCODING_PARAM; + const AVDictionaryEntry *e = NULL; + + while ((e = av_dict_iterate(opts, e))) { + const AVOption *option, *foption; + char *optname, *p; + + if (av_dict_get(opts_used, e->key, NULL, 0)) + continue; + + optname = av_strdup(e->key); + if (!optname) + return AVERROR(ENOMEM); + + p = strchr(optname, ':'); + if (p) + *p = 0; + + option = av_opt_find(&class, optname, NULL, 0, + AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); + foption = av_opt_find(&fclass, optname, NULL, 0, + AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); + av_freep(&optname); + if (!option || foption) + continue; + + if (!(option->flags & flag)) { + av_log(logctx, AV_LOG_ERROR, "Codec AVOption %s (%s) is not a %s " + "option.\n", option->name, option->help ? option->help : "", + decode ? "decoding" : "encoding"); + return AVERROR(EINVAL); + } + + av_log(logctx, AV_LOG_WARNING, "Codec AVOption %s (%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 decoder which was not actually used " + "for any stream.\n", option->name, option->help ? option->help : ""); + } + + return 0; +} + void update_benchmark(const char *fmt, ...) { if (do_benchmark_all) { diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index fe75706afd..8e849bbedc 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -710,8 +710,10 @@ void term_exit(void); void show_usage(void); +int check_avoptions_used(const AVDictionary *opts, const AVDictionary *opts_used, + void *logctx, int decode); + int assert_file_overwrite(const char *filename); -AVDictionary *strip_specifiers(const AVDictionary *dict); int find_codec(void *logctx, const char *name, enum AVMediaType type, int encoder, const AVCodec **codec); 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_demux.c b/fftools/ffmpeg_demux.c index 1ca8d804ae..3762d589e3 100644 --- a/fftools/ffmpeg_demux.c +++ b/fftools/ffmpeg_demux.c @@ -1207,7 +1207,7 @@ static DemuxStream *demux_stream_alloc(Demuxer *d, AVStream *st) return ds; } -static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) +static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st, AVDictionary **opts_used) { AVFormatContext *ic = d->f.ctx; AVCodecParameters *par = st->codecpar; @@ -1334,7 +1334,7 @@ static int ist_add(const OptionsContext *o, Demuxer *d, AVStream *st) if (ist->dec) { ret = filter_codec_opts(o->g->codec_opts, ist->st->codecpar->codec_id, - ic, st, ist->dec, &ds->decoder_opts); + ic, st, ist->dec, &ds->decoder_opts, opts_used); if (ret < 0) return ret; } @@ -1553,8 +1553,7 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) const AVInputFormat *file_iformat = NULL; int err, i, ret = 0; int64_t timestamp; - AVDictionary *unused_opts = NULL; - const AVDictionaryEntry *e = NULL; + AVDictionary *opts_used = NULL; const char* video_codec_name = NULL; const char* audio_codec_name = NULL; const char* subtitle_codec_name = NULL; @@ -1826,48 +1825,21 @@ int ifile_open(const OptionsContext *o, const char *filename, Scheduler *sch) /* Add all the streams from the given input file to the demuxer */ for (int i = 0; i < ic->nb_streams; i++) { - ret = ist_add(o, d, ic->streams[i]); - if (ret < 0) + ret = ist_add(o, d, ic->streams[i], &opts_used); + if (ret < 0) { + av_dict_free(&opts_used); return ret; + } } /* dump the file content */ av_dump_format(ic, f->index, filename, 0); /* check if all codec options have been used */ - unused_opts = strip_specifiers(o->g->codec_opts); - for (i = 0; i < f->nb_streams; i++) { - DemuxStream *ds = ds_from_ist(f->streams[i]); - e = NULL; - while ((e = av_dict_iterate(ds->decoder_opts, e))) - av_dict_set(&unused_opts, e->key, NULL, 0); - } - - e = NULL; - while ((e = av_dict_iterate(unused_opts, e))) { - 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_DECODING_PARAM)) { - av_log(d, AV_LOG_ERROR, "Codec AVOption %s (%s) is not a decoding " - "option.\n", e->key, option->help ? option->help : ""); - return AVERROR(EINVAL); - } - - av_log(d, AV_LOG_WARNING, "Codec AVOption %s (%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 decoder which was not actually used " - "for any stream.\n", e->key, option->help ? option->help : ""); - } - av_dict_free(&unused_opts); + ret = check_avoptions_used(o->g->codec_opts, opts_used, d, 1); + av_dict_free(&opts_used); + if (ret < 0) + return ret; for (i = 0; i < o->dump_attachment.nb_opt; i++) { int j; diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index a1583edd61..055e2f3678 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -865,6 +865,7 @@ void of_free(OutputFile **pof) av_freep(&mux->sch_stream_idx); av_dict_free(&mux->opts); + av_dict_free(&mux->enc_opts_used); av_packet_free(&mux->sq_pkt); diff --git a/fftools/ffmpeg_mux.h b/fftools/ffmpeg_mux.h index 1e9ea35412..1c1b407484 100644 --- a/fftools/ffmpeg_mux.h +++ b/fftools/ffmpeg_mux.h @@ -99,6 +99,9 @@ typedef struct Muxer { AVDictionary *opts; + // used to validate that all encoder avoptions have been actually used + AVDictionary *enc_opts_used; + /* filesize limit expressed in bytes */ int64_t limit_filesize; atomic_int_least64_t last_filesize; diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index 1f19d9283a..b1250d668f 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -1160,7 +1160,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, const char *enc_time_base = NULL; ret = filter_codec_opts(o->g->codec_opts, enc->codec_id, - oc, st, enc->codec, &ost->encoder_opts); + oc, st, enc->codec, &ost->encoder_opts, + &mux->enc_opts_used); if (ret < 0) return ret; @@ -1265,7 +1266,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, } } else { ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, - NULL, &ost->encoder_opts); + NULL, &ost->encoder_opts, + &mux->enc_opts_used); if (ret < 0) return ret; } @@ -3118,53 +3120,6 @@ static int process_forced_keyframes(Muxer *mux, const OptionsContext *o) return 0; } -static int validate_enc_avopt(Muxer *mux, const AVDictionary *codec_avopt) -{ - const AVClass *class = avcodec_get_class(); - const AVClass *fclass = avformat_get_class(); - 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_iterate(of->streams[i]->encoder_opts, e))) - av_dict_set(&unused_opts, e->key, NULL, 0); - } - - e = NULL; - while ((e = av_dict_iterate(unused_opts, e))) { - const AVOption *option = av_opt_find(&class, e->key, NULL, 0, - AV_OPT_SEARCH_CHILDREN | AV_OPT_SEARCH_FAKE_OBJ); - 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(mux, AV_LOG_ERROR, "Codec AVOption %s (%s) is not an " - "encoding option.\n", e->key, option->help ? option->help : ""); - av_dict_free(&unused_opts); - return AVERROR(EINVAL); - } - - // gop_timecode is injected by generic code but not always used - if (!strcmp(e->key, "gop_timecode")) - continue; - - av_log(mux, AV_LOG_WARNING, "Codec AVOption %s (%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 : ""); - } - av_dict_free(&unused_opts); - - return 0; -} - static const char *output_file_item_name(void *obj) { const Muxer *mux = obj; @@ -3272,7 +3227,8 @@ int of_open(const OptionsContext *o, const char *filename, Scheduler *sch) return err; /* check if all codec options have been used */ - err = validate_enc_avopt(mux, o->g->codec_opts); + err = check_avoptions_used(o->g->codec_opts, mux->enc_opts_used, mux, 0); + av_dict_free(&mux->enc_opts_used); if (err < 0) return err; diff --git a/fftools/ffmpeg_opt.c b/fftools/ffmpeg_opt.c index 910e4a336b..b256fc9372 100644 --- a/fftools/ffmpeg_opt.c +++ b/fftools/ffmpeg_opt.c @@ -151,24 +151,6 @@ static int show_hwaccels(void *optctx, const char *opt, const char *arg) return 0; } -/* return a copy of the input with the stream specifiers removed from the keys */ -AVDictionary *strip_specifiers(const AVDictionary *dict) -{ - const AVDictionaryEntry *e = NULL; - AVDictionary *ret = NULL; - - while ((e = av_dict_iterate(dict, e))) { - char *p = strchr(e->key, ':'); - - if (p) - *p = 0; - av_dict_set(&ret, e->key, e->value, 0); - if (p) - *p = ':'; - } - return ret; -} - const char *opt_match_per_type_str(const SpecifierOptList *sol, char mediatype) { diff --git a/fftools/ffplay.c b/fftools/ffplay.c index 1d0511b254..30719e9417 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -2673,7 +2673,7 @@ static int stream_component_open(VideoState *is, int stream_index) avctx->flags2 |= AV_CODEC_FLAG2_FAST; ret = filter_codec_opts(codec_opts, avctx->codec_id, ic, - ic->streams[stream_index], codec, &opts); + ic->streams[stream_index], codec, &opts, NULL); if (ret < 0) goto fail; diff --git a/fftools/ffprobe.c b/fftools/ffprobe.c index d7ba980ff9..e7e27d31ba 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -3927,7 +3927,7 @@ static int open_input_file(InputFile *ifile, const char *filename, AVDictionary *opts; err = filter_codec_opts(codec_opts, stream->codecpar->codec_id, - fmt_ctx, stream, codec, &opts); + fmt_ctx, stream, codec, &opts, NULL); if (err < 0) exit(1); From patchwork Thu Jun 27 08:44:01 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 50193 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:bc92:0:b0:482:c625:d099 with SMTP id p18csp320295vqy; Thu, 27 Jun 2024 01:52:51 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCXG6lNIhY74hLpvVo2z12f2e8KXRHGCwNvuILxZl5DJsqvslAGCfV5PQqVZh1kemfDjgK+JKeispPTDkGd7W3xFXMEEM9DxA9eKag== X-Google-Smtp-Source: AGHT+IH786ETjbqEJ3tJcLhDFL6dR+kgYgSeHcy+0gV5lY3Hkwfq89QRKtIipt8jOwKYE1Shj43d X-Received: by 2002:a17:906:e48:b0:a6e:46ab:9a9b with SMTP id a640c23a62f3a-a7245cce92cmr758757066b.31.1719478370900; Thu, 27 Jun 2024 01:52:50 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1719478370; cv=none; d=google.com; s=arc-20160816; b=VK3nusvwMdjffXn0C8OoiGKTarGo/6w7RUYBOXpPjGvVCYp4+kdWaKiAgyxUHKeKc9 byJWzvklCs7M934WbnOK5z74ifXWOGn8wiuA59f6a6aqKxdOIW2aQoj1EDU2Av7SP4Hr 0U9XGc+ALhhCV3uTI8aQhhnJLJVqg5jBvxdYKgHO3lWZR1vvy1P9tOJlJFEi33QchuC0 aKkLi6jVj+yl90TVxry3wyJ8q4UQ9uZpX86DBQVZnFlxxVtUemPTmBBmO7fO0oqQXIU2 FY7QB6GnqzRAVUTh4uV29FWKg5piFn1HLtqCDigZ8zrt/HHyGTnct8oGioXye+cAIi7s K2rw== 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:dkim-signature:delivered-to; bh=HPTAGoI4rrUVRGBUEFlqxbTi1i3wkXCjpItmNz9XqMc=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=It6TcMGAnNdui8rKWKVLqMgQVHLB8os2ETmZTU+LbjIIlKowaHAjEp+20oJsoEPt27 bUsO1fWiliWzsW97EPAY7KhD48VeTqdPRMpfXpcwzaucw9QH+l64RHHvbc8gwC0SLpdR OGx71f7kKvgXSSMWXJOHCdY2or2ePgkJqYRA8J5xtUFAkWPIhi1KMfT47H1e2sVX1KPF E1cXlGb442FS6jhqrNm6qV2DCmz0hUBcku9d+VSmCc6/CWmg9t3mtRaIE+ozw3s/BIyP F2yHSL1cD2FN6BcemKCYPN9veeoqKuqzSP161hB6SMtwYIpaloDNJBzEu8fF8vFCTOVJ sLpg==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=bGx8XUKH; 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 a640c23a62f3a-a729d7c56bdsi42863466b.789.2024.06.27.01.52.50; Thu, 27 Jun 2024 01:52:50 -0700 (PDT) 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; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=bGx8XUKH; 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 CD48268D594; Thu, 27 Jun 2024 11:44:22 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail1.khirnov.net (quelana.khirnov.net [94.230.150.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 2C36868C5BB for ; Thu, 27 Jun 2024 11:44:13 +0300 (EEST) Authentication-Results: mail1.khirnov.net; dkim=pass (2048-bit key; unprotected) header.d=khirnov.net header.i=@khirnov.net header.a=rsa-sha256 header.s=mail header.b=bGx8XUKH; dkim-atps=neutral Received: from localhost (mail1.khirnov.net [IPv6:::1]) by mail1.khirnov.net (Postfix) with ESMTP id B26FB4DE2 for ; Thu, 27 Jun 2024 10:44:11 +0200 (CEST) Received: from mail1.khirnov.net ([IPv6:::1]) by localhost (mail1.khirnov.net [IPv6:::1]) (amavis, port 10024) with ESMTP id 4EnrjZmkP4_B for ; Thu, 27 Jun 2024 10:44:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=khirnov.net; s=mail; t=1719477850; bh=xtNio52uFB9KDE8cCiUgh939Qrlm/1JyGC/ro5hxTPI=; h=From:To:Subject:Date:In-Reply-To:References:From; b=bGx8XUKHwk6CUM98rb3MfSfIRkV2V4AZZD3Awxve0SBZ6Ucfy2OAPqR3ajgo7Jm+b bWoRj4G9bPQCBEHOYb5XOt+kuBLniUcFTtR7xiTaaeerxI4rC6jsR1VtuMkFoFrPiB Tfk4egUpvRZKi0eKUsc5doBHzfj/ylpsTsiKVbiQ+LjzyXFEVSmig5iOHlvuQ/RdmW Z6hiJRX8BEdTJWJApkq4CtPdejjBG11/GrPPjR8PRArmC0BjzeTgcCZ5Hxd06S09eJ Ns9qkSEJ6y7Vc3qaAyaRVoaHNU0L5JnPkNYC0UEoIzRLvGNlaEJHZDTautOGyeJf87 hXWHtfVnX0cDw== 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 mail1.khirnov.net (Postfix) with ESMTPS id 97B154D9D for ; Thu, 27 Jun 2024 10:44:10 +0200 (CEST) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id 546BB3A05C5 for ; Thu, 27 Jun 2024 10:44:04 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Thu, 27 Jun 2024 10:44:01 +0200 Message-ID: <20240627084402.32474-2-anton@khirnov.net> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240627084402.32474-1-anton@khirnov.net> References: <20240627084402.32474-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/3] fftools/ffmpeg_mux_init: apply encoder options manually 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: xu4LjjjDM8fK Do not pass an options dictionary to the avcodec_open2() in enc_open(). This is cleaner and more robust, as previously various bits of code would try to interpret the contents of the options dictionary, with varying degrees of correctness. Now they can just access the encoder AVCodecContext directly. Cf. 372c78dd42f2b1ca743473b9c32fad71c65919e0 - analogous change for decoding. A non-progressive field order is now written on the container level in interlaced ProRes encoding tests. --- fftools/ffmpeg_enc.c | 18 ++---- fftools/ffmpeg_mux_init.c | 66 +++++++++++---------- tests/ref/vsynth/vsynth1-prores_444_int | 2 +- tests/ref/vsynth/vsynth1-prores_int | 2 +- tests/ref/vsynth/vsynth2-prores_444_int | 2 +- tests/ref/vsynth/vsynth2-prores_int | 2 +- tests/ref/vsynth/vsynth3-prores_444_int | 2 +- tests/ref/vsynth/vsynth3-prores_int | 2 +- tests/ref/vsynth/vsynth_lena-prores_444_int | 2 +- tests/ref/vsynth/vsynth_lena-prores_int | 2 +- 10 files changed, 47 insertions(+), 53 deletions(-) diff --git a/fftools/ffmpeg_enc.c b/fftools/ffmpeg_enc.c index 618ba193ff..029980063d 100644 --- a/fftools/ffmpeg_enc.c +++ b/fftools/ffmpeg_enc.c @@ -307,16 +307,10 @@ int enc_open(void *opaque, const AVFrame *frame) if (ost->bitexact) enc_ctx->flags |= AV_CODEC_FLAG_BITEXACT; - if (!av_dict_get(ost->encoder_opts, "threads", NULL, 0)) - av_dict_set(&ost->encoder_opts, "threads", "auto", 0); + if (enc->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE) + enc_ctx->flags |= AV_CODEC_FLAG_COPY_OPAQUE; - if (enc->capabilities & AV_CODEC_CAP_ENCODER_REORDERED_OPAQUE) { - ret = av_dict_set(&ost->encoder_opts, "flags", "+copy_opaque", AV_DICT_MULTIKEY); - if (ret < 0) - return ret; - } - - av_dict_set(&ost->encoder_opts, "flags", "+frame_duration", AV_DICT_MULTIKEY); + enc_ctx->flags |= AV_CODEC_FLAG_FRAME_DURATION; ret = hw_device_setup_for_encode(ost, frame ? frame->hw_frames_ctx : NULL); if (ret < 0) { @@ -325,7 +319,7 @@ int enc_open(void *opaque, const AVFrame *frame) return ret; } - if ((ret = avcodec_open2(ost->enc_ctx, enc, &ost->encoder_opts)) < 0) { + if ((ret = avcodec_open2(ost->enc_ctx, enc, NULL)) < 0) { if (ret != AVERROR_EXPERIMENTAL) av_log(ost, AV_LOG_ERROR, "Error while opening encoder - maybe " "incorrect parameters such as bit_rate, rate, width or height.\n"); @@ -337,10 +331,6 @@ int enc_open(void *opaque, const AVFrame *frame) if (ost->enc_ctx->frame_size) frame_samples = ost->enc_ctx->frame_size; - ret = check_avoptions(ost->encoder_opts); - if (ret < 0) - return ret; - if (ost->enc_ctx->bit_rate && ost->enc_ctx->bit_rate < 1000 && ost->enc_ctx->codec_id != AV_CODEC_ID_CODEC2 /* don't complain about 700 bit/s modes */) av_log(ost, AV_LOG_WARNING, "The bitrate parameter is set too low." diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index b1250d668f..447d6a5329 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -711,14 +711,10 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, /* two pass mode */ MATCH_PER_STREAM_OPT(pass, i, do_pass, oc, st); if (do_pass) { - if (do_pass & 1) { + if (do_pass & 1) video_enc->flags |= AV_CODEC_FLAG_PASS1; - av_dict_set(&ost->encoder_opts, "flags", "+pass1", AV_DICT_APPEND); - } - if (do_pass & 2) { + if (do_pass & 2) video_enc->flags |= AV_CODEC_FLAG_PASS2; - av_dict_set(&ost->encoder_opts, "flags", "+pass2", AV_DICT_APPEND); - } } MATCH_PER_STREAM_OPT(passlogfiles, str, ost->logfile_prefix, oc, st); @@ -740,7 +736,10 @@ static int new_stream_video(Muxer *mux, const OptionsContext *o, DEFAULT_PASS_LOGFILENAME_PREFIX, ost_idx); if (!strcmp(ost->enc_ctx->codec->name, "libx264") || !strcmp(ost->enc_ctx->codec->name, "libvvenc")) { - av_dict_set(&ost->encoder_opts, "stats", logfilename, AV_DICT_DONT_OVERWRITE); + if (av_opt_is_set_to_default_by_name(ost->enc_ctx, "stats", + AV_OPT_SEARCH_CHILDREN) > 0) + av_opt_set(ost->enc_ctx, "stats", logfilename, + AV_OPT_SEARCH_CHILDREN); } else { if (video_enc->flags & AV_CODEC_FLAG_PASS2) { char *logbuffer = file_read(logfilename); @@ -1041,6 +1040,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, const AVCodec *enc; AVStream *st; int ret = 0, keep_pix_fmt = 0, autoscale = 1; + int threads_manual = 0; AVRational enc_tb = { 0, 0 }; enum VideoSyncMethod vsync_method = VSYNC_AUTO; const char *bsfs = NULL, *time_base = NULL; @@ -1264,6 +1264,23 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, enc_tb = q; } + + threads_manual = !!av_dict_get(ost->encoder_opts, "threads", NULL, 0); + + ret = av_opt_set_dict2(ost->enc_ctx, &ost->encoder_opts, AV_OPT_SEARCH_CHILDREN); + if (ret < 0) { + av_log(ost, AV_LOG_ERROR, "Error applying encoder options: %s\n", + av_err2str(ret)); + return ret; + } + + ret = check_avoptions(ost->encoder_opts); + if (ret < 0) + return ret; + + // default to automatic thread count + if (!threads_manual) + ost->enc_ctx->thread_count = 0; } else { ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, NULL, &ost->encoder_opts, @@ -1276,8 +1293,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (o->bitexact) { ost->bitexact = 1; } else if (ost->enc_ctx) { - ost->bitexact = check_opt_bitexact(ost->enc_ctx, ost->encoder_opts, "flags", - AV_CODEC_FLAG_BITEXACT); + ost->bitexact = !!(ost->enc_ctx->flags & AV_CODEC_FLAG_BITEXACT); } MATCH_PER_STREAM_OPT(time_bases, str, time_base, oc, st); @@ -1372,7 +1388,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (ost->enc && (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO)) { - const AVDictionaryEntry *e; char name[16]; OutputFilterOptions opts = { .enc = enc, @@ -1398,10 +1413,6 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, snprintf(name, sizeof(name), "#%d:%d", mux->of.index, ost->index); - e = av_dict_get(ost->encoder_opts, "threads", NULL, 0); - if (e) - opts.nb_threads = e->value; - // MJPEG encoder exports a full list of supported pixel formats, // but the full-range ones are experimental-only. // Restrict the auto-conversion list unless -strict experimental @@ -1413,33 +1424,26 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, { AV_PIX_FMT_YUVJ420P, AV_PIX_FMT_YUVJ422P, AV_PIX_FMT_YUVJ444P, AV_PIX_FMT_NONE }; - const AVDictionaryEntry *strict = av_dict_get(ost->encoder_opts, "strict", NULL, 0); - int strict_val = ost->enc_ctx->strict_std_compliance; - - if (strict) { - const AVOption *o = av_opt_find(ost->enc_ctx, strict->key, NULL, 0, 0); - av_assert0(o); - av_opt_eval_int(ost->enc_ctx, o, strict->value, &strict_val); - } - - if (strict_val > FF_COMPLIANCE_UNOFFICIAL) + if (ost->enc_ctx->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) opts.pix_fmts = mjpeg_formats; } + if (threads_manual) { + ret = av_opt_get(ost->enc_ctx, "threads", 0, (uint8_t**)&opts.nb_threads); + if (ret < 0) + return ret; + } + if (ofilter) { ost->filter = ofilter; ret = ofilter_bind_ost(ofilter, ost, ms->sch_idx_enc, &opts); - if (ret < 0) - return ret; } else { ret = init_simple_filtergraph(ost->ist, ost, filters, mux->sch, ms->sch_idx_enc, &opts); - if (ret < 0) { - av_log(ost, AV_LOG_ERROR, - "Error initializing a simple filtergraph\n"); - return ret; - } } + av_freep(&opts.nb_threads); + if (ret < 0) + return ret; ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); diff --git a/tests/ref/vsynth/vsynth1-prores_444_int b/tests/ref/vsynth/vsynth1-prores_444_int index 76db62d4e9..3d4c616c7a 100644 --- a/tests/ref/vsynth/vsynth1-prores_444_int +++ b/tests/ref/vsynth/vsynth1-prores_444_int @@ -1,4 +1,4 @@ -fd2a2f49c61817c2338f39d5736d5fd2 *tests/data/fate/vsynth1-prores_444_int.mov +bd1502671ce7144c106a6a460b2af404 *tests/data/fate/vsynth1-prores_444_int.mov 9940947 tests/data/fate/vsynth1-prores_444_int.mov 732ceeb6887524e0aee98762fe50578b *tests/data/fate/vsynth1-prores_444_int.out.rawvideo stddev: 2.83 PSNR: 39.08 MAXDIFF: 45 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth1-prores_int b/tests/ref/vsynth/vsynth1-prores_int index 3e2bbeff2a..c3b57631c8 100644 --- a/tests/ref/vsynth/vsynth1-prores_int +++ b/tests/ref/vsynth/vsynth1-prores_int @@ -1,4 +1,4 @@ -1f1b246dfabe028f04c78887e5da51ed *tests/data/fate/vsynth1-prores_int.mov +842f92426e56cf6208cc94360d29fc69 *tests/data/fate/vsynth1-prores_int.mov 6308688 tests/data/fate/vsynth1-prores_int.mov 164a4ca890695cf594293d1acec9463c *tests/data/fate/vsynth1-prores_int.out.rawvideo stddev: 2.66 PSNR: 39.62 MAXDIFF: 34 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores_444_int b/tests/ref/vsynth/vsynth2-prores_444_int index a2ee569c49..8d2a13b91b 100644 --- a/tests/ref/vsynth/vsynth2-prores_444_int +++ b/tests/ref/vsynth/vsynth2-prores_444_int @@ -1,4 +1,4 @@ -5ac517fc2380a6cf11b7d86d2fafee0a *tests/data/fate/vsynth2-prores_444_int.mov +6f5fa77609698fbed3a7eef1c91bb9ea *tests/data/fate/vsynth2-prores_444_int.mov 6420787 tests/data/fate/vsynth2-prores_444_int.mov 33a5db4f0423168d4ae4f1db3610928e *tests/data/fate/vsynth2-prores_444_int.out.rawvideo stddev: 0.93 PSNR: 48.73 MAXDIFF: 14 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth2-prores_int b/tests/ref/vsynth/vsynth2-prores_int index 72139ee6c3..f80ff34601 100644 --- a/tests/ref/vsynth/vsynth2-prores_int +++ b/tests/ref/vsynth/vsynth2-prores_int @@ -1,4 +1,4 @@ -4062c74196d95a64e642bd917377ed93 *tests/data/fate/vsynth2-prores_int.mov +a9a9812dd8944a58c2c2b3b0ce41247d *tests/data/fate/vsynth2-prores_int.mov 4070996 tests/data/fate/vsynth2-prores_int.mov bef9e38387a1fbb1ce2e4401b6d41674 *tests/data/fate/vsynth2-prores_int.out.rawvideo stddev: 1.54 PSNR: 44.37 MAXDIFF: 13 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth3-prores_444_int b/tests/ref/vsynth/vsynth3-prores_444_int index ac30691143..ca30db5383 100644 --- a/tests/ref/vsynth/vsynth3-prores_444_int +++ b/tests/ref/vsynth/vsynth3-prores_444_int @@ -1,4 +1,4 @@ -50db4bbc4674de3dfdd41f306af1cb17 *tests/data/fate/vsynth3-prores_444_int.mov +b61864cafb35ad8e592b4f899bdd84b6 *tests/data/fate/vsynth3-prores_444_int.mov 184397 tests/data/fate/vsynth3-prores_444_int.mov a8852aa2841c2ce5f2aa86176ceda4ef *tests/data/fate/vsynth3-prores_444_int.out.rawvideo stddev: 3.24 PSNR: 37.91 MAXDIFF: 41 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth3-prores_int b/tests/ref/vsynth/vsynth3-prores_int index 86fc2266b5..0feee26de1 100644 --- a/tests/ref/vsynth/vsynth3-prores_int +++ b/tests/ref/vsynth/vsynth3-prores_int @@ -1,4 +1,4 @@ -24b765064b4aec754fdd0cc3658bba19 *tests/data/fate/vsynth3-prores_int.mov +2e89dfb5e2b5146337c1d65ccc4fe196 *tests/data/fate/vsynth3-prores_int.mov 120484 tests/data/fate/vsynth3-prores_int.mov e5859ba47a99f9e53c1ddcaa68a8f8f8 *tests/data/fate/vsynth3-prores_int.out.rawvideo stddev: 2.92 PSNR: 38.81 MAXDIFF: 29 bytes: 86700/ 86700 diff --git a/tests/ref/vsynth/vsynth_lena-prores_444_int b/tests/ref/vsynth/vsynth_lena-prores_444_int index f05f1fe775..b13a7a126a 100644 --- a/tests/ref/vsynth/vsynth_lena-prores_444_int +++ b/tests/ref/vsynth/vsynth_lena-prores_444_int @@ -1,4 +1,4 @@ -09b5dffd1a484e2152a3b5a0bcceed32 *tests/data/fate/vsynth_lena-prores_444_int.mov +e76d98c772c65c7ac75f7d43484883d3 *tests/data/fate/vsynth_lena-prores_444_int.mov 5696258 tests/data/fate/vsynth_lena-prores_444_int.mov 466380156e4d2b811f4ffb9c5a8bca72 *tests/data/fate/vsynth_lena-prores_444_int.out.rawvideo stddev: 0.88 PSNR: 49.23 MAXDIFF: 9 bytes: 7603200/ 7603200 diff --git a/tests/ref/vsynth/vsynth_lena-prores_int b/tests/ref/vsynth/vsynth_lena-prores_int index ea08089745..cec45a59b9 100644 --- a/tests/ref/vsynth/vsynth_lena-prores_int +++ b/tests/ref/vsynth/vsynth_lena-prores_int @@ -1,4 +1,4 @@ -c7e9a61054f44fe372a3bce619b68ce9 *tests/data/fate/vsynth_lena-prores_int.mov +21d328216b194500a3c87c45afa5e927 *tests/data/fate/vsynth_lena-prores_int.mov 3532698 tests/data/fate/vsynth_lena-prores_int.mov eb5caa9824ca294f403cd13f33c40f23 *tests/data/fate/vsynth_lena-prores_int.out.rawvideo stddev: 1.47 PSNR: 44.78 MAXDIFF: 12 bytes: 7603200/ 7603200 From patchwork Thu Jun 27 08:44:02 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 50192 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:bc92:0:b0:482:c625:d099 with SMTP id p18csp317022vqy; Thu, 27 Jun 2024 01:44:48 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCUdGMN125u2ckLp+syERDaeAsZnP0B2LsMv024+/2/iBqIHPdw+GY7pbS7prf1dTmMykvj0M/3Q7JBv4tyWlnKi90nMd4BplAvu6g== X-Google-Smtp-Source: AGHT+IG7IQIPPsTMSwCULMhjQOqDEND0gJwAYNmvEp9ZTbfEOVnaTMTnejB4UyRDG93MRW1V0lgk X-Received: by 2002:a05:6512:3a8b:b0:52c:e1d4:8ecd with SMTP id 2adb3069b0e04-52ce1d49146mr10605141e87.8.1719477888643; Thu, 27 Jun 2024 01:44:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1719477888; cv=none; d=google.com; s=arc-20160816; b=f1vkMiRfvn6GpwZBs0HgVyMXJSWZP1hQySJ97eRAQTUl6cGm2uMU9OgqeLDdGo2kF/ VEGGr3yVuIha6P5LoxKbEVyN9ID/KWNjFJZ4XAfj5CP9Tr8TYgqo3LjFD+MR0c4xLi51 kV2AxGQOy7zJg0NpS+9WUp58tio7+anaVw9v1priPTMgi0i3EADx9Yn309y/Kx4TQwVF IDkG/VfHqOv8E8i/6h8UT1yExbC6UYDOR/c4CnvLxKNEF5zjhaHIzqUDdRryP4IUB488 22EfdcaiLGDrwKmiN0cZG8WxGoiO9/x3Bx9oZLqYMRsI7+Z9HV+jC9/+hVpsVIAzqQri VtIg== 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:dkim-signature:delivered-to; bh=iRuxntoBYOS7443iw5mnmeBmy9N0c57R+7SGNpstHeU=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=fZd7uUWYNOV/qbFmkVj4IZPbVYQ9vriI1EcT2xXL/cmkpSZBOnm7wLg76sVDS8FkB/ 5XY5jSekIsHPc9dutIkQIVUh1AbH2VESRlzbZwhgQfLNcaT2aATRHbYospLDpXDJ1lWC 8wgVZdUbdCQZshJ4dA6tNjanKbOdA6ij+i5jOtZ31ro0ccxJsYbzQf1SGRpvgIH+q/b7 lzLyalxFpdLYekwdhgECBi42xMwSCeuVhjo5vnWSQuAge0NF+I11qfN4RQWu/npN2M/W 8TFKUDxpwhMv/MQrpREOxtHE6Zhu/x95CFNWgPtXD21To2/mWeyQZvP30pU5kRGYqoko +cQA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=BK7i0nQv; 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 2adb3069b0e04-52e7131ecf2si263078e87.620.2024.06.27.01.44.48; Thu, 27 Jun 2024 01:44:48 -0700 (PDT) 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; dkim=neutral (body hash did not verify) header.i=@khirnov.net header.s=mail header.b=BK7i0nQv; 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 BAED068D5B7; Thu, 27 Jun 2024 11:44:23 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail1.khirnov.net (quelana.khirnov.net [94.230.150.81]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 9492468C5BB for ; Thu, 27 Jun 2024 11:44:13 +0300 (EEST) Authentication-Results: mail1.khirnov.net; dkim=pass (2048-bit key; unprotected) header.d=khirnov.net header.i=@khirnov.net header.a=rsa-sha256 header.s=mail header.b=BK7i0nQv; dkim-atps=neutral Received: from localhost (mail1.khirnov.net [IPv6:::1]) by mail1.khirnov.net (Postfix) with ESMTP id 27DB14DA2 for ; Thu, 27 Jun 2024 10:44:13 +0200 (CEST) Received: from mail1.khirnov.net ([IPv6:::1]) by localhost (mail1.khirnov.net [IPv6:::1]) (amavis, port 10024) with ESMTP id p2LZxeuRa15E for ; Thu, 27 Jun 2024 10:44:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=khirnov.net; s=mail; t=1719477850; bh=MsQa3HB198GOt83vPVL99dnBDWq3xLHg/Ix3w26msqM=; h=From:To:Subject:Date:In-Reply-To:References:From; b=BK7i0nQvrSDP0r7vCjoe7Ghy9bpOPaXEoNIzsf/ODas1RmD4TBaTrB+HoiLA92WhA qan0PlE2gcIetULpfzoKg9ry9nLsEEVdN1Lb337ZE2nIufivfOk7UvrTjNVsckbXYf Zgo1zBEAA1gd7uN/pSMVtiogqOgsWWjp4Q9aYF0Z+DAIH/PRH5JFDDKk6Dmbyv82YR ath0uAFno9UlykUs0EVQj9soAkdaMCoge9mGxbOSZI7w3TL30fQZH02k56O4Dz+Ihd wZW3NE0MBcjLAGW+jh0PzvcMypBxNIXEKiPUhsNeNbJOQARa/Jj9Yv+cvgrQZUCRNi OTBolR8K2JysA== 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 mail1.khirnov.net (Postfix) with ESMTPS id 95B7E207 for ; Thu, 27 Jun 2024 10:44:10 +0200 (CEST) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id 605563A083A for ; Thu, 27 Jun 2024 10:44:04 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Thu, 27 Jun 2024 10:44:02 +0200 Message-ID: <20240627084402.32474-3-anton@khirnov.net> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240627084402.32474-1-anton@khirnov.net> References: <20240627084402.32474-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 3/3] fftools/ffmpeg_mux_init: make encoder_opts local to ost_add() 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: 59g+4nEbVovQ It is no longer needed after this function returns. --- fftools/ffmpeg.h | 2 -- fftools/ffmpeg_mux.c | 1 - fftools/ffmpeg_mux_init.c | 71 ++++++++++++++++++++++----------------- 3 files changed, 40 insertions(+), 34 deletions(-) diff --git a/fftools/ffmpeg.h b/fftools/ffmpeg.h index 8e849bbedc..8b51659693 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -586,8 +586,6 @@ typedef struct OutputStream { FilterGraph *fg_simple; OutputFilter *filter; - AVDictionary *encoder_opts; - char *attachment_filename; /* stats */ diff --git a/fftools/ffmpeg_mux.c b/fftools/ffmpeg_mux.c index 055e2f3678..de3e052152 100644 --- a/fftools/ffmpeg_mux.c +++ b/fftools/ffmpeg_mux.c @@ -813,7 +813,6 @@ static void ost_free(OutputStream **post) av_packet_free(&ms->bsf_pkt); av_packet_free(&ms->pkt); - av_dict_free(&ost->encoder_opts); av_freep(&ost->kf.pts); av_expr_free(ost->kf.pexpr); diff --git a/fftools/ffmpeg_mux_init.c b/fftools/ffmpeg_mux_init.c index 447d6a5329..3e4661fd6d 100644 --- a/fftools/ffmpeg_mux_init.c +++ b/fftools/ffmpeg_mux_init.c @@ -905,7 +905,7 @@ static int new_stream_subtitle(Muxer *mux, const OptionsContext *o, return 0; } -static int streamcopy_init(const Muxer *mux, OutputStream *ost) +static int streamcopy_init(const Muxer *mux, OutputStream *ost, AVDictionary **encoder_opts) { MuxStream *ms = ms_from_ost(ost); @@ -928,7 +928,7 @@ static int streamcopy_init(const Muxer *mux, OutputStream *ost) ret = avcodec_parameters_to_context(codec_ctx, ist->par); if (ret >= 0) - ret = av_opt_set_dict(codec_ctx, &ost->encoder_opts); + ret = av_opt_set_dict(codec_ctx, encoder_opts); if (ret < 0) { av_log(ost, AV_LOG_FATAL, "Error setting up codec context options.\n"); @@ -1039,6 +1039,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, OutputStream *ost; const AVCodec *enc; AVStream *st; + AVDictionary *encoder_opts = NULL; int ret = 0, keep_pix_fmt = 0, autoscale = 1; int threads_manual = 0; AVRational enc_tb = { 0, 0 }; @@ -1160,10 +1161,10 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, const char *enc_time_base = NULL; ret = filter_codec_opts(o->g->codec_opts, enc->codec_id, - oc, st, enc->codec, &ost->encoder_opts, + oc, st, enc->codec, &encoder_opts, &mux->enc_opts_used); if (ret < 0) - return ret; + goto fail; MATCH_PER_STREAM_OPT(presets, str, preset, oc, st); @@ -1187,7 +1188,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, break; } *arg++ = 0; - av_dict_set(&ost->encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE); + av_dict_set(&encoder_opts, buf, arg, AV_DICT_DONT_OVERWRITE); } while (!s->eof_reached); av_bprint_finalize(&bprint, NULL); avio_closep(&s); @@ -1195,7 +1196,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (ret) { av_log(ost, AV_LOG_FATAL, "Preset %s specified, but could not be opened.\n", preset); - return ret; + goto fail; } MATCH_PER_STREAM_OPT(enc_stats_pre, str, enc_stats_pre, oc, st); @@ -1207,7 +1208,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, ret = enc_stats_init(ost, &ost->enc_stats_pre, 1, enc_stats_pre, format); if (ret < 0) - return ret; + goto fail; } MATCH_PER_STREAM_OPT(enc_stats_post, str, enc_stats_post, oc, st); @@ -1219,7 +1220,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, ret = enc_stats_init(ost, &ost->enc_stats_post, 0, enc_stats_post, format); if (ret < 0) - return ret; + goto fail; } MATCH_PER_STREAM_OPT(mux_stats, str, mux_stats, oc, st); @@ -1231,7 +1232,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, ret = enc_stats_init(ost, &ms->stats, 0, mux_stats, format); if (ret < 0) - return ret; + goto fail; } MATCH_PER_STREAM_OPT(enc_time_bases, str, enc_time_base, oc, st); @@ -1253,7 +1254,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, #endif ) { av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", enc_time_base); - return ret < 0 ? ret : AVERROR(EINVAL); + ret = ret < 0 ? ret : AVERROR(EINVAL); + goto fail; } #if FFMPEG_OPT_ENC_TIME_BASE_NUM if (q.num < 0) @@ -1265,28 +1267,28 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, enc_tb = q; } - threads_manual = !!av_dict_get(ost->encoder_opts, "threads", NULL, 0); + threads_manual = !!av_dict_get(encoder_opts, "threads", NULL, 0); - ret = av_opt_set_dict2(ost->enc_ctx, &ost->encoder_opts, AV_OPT_SEARCH_CHILDREN); + ret = av_opt_set_dict2(ost->enc_ctx, &encoder_opts, AV_OPT_SEARCH_CHILDREN); if (ret < 0) { av_log(ost, AV_LOG_ERROR, "Error applying encoder options: %s\n", av_err2str(ret)); - return ret; + goto fail; } - ret = check_avoptions(ost->encoder_opts); + ret = check_avoptions(encoder_opts); if (ret < 0) - return ret; + goto fail; // default to automatic thread count if (!threads_manual) ost->enc_ctx->thread_count = 0; } else { ret = filter_codec_opts(o->g->codec_opts, AV_CODEC_ID_NONE, oc, st, - NULL, &ost->encoder_opts, + NULL, &encoder_opts, &mux->enc_opts_used); if (ret < 0) - return ret; + goto fail; } @@ -1302,7 +1304,8 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (av_parse_ratio(&q, time_base, INT_MAX, 0, NULL) < 0 || q.num <= 0 || q.den <= 0) { av_log(ost, AV_LOG_FATAL, "Invalid time base: %s\n", time_base); - return AVERROR(EINVAL); + ret = AVERROR(EINVAL); + goto fail; } st->time_base = q; } @@ -1325,7 +1328,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, ret = av_bsf_list_parse_str(bsfs, &ms->bsf_ctx); if (ret < 0) { av_log(ost, AV_LOG_ERROR, "Error parsing bitstream filter sequence '%s': %s\n", bsfs, av_err2str(ret)); - return ret; + goto fail; } } @@ -1378,12 +1381,12 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, case AVMEDIA_TYPE_SUBTITLE: ret = new_stream_subtitle (mux, o, ost); break; } if (ret < 0) - return ret; + goto fail; if (type == AVMEDIA_TYPE_VIDEO || type == AVMEDIA_TYPE_AUDIO) { ret = ost_get_filters(o, oc, ost, &filters); if (ret < 0) - return ret; + goto fail; } if (ost->enc && @@ -1431,7 +1434,7 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (threads_manual) { ret = av_opt_get(ost->enc_ctx, "threads", 0, (uint8_t**)&opts.nb_threads); if (ret < 0) - return ret; + goto fail; } if (ofilter) { @@ -1443,18 +1446,19 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, } av_freep(&opts.nb_threads); if (ret < 0) - return ret; + goto fail; ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); if (ret < 0) - return ret; + goto fail; } else if (ost->ist) { int sched_idx = ist_output_add(ost->ist, ost); if (sched_idx < 0) { av_log(ost, AV_LOG_ERROR, "Error binding an input stream\n"); - return sched_idx; + ret = sched_idx; + goto fail; } ms->sch_idx_src = sched_idx; @@ -1462,24 +1466,24 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, ret = sch_connect(mux->sch, SCH_DEC(sched_idx), SCH_ENC(ms->sch_idx_enc)); if (ret < 0) - return ret; + goto fail; ret = sch_connect(mux->sch, SCH_ENC(ms->sch_idx_enc), SCH_MSTREAM(mux->sch_idx, ms->sch_idx)); if (ret < 0) - return ret; + goto fail; } else { ret = sch_connect(mux->sch, SCH_DSTREAM(ost->ist->file->index, sched_idx), SCH_MSTREAM(ost->file->index, ms->sch_idx)); if (ret < 0) - return ret; + goto fail; } } if (ost->ist && !ost->enc) { - ret = streamcopy_init(mux, ost); + ret = streamcopy_init(mux, ost, &encoder_opts); if (ret < 0) - return ret; + goto fail; } // copy estimated duration as a hint to the muxer @@ -1491,7 +1495,12 @@ static int ost_add(Muxer *mux, const OptionsContext *o, enum AVMediaType type, if (post) *post = ost; - return 0; + ret = 0; + +fail: + av_dict_free(&encoder_opts); + + return ret; } static int map_auto_video(Muxer *mux, const OptionsContext *o)