PR #23125 opened by Lynne
URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23125
Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23125.patch

This completes the rendering pipeline for ProRes RAW. Output from the decoder 
is camera-specific until the side data is applied, after which it becomes a 
regular BT2020 linear. mpv/libplacebo will automatically tone-map down from 
however many stops of dynamic range the camera has to display.


>From b1c03d706b414ee656453914fd6e9c449b3a222e Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sat, 16 May 2026 17:40:14 +0900
Subject: [PATCH 1/3] lavu/frame: add camera raw codec side data

Required to correctly present raw video.
Codec-specific since I'd like to support ARRIRAW in the future, which
has a different format.
---
 libavutil/Makefile           |   2 +
 libavutil/frame.h            |   7 ++
 libavutil/raw_color_params.c |  47 +++++++++++
 libavutil/raw_color_params.h | 158 +++++++++++++++++++++++++++++++++++
 libavutil/side_data.c        |   1 +
 libavutil/version.h          |   2 +-
 6 files changed, 216 insertions(+), 1 deletion(-)
 create mode 100644 libavutil/raw_color_params.c
 create mode 100644 libavutil/raw_color_params.h

diff --git a/libavutil/Makefile b/libavutil/Makefile
index b7d6e4906f..bb4c5cab64 100644
--- a/libavutil/Makefile
+++ b/libavutil/Makefile
@@ -76,6 +76,7 @@ HEADERS = adler32.h                                           
          \
           pixelutils.h                                                  \
           pixfmt.h                                                      \
           random_seed.h                                                 \
+          raw_color_params.h                                            \
           rc4.h                                                         \
           rational.h                                                    \
           refstruct.h                                                   \
@@ -169,6 +170,7 @@ OBJS = adler32.o                                            
            \
        pixdesc.o                                                        \
        pixelutils.o                                                     \
        random_seed.o                                                    \
+       raw_color_params.o                                               \
        rational.o                                                       \
        refstruct.o                                                      \
        reverse.o                                                        \
