From patchwork Thu Nov 9 12:19:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 44596 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:4fa4:b0:181:818d:5e7f with SMTP id gh36csp444978pzb; Thu, 9 Nov 2023 04:28:01 -0800 (PST) X-Google-Smtp-Source: AGHT+IHXouAxK3sZHQHrtb0gv7juBjhkD0eD8Q6NmpLsjsGx+Z0rIz3No5H8bQpIseEQtZHhAirx X-Received: by 2002:a17:906:2a0c:b0:9b2:aa2f:ab69 with SMTP id j12-20020a1709062a0c00b009b2aa2fab69mr3431522eje.30.1699532880703; Thu, 09 Nov 2023 04:28:00 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1699532880; cv=none; d=google.com; s=arc-20160816; b=Hecxg+mirNizK99+cnfJwN3nwXg+ImgnrtiWBPyWoLJj3oDfB98DIs0mkRMLi4rOlC ysC0TJtvKbUSU0rzVEWMZqwKEqzyb1RKknFk7gszAyxKggqp7DtpvDpdZqGgsLxYFG3G 6HbeFcGib8nD3nsqaDCRgQhLgGCQZOfZXZehQy63L86dKunDoLIQTXmMkgIIQ9oSXG19 i2H6P8jkfEpibYxjyZk+6iW+bj5cXlldDOANPuB3689eVUlkHJXL+XMyWVbWM1ETjWSh dO2IoU0NNjES29sVTBtG3aCcK/gdeLUG6tH/hUnYix7QdRDATISUFKPbFhSuym17Vz/Q b7jA== 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=3kS4fuLEGVFRvTLnjKupsKvrfPuuUgU1ogLHbWUlYCY=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=mXTWkkhRFEWafpIIYZ28/By69a0Eow9fESMxju5Y+5HfhGDG46zp7xSqFJX1cyVhpt G5+zc8YjMs61G/optC+pBPn31jYg5eqY1qUagAIeRGjqasEwkBH69oAMBp7megA7JgRo lvvxti8im4Ra0h8mVgTwqbrDCQhCw+V6CRWSYU1xT+/rZqRLqWxMPa8+rV9TdPLp97KC UGsLRoOBaBsUNrNSq/DZkNChYVKyVWlWHDoqNykagGXkgsGh9gCQPjfb1UDxfIchG3/J aCw4oH6CLwvhnODZuofFxnxFrUCgpjK45XETmNUSMYSGhIvLnbHQ26oeKRDnZiOopJ6G LxTw== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b="okv/ADFk"; 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 oz38-20020a1709077da600b0099b7f483374si3140668ejc.183.2023.11.09.04.28.00; Thu, 09 Nov 2023 04:28:00 -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; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b="okv/ADFk"; 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 BC4B668CC9B; Thu, 9 Nov 2023 14:25:58 +0200 (EET) 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 61D2568CBE0 for ; Thu, 9 Nov 2023 14:25:42 +0200 (EET) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 343954BD2D; Thu, 9 Nov 2023 13:25:41 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1699532741; bh=yvpC3EjuKot+GyIBwEu/eJvsbqAvWISjmNO8tD0zTFU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=okv/ADFk22b0exECiBOQM7K/ZSdu5UndnY0Zn3gA8/MfMgY2y3kVb8tyeMMDlMn2D dYELnvgsnDb46n1QrIspZ8RxpJMJPxo0e3FFtsw2hCKT+HVimShRVZwkz86g5tkLn+ zwjV5WzKDn4gzPHEjZhaRrTRZW4lw5k+YPQhs6Ts= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Thu, 9 Nov 2023 13:19:53 +0100 Message-ID: <20231109122534.124157-22-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231109122534.124157-1-ffmpeg@haasn.xyz> References: <20231109122534.124157-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 21/25] fftools/ffmpeg_filter: propagate codec yuv metadata to filters 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: mxEqucEThrhb From: Niklas Haas To convert between color spaces/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 an upcoming 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 | 55 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index 5b99c4ba40..da770ef650 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -173,6 +173,8 @@ typedef struct OutputFilterPriv { int width, height; int sample_rate; AVChannelLayout ch_layout; + enum AVColorSpace color_space; + enum AVColorRange color_range; // time base in which the output is sent to our downstream // does not need to match the filtersink's timebase @@ -188,6 +190,8 @@ typedef struct OutputFilterPriv { const int *formats; const AVChannelLayout *ch_layouts; const int *sample_rates; + const enum AVColorSpace *color_spaces; + const enum AVColorRange *color_ranges; AVRational enc_timebase; // offset for output timestamps, in AV_TIME_BASE_Q @@ -344,6 +348,12 @@ DEF_CHOOSE_FORMAT(sample_fmts, enum AVSampleFormat, format, formats, DEF_CHOOSE_FORMAT(sample_rates, int, sample_rate, sample_rates, 0, "%d", ) +DEF_CHOOSE_FORMAT(color_spaces, enum AVColorSpace, color_space, color_spaces, + AVCOL_SPC_UNSPECIFIED, "%s", av_color_space_name); + +DEF_CHOOSE_FORMAT(color_ranges, enum AVColorRange, color_range, color_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)) { @@ -570,6 +580,8 @@ static OutputFilter *ofilter_alloc(FilterGraph *fg) ofilter = &ofp->ofilter; ofilter->graph = fg; ofp->format = -1; + ofp->color_space = AVCOL_SPC_UNSPECIFIED; + ofp->color_range = AVCOL_RANGE_UNSPECIFIED; ofilter->last_pts = AV_NOPTS_VALUE; return ofilter; @@ -638,6 +650,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]; @@ -645,6 +668,8 @@ 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 AVColorSpace color_space; + enum AVColorRange color_range; av_assert0(!ofilter->ost); @@ -658,6 +683,8 @@ 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_space = ost_opt_int(ost, "color_space", ost->enc_ctx->colorspace); + color_range = ost_opt_int(ost, "color_range", ost->enc_ctx->color_range); if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) { ofp->format = ost->enc_ctx->pix_fmt; } else if (!ost->keep_pix_fmt) { @@ -687,6 +714,30 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost) ofp->formats = mjpeg_formats; } } + if (color_space != AVCOL_SPC_UNSPECIFIED) { + ofp->color_space = color_space; + } else { + ofp->color_spaces = c->color_spaces; + } + if (color_range != AVCOL_RANGE_UNSPECIFIED) { + ofp->color_range = color_range; + } else { + ofp->color_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->color_ranges = mjpeg_ranges; + } + } fgp->disable_conversions |= ost->keep_pix_fmt; @@ -1176,6 +1227,8 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, av_assert0(!ost->keep_pix_fmt || (!ofp->format && !ofp->formats)); av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); choose_pix_fmts(ofp, &bprint); + choose_color_spaces(ofp, &bprint); + choose_color_ranges(ofp, &bprint); if (!av_bprint_is_complete(&bprint)) return AVERROR(ENOMEM); if (bprint.len) { @@ -1678,6 +1731,8 @@ static int configure_filtergraph(FilterGraph *fg) ofp->width = av_buffersink_get_w(sink); ofp->height = av_buffersink_get_h(sink); + ofp->color_space = av_buffersink_get_colorspace(sink); + ofp->color_range = av_buffersink_get_color_range(sink); // If the timing parameters are not locked yet, get the tentative values // here but don't lock them. They will only be used if no output frames