From patchwork Thu May 12 15:34:27 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Leo Izen X-Patchwork-Id: 35748 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:a885:b0:7f:4be2:bd17 with SMTP id ca5csp508777pzb; Thu, 12 May 2022 08:34:51 -0700 (PDT) X-Google-Smtp-Source: ABdhPJx91jZ7iJmTqHAbhrDLVuhUCNxUuefMz5ljPyAtAB8oP/NtCAJs7CyHP0271m3szablrBPx X-Received: by 2002:aa7:d4c3:0:b0:425:e26d:aee2 with SMTP id t3-20020aa7d4c3000000b00425e26daee2mr36129941edr.64.1652369691329; Thu, 12 May 2022 08:34:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1652369691; cv=none; d=google.com; s=arc-20160816; b=BS0cT6CLoR/7f2jIRekxZKRCccznp8SQeIWs0PRZ6bVwJSMvfKtTIsmEtnN8Bj4Zp4 f2I9fxay4lL9pAkJ6LjMAPwdrF3R1tD6AbqhtetR6RAlVF4Cjw/X1bcE0UNg9ff4WAKF /U4vLPctPY+H2DAdG3e7EPwWvNDNXyd7Tu9+Mvp/pNgwEJy9VTDlzcQLr4VijQwmnAi8 9X72x/OxMa0z+6ZgN2Ho5GvAVRyy8cqMtwXB/AQkmmXDujem5CMBoaYKWvej2EUwlMT6 LQLyKMmad2TUT2S9KMY8AmhMvTcumT/AI6ZNgUO2luf4DeM6JmHeLSyBZQ8b8n9Dx4jL 4/Tw== 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=i9cTOXulFURobP78cXObLeFWC8q3S7jq3VbLexv6Jxg=; b=RaT4ZlMm9F0gVAhYToZc2R8geBqKlGGYz4vdXjyTf2aJY4gzhy8WDD1P8sNNZIQN1g w3N0l5a8aBSoVJQe3ETk78q7VZvWelC/Eut9XJqJ0juuf0oli4ITsQ13ibId589q1NeG dwovadgW5iiHPQrNbmGDcyHoBfxOmZiw3a9yfvQZiYW+DooBLgrT8/CVnKJxss8O9v7e jR5ugCk/Xj6/Cp+SAevbk4zv9dlTXWBdH55YVtSOHpYZczZCAE/b6kCw9K83Ensyi3sq sMDRszrceO2f070FMlUs6BkZDqv6SZemx5nl789YLyGPpLKkcFG2dG7YTjaLw72Hfw9N D9nA== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20210112 header.b=LXtoRPQz; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from ffbox0-bg.mplayerhq.hu (ffbox0-bg.ffmpeg.org. [79.124.17.100]) by mx.google.com with ESMTP id sa21-20020a1709076d1500b006fa6b0ba8e6si7269563ejc.83.2022.05.12.08.34.50; Thu, 12 May 2022 08:34: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=@gmail.com header.s=20210112 header.b=LXtoRPQz; 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; dmarc=fail (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Received: from [127.0.1.1] (localhost [127.0.0.1]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTP id A35DC68B460; Thu, 12 May 2022 18:34:43 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-qt1-f180.google.com (mail-qt1-f180.google.com [209.85.160.180]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 68A8D68B3E0 for ; Thu, 12 May 2022 18:34:37 +0300 (EEST) Received: by mail-qt1-f180.google.com with SMTP id v14so3513548qtc.3 for ; Thu, 12 May 2022 08:34:37 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=HPCJp8F7SI17D+UDiT4Rh4hxLrLFAlXBovkRibcG240=; b=LXtoRPQzjqVv/xsFrll/XwtehfuTKLHvhieQbAIftd8qYmqindwnpPiAhcEICHHs3L /NB/XLwKmtXek0tgXTmBEjznlqAkxAt36hBgspi3VSljnT4Vad0I1hCKowcRgcvJuR8/ kCVYtwO9HS9KDBec2AC9T4fGvYX/nSbWx86YJmxHhBAJ00Xt6ZhosFQqZ3MWrJKJZxzy rzpW7a8WF82eFd/gVknZU7351TV6buX0rFSvDHKr7fmuR5HDQKdPJL6QQm3qWPCuytSQ 5WuGBgN1SN2vF8H1W66u1sN9RWWbKKLHnYHNs4tEQiAh+swRZdq15K49u/a/KVJYVsM8 Uu9w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=HPCJp8F7SI17D+UDiT4Rh4hxLrLFAlXBovkRibcG240=; b=g+K02jYTl3mW5HNoTr/O1etZYHzxH2MrmMdfc7tM9Lhff1li0rMWhVllMs0nsPHZyJ NSMa14QvZ5CtJCyvj0SKsBxYGDMEGnPDx+spsubh++x54WXKw7zYAB1/iB70I1t/pKrA KnEITkB2hBMxKB3wqAE0NgXHm0k9tskWXWRgNtAOy4c5HvX2z/HzJGYyvDZxI40tSp+S TNP/KfkNJKrboux3M9HDlf4SIN5VaKIVbc+EDga5nwEs1NTc8xOVeCSDf7OzDmqacUJv 5gkyBx543qSioTDWkTikzF0ie6Tr2j5aUsWPcEMKNBQzYEieAm0EIGLc+evrlveM437R l0zQ== X-Gm-Message-State: AOAM5304VYl9jcO4nKkToqx40tT9NKqTOUn7+Iojzx6zdafle52N0uQY cQWrQmMj6+nOratmJMdLUL7CrLXEzfqkkA== X-Received: by 2002:ac8:5cd1:0:b0:2f3:dd63:9694 with SMTP id s17-20020ac85cd1000000b002f3dd639694mr329416qta.518.1652369675624; Thu, 12 May 2022 08:34:35 -0700 (PDT) Received: from localhost.localdomain (64-233-244-163.static.clv.wideopenwest.com. [64.233.244.163]) by smtp.gmail.com with ESMTPSA id c17-20020ac80091000000b002f39b99f693sm3187734qtg.45.2022.05.12.08.34.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 12 May 2022 08:34:35 -0700 (PDT) From: Leo Izen To: ffmpeg-devel@ffmpeg.org Date: Thu, 12 May 2022 11:34:27 -0400 Message-Id: <20220512153428.251357-2-leo.izen@gmail.com> X-Mailer: git-send-email 2.36.1 In-Reply-To: <20220512153428.251357-1-leo.izen@gmail.com> References: <20220512153428.251357-1-leo.izen@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH v7 1/2] avcodec/libjxldec: properly tag output colorspace 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: Leo Izen Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: fdkoOi/t91dg Whether an ICC profile is present or not, the decoder should now properly tag the colorspace of pixel data received by the decoder. --- libavcodec/libjxldec.c | 128 +++++++++++++++++++++++++++++++++++------ 1 file changed, 109 insertions(+), 19 deletions(-) diff --git a/libavcodec/libjxldec.c b/libavcodec/libjxldec.c index cd4bca3343..651ac56a36 100644 --- a/libavcodec/libjxldec.c +++ b/libavcodec/libjxldec.c @@ -47,7 +47,6 @@ typedef struct LibJxlDecodeContext { JxlBasicInfo basic_info; JxlPixelFormat jxl_pixfmt; JxlDecoderStatus events; - AVBufferRef *iccp; } LibJxlDecodeContext; static int libjxl_init_jxl_decoder(AVCodecContext *avctx) @@ -129,12 +128,84 @@ static enum AVPixelFormat libjxl_get_pix_fmt(AVCodecContext *avctx, JxlBasicInfo return AV_PIX_FMT_NONE; } +static enum AVColorPrimaries libjxl_get_primaries(void *avctx, JxlColorEncoding *encoding) +{ + if (encoding->white_point != JXL_WHITE_POINT_D65 && + (encoding->primaries != JXL_PRIMARIES_P3 || encoding->white_point != JXL_WHITE_POINT_DCI)) { + av_log(avctx, AV_LOG_WARNING, "Unsupported JXL white point: %d\n", encoding->white_point); + return AVCOL_PRI_UNSPECIFIED; + } + switch (encoding->primaries) { + case JXL_PRIMARIES_SRGB: + /* BT709 and sRGB use the same primaries */ + return AVCOL_PRI_BT709; + case JXL_PRIMARIES_2100: + /* BT2020 and BT2100 use the same primaries */ + return AVCOL_PRI_BT2020; + case JXL_PRIMARIES_P3: + /* DCI P3 uses DCI, Display P3 uses D65 */ + if (encoding->white_point == JXL_WHITE_POINT_DCI) + return AVCOL_PRI_SMPTE431; + return AVCOL_PRI_SMPTE432; + case JXL_PRIMARIES_CUSTOM: + av_log(avctx, AV_LOG_WARNING, "Custom primaries are unsupported\n"); + return AVCOL_PRI_UNSPECIFIED; + } + + av_log(avctx, AV_LOG_WARNING, "Unknown JXL color primaries: %d\n", encoding->primaries); + + return AVCOL_PRI_UNSPECIFIED; +} + +static enum AVColorTransferCharacteristic libjxl_get_trc(void *avctx, JxlColorEncoding *encoding) +{ + switch (encoding->transfer_function) { + case JXL_TRANSFER_FUNCTION_709: + return AVCOL_TRC_BT709; + case JXL_TRANSFER_FUNCTION_LINEAR: + return AVCOL_TRC_LINEAR; + case JXL_TRANSFER_FUNCTION_SRGB: + return AVCOL_TRC_IEC61966_2_1; + case JXL_TRANSFER_FUNCTION_PQ: + return AVCOL_TRC_SMPTE2084; + case JXL_TRANSFER_FUNCTION_DCI: + return AVCOL_TRC_SMPTE428; + case JXL_TRANSFER_FUNCTION_HLG: + return AVCOL_TRC_ARIB_STD_B67; + case JXL_TRANSFER_FUNCTION_GAMMA: + if (encoding->gamma > 2.199 && encoding->gamma < 2.201) + return AVCOL_TRC_GAMMA22; + if (encoding->gamma > 2.799 && encoding->gamma < 2.801) + return AVCOL_TRC_GAMMA28; + av_log(avctx, AV_LOG_WARNING, "Unsupported gamma transfer: %f\n", encoding->gamma); + return AVCOL_TRC_UNSPECIFIED; + } + + av_log(avctx, AV_LOG_WARNING, "Unknown transfer function: %d\n", encoding->transfer_function); + + return AVCOL_TRC_UNSPECIFIED; +} + +static int libjxl_populate_encoding(AVCodecContext *avctx, JxlColorEncoding *encoding) +{ + if (avctx->colorspace == AVCOL_SPC_RGB) + avctx->color_primaries = libjxl_get_primaries(avctx, encoding); + avctx->color_trc = libjxl_get_trc(avctx, encoding); + + if (avctx->color_trc == AVCOL_TRC_UNSPECIFIED || + avctx->colorspace == AVCOL_SPC_RGB && avctx->color_primaries == AVCOL_PRI_UNSPECIFIED) + return -1; + + return 0; +} + static int libjxl_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_frame, AVPacket *avpkt) { LibJxlDecodeContext *ctx = avctx->priv_data; uint8_t *buf = avpkt->data; - size_t remaining = avpkt->size, iccp_len; + size_t remaining = avpkt->size; JxlDecoderStatus jret; + JxlColorEncoding jxl_encoding; int ret; *got_frame = 0; @@ -189,16 +260,43 @@ static int libjxl_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_f continue; case JXL_DEC_COLOR_ENCODING: av_log(avctx, AV_LOG_DEBUG, "COLOR_ENCODING event emitted\n"); - jret = JxlDecoderGetICCProfileSize(ctx->decoder, &ctx->jxl_pixfmt, JXL_COLOR_PROFILE_TARGET_ORIGINAL, &iccp_len); - if (jret == JXL_DEC_SUCCESS && iccp_len > 0) { - av_buffer_unref(&ctx->iccp); - ctx->iccp = av_buffer_alloc(iccp_len); - if (!ctx->iccp) - return AVERROR(ENOMEM); - jret = JxlDecoderGetColorAsICCProfile(ctx->decoder, &ctx->jxl_pixfmt, JXL_COLOR_PROFILE_TARGET_ORIGINAL, ctx->iccp->data, iccp_len); - if (jret != JXL_DEC_SUCCESS) - av_buffer_unref(&ctx->iccp); + avctx->color_range = frame->color_range = AVCOL_RANGE_JPEG; + if (ctx->jxl_pixfmt.num_channels >= 3) + avctx->colorspace = AVCOL_SPC_RGB; + else + avctx->colorspace = AVCOL_SPC_UNSPECIFIED; + jret = JxlDecoderGetColorAsEncodedProfile(ctx->decoder, NULL, JXL_COLOR_PROFILE_TARGET_ORIGINAL, &jxl_encoding); + if (jret == JXL_DEC_SUCCESS) + jret = JxlDecoderSetPreferredColorProfile(ctx->decoder, &jxl_encoding); + if (jret == JXL_DEC_SUCCESS) + jret = JxlDecoderGetColorAsEncodedProfile(ctx->decoder, &ctx->jxl_pixfmt, JXL_COLOR_PROFILE_TARGET_DATA, &jxl_encoding); + if (jret == JXL_DEC_SUCCESS) + ret = libjxl_populate_encoding(avctx, &jxl_encoding); + else + ret = -1; + + /* fall back on HDR gamut if enum values fail */ + if (ret < 0) { + av_log(avctx, AV_LOG_WARNING, "Falling back on HDR gamut\n"); + jxl_encoding.rendering_intent = JXL_RENDERING_INTENT_RELATIVE; + jxl_encoding.white_point = JXL_WHITE_POINT_D65; + if (avctx->colorspace == AVCOL_SPC_RGB) + jxl_encoding.primaries = JXL_PRIMARIES_2100; + if (ctx->jxl_pixfmt.data_type == JXL_TYPE_FLOAT || ctx->jxl_pixfmt.data_type == JXL_TYPE_FLOAT16) + jxl_encoding.transfer_function = JXL_TRANSFER_FUNCTION_LINEAR; + else + jxl_encoding.transfer_function = JXL_TRANSFER_FUNCTION_SRGB; + /* this shouldn't fail, barring libjxl decoder bug */ + jret = JxlDecoderSetPreferredColorProfile(ctx->decoder, &jxl_encoding); + if (jret == JXL_DEC_SUCCESS) + ret = libjxl_populate_encoding(avctx, &jxl_encoding); } + if (ret < 0) + av_log(avctx, AV_LOG_WARNING, "Unable to set default colorspace values\n"); + + frame->color_trc = avctx->color_trc; + frame->color_primaries = avctx->color_primaries; + frame->colorspace = avctx->colorspace; continue; case JXL_DEC_NEED_IMAGE_OUT_BUFFER: av_log(avctx, AV_LOG_DEBUG, "NEED_IMAGE_OUT_BUFFER event emitted\n"); @@ -216,13 +314,6 @@ static int libjxl_decode_frame(AVCodecContext *avctx, AVFrame *frame, int *got_f av_log(avctx, AV_LOG_DEBUG, "FULL_IMAGE event emitted\n"); frame->pict_type = AV_PICTURE_TYPE_I; frame->key_frame = 1; - if (ctx->iccp) { - AVFrameSideData *sd = av_frame_new_side_data_from_buf(frame, AV_FRAME_DATA_ICC_PROFILE, ctx->iccp); - if (!sd) - return AVERROR(ENOMEM); - /* ownership is transfered, and it is not ref-ed */ - ctx->iccp = NULL; - } *got_frame = 1; return avpkt->size - remaining; case JXL_DEC_SUCCESS: @@ -260,7 +351,6 @@ static av_cold int libjxl_decode_close(AVCodecContext *avctx) if (ctx->decoder) JxlDecoderDestroy(ctx->decoder); ctx->decoder = NULL; - av_buffer_unref(&ctx->iccp); return 0; }