From patchwork Sat Sep 23 15:36:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Chen Yufei X-Patchwork-Id: 43880 Delivered-To: ffmpegpatchwork2@gmail.com Received: by 2002:a05:6a20:2a18:b0:15d:8365:d4b8 with SMTP id e24csp282952pzh; Sat, 23 Sep 2023 08:42:42 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFPfy76t4ZPxGHJNVWgMRxRdGf00BOIsEBiKcxFOL5b4Lzd1libkxeYk6NHDc3oTYXaqVUA X-Received: by 2002:a17:907:3ea8:b0:9ad:e62c:4517 with SMTP id hs40-20020a1709073ea800b009ade62c4517mr8459093ejc.34.1695483762083; Sat, 23 Sep 2023 08:42:42 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1695483762; cv=none; d=google.com; s=arc-20160816; b=y/cNsKl/ZQRFX5zwHnC8GerTgQVySvthRxlEmKbCfdlZZj7ozrgupUtyw5HtQZ4kbj yq3QrkcOx7nyRch8bagUAGNh/BhNGIeen2rmNbdI546kzwFYfC8VPGa7+BdHW4odRVwL uiEB3Q41rFUX9Z2KJFDuGc7p+WpWA1ZU854pma2zkag2m5fWN9WtqTCG3lPDL0xmJ62E QwPrCavylY9Tq1JW6Xr7qL/02cfSQl5l+wX+stvUEMb+xbJcyasaI2TNpIflH1qFg07n HTf/1kBDt7/NxicpCyCtQIv7XjPTH/ZyF0uoHVf3yMAOv4m7q/FXoFapoznbKiK3IByq dxtg== 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=AYY15uyvj07CV0kj46tsK5gsap2Q2SQWRjuy3IPOZ0I=; fh=WMNJqm9yn32VIGoZSiFxz00xdqNXh1DsfrkZBt4KBsg=; b=vd0xsMJr5WFPVq6i3/w6s0ySvWikqbmEV2W+0uhhdxlEEFX6H0wVcQcnZS1ImhvOF/ m7yqFCgIsNwbXMb2AXazjNhfaMuz1obsJdWqMIPssHXaLgPglhmS4hkRio8lhg4ganCF o99R6Rzu3hlnO7M8lHZCNc+nsFsX0DGix0VNOCqE4ZyDxdS7GEUzxYU7B7InyMH0gt2q N3YoGaU+w8MyGEDygzg10yZjF+dNV/q0sYxJdbjz8nq6XEDhJNXKBK2z6bJtHODqGFY1 /XEm2pp1sgeY2eQ9HrmhLQT1K+ybAO/TNv4iXxhOT8s8VpbFtUr7d1Tl6XwKElxyjacz h3DQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=neutral (body hash did not verify) header.i=@gmail.com header.s=20230601 header.b=dIxJQnWr; 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 a24-20020a170906685800b00987d26a0998si5624580ejs.455.2023.09.23.08.42.41; Sat, 23 Sep 2023 08:42:42 -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=20230601 header.b=dIxJQnWr; 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 5061768C9D5; Sat, 23 Sep 2023 18:42:33 +0300 (EEST) X-Original-To: ffmpeg-devel@ffmpeg.org Delivered-To: ffmpeg-devel@ffmpeg.org Received: from mail-oa1-f41.google.com (mail-oa1-f41.google.com [209.85.160.41]) by ffbox0-bg.mplayerhq.hu (Postfix) with ESMTPS id 587EC68C8B4 for ; Sat, 23 Sep 2023 18:42:27 +0300 (EEST) Received: by mail-oa1-f41.google.com with SMTP id 586e51a60fabf-1dce0c05171so925126fac.3 for ; Sat, 23 Sep 2023 08:42:27 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1695483745; x=1696088545; darn=ffmpeg.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=hUsW82VKYajesMKCas5NqDRFnHKGpntaP6Y7kAK9iUM=; b=dIxJQnWr83eVy/E2onz2QjmvqhT6auAiLwpJW1f5u1Leb7oj/HAo5qJBd5A7mqqwQr PiWMvkQ4KXil18f8oOvX1H2gR0IMqLd9N7bfJrJve2eR5EnO5cz7kAhVmI3wN+BoKC2O 8OnIONCgapqdzi8xRo/SSC//89Mlrmu5GKG+zc7CNWKIkkuXcpIAhz0GH2yZSblW0Wyx fMbPjSgf15q0x9mAhMHRNg79m668qw/10DMGsZpQqNkt0lhyx5uWnOEe8cSDWAapEL/z JTmW0h/OO5LMnfFpyIQ8dEsEN1TfiqcJTrQhdqa6RJLkaykBk5hOGvuNjHzfWXOBQtWo o4XA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1695483745; x=1696088545; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=hUsW82VKYajesMKCas5NqDRFnHKGpntaP6Y7kAK9iUM=; b=XcR2XCLvKT+cEfpolxuMgCOgO1QEzO0xKvFbTU8X7EllxUYzVsdydKPXNAL8WILbzt RO5fiBaEBoEytYOvXLxPbuvKUZtNQv95UH4aVB6uNFUHLdvY0FQy1Z+7jdaPko4XqhOX m9V6k2g0r5QtSbGF5lZ3Q3FU9WW6C7JQAn6w/3orq8jWSJcF1Ras3FtXcV09aXh8NriU vPAyjl1cTPb+M/J9G0rbxWhlX7CzMDIww9LnB492At+L4Bscn5N1Mpj21RP2uGMwTvOo kbEDZSO68TXhauiF7fzhxuGVnD5cc2j7UL22JQvs10JgzEivZ0+B4m67GL0RVdOGj5vO ge9A== X-Gm-Message-State: AOJu0Yyxr8jft/qvtAph7tkxxxYar6Kxt7XR0Hk+fD41/qkXki2aVKyL ykEuuV9JiUUUwtzw3wmXihB36DlKq0k= X-Received: by 2002:a05:6870:a90e:b0:1d5:5d44:7404 with SMTP id eq14-20020a056870a90e00b001d55d447404mr3408257oab.43.1695483745500; Sat, 23 Sep 2023 08:42:25 -0700 (PDT) Received: from archvm.home (hwsrv-1088392.hostwindsdns.com. [23.254.253.23]) by smtp.gmail.com with ESMTPSA id e2-20020a63ae42000000b0057c630d606asm3307178pgp.69.2023.09.23.08.42.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 23 Sep 2023 08:42:25 -0700 (PDT) From: Chen Yufei To: ffmpeg-devel@ffmpeg.org Date: Sat, 23 Sep 2023 23:36:10 +0800 Message-ID: <20230923154125.31376-3-cyfdecyf@gmail.com> X-Mailer: git-send-email 2.42.0 In-Reply-To: <20230923154125.31376-1-cyfdecyf@gmail.com> References: <20230923154125.31376-1-cyfdecyf@gmail.com> MIME-Version: 1.0 Subject: [FFmpeg-devel] [PATCH 2/2] avfilter/vf_vpp_qsv: apply 3D LUT from file. 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: Chen Yufei Errors-To: ffmpeg-devel-bounces@ffmpeg.org Sender: "ffmpeg-devel" X-TUID: 7m9M+EJnQrYC Usage: "vpp_qsv=lut3d_file=" Only enabled with VAAPI because using VASurface to store 3D LUT. Signed-off-by: Chen Yufei --- libavfilter/vf_vpp_qsv.c | 241 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 236 insertions(+), 5 deletions(-) diff --git a/libavfilter/vf_vpp_qsv.c b/libavfilter/vf_vpp_qsv.c index c07b45fedb..cd913d3c40 100644 --- a/libavfilter/vf_vpp_qsv.c +++ b/libavfilter/vf_vpp_qsv.c @@ -23,6 +23,7 @@ #include +#include "config.h" #include "config_components.h" #include "libavutil/opt.h" @@ -37,10 +38,15 @@ #include "internal.h" #include "avfilter.h" #include "filters.h" +#include "lut3d.h" #include "qsvvpp.h" #include "transpose.h" +#if QSV_ONEVPL && CONFIG_VAAPI +#include +#endif + #define OFFSET(x) offsetof(VPPContext, x) #define FLAGS (AV_OPT_FLAG_VIDEO_PARAM | AV_OPT_FLAG_FILTERING_PARAM) @@ -67,6 +73,10 @@ typedef struct VPPContext{ /** HDR parameters attached on the input frame */ mfxExtMasteringDisplayColourVolume mdcv_conf; mfxExtContentLightLevelInfo clli_conf; + + /** LUT parameters attached on the input frame */ + mfxExtVPP3DLut lut3d_conf; + LUT3DContext lut3d; #endif /** @@ -260,6 +270,7 @@ static av_cold int vpp_preinit(AVFilterContext *ctx) static av_cold int vpp_init(AVFilterContext *ctx) { + int ret = 0; VPPContext *vpp = ctx->priv; if (!vpp->output_format_str || !strcmp(vpp->output_format_str, "same")) { @@ -288,9 +299,9 @@ static av_cold int vpp_init(AVFilterContext *ctx) STRING_OPTION(color_primaries, color_primaries, AVCOL_PRI_UNSPECIFIED); STRING_OPTION(color_transfer, color_transfer, AVCOL_TRC_UNSPECIFIED); STRING_OPTION(color_matrix, color_space, AVCOL_SPC_UNSPECIFIED); - #undef STRING_OPTION - return 0; + + return ret; } static int config_input(AVFilterLink *inlink) @@ -388,6 +399,194 @@ static mfxStatus get_mfx_version(const AVFilterContext *ctx, mfxVersion *mfx_ver return MFXQueryVersion(device_hwctx->session, mfx_version); } +#if QSV_ONEVPL && CONFIG_VAAPI +static mfxStatus get_va_display(AVFilterContext *ctx, VADisplay *va_display) +{ + VPPContext *vpp = ctx->priv; + QSVVPPContext *qsvvpp = &vpp->qsv; + mfxHDL handle; + mfxStatus ret; + + ret = MFXVideoCORE_GetHandle(qsvvpp->session, MFX_HANDLE_VA_DISPLAY, &handle); + if (ret != MFX_ERR_NONE) { + av_log(ctx, AV_LOG_ERROR, "MFXVideoCORE_GetHandle failed, status: %d\n", ret); + *va_display = NULL; + return ret; + } + + *va_display = (VADisplay)handle; + return MFX_ERR_NONE; +} + +// Allocate memory on device and copy 3D LUT table. +// Reference https://spec.oneapi.io/onevpl/2.9.0/programming_guide/VPL_prg_vpp.html#video-processing-3dlut +static int init_3dlut_surface(AVFilterContext *ctx) +{ + VPPContext *vpp = ctx->priv; + LUT3DContext *lut3d = &vpp->lut3d; + mfxExtVPP3DLut *lut3d_conf = &vpp->lut3d_conf; + + VAStatus ret = 0; + VADisplay va_dpy = 0; + VASurfaceID surface_id = 0; + VASurfaceAttrib surface_attrib; + VAImage surface_image; + mfxU16 *surface_u16 = NULL; + mfx3DLutMemoryLayout mem_layout; + mfxMemId mem_id = 0; + + int lut_size = lut3d->lutsize; + int mul_size = 0; + + int r, g, b, lut_idx, sf_idx; + struct rgbvec *s = NULL; + + av_log(ctx, AV_LOG_VERBOSE, "create 3D LUT surface, size: %u.\n", lut_size); + + switch (lut_size) { + case 17: + mul_size = 32; + mem_layout = MFX_3DLUT_MEMORY_LAYOUT_INTEL_17LUT; + break; + case 33: + mul_size = 64; + mem_layout = MFX_3DLUT_MEMORY_LAYOUT_INTEL_33LUT; + break; + case 65: + mul_size = 128; + mem_layout = MFX_3DLUT_MEMORY_LAYOUT_INTEL_65LUT; + break; + default: + av_log(ctx, AV_LOG_ERROR, "3D LUT surface supports only LUT size: 17, 33, 65."); + return AVERROR(EINVAL); + } + + ret = get_va_display(ctx, &va_dpy); + if (ret != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "get VADisplay failed, unable to create 3D LUT surface.\n"); + return ret; + } + + memset(&surface_attrib, 0, sizeof(surface_attrib)); + surface_attrib.type = VASurfaceAttribPixelFormat; + surface_attrib.flags = VA_SURFACE_ATTRIB_SETTABLE; + surface_attrib.value.type = VAGenericValueTypeInteger; + surface_attrib.value.value.i = VA_FOURCC_RGBA; + + ret = vaCreateSurfaces(va_dpy, + VA_RT_FORMAT_RGB32, // 4 bytes + lut_size * mul_size, // width + lut_size * 2, // height + &surface_id, 1, + &surface_attrib, 1); + if (ret != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "vaCreateSurfaces for 3D LUT surface failed, status: %d %s\n", ret, vaErrorStr(ret)); + return AVERROR(ret); + } + av_log(ctx, AV_LOG_DEBUG, "3D LUT surface id %u\n", surface_id); + + ret = vaSyncSurface(va_dpy, surface_id); + if (ret != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "vaSyncSurface for 3D LUT surface failed, status: %d %s\n", ret, vaErrorStr(ret)); + goto err_destroy_surface; + } + + memset(&surface_image, 0, sizeof(surface_image)); + ret = vaDeriveImage(va_dpy, surface_id, &surface_image); + if (ret != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "vaDeriveImage for 3D LUT surface failed, status: %d %s\n", ret, vaErrorStr(ret)); + goto err_destroy_surface; + } + if (surface_image.format.fourcc != VA_FOURCC_RGBA) { + av_log(ctx, AV_LOG_ERROR, "vaDeriveImage format is not expected VA_FOURCC_RGBA, got 0x%x\n", surface_image.format.fourcc); + goto err_destroy_image; + } + + // Map surface to system memory for copy 3D LUT table. + ret = vaMapBuffer(va_dpy, surface_image.buf, (void **)&surface_u16); + if (ret != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "vaMapBuffer for 3D LUT surface failed, status: %d %s\n", ret, vaErrorStr(ret)); + goto err_destroy_image; + } + + // Copy 3D LUT to surface. + memset(surface_u16, 0, surface_image.width * surface_image.height * 4); +#define INTEL_3DLUT_SCALE (UINT16_MAX - 1) + for (r = 0; r < lut_size; ++r) { + for (g = 0; g < lut_size; ++g) { + for (b = 0; b < lut_size; ++b) { + lut_idx = r * lut_size * lut_size + g * lut_size + b; + s = &lut3d->lut[lut_idx]; + + sf_idx = (r * lut_size * mul_size + g * mul_size + b) * 4; + surface_u16[sf_idx + 0] = (mfxU16)(s->r * INTEL_3DLUT_SCALE); + surface_u16[sf_idx + 1] = (mfxU16)(s->g * INTEL_3DLUT_SCALE); + surface_u16[sf_idx + 2] = (mfxU16)(s->b * INTEL_3DLUT_SCALE); + // surface_u16[sf_idx + 4] is reserved channel. + } + } + } +#undef INTEL_3DLUT_SCALE + + if (vaUnmapBuffer(va_dpy, surface_image.buf)) { + av_log(ctx, AV_LOG_ERROR, "vaUnmapBuffer for 3D LUT surface failed, status: %d %s\n", ret, vaErrorStr(ret)); + goto err_destroy_image; + } + vaDestroyImage(va_dpy, surface_image.image_id); + + mem_id = av_malloc(sizeof(VASurfaceID)); + if (mem_id == 0) { + ret = AVERROR(ENOMEM); + goto err_destroy_surface; + } + + av_log(ctx, AV_LOG_DEBUG, + "upload 3D LUT surface width %d, height %d\n", + (int)surface_image.width, (int)surface_image.height); + + memset(lut3d_conf, 0, sizeof(*lut3d_conf)); + lut3d_conf->Header.BufferId = MFX_EXTBUFF_VPP_3DLUT; + lut3d_conf->Header.BufferSz = sizeof(*lut3d_conf); + lut3d_conf->ChannelMapping = MFX_3DLUT_CHANNEL_MAPPING_RGB_RGB; + lut3d_conf->BufferType = MFX_RESOURCE_VA_SURFACE; + lut3d_conf->VideoBuffer.DataType = MFX_DATA_TYPE_U16; + lut3d_conf->VideoBuffer.MemLayout = mem_layout; + lut3d_conf->VideoBuffer.MemId = mem_id; + *((VASurfaceID*)lut3d_conf->VideoBuffer.MemId) = surface_id; + + return 0; + +err_destroy_image: + vaDestroyImage(va_dpy, surface_image.image_id); +err_destroy_surface: + vaDestroySurfaces(va_dpy, &surface_id, 1); + return ret; +} + +static int uninit_3dlut_surface(AVFilterContext *ctx) { + VPPContext *vpp = ctx->priv; + mfxExtVPP3DLut *lut3d_conf = &vpp->lut3d_conf; + VADisplay va_dpy = 0; + int ret; + + if (lut3d_conf->Header.BufferId == MFX_EXTBUFF_VPP_3DLUT) { + ret = get_va_display(ctx, &va_dpy); + if (!va_dpy) { + return ret; + } + ret = vaDestroySurfaces(va_dpy, (VASurfaceID*)lut3d_conf->VideoBuffer.MemId, 1); + if (ret != VA_STATUS_SUCCESS) { + av_log(ctx, AV_LOG_ERROR, "vaDestroySurfaces failed, status: %d %s\n", ret, vaErrorStr(ret) ); + return ret; + } + av_free(lut3d_conf->VideoBuffer.MemId); + } + memset(lut3d_conf, 0, sizeof(*lut3d_conf)); + + return 0; +} +#endif // QSV_ONEVPL && CONFIG_VAAPI + static int vpp_set_frame_ext_params(AVFilterContext *ctx, const AVFrame *in, AVFrame *out, QSVVPPFrameParam *fp) { #if QSV_ONEVPL @@ -401,6 +600,7 @@ static int vpp_set_frame_ext_params(AVFilterContext *ctx, const AVFrame *in, AVF fp->num_ext_buf = 0; + av_log(ctx, AV_LOG_DEBUG, "vpp_set_frame_ext_params QSV_ONEVPL\n"); if (!in || !out || !QSV_RUNTIME_VERSION_ATLEAST(qsvvpp->ver, 2, 0)) return 0; @@ -499,6 +699,13 @@ static int vpp_set_frame_ext_params(AVFilterContext *ctx, const AVFrame *in, AVF outvsi_conf.MatrixCoefficients = (out->colorspace == AVCOL_SPC_UNSPECIFIED) ? AVCOL_SPC_BT709 : out->colorspace; outvsi_conf.ColourDescriptionPresent = 1; +#if CONFIG_VAAPI + if (vpp->lut3d.file && (vpp->lut3d_conf.Header.BufferId == 0)) { + // 3D LUT does not depend on in/out frame, so initialize just once. + init_3dlut_surface(ctx); + } +#endif + if (memcmp(&vpp->invsi_conf, &invsi_conf, sizeof(mfxExtVideoSignalInfo)) || memcmp(&vpp->mdcv_conf, &mdcv_conf, sizeof(mfxExtMasteringDisplayColourVolume)) || memcmp(&vpp->clli_conf, &clli_conf, sizeof(mfxExtContentLightLevelInfo)) || @@ -516,6 +723,10 @@ static int vpp_set_frame_ext_params(AVFilterContext *ctx, const AVFrame *in, AVF vpp->clli_conf = clli_conf; if (clli_conf.Header.BufferId) fp->ext_buf[fp->num_ext_buf++] = (mfxExtBuffer*)&vpp->clli_conf; + + if (vpp->lut3d_conf.Header.BufferId) { + fp->ext_buf[fp->num_ext_buf++] = (mfxExtBuffer *)&vpp->lut3d_conf; + } } #endif @@ -524,6 +735,7 @@ static int vpp_set_frame_ext_params(AVFilterContext *ctx, const AVFrame *in, AVF static int config_output(AVFilterLink *outlink) { + int ret; AVFilterContext *ctx = outlink->src; VPPContext *vpp = ctx->priv; QSVVPPParam param = { NULL }; @@ -711,9 +923,17 @@ static int config_output(AVFilterLink *outlink) vpp->color_transfer != AVCOL_TRC_UNSPECIFIED || vpp->color_matrix != AVCOL_SPC_UNSPECIFIED || vpp->tonemap || - !vpp->has_passthrough) + vpp->lut3d.file || + !vpp->has_passthrough) { + if (vpp->lut3d.file) { + av_log(ctx, AV_LOG_INFO, "load 3D LUT from file: %s\n", vpp->lut3d.file); + ret = ff_lut3d_init(ctx, &vpp->lut3d); + if (ret != 0) { + return ret; + } + } return ff_qsvvpp_init(ctx, ¶m); - else { + } else { /* No MFX session is created in this case */ av_log(ctx, AV_LOG_VERBOSE, "qsv vpp pass through mode.\n"); if (inlink->hw_frames_ctx) @@ -801,6 +1021,15 @@ eof: static av_cold void vpp_uninit(AVFilterContext *ctx) { + VPPContext *vpp = ctx->priv; + +#if QSV_ONEVPL && CONFIG_VAAPI + uninit_3dlut_surface(ctx); +#endif + + if (vpp->lut3d.file) { + ff_lut3d_uninit(&vpp->lut3d); + } ff_qsvvpp_close(ctx); } @@ -924,7 +1153,9 @@ static const AVOption vpp_options[] = { OFFSET(color_transfer_str), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, {"tonemap", "Perform tonemapping (0=disable tonemapping, 1=perform tonemapping if the input has HDR metadata)", OFFSET(tonemap), AV_OPT_TYPE_INT, {.i64 = 0 }, 0, 1, .flags = FLAGS}, - +#if QSV_ONEVPL && CONFIG_VAAPI + { "lut3d_file", "Load and apply 3D LUT file", OFFSET(lut3d) + offsetof(LUT3DContext, file), AV_OPT_TYPE_STRING, { .str = NULL }, .flags = FLAGS }, +#endif { NULL } };