From patchwork Wed Oct 11 14:55:37 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Niklas Haas X-Patchwork-Id: 44223 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:4b22:b0:15d:8365:d4b8 with SMTP id fp34csp965557pzb; Wed, 11 Oct 2023 08:10:01 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHNz7O53DkqqW3cDOlZpNsg+SJwP0GATulzXUA+moqwB6AO9eXsT97w0Lget89P8T/gTEOP X-Received: by 2002:a05:6402:7d6:b0:523:1fa2:4f40 with SMTP id u22-20020a05640207d600b005231fa24f40mr18543333edy.19.1697037001351; Wed, 11 Oct 2023 08:10:01 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1697037001; cv=none; d=google.com; s=arc-20160816; b=vw5B7kPmNCjV0zP0wM5DigtRWbKNq0lX6hJ3SyZiEv2BjO0xeRC+C6nNmTAsKk5NR3 Ku49P5SLYy5C1GgCi/kJ788A6oHMLHPzri/5JYj+KmkJc5ggxa0fxpJ+BZHwFAN4U9OI eR15+2Kzg2yKrowFwCJlJ+8Inu3aevTlFjTbIZBcVva84F+dXnWKdJDM9tEweOATZCfI NkaEf6fEfjnwz9u8IaBUxCPanT2ZLuFP4FYtYJlq6vb2HXAIi+vj83WGxG4Crx3uFVIs 34G7HYAMVtLCil5uAa4bIv3mk/hnRxr9e6EdPTCa/eChEPAzzaorIlGdboqIAzV5M0U5 4PxQ== 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=ziyXRLf7gKhqhfQCgwmIAaAUcZ1TgLkI78gM5b6s5h8=; fh=xmAeKtysnShNOmkhiJmYkS30uw4Fu2hvBJ7qlIwukxQ=; b=GKy762tQcExMtae/5AycXzfduK+T5jCTPgOOiofjh66JmHadnASyZAocVE0JVxcw3Y Z+8f7V9JgT1GRIOs0rtK6/qWW43Vgen5KdF6joT4diz2QAop2dOE6cygqklqOfWPNxd8 j8QK1i8siR4IRvO0XsGU7HBjj8aHMwuxn4YBvjbHFC4wvPtxJ5fgoniV2EblhkR8hK1n ztP85qHSIQWnXzaefKfE+DRG3mT45zMG992jcx3OL+88NAW3zExhzOk8M0tKBnqi5SDG VqH9nf6yjR1ZJ95GCeMSFJVXJNB7HWGeFG841Sg/6h6rdX4jRTS/9uTzI8m3hKXIQmew +JwQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@haasn.xyz header.s=mail header.b=UR5157Xd; 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 k24-20020aa7d8d8000000b005221a36025asi6716602eds.676.2023.10.11.08.09.35; Wed, 11 Oct 2023 08:10:01 -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=UR5157Xd; 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 A711968CBF6; Wed, 11 Oct 2023 18:09:03 +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 525EA68CB01 for ; Wed, 11 Oct 2023 18:08:54 +0300 (EEST) Received: from haasn.dev (unknown [10.30.0.2]) by haasn.dev (Postfix) with ESMTP id 121EA4BBFF; Wed, 11 Oct 2023 17:08:54 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=simple/simple; d=haasn.xyz; s=mail; t=1697036934; bh=Z3TrOqnsv0H6vwRbnP34S8gyRKy56apLqLs1PnD+jfI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UR5157XdrQk6a8ZrQnCaj1aHuDD47yupd76YSa655ojNZO6mZvdH/bpVED09k3sC6 eixJ1dmJKdlQzRhAdmk2LwrnOytc4IjdEXkHdJiCm6jA1Ob276j0IYx9XEr1odMzJ9 4DMJ/1BAe05LjDgXzZS6U4WhF9dSe7mfsUE5zwf4= From: Niklas Haas To: ffmpeg-devel@ffmpeg.org Date: Wed, 11 Oct 2023 16:55:37 +0200 Message-ID: <20231011150848.117897-4-ffmpeg@haasn.xyz> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20231011150848.117897-1-ffmpeg@haasn.xyz> References: <20231011150848.117897-1-ffmpeg@haasn.xyz> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 3/7] fftools/ffmpeg_filter: auto-insert csp conversion filter 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: z1MSinCYLpkz From: Niklas Haas To convert between color ranges/matrices, if needed by the codec properties. Swscale can't do this currently, so we fall back to using zscale. We momentarily duplicate the mjpeg strictness logic to also enfoce full range. This duplication will be cleaned up in the next commit. In theory this scaler can also handle chroma locations, but the configuration for it is non-trivial due to the split between x/y offsets, and no codec currently signals a chroma location requirement. (Though this is subject to change in the future) --- fftools/ffmpeg_filter.c | 73 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 73 insertions(+) diff --git a/fftools/ffmpeg_filter.c b/fftools/ffmpeg_filter.c index c738fc3397..c1bedfda00 100644 --- a/fftools/ffmpeg_filter.c +++ b/fftools/ffmpeg_filter.c @@ -169,6 +169,8 @@ typedef struct OutputFilterPriv { int width, height; int sample_rate; AVChannelLayout ch_layout; + enum AVColorSpace csp; + enum AVColorRange color_range; // time base in which the output is sent to our downstream // does not need to match the filtersink's timebase @@ -184,6 +186,8 @@ typedef struct OutputFilterPriv { const int *formats; const AVChannelLayout *ch_layouts; const int *sample_rates; + const enum AVColorSpace *csps; + const enum AVColorRange *color_ranges; AVRational enc_timebase; // offset for output timestamps, in AV_TIME_BASE_Q @@ -368,6 +372,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(out_color_matrix, enum AVColorSpace, csp, csps, + AVCOL_SPC_UNSPECIFIED, "%s", av_color_space_name); + +DEF_CHOOSE_FORMAT(out_range, 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)) { @@ -594,6 +604,7 @@ static OutputFilter *ofilter_alloc(FilterGraph *fg) ofilter = &ofp->ofilter; ofilter->graph = fg; ofp->format = -1; + ofp->csp = AVCOL_SPC_UNSPECIFIED; ofilter->last_pts = AV_NOPTS_VALUE; return ofilter; @@ -682,6 +693,37 @@ int ofilter_bind_ost(OutputFilter *ofilter, OutputStream *ost) case AVMEDIA_TYPE_VIDEO: ofp->width = ost->enc_ctx->width; ofp->height = ost->enc_ctx->height; + if (ost->enc_ctx->colorspace != AVCOL_SPC_UNSPECIFIED) { + ofp->csp = ost->enc_ctx->colorspace; + } else { + ofp->csps = c->csps; + } + if (ost->enc_ctx->color_range) { + ofp->color_range = ost->enc_ctx->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 }; + + 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) + ofp->color_ranges = mjpeg_ranges; + } + } if (ost->enc_ctx->pix_fmt != AV_PIX_FMT_NONE) { ofp->format = ost->enc_ctx->pix_fmt; } else { @@ -1149,6 +1191,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; @@ -1209,6 +1252,36 @@ static int configure_output_video_filter(FilterGraph *fg, OutputFilter *ofilter, pad_idx = 0; } + if (!fgp->disable_conversions) { + av_bprint_init(&bprint, 0, AV_BPRINT_SIZE_UNLIMITED); + choose_out_color_matrix(ofp, &bprint); + choose_out_range(ofp, &bprint); + if (bprint.len) { + const AVDictionaryEntry *e = NULL; + AVFilterContext *filter; + + while ((e = av_dict_iterate(ost->sws_dict, e))) + av_bprintf(&bprint, "%s=%s:", e->key, e->value); + + if (!av_bprint_is_complete(&bprint)) + return AVERROR(ENOMEM); + + snprintf(name, sizeof(name), "conv_out_%d_%d", + ost->file_index, ost->index); + 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; + + last_filter = filter; + pad_idx = 0; + } + } + snprintf(name, sizeof(name), "trim_out_%d_%d", ost->file_index, ost->index); ret = insert_trim(of->start_time, of->recording_time,