From: Michael Niedermayer <[email protected]>

The implementation is heavily based on Matthias Buercher's and Nicolas
Bertrand's vf_xyz2rgb

Signed-off-by: Anton Khirnov <[email protected]>
---
 libswscale/swscale_internal.h |    9 +++++
 libswscale/swscale_unscaled.c |   82 ++++++++++++++++++++++++++++++++++++++---
 libswscale/utils.c            |   42 +++++++++++++++++++++
 3 files changed, 128 insertions(+), 5 deletions(-)

diff --git a/libswscale/swscale_internal.h b/libswscale/swscale_internal.h
index f9f023f..d7979ea 100644
--- a/libswscale/swscale_internal.h
+++ b/libswscale/swscale_internal.h
@@ -362,6 +362,8 @@ typedef struct SwsContext {
     int dstColorspaceTable[4];
     int srcRange;                 ///< 0 = MPG YUV range, 1 = JPG YUV range 
(source      image).
     int dstRange;                 ///< 0 = MPG YUV range, 1 = JPG YUV range 
(destination image).
+    int src_xyz;
+    int dst_xyz;
     int yuv2rgb_y_offset;
     int yuv2rgb_y_coeff;
     int yuv2rgb_v2r_coeff;
@@ -454,6 +456,13 @@ typedef struct SwsContext {
     DECLARE_ALIGNED(8, uint64_t, sparc_coeffs)[10];
 #endif
 
+/* pre defined color-spaces gamma */
+#define XYZ_GAMMA (2.6f)
+#define RGB_GAMMA (2.2f)
+    int16_t xyzgamma[4096];
+    int16_t rgbgamma[4096];
+    int16_t xyz2rgb_matrix[3][4];
+
     /* function pointers for swScale() */
     yuv2planar1_fn yuv2plane1;
     yuv2planarX_fn yuv2planeX;
diff --git a/libswscale/swscale_unscaled.c b/libswscale/swscale_unscaled.c
index a994d6f..a4f5a34 100644
--- a/libswscale/swscale_unscaled.c
+++ b/libswscale/swscale_unscaled.c
@@ -1122,6 +1122,62 @@ static int check_image_pointers(uint8_t *data[4], enum 
AVPixelFormat pix_fmt,
     return 1;
 }
 
+static void xyz12_to_rgb48(struct SwsContext *c, uint16_t *dst,
+                           const uint16_t *src, int stride, int h)
+{
+    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(c->srcFormat);
+    int xp, yp;
+
+    for (yp = 0; yp < h; yp++) {
+        for (xp = 0; xp + 2 < stride; xp += 3) {
+            int x, y, z, r, g, b;
+
+            if (desc->flags & PIX_FMT_BE) {
+                x = AV_RB16(src + xp + 0);
+                y = AV_RB16(src + xp + 1);
+                z = AV_RB16(src + xp + 2);
+            } else {
+                x = AV_RL16(src + xp + 0);
+                y = AV_RL16(src + xp + 1);
+                z = AV_RL16(src + xp + 2);
+            }
+
+            x = c->xyzgamma[x >> 4];
+            y = c->xyzgamma[y >> 4];
+            z = c->xyzgamma[z >> 4];
+
+            // convert from XYZlinear to sRGBlinear
+            r = c->xyz2rgb_matrix[0][0] * x +
+                c->xyz2rgb_matrix[0][1] * y +
+                c->xyz2rgb_matrix[0][2] * z >> 12;
+            g = c->xyz2rgb_matrix[1][0] * x +
+                c->xyz2rgb_matrix[1][1] * y +
+                c->xyz2rgb_matrix[1][2] * z >> 12;
+            b = c->xyz2rgb_matrix[2][0] * x +
+                c->xyz2rgb_matrix[1][2] * y +
+                c->xyz2rgb_matrix[2][2] * z >> 12;
+
+            // limit values to 12-bit depth
+            r = av_clip_c(r, 0, 4095);
+            g = av_clip_c(g, 0, 4095);
+            b = av_clip_c(b, 0, 4095);
+
+            // convert from sRGBlinear to RGB and scale from 12bit to 16bit
+            if (desc->flags & PIX_FMT_BE) {
+                AV_WB16(dst + xp + 0, c->rgbgamma[r] << 4);
+                AV_WB16(dst + xp + 1, c->rgbgamma[g] << 4);
+                AV_WB16(dst + xp + 2, c->rgbgamma[b] << 4);
+            } else {
+                AV_WL16(dst + xp + 0, c->rgbgamma[r] << 4);
+                AV_WL16(dst + xp + 1, c->rgbgamma[g] << 4);
+                AV_WL16(dst + xp + 2, c->rgbgamma[b] << 4);
+            }
+        }
+        src += stride;
+        dst += stride;
+    }
+}
+
 /**
  * swscale wrapper, so we don't need to export the SwsContext.
  * Assumes planar YUV to be in YUV order instead of YVU.
@@ -1132,9 +1188,10 @@ int attribute_align_arg sws_scale(struct SwsContext *c,
                                   int srcSliceH, uint8_t *const dst[],
                                   const int dstStride[])
 {
-    int i;
+    int i, ret;
     const uint8_t *src2[4] = { srcSlice[0], srcSlice[1], srcSlice[2], 
srcSlice[3] };
     uint8_t *dst2[4] = { dst[0], dst[1], dst[2], dst[3] };
+    uint8_t *tmp = NULL;
 
     // do not mess up sliceDir if we have a "trailing" 0-size slice
     if (srcSliceH == 0)
@@ -1220,6 +1277,18 @@ int attribute_align_arg sws_scale(struct SwsContext *c,
         }
     }
 
+    if (c->src_xyz && !(c->dst_xyz && c->srcW == c->dstW && c->srcH == 
c->dstH)) {
+        uint8_t *base;
+        tmp = av_malloc(FFABS(srcStride[0]) * srcSliceH + 32);
+        if (!tmp)
+            return 0;
+
+        base = srcStride[0] < 0 ? tmp - srcStride[0] * (srcSliceH - 1) : tmp;
+
+        xyz12_to_rgb48(c, base, src2[0], srcStride[0]/2, srcSliceH);
+        src2[0] = base;
+    }
+
     // copy strides, so they can safely be modified
     if (c->sliceDir == 1) {
         // slices go from top to bottom
@@ -1235,8 +1304,8 @@ int attribute_align_arg sws_scale(struct SwsContext *c,
         if (srcSliceY + srcSliceH == c->srcH)
             c->sliceDir = 0;
 
-        return c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2,
-                          dstStride2);
+        ret = c->swScale(c, src2, srcStride2, srcSliceY, srcSliceH, dst2,
+                         dstStride2);
     } else {
         // slices go from bottom to top => we flip the image internally
         int srcStride2[4] = { -srcStride[0], -srcStride[1], -srcStride[2],
@@ -1261,9 +1330,12 @@ int attribute_align_arg sws_scale(struct SwsContext *c,
         if (!srcSliceY)
             c->sliceDir = 0;
 
-        return c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH,
-                          srcSliceH, dst2, dstStride2);
+        ret = c->swScale(c, src2, srcStride2, c->srcH-srcSliceY-srcSliceH,
+                         srcSliceH, dst2, dstStride2);
     }
+
+    av_freep(&tmp);
+    return ret;
 }
 
 /* Convert the palette to the same packed 32-bit format as the palette */
diff --git a/libswscale/utils.c b/libswscale/utils.c
index 6bbdb64..8b9adbd 100644
--- a/libswscale/utils.c
+++ b/libswscale/utils.c
@@ -170,6 +170,8 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = {
     [AV_PIX_FMT_GBRP10BE]    = { 1, 1 },
     [AV_PIX_FMT_GBRP16LE]    = { 1, 0 },
     [AV_PIX_FMT_GBRP16BE]    = { 1, 0 },
+    [AV_PIX_FMT_XYZ12LE]     = { 1, 0 },
+    [AV_PIX_FMT_XYZ12BE]     = { 1, 0 },
 };
 
 int sws_isSupportedInput(enum AVPixelFormat pix_fmt)
@@ -772,6 +774,26 @@ static void getSubSampleFactors(int *h, int *v, enum 
AVPixelFormat format)
     *v = desc->log2_chroma_h;
 }
 
+
+static void fill_xyztables(struct SwsContext *c)
+{
+    int i;
+    double xyzgamma = XYZ_GAMMA;
+    double rgbgamma = 1.0 / RGB_GAMMA;
+    static const int16_t xyz2rgb_matrix[3][4] = {
+        { 13270, -6295, -2041 },
+        { -3969,  7682,   170 },
+        {   228,  -835,  4329 } };
+
+    /* set gamma vectors */
+    for (i = 0; i < 4096; i++) {
+        c->xyzgamma[i] = lrint(pow(i / 4095.0, xyzgamma) * 4095.0);
+        c->rgbgamma[i] = lrint(pow(i / 4095.0, rgbgamma) * 4095.0);
+    }
+    memcpy(c->xyz2rgb_matrix, xyz2rgb_matrix, sizeof(c->xyz2rgb_matrix));
+}
+
+
 int sws_setColorspaceDetails(struct SwsContext *c, const int inv_table[4],
                              int srcRange, const int table[4], int dstRange,
                              int brightness, int contrast, int saturation)
@@ -786,6 +808,9 @@ int sws_setColorspaceDetails(struct SwsContext *c, const 
int inv_table[4],
     c->saturation = saturation;
     c->srcRange   = srcRange;
     c->dstRange   = dstRange;
+
+    fill_xyztables(c);
+
     if (isYUV(c->dstFormat) || isGray(c->dstFormat))
         return -1;
 
@@ -852,6 +877,16 @@ SwsContext *sws_alloc_context(void)
     return c;
 }
 
+
+static int handle_xyz(enum AVPixelFormat *format)
+{
+    switch (*format) {
+    case AV_PIX_FMT_XYZ12BE : *format = AV_PIX_FMT_RGB48BE; return 1;
+    case AV_PIX_FMT_XYZ12LE : *format = AV_PIX_FMT_RGB48LE; return 1;
+    default:                                                return 0;
+    }
+}
+
 av_cold int sws_init_context(SwsContext *c, SwsFilter *srcFilter,
                              SwsFilter *dstFilter)
 {
@@ -879,6 +914,9 @@ av_cold int sws_init_context(SwsContext *c, SwsFilter 
*srcFilter,
 
     unscaled = (srcW == dstW && srcH == dstH);
 
+    handle_xyz(&srcFormat);
+    handle_xyz(&dstFormat);
+
     if (!sws_isSupportedInput(srcFormat)) {
         av_log(c, AV_LOG_ERROR, "%s is not supported as input pixel format\n",
                sws_format_name(srcFormat));
@@ -1310,6 +1348,8 @@ SwsContext *sws_getContext(int srcW, int srcH, enum 
AVPixelFormat srcFormat,
     c->dstH      = dstH;
     c->srcRange  = handle_jpeg(&srcFormat);
     c->dstRange  = handle_jpeg(&dstFormat);
+    c->src_xyz   = handle_xyz(&srcFormat);
+    c->dst_xyz   = handle_xyz(&dstFormat);
     c->srcFormat = srcFormat;
     c->dstFormat = dstFormat;
 
@@ -1737,10 +1777,12 @@ struct SwsContext *sws_getCachedContext(struct 
SwsContext *context, int srcW,
         context->srcW      = srcW;
         context->srcH      = srcH;
         context->srcRange  = handle_jpeg(&srcFormat);
+        context->src_xyz   = handle_xyz(&srcFormat);
         context->srcFormat = srcFormat;
         context->dstW      = dstW;
         context->dstH      = dstH;
         context->dstRange  = handle_jpeg(&dstFormat);
+        context->dst_xyz   = handle_xyz(&dstFormat);
         context->dstFormat = dstFormat;
         context->flags     = flags;
         context->param[0]  = param[0];
-- 
1.7.10.4

_______________________________________________
libav-devel mailing list
[email protected]
https://lists.libav.org/mailman/listinfo/libav-devel

Reply via email to