diff --git a/libavutil/frame.h b/libavutil/frame.h
index e123668124..52adbc6288 100644
--- a/libavutil/frame.h
+++ b/libavutil/frame.h
@@ -292,6 +292,13 @@ enum AVFrameSideDataType {
     * and Formats standard.
     */
     AV_FRAME_DATA_IAMF_RECON_GAIN_INFO_PARAM,
+
+    /**
+     * Color information from a RAW camera codecs, needed to correctly process
+     * the video data. The payload is an AVRawColorParams struct defined in
+     * libavutil/raw_color_params.h.
+     */
+    AV_FRAME_DATA_RAW_COLOR_PARAMS,
 };
 
 enum AVActiveFormatDescription {
diff --git a/libavutil/raw_color_params.c b/libavutil/raw_color_params.c
new file mode 100644
index 0000000000..7b096fa793
--- /dev/null
+++ b/libavutil/raw_color_params.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2026 Lynne <[email protected]>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "raw_color_params.h"
+#include "mem.h"
+
+AVRawColorParams *av_raw_color_params_alloc(size_t *size)
+{
+    AVRawColorParams *p = av_mallocz(sizeof(AVRawColorParams));
+    if (!p)
+        return NULL;
+
+    if (size)
+        *size = sizeof(*p);
+
+    return p;
+}
+
+AVRawColorParams *av_raw_color_params_create_side_data(AVFrame *frame)
+{
+    AVFrameSideData *side_data =
+        av_frame_new_side_data(frame, AV_FRAME_DATA_RAW_COLOR_PARAMS,
+                               sizeof(AVRawColorParams));
+    if (!side_data)
+        return NULL;
+
+    memset(side_data->data, 0, side_data->size);
+
+    return (AVRawColorParams *)side_data->data;
+}
diff --git a/libavutil/raw_color_params.h b/libavutil/raw_color_params.h
new file mode 100644
index 0000000000..6fe5001b15
--- /dev/null
+++ b/libavutil/raw_color_params.h
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2026 Lynne <[email protected]>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef AVUTIL_RAW_COLOR_PARAMS_H
+#define AVUTIL_RAW_COLOR_PARAMS_H
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "frame.h"
+#include "pixfmt.h"
+#include "rational.h"
+
+enum AVRawColorParamsType {
+    AV_RAW_COLOR_PARAMS_NONE = 0,
+
+    /**
+     * The union is valid when interpreted as AVProResRawColorParams
+     * (codec.prores_raw).
+     */
+    AV_RAW_COLOR_PARAMS_PRORES_RAW,
+};
+
+/**
+ * ProRes RAW per-frame color transform, parsed from the prrf frame header.
+ *
+ * The correct rendering pipeline is:
+ *  -> (sample - black_level) / (white_level - black_level)
+ *  -> per-channel white balance (wb_red, 1.0 for G, wb_blue) pre-debayer
+ *  -> debayer
+ *  -> color_matrix (camera RGB -> target primaries)
+ *  -> gain (scene-linear scale)
+ *
+ * Black/white levels and the target primaries/transfer live on the outer
+ * AVRawColorParams.
+ *
+ * @note The struct must be allocated as part of AVRawColorParams using
+ *       av_raw_color_params_alloc(). Its size is not a part of the public ABI.
+ */
+typedef struct AVProResRawColorParams {
+    /**
+     * White balance multiplier for the red channel, applied pre-debayer.
+     */
+    AVRational wb_red;
+
+    /**
+     * White balance multiplier for the blue channel, applied pre-debayer.
+     * (The green channel is implicit 1.0 for ProRes RAW)
+     */
+    AVRational wb_blue;
+
+    /**
+     * 3x3 row-major color matrix from camera RGB to the target primaries
+     * declared on the outer AVRawColorParams, applied post-debayer.
+     * out[i] = sum_j color_matrix[i][j] * in[j].
+     */
+    AVRational color_matrix[3][3];
+
+    /**
+     * Post-matrix scene-linear scaling factor. Encodes highlight headroom the
+     * encoder reserved; multiply the matrixed values by this to recover
+     * scene-linear light.
+     */
+    AVRational gain;
+} AVProResRawColorParams;
+
+/**
+ * Per-frame color information for a RAW camera codec. Carried as side data of
+ * type AV_FRAME_DATA_RAW_COLOR_PARAMS.
+ *
+ * The outer struct carries the fields every RAW codec exposes: the sensor's
+ * valid sample range, the target colorspace the codec-specific transform
+ * lands in, and the white-balance correlated color temperature. The codec
+ * union holds the codec-specific transform parameters; `type` selects which
+ * member of the union is valid.
+ *
+ * @note The struct must be allocated using av_raw_color_params_alloc() or
+ *       av_raw_color_params_create_side_data(). Its size is not a part of the
+ *       public ABI.
+ */
+typedef struct AVRawColorParams {
+    /**
+     * Selects which member of `codec` is valid.
+     */
+    enum AVRawColorParamsType type;
+
+    /**
+     * Lowest valid raw sample code (sensor black point)
+     */
+    AVRational black_level;
+
+    /**
+     * Highest valid raw sample code (sensor white point)
+     */
+    AVRational white_level;
+
+    /**
+     * Target color primaries the codec-specific transform lands in. The
+     * `color_matrix` (or equivalent) in the codec-specific struct converts
+     * camera RGB to these primaries.
+     */
+    enum AVColorPrimaries primaries;
+
+    /**
+     * Target transfer characteristic. Typically AVCOL_TRC_LINEAR, since codecs
+     * decode to scene-linear before any creative grading.
+     */
+    enum AVColorTransferCharacteristic trc;
+
+    /**
+     * Color temperature in Kelvin from with the camera's white balance.
+     * Informational; the math uses the codec-specific white-balance fields.
+     * 0 if not signaled.
+     */
+    uint32_t wb_cct;
+
+    /**
+     * Additional codec-specific fields.
+     */
+    union {
+        AVProResRawColorParams prores_raw;
+    } codec;
+} AVRawColorParams;
+
+/**
+ * Allocate an AVRawColorParams structure and zero-initialize it.
+ *
+ * @param size if non-NULL, set to sizeof(AVRawColorParams)
+ * @return the newly allocated struct or NULL on failure
+ */
+AVRawColorParams *av_raw_color_params_alloc(size_t *size);
+
+/**
+ * Allocate and add an AVRawColorParams structure to an existing AVFrame as
+ * AV_FRAME_DATA_RAW_COLOR_PARAMS side data.
+ *
+ * @return the newly allocated struct, or NULL on failure
+ */
+AVRawColorParams *av_raw_color_params_create_side_data(AVFrame *frame);
+
+#endif /* AVUTIL_RAW_COLOR_PARAMS_H */
diff --git a/libavutil/side_data.c b/libavutil/side_data.c
index 64c4220ed9..762bc59d53 100644
--- a/libavutil/side_data.c
+++ b/libavutil/side_data.c
@@ -61,6 +61,7 @@ static const AVSideDataDescriptor sd_props[] = {
     [AV_FRAME_DATA_IAMF_MIX_GAIN_PARAM]         = { "IAMF Mix Gain Parameter 
Data" },
     [AV_FRAME_DATA_IAMF_DEMIXING_INFO_PARAM]    = { "IAMF Demixing Info 
Parameter Data",            AV_SIDE_DATA_PROP_CHANNEL_DEPENDENT },
     [AV_FRAME_DATA_IAMF_RECON_GAIN_INFO_PARAM]  = { "IAMF Recon Gain Info 
Parameter Data" },
+    [AV_FRAME_DATA_RAW_COLOR_PARAMS]            = { "RAW camera color 
parameters",                  AV_SIDE_DATA_PROP_GLOBAL | 
AV_SIDE_DATA_PROP_COLOR_DEPENDENT },
 };
 
 const AVSideDataDescriptor *av_frame_side_data_desc(enum AVFrameSideDataType 
type)
diff --git a/libavutil/version.h b/libavutil/version.h
index 07c47da803..e7aeab9995 100644
--- a/libavutil/version.h
+++ b/libavutil/version.h
@@ -79,7 +79,7 @@
  */
 
 #define LIBAVUTIL_VERSION_MAJOR  60
-#define LIBAVUTIL_VERSION_MINOR  31
+#define LIBAVUTIL_VERSION_MINOR  32
 #define LIBAVUTIL_VERSION_MICRO 100
 
 #define LIBAVUTIL_VERSION_INT   AV_VERSION_INT(LIBAVUTIL_VERSION_MAJOR, \
-- 
2.52.0


>From 53e805df9d03cc80c7cd1f8c2f78530c9fd5fddd Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sat, 16 May 2026 17:40:35 +0900
Subject: [PATCH 2/3] prores_raw: export raw camera color data values

---
 libavcodec/prores_raw.c | 43 +++++++++++++++++++++++++++++++++++------
 1 file changed, 37 insertions(+), 6 deletions(-)

diff --git a/libavcodec/prores_raw.c b/libavcodec/prores_raw.c
index f386b22496..1ffabdba92 100644
--- a/libavcodec/prores_raw.c
+++ b/libavcodec/prores_raw.c
@@ -21,9 +21,12 @@
  */
 
 #include "libavutil/avassert.h"
+#include "libavutil/intfloat.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/mem_internal.h"
 #include "libavutil/mem.h"
+#include "libavutil/raw_color_params.h"
+#include "libavutil/rational.h"
 
 #define CACHED_BITSTREAM_READER !ARCH_X86_32
 
@@ -417,12 +420,22 @@ static int decode_frame(AVCodecContext *avctx,
         return AVERROR_PATCHWELCOME;
     }
 
-    bytestream2_skip(&gb_hdr, 2); /* senselValueRange (white_level = value + 
0x100, black_level = 0x100) */
-    bytestream2_skip(&gb_hdr, 4); /* WhiteBalanceRedFactor (float, pre-debayer 
R gain) */
-    bytestream2_skip(&gb_hdr, 4); /* WhiteBalanceBlueFactor (float, 
pre-debayer B gain) */
-    bytestream2_skip(&gb_hdr, 4 * 3 * 3); /* ColorMatrix (3x3 float, camera 
RGB -> Rec.2020 linear, row-major) */
-    bytestream2_skip(&gb_hdr, 4); /* GainFactor (float, post-matrix 
scene-linear scale) */
-    bytestream2_skip(&gb_hdr, 2); /* WhiteBalanceCCT (Kelvin, informational) */
+    /* senselValueRange: black_level is hardcoded to 0x100,
+     * white_level = senselValueRange + 0x100 */
+    uint16_t black_level = 0x100;
+    uint16_t white_level = bytestream2_get_be16(&gb_hdr) + 0x100;
+
+    float wb_red  = av_int2float(bytestream2_get_be32(&gb_hdr)); /* 
WhiteBalanceRedFactor */
+    float wb_blue = av_int2float(bytestream2_get_be32(&gb_hdr)); /* 
WhiteBalanceBlueFactor */
+
+    /* ColorMatrix (3x3 float, camera RGB -> Rec.2020 linear, row-major) */
+    float color_matrix[3][3];
+    for (int r = 0; r < 3; r++)
+        for (int c = 0; c < 3; c++)
+            color_matrix[r][c] = av_int2float(bytestream2_get_be32(&gb_hdr));
+
+    float gain = av_int2float(bytestream2_get_be32(&gb_hdr)); /* GainFactor 
(post-matrix mult) */
+    uint16_t wb_cct = bytestream2_get_be16(&gb_hdr); /* WhiteBalanceCCT 
(Kelvin, informational) */
 
     /* Flags */
     int flags = bytestream2_get_be16(&gb_hdr);
@@ -532,6 +545,24 @@ static int decode_frame(AVCodecContext *avctx,
     frame->pict_type = AV_PICTURE_TYPE_I;
     frame->flags    |= AV_FRAME_FLAG_KEY;
 
+    AVRawColorParams *rcp = av_raw_color_params_create_side_data(frame);
+    if (!rcp)
+        return AVERROR(ENOMEM);
+    rcp->type        = AV_RAW_COLOR_PARAMS_PRORES_RAW;
+    rcp->black_level = av_make_q(black_level, 65535);
+    rcp->white_level = av_make_q(white_level, 65535);
+    rcp->wb_cct      = av_make_q(wb_cct,      65535);
+    rcp->primaries   = AVCOL_PRI_BT2020;
+    rcp->trc         = AVCOL_TRC_LINEAR;
+
+    AVProResRawColorParams *pr = &rcp->codec.prores_raw;
+    pr->wb_red  = av_d2q(wb_red);
+    pr->wb_blue = av_d2q(wb_blue);
+    pr->gain    = av_d2q(gain);
+    for (int r = 0; r < 3; r++)
+        for (int c = 0; c < 3; c++)
+            pr->color_matrix[r][c] = av_d2q(color_matrix[r][c]);
+
     *got_frame_ptr = 1;
 
     return avpkt->size;
-- 
2.52.0


>From 5c1969240186ebbb1fad6c60f30a5cf17cd91227 Mon Sep 17 00:00:00 2001
From: Lynne <[email protected]>
Date: Sat, 16 May 2026 16:42:04 +0900
Subject: [PATCH 3/3] scale_vulkan: apply camera raw data

---
 libavfilter/vf_scale_vulkan.c        | 76 ++++++++++++++++++++++--
 libavfilter/vulkan/debayer.comp.glsl | 88 +++++++++++++++++++---------
 2 files changed, 130 insertions(+), 34 deletions(-)

diff --git a/libavfilter/vf_scale_vulkan.c b/libavfilter/vf_scale_vulkan.c
index 19b4e5e5ac..0fc01a9638 100644
--- a/libavfilter/vf_scale_vulkan.c
+++ b/libavfilter/vf_scale_vulkan.c
@@ -18,8 +18,10 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  */
 
+#include "libavutil/mastering_display_metadata.h"
 #include "libavutil/random_seed.h"
 #include "libavutil/opt.h"
+#include "libavutil/raw_color_params.h"
 #include "libavutil/vulkan_spirv.h"
 #include "vulkan_filter.h"
 #include "scale_eval.h"
@@ -55,13 +57,19 @@ typedef struct ScaleVulkanContext {
     FFVulkanShader shd;
     VkSampler sampler;
 
-    /* Push constants / options */
     struct {
-        float yuv_matrix[4][4];
+        float matrix[4][4];
         int crop_x;
         int crop_y;
         int crop_w;
         int crop_h;
+
+        /* RAW camera color processing (debayering only) */
+        float wb_red;
+        float wb_blue;
+        float gain;
+        float black_level_norm;
+        float inv_range;
     } opts;
 
     char *out_format_string;
@@ -191,8 +199,8 @@ static int init_scale_shader(AVFilterContext *ctx, 
FFVulkanShader *shd,
 
         for (int y = 0; y < 3; y++)
             for (int x = 0; x < 3; x++)
-                s->opts.yuv_matrix[x][y] = tmp_mat[x][y];
-        s->opts.yuv_matrix[3][3] = 1.0;
+                s->opts.matrix[x][y] = tmp_mat[x][y];
+        s->opts.matrix[3][3] = 1.0;
     }
 
     return 0;
@@ -268,6 +276,11 @@ static av_cold int init_filter(AVFilterContext *ctx, 
AVFrame *in)
     GLSLC(1,    int crop_y;                                               );
     GLSLC(1,    int crop_w;                                               );
     GLSLC(1,    int crop_h;                                               );
+    GLSLC(1,    float wb_red;                                             );
+    GLSLC(1,    float wb_blue;                                            );
+    GLSLC(1,    float gain;                                               );
+    GLSLC(1,    float black_level_norm;                                   );
+    GLSLC(1,    float inv_range;                                          );
     GLSLC(0, };                                                           );
     GLSLC(0,                                                              );
 
@@ -363,6 +376,59 @@ static int scale_vulkan_filter_frame(AVFilterLink *link, 
AVFrame *in)
     if (err < 0)
         goto fail;
 
+    if (s->vkctx.input_format == AV_PIX_FMT_BAYER_RGGB16) {
+        memset(s->opts.matrix, 0, sizeof(s->opts.matrix));
+        s->opts.matrix[0][0]     = 1.0f;
+        s->opts.matrix[1][1]     = 1.0f;
+        s->opts.matrix[2][2]     = 1.0f;
+        s->opts.matrix[3][3]     = 1.0f;
+        s->opts.wb_red           = 1.0f;
+        s->opts.wb_blue          = 1.0f;
+        s->opts.gain             = 1.0f;
+        s->opts.black_level_norm = 0.0f;
+        s->opts.inv_range        = 1.0f;
+
+        AVFrameSideData *sd = av_frame_get_side_data(in, 
AV_FRAME_DATA_RAW_COLOR_PARAMS);
+        if (sd) {
+            const AVRawColorParams *rcp = (const AVRawColorParams *)sd->data;
+            if (rcp->type == AV_RAW_COLOR_PARAMS_PRORES_RAW) {
+                const AVProResRawColorParams *pr = &rcp->codec.prores_raw;
+
+                for (int r = 0; r < 3; r++)
+                    for (int c = 0; c < 3; c++)
+                        s->opts.matrix[r][c] = av_q2d(pr->color_matrix[r][c]);
+                s->opts.wb_red           = av_q2d(pr->wb_red);
+                s->opts.wb_blue          = av_q2d(pr->wb_blue);
+                s->opts.gain             = av_q2d(pr->gain);
+                float black              = av_q2d(rcp->black_level);
+                float white              = av_q2d(rcp->white_level);
+                s->opts.black_level_norm = black;
+                s->opts.inv_range        = 1.0 / (white - black);
+
+                out->color_primaries = rcp->primaries;
+                out->color_trc       = rcp->trc;
+                out->colorspace      = AVCOL_SPC_RGB;
+                out->color_range     = AVCOL_RANGE_JPEG;
+
+                av_frame_side_data_remove(&out->side_data, &out->nb_side_data,
+                                          AV_FRAME_DATA_RAW_COLOR_PARAMS);
+
+                /* Tag the source as HDR.
+                 * Sensor headroom is pr->gain times above the 203 nits
+                 * SDR reference white */
+                AVMasteringDisplayMetadata *mdm =
+                    av_mastering_display_metadata_create_side_data(out);
+                if (!mdm)
+                    return AVERROR(ENOMEM);
+
+                mdm->max_luminance = av_mul_q(pr->gain,
+                                              av_make_q(203, 1));
+                mdm->min_luminance = av_make_q(1, 10000);
+                mdm->has_luminance = 1;
+            }
+        }
+    }
+
     if (out->width != in->width || out->height != in->height) {
         av_frame_side_data_remove_by_props(&out->side_data, &out->nb_side_data,
                                            AV_SIDE_DATA_PROP_SIZE_DEPENDENT);
@@ -440,7 +506,7 @@ static int scale_vulkan_config_output(AVFilterLink *outlink)
 
     if (s->vkctx.input_format == AV_PIX_FMT_BAYER_RGGB16) {
         if (s->vkctx.output_format == s->vkctx.input_format) {
-            s->vkctx.output_format = AV_PIX_FMT_RGBA64;
+            s->vkctx.output_format = AV_PIX_FMT_RGBAF16;
         } else if (!ff_vk_mt_is_np_rgb(s->vkctx.output_format)) {
             av_log(avctx, AV_LOG_ERROR, "Unsupported output format for 
debayer\n");
             return AVERROR(EINVAL);
diff --git a/libavfilter/vulkan/debayer.comp.glsl 
b/libavfilter/vulkan/debayer.comp.glsl
index 0a4e22de99..264b2b37db 100644
--- a/libavfilter/vulkan/debayer.comp.glsl
+++ b/libavfilter/vulkan/debayer.comp.glsl
@@ -22,6 +22,7 @@
 #pragma shader_stage(compute)
 
 #extension GL_EXT_shader_image_load_formatted : require
+#extension GL_EXT_scalar_block_layout : require
 
 layout (local_size_x_id = 253, local_size_y_id = 254, local_size_z_id = 255) 
in;
 
@@ -30,90 +31,119 @@ layout (set = 0, binding = 1) uniform writeonly image2D 
dst;
 
 layout (constant_id = 0) const int debayer_mode = 0;
 
-layout(push_constant, std430) uniform pushConstants {
-   mat4 yuv_matrix;
+layout(push_constant, scalar) uniform pushConstants {
+   mat4 rgb_matrix;
    int crop_x;
    int crop_y;
    int crop_w;
    int crop_h;
+   float wb_red;
+   float wb_blue;
+   float gain;
+   float black_level_norm;
+   float inv_range;
 };
 
-#define LD(xo, yo) \
-    (imageLoad(src, pos + ivec2((xo), (yo))).r)
+/* Read a sample, apply black-level, normalize, and apply white balance.
+ * Mirrored coords. */
+float ld_at(ivec2 base, int xo, int yo)
+{
+    ivec2 p = base + ivec2(xo, yo);
+    ivec2 cmin = ivec2(crop_x, crop_y);
+    ivec2 cmax = ivec2(crop_x + crop_w - 1, crop_y + crop_h - 1);
+    p = mix(p, 2*cmin - p, lessThan(p, cmin));
+    p = mix(p, 2*cmax - p, greaterThan(p, cmax));
+
+    float v = imageLoad(src, p).r;
+    v = max(v - black_level_norm, 0.0) * inv_range;
+
+    bool x_odd = (p.x & 1) != 0;
+    bool y_odd = (p.y & 1) != 0;
+    float wb = x_odd == y_odd ? (x_odd ? wb_blue : wb_red) : 1.0;
+    return v * wb;
+}
+
+#define LD(xo, yo) ld_at(pos, (xo), (yo))
+
+void write(ivec2 pos, vec4 c)
+{
+    /* Apply RGB conversion matrix */
+    c.rgb = (c.rgb * mat3(rgb_matrix)) * gain;
+    imageStore(dst, pos, c);
+}
 
 void debayer_bilinear(ivec2 pos)
 {
     /* R basis */
-    vec4 tl = vec4(LD(0, 0),
+    write(pos,
+              vec4(LD(0, 0),
                    (LD(1, 0) + LD(-1, 0) + LD(0, 1) + LD(0, -1)) / 4.0f,
                    (LD(-1, -1) + LD(1, 1) + LD(-1, 1) + LD(1, -1)) / 4.0f,
-                   1.0f);
-    imageStore(dst, pos, tl);
+                   1.0f));
 
     /* G1 basis */
-    vec4 tr = vec4((LD(2, 0) + LD(0, 0)) / 2.0f,
+    write(pos + ivec2(1, 0),
+              vec4((LD(2, 0) + LD(0, 0)) / 2.0f,
                    LD(1, 0),
                    (LD(1, 1) + LD(1, -1)) / 2.0f,
-                   1.0f);
-    imageStore(dst, pos + ivec2(1, 0), tr);
+                   1.0f));
 
     /* G2 basis */
-    vec4 bl = vec4((LD(0, 2) + LD(0, 0)) / 2.0f,
+    write(pos + ivec2(0, 1),
+              vec4((LD(0, 2) + LD(0, 0)) / 2.0f,
                    LD(0, 1),
                    (LD(1, 1) + LD(-1, 1)) / 2.0f,
-                   1.0f);
-    imageStore(dst, pos + ivec2(0, 1), bl);
+                   1.0f));
 
     /* B basis */
-    vec4 br = vec4((LD(0, 0) + LD(2, 2) + LD(0, 2) + LD(2, 0)) / 4.0f,
+    write(pos + ivec2(1, 1),
+              vec4((LD(0, 0) + LD(2, 2) + LD(0, 2) + LD(2, 0)) / 4.0f,
                    (LD(2, 1) + LD(0, 1) + LD(1, 2) + LD(1, 0)) / 4.0f,
                    LD(1, 1),
-                   1.0f);
-    imageStore(dst, pos + ivec2(1, 1), br);
+                   1.0f));
 }
 
 void debayer_bilinear_hq(ivec2 pos)
 {
     /* R basis */
-    vec4 tl = vec4(LD(0, 0),
+    write(pos,
+              vec4(LD(0, 0),
                    (4.0f*LD(0, 0) + 2.0f*(LD(0, -1) + LD(0, 1) + LD(-1, 0) + 
LD(1, 0)) -
                     (LD(0, -2) + LD(0, 2) + LD(-2, 0) + LD(2, 0))) / 8.0f,
                    (12.0f*LD(0, 0) + 4.0f*(LD(-1, -1) + LD(-1, 1) + LD(1, -1) 
+ LD(1, 1)) -
                     3.0f*(LD(0, -2) + LD(0, 2) + LD(-2, 0) + LD(2, 0))) / 
16.0f,
-                   1.0f);
-    imageStore(dst, pos, tl);
+                   1.0f));
 
     /* G1 basis */
-    vec4 tr = vec4((10.0f*LD(1, 0) + 8.0f*(LD(0, 0) + LD(2, 0)) -
+    write(pos + ivec2(1, 0),
+              vec4((10.0f*LD(1, 0) + 8.0f*(LD(0, 0) + LD(2, 0)) -
                     2.0f*(LD(0, -1) + LD(2, 1) + LD(0, 1) + LD(2, -1) + LD(-1, 
0) + LD(3, 0)) +
                     LD(1, -2) + LD(1, 2)) / 16.0f,
                    LD(1, 0),
                    (10.0f*LD(1, 0) + 8.0f*(LD(1, -1) + LD(1, 1)) -
                     2.0f*(LD(0, -1) + LD(0, 1) + LD(2, -1) + LD(2, 1) + LD(1, 
-2) + LD(1, 2)) +
                     LD(-1, 0) + LD(3, 0)) / 16.0f,
-                   1.0f);
-    imageStore(dst, pos + ivec2(1, 0), tr);
-
+                   1.0f));
 
     /* G2 basis */
-    vec4 bl = vec4((10.0f*LD(0, 1) + 8.0f*(LD(0, 0) + LD(0, 2)) -
+    write(pos + ivec2(0, 1),
+              vec4((10.0f*LD(0, 1) + 8.0f*(LD(0, 0) + LD(0, 2)) -
                    2.0f*(LD(-1, 0) + LD(-1, 2) + LD(1, 0) + LD(1, 2) + LD(0, 
-1) + LD(0, 3)) +
                    LD(-2, 1) + LD(2, 1)) / 16.0f,
                    LD(0, 1),
                    (10.0f*LD(0, 1) + 8.0f*(LD(-1, 1) + LD(1, 1)) -
                    2.0f*(LD(-1, 0) + LD(1, 2) + LD(-1, 2) + LD(1, 0) + LD(-2, 
1) + LD(2, 1)) +
                     LD(0, -1) + LD(0, 3)) / 16.0f,
-                   1.0f);
-    imageStore(dst, pos + ivec2(0, 1), bl);
+                   1.0f));
 
     /* B basis */
-    vec4 br = vec4((12.0f*LD(1, 1) + 4.0f*(LD(0, 0) + LD(0, 2) + LD(2, 0) + 
LD(2, 2)) -
+    write(pos + ivec2(1, 1),
+              vec4((12.0f*LD(1, 1) + 4.0f*(LD(0, 0) + LD(0, 2) + LD(2, 0) + 
LD(2, 2)) -
                     3.0f*(LD(1, -1) + LD(1, 3) + LD(-1, 1) + LD(3, 1))) / 
16.0f,
                    (4.0f*LD(1, 1) + 2.0f*(LD(1, 0) + LD(1, 2) + LD(0, 1) + 
LD(2, 1)) -
                     (LD(1, -1) + LD(1, 3) + LD(-1, 1) + LD(3, 1))) / 8.0f,
                    LD(1, 1),
-                   1.0f);
-    imageStore(dst, pos + ivec2(1, 1), br);
+                   1.0f));
 }
 
 void main(void)
-- 
2.52.0

_______________________________________________
ffmpeg-devel mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to