From patchwork Thu May 23 09:03:37 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Anton Khirnov X-Patchwork-Id: 49174 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a59:542:0:b0:460:55fa:d5ed with SMTP id 63csp895761vqf; Thu, 23 May 2024 02:04:34 -0700 (PDT) X-Forwarded-Encrypted: i=2; AJvYcCX/242pP+qZcZPVJ5rPy0CZdCDsfsnMXTznK8UL2A+V60cnTgXWCzrlnUMTJMoKeHQqpgA35Dj3Uxm/+6LqamzMMIvMUYKowsVZUQ== X-Google-Smtp-Source: AGHT+IFBZrcfbhg+UgAy7f92a0PQEWAoKVAJGIrTztBuBAvlbPjppQmGSR1XOH7pVyNylWz8JqjX X-Received: by 2002:ac2:5930:0:b0:523:89b0:9b64 with SMTP id 2adb3069b0e04-526bebb45afmr2365618e87.7.1716455074357; Thu, 23 May 2024 02:04:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1716455074; cv=none; d=google.com; s=arc-20160816; b=sUHd3tgNW3RcNh8Apz3B83LK+HW6edGOa2nbJ2+AhHxedyH8MBUnRY7gp8/fm4trSL dv9Cutet5EAXXnH+wqR7mvCo/D3NMnpAcTsE7sI02LBRqHGaYu/73oDJh9w9TAELXX9v mPIdLRnqFKsYCHGNPqm3YJdNU64DIFbyxfbt5/YnY2N0s38kilTAx/OMs2+B07hVu/Xf d5unxIzwHqMC7DscvDKxIOSeAZHAlCS0H8D9hqyb1SVC/09xESVhrAC6UE4iX6Gm1pmg V7Did9WKZWag/Fe0fJlAcBearpAGaDzpSoFkZopX4j0Tq9C7vl4vCqFgW+glNoipFa/c hbEg== 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=a+nx8l3CAPN30CdzJeT1g4xsbmjz62YcK2OB87LXGaA=; fh=YOA8vD9MJZuwZ71F/05pj6KdCjf6jQRmzLS+CATXUQk=; b=eqkZYwqdrSN04/4Wzh/TN5ekLayk5ZHVpWS2GK2P0bmfPHy94HsteRMXVv1PcZ6YOk m+XK0gnDmq/upAO77zuOgwmE5XHM3OyZY3K8cy5U6sZijUUtoP2j3bLQQBSFj98Isz6A mzH3KVr6UuF5dXqVOWVAID9KKR4VVgSRYkIGVuVnTO1H/RLgr55rFxk7iy5hA3QWQpKV /NhvNa0T3g2KOWOFlaVfVMdtw0hhaOIPNnxw65Ywxm0fv97ThNulLCQDPaDpu6SM8Ipm O6pnnCUBlhYN+INrBFdeDH6P6WWFKxLcgQY5UM7CW4v0XScxFT+ZG0TgbvRLP1VINz7J xATg==; 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=juW2hPZF; 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-a5a17ba5d70si1555202866b.659.2024.05.23.02.04.34; Thu, 23 May 2024 02:04:34 -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=juW2hPZF; 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 BC3E668D485; Thu, 23 May 2024 12:03:59 +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 0154068D1C4 for ; Thu, 23 May 2024 12:03:49 +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=juW2hPZF; dkim-atps=neutral Received: from localhost (mail1.khirnov.net [IPv6:::1]) by mail1.khirnov.net (Postfix) with ESMTP id 9E7AD4D58 for ; Thu, 23 May 2024 11:03:49 +0200 (CEST) Received: from mail1.khirnov.net ([IPv6:::1]) by localhost (mail1.khirnov.net [IPv6:::1]) (amavis, port 10024) with ESMTP id PV4xChiQgbuZ for ; Thu, 23 May 2024 11:03:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=khirnov.net; s=mail; t=1716455027; bh=e0o/Ez/HZ+zhaGSIk2DCo9ipdPA2h8ACo8dIbBuqs7o=; h=From:To:Subject:Date:In-Reply-To:References:From; b=juW2hPZFZ2Ab7xZASDXFZtogBlJWYcbOOJsRi2pCehrAAD7rO8ZwK0613yUp+RbGN NfZFqIYD6zhpybzcN55v8VzH0TaJlurJp0F/mpbSn0bSxi0p6Cvnc9zS1KRYdoDhzB a4M5Q5UwG0dM4zP8hhyLohB9jN+QflwIxg+Y22nGHmm2Vwo2RAQyo4QYdz+aHrctst kthRWK68GDSnL3nVulm9NQsUriyIVcf80zpDNZF8XkW+c1vm0o+XvlP6qo6Zmo49S3 5eql7nSKL4ICc5hOvaEsrD27ywz2JtN+cYsmPjZ4yuAkNE34P5CCfAewOENQRWdOyt FIJJs2/TAdXgA== 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 3AE804D76 for ; Thu, 23 May 2024 11:03:47 +0200 (CEST) Received: from libav.khirnov.net (libav.khirnov.net [IPv6:::1]) by libav.khirnov.net (Postfix) with ESMTP id DA5713A0423 for ; Thu, 23 May 2024 11:03:41 +0200 (CEST) From: Anton Khirnov To: ffmpeg-devel@ffmpeg.org Date: Thu, 23 May 2024 11:03:37 +0200 Message-ID: <20240523090339.4228-2-anton@khirnov.net> X-Mailer: git-send-email 2.43.0 In-Reply-To: <20240523090339.4228-1-anton@khirnov.net> References: <20240523090339.4228-1-anton@khirnov.net> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/4] 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: 0vFTCP16aASq 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 | 49 ++++++++++++++++++++++++++++++++++ fftools/ffmpeg.h | 3 ++- fftools/ffmpeg_demux.c | 50 ++++++++--------------------------- fftools/ffmpeg_mux.c | 1 + fftools/ffmpeg_mux.h | 3 +++ fftools/ffmpeg_mux_init.c | 55 +++++---------------------------------- fftools/ffmpeg_opt.c | 18 ------------- fftools/ffplay.c | 2 +- fftools/ffprobe.c | 2 +- 11 files changed, 89 insertions(+), 115 deletions(-) diff --git a/fftools/cmdutils.c b/fftools/cmdutils.c index a8f5c6d89b..265ce5c04c 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 d0c773663b..5966501d84 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 c86fd5065e..5e27f073aa 100644 --- a/fftools/ffmpeg.c +++ b/fftools/ffmpeg.c @@ -493,6 +493,55 @@ int check_avoptions(AVDictionary *m) return 0; } +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; + + 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); + } + + if (!av_dict_get(opts_used, e->key, NULL, 0)) { + 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 885a7c0c10..9cab8148ca 100644 --- a/fftools/ffmpeg.h +++ b/fftools/ffmpeg.h @@ -712,9 +712,10 @@ void show_usage(void); void remove_avoptions(AVDictionary **a, AVDictionary *b); int check_avoptions(AVDictionary *m); +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 cba63dab5f..52e427ea49 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; } @@ -1532,8 +1532,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; @@ -1805,48 +1804,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 8797265145..41afe8259d 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; } @@ -3114,52 +3116,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 : ""); - 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; @@ -3267,7 +3223,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 5a66bfa38d..14999349ac 100644 --- a/fftools/ffplay.c +++ b/fftools/ffplay.c @@ -2674,7 +2674,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 2d38e5dfdc..ce1b0fb6ba 100644 --- a/fftools/ffprobe.c +++ b/fftools/ffprobe.c @@ -3922,7 +3922,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);