From patchwork Fri Oct 13 14:24:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 44241 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:4b15:b0:15d:8365:d4b8 with SMTP id fp21csp1039391pzb; Fri, 13 Oct 2023 07:27:51 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFBeLEEJMTp0IkR7/AL564AS2kPvo7DxGrPUdrjfTLTKKnfqRWKKhCD35Eu0y6Y9G1CQO0Y X-Received: by 2002:a17:907:3f12:b0:9ad:e3fd:d46c with SMTP id hq18-20020a1709073f1200b009ade3fdd46cmr290322ejc.10.1697207271737; Fri, 13 Oct 2023 07:27:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1697207271; cv=none; d=google.com; s=arc-20160816; b=e72g1FUXnPMX18HNgZGkEZZ0XfYGk+5T4aQKquONiocgRrX45SvVxoVlMT5C9cnEdM PI5RJFULY0Tw+OpvkoVK/bTHxxz7sXu5wfS2nSeHzBK1p3M5Vup31Oy99odylHg8R7f+ LhbucOu4I8sTcBjXR0LWJXpu6RS5dxWgvCkM1AkKKegLzffgkVmx5T2nsjjHXpSwcfdY vHqXfh7h9tlJGwEHsnqeS9mmbLp+ZQ9JjPCchoYj9ddvud/EHFXDnupQzeNrE9iZNgOJ Pq3+UVfWt1pubzeo8uXU3vvw7K5liFAsCHnkXnrqB5HUEeqAQp2wj2pZASWfWCsN1Hp+ lLWQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:content-transfer-encoding:cc: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=9trUN4jR76DbyFcHQLNhLP+3pEvImOR3XNPZZjsGEaA=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=f7bQ6SShmCndAacsZ6d4VW2ST5CJIhn5W5SzKSSxr/qmlFP2urIqdT3RGP65zs9zac YFUYe02OlsUxOOBOA1Cmybq9PpS4jrkrA4hai4ImxWWY60pAOo4PNqzSVPTkTfYjEY/Y 0IEbsj9DW4QMSA8x2O0UdqXTDFOmp2v1dTkL/nRrVK5mFvXeFCLb9Vu7WTPFnzC/XS9B erDCUFCTT6/QhlrD36TsUTjtzCBFLNRQEZI1Hvht+ZwCsIhNeLwj3cDmSd12B9uGQuI/ FjMAjYT+7eoQXBthdhXsKt+UNFwpstakvtTpSfW6S1NAqFT/iYm7Fyxe586kzHoKdwy3 mfyw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=qRTL71ED; 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 sa21-20020a1709076d1500b009b9ee6a33e1si9399027ejc.455.2023.10.13.07.27.46; Fri, 13 Oct 2023 07:27:51 -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=@haasn.xyz header.s=mail header.b=qRTL71ED; 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 877DF68C9AE; Fri, 13 Oct 2023 17:27:20 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from haasn.dev (haasn.dev [78.46.187.166]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id 38FD768C8C8 for ; Fri, 13 Oct 2023 17:27:11 +0300 (EEST) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id E90134BB2B; Fri, 13 Oct 2023 16:27:10 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1697207231; bh=MNS7jN8kqwc9+govOiWdSb8cBqfaLb98fw0XdIouJx4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qRTL71EDqQ+9GTWJKj02d7ppGlU1tUxS2Pw7ChmxlcFfWWJb+cTdylaCXrImTTv43 hvNKdZC9rKcz1t38Fy4ESYfqvTLtDSbgp4BwEYuCkmECMbiCs03CZzITOoSTysuOYW rcbPGsZ4jajIZLWmwLuD6wLtNGWkyHwnNmhTzBac= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Fri, 13 Oct 2023 16:24:41 +0200 Message-ID: <20231013142706.23971-4-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231013142706.23971-1-ffmpeg@haasn.xyz> References: <20231013142706.23971-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v2 03/13] fftools/ffmpeg_filter: auto-convert range if needed 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 Cc: Niklas Haas Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 6gqfWRBjFOEC From: Niklas Haas To convert between color ranges, if needed by the codec properties. We momentarily duplicate the mjpeg strictness logic to also enfoce full range. This duplication will be cleaned up in the next commit. Due to avcodec_open2 being called after ofilter_bind_ost, we need to look up the eventual encoder options from the options dictionary directly, following the same design as the "strict" option. --- fftools/ffmpeg_filter.c | 61 +++++++++++++++++++++++++++++++++++------ 1 file changed, 52 insertions(+), 9 deletions(-) diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index c738fc3397..acdfa72043 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -169,6 +169,7 @@ typedef struct OutputFilterPriv { int width, height; int sample_rate; AVChannelLayout ch_layout; + enum AVColorRange range; // time base in which the output is sent to our downstream // does not need to match the filtersink's timebase @@ -184,6 +185,7 @@ typedef struct OutputFilterPriv { const int *formats; const AVChannelLayout *ch_layouts; const int *sample_rates; + const enum AVColorRange *ranges; AVRational enc_timebase; // offset for output timestamps, in AV_TIME_BASE_Q @@ -368,6 +370,9 @@ DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0, "%d", ) +DEF_CHOOSE_FORMAT(out_range, enum AVColorRange, range, ranges, + AVCOL_RANGE_UNSPECIFIED, "%s", av_color_range_name); + static void choose_channel_layouts(OutputFilterPriv *ofp, AVBPrint *bprint) { if (av_channel_layout_check(&ofp->ch_layout)) { @@ -662,6 +667,17 @@ static int set_channel_layout(OutputFilterPriv *f, OutputStream *ost) return 0; } +static int ost_opt_int(OutputStream *ost, const char *name, int defval) +{ + const AVDictionaryEntry *e = av_dict_get(ost->encoder_opts, name, NULL, 0); + if (e) { + const AVOption *o = av_opt_find(ost->enc_ctx, e->key, NULL, 0, 0); + av_assert0(o); + av_opt_eval_int(ost->enc_ctx, o, e->value, &defval); + } + return defval; +} + int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost) { const OutputFile *of = output_files[ost->file_index]; @@ -669,6 +685,7 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost) FilterGraph *fg = ofilter->graph; FilterGraphPriv *fgp = fgp_from_fg(fg); const AVCodec *c = ost->enc_ctx->codec; + enum AVColorRange color_range; av_assert0(!ofilter->ost); @@ -682,6 +699,26 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost) case AVMEDIA_TYPE_VIDEO: ofp->width = ost->enc_ctx->width; ofp->height = ost->enc_ctx->height; + color_range = ost_opt_int(ost, "color_range", ost->enc_ctx->color_range); + if (color_range != AVCOL_RANGE_UNSPECIFIED) { + ofp->range = color_range; + } else { + ofp->ranges = c->color_ranges; + + // 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 + // has been specified. + if (!strcmp(c->name, "mjpeg")) { + static const enum AVColorRange mjpeg_ranges[] = + { AVCOL_RANGE_JPEG, AVCOL_RANGE_UNSPECIFIED }; + + int strict_val = ost->enc_ctx->strict_std_compliance; + strict_val = ost_opt_int(ost, "strict", strict_val); + if (strict_val > FF_COMPLIANCE_UNOFFICIAL) + ofp->ranges = mjpeg_ranges; + } + } if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) { ofp->format = ost->enc_ctx->pix_fmt; } else { @@ -1149,6 +1186,7 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, OutputFilterPriv *ofp = ofp_from_ofilter(ofilter); OutputStream *ost = ofilter->ost; OutputFile *of = output_files[ost->file_index]; + FilterGraphPriv *fgp = fgp_from_fg(fg); AVFilterContext *last_filter = out->filter_ctx; AVBPrint bprint; int pad_idx = out->pad_idx; @@ -1164,22 +1202,27 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, if (ret < 0) return ret; - if ((ofp->width || ofp->height) && ofilter->ost->autoscale) { - char args[255]; + av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); + if ((ofp->width || ofp->height) && ofilter->ost->autoscale) + av_bprintf(&bprint, "w=%d:h=%d:", ofp->width, ofp->height); + if (!fgp->disable_conversions) + choose_out_range(ofp, &bprint); + if (bprint.len) { AVFilterContext *filter; const AVDictionaryEntry *e = NULL; - snprintf(args, sizeof(args), "%d:%d", - ofp->width, ofp->height); + while ((e = av_dict_iterate(ost->sws_dict, e))) + av_bprintf(&bprint, "%s=%s:", e->key, e->value); - while ((e = av_dict_iterate(ost->sws_dict, e))) { - av_strlcatf(args, sizeof(args), ":%s=%s", e->key, e->value); - } + if (!av_bprint_is_complete(&bprint)) + return AVERROR(ENOMEM); snprintf(name, sizeof(name), "scaler_out_%d_%d", ost->file_index, ost->index); - if ((ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), - name, args, NULL, fg->graph)) < 0) + ret = avfilter_graph_create_filter(&filter, avfilter_get_by_name("scale"), + name, bprint.str, NULL, fg->graph); + av_bprint_finalize(&bprint, NULL); + if (ret < 0) return ret; if ((ret = avfilter_link(last_filter, pad_idx, filter, 0)) < 0) return ret;