libswscale: bayer to rgb24 & yv12 colorspace converters
authorPeter Ross <pross@xvid.org>
Sun, 23 Feb 2014 01:18:57 +0000 (12:18 +1100)
committerMichael Niedermayer <michaelni@gmx.at>
Sun, 23 Feb 2014 01:38:22 +0000 (02:38 +0100)
Signed-off-by: Michael Niedermayer <michaelni@gmx.at>
libswscale/bayer_template.c [new file with mode: 0644]
libswscale/swscale_internal.h
libswscale/swscale_unscaled.c
libswscale/utils.c

diff --git a/libswscale/bayer_template.c b/libswscale/bayer_template.c
new file mode 100644 (file)
index 0000000..67ab2ae
--- /dev/null
@@ -0,0 +1,236 @@
+/*
+ * Bayer-to-RGB/YV12 template
+ * Copyright (c) 2011-2014 Peter Ross <pross@xvid.org>
+ *
+ * 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
+ */
+
+#if defined(BAYER_BGGR) || defined(BAYER_GBRG)
+#define BAYER_R       0
+#define BAYER_G       1
+#define BAYER_B       2
+#endif
+#if defined(BAYER_RGGB) || defined(BAYER_GRBG)
+#define BAYER_R       2
+#define BAYER_G       1
+#define BAYER_B       0
+#endif
+
+#if defined(BAYER_8)
+#define BAYER_READ(x) (x)
+#define BAYER_SIZEOF  1
+#define BAYER_SHIFT   0
+#endif
+#if defined(BAYER_16LE)
+#define BAYER_READ(x) AV_RL16(&x)
+#define BAYER_SIZEOF  2
+#define BAYER_SHIFT   8
+#endif
+#if defined(BAYER_16BE)
+#define BAYER_READ(x) AV_RB16(&x)
+#define BAYER_SIZEOF  2
+#define BAYER_SHIFT   8
+#endif
+
+#define S(y, x) BAYER_READ(src[(y)*src_stride + BAYER_SIZEOF*(x)])
+#define T(y, x) (unsigned int)S(y, x)
+#define R(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_R]
+#define G(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_G]
+#define B(y, x) dst[(y)*dst_stride + (x)*3 + BAYER_B]
+
+#if defined(BAYER_BGGR) || defined(BAYER_RGGB)
+#define BAYER_TO_RGB24_COPY \
+    R(0, 0) = \
+    R(0, 1) = \
+    R(1, 1) = \
+    R(1, 0) = S(1, 1) >> BAYER_SHIFT; \
+    \
+    G(0, 1) = S(0, 1) >> BAYER_SHIFT; \
+    G(0, 0) = \
+    G(1, 1) = (T(0, 1) + T(1, 0)) >> (1 + BAYER_SHIFT); \
+    G(1, 0) = S(1, 0) >> BAYER_SHIFT; \
+    \
+    B(1, 1) = \
+    B(0, 0) = \
+    B(0, 1) = \
+    B(1, 0) = S(0, 0) >> BAYER_SHIFT;
+#define BAYER_TO_RGB24_INTERPOLATE \
+    R(0, 0) = (T(-1, -1) + T(-1,  1) + T(1, -1) + T(1, 1)) >> (2 + BAYER_SHIFT); \
+    G(0, 0) = (T(-1,  0) + T( 0, -1) + T(0,  1) + T(1, 0)) >> (2 + BAYER_SHIFT); \
+    B(0, 0) =  S(0, 0) >> BAYER_SHIFT; \
+    \
+    R(0, 1) = (T(-1, 1) + T(1, 1)) >> (1 + BAYER_SHIFT); \
+    G(0, 1) =  S(0,  1) >> BAYER_SHIFT; \
+    B(0, 1) = (T(0,  0) + T(0, 2)) >> (1 + BAYER_SHIFT); \
+    \
+    R(1, 0) = (T(1, -1) + T(1, 1)) >> (1 + BAYER_SHIFT); \
+    G(1, 0) =  S(1,  0) >> BAYER_SHIFT; \
+    B(1, 0) = (T(0,  0) + T(2, 0)) >> (1 + BAYER_SHIFT); \
+    \
+    R(1, 1) =  S(1, 1) >> BAYER_SHIFT; \
+    G(1, 1) = (T(0, 1) + T(1, 0) + T(1, 2) + T(2, 1)) >> (2 + BAYER_SHIFT); \
+    B(1, 1) = (T(0, 0) + T(0, 2) + T(2, 0) + T(2, 2)) >> (2 + BAYER_SHIFT);
+#else
+#define BAYER_TO_RGB24_COPY \
+    R(0, 0) = \
+    R(0, 1) = \
+    R(1, 1) = \
+    R(1, 0) = S(1, 0) >> BAYER_SHIFT; \
+    \
+    G(0, 0) = S(0, 0) >> BAYER_SHIFT; \
+    G(1, 1) = S(1, 1) >> BAYER_SHIFT; \
+    G(0, 1) = \
+    G(1, 0) = (T(0, 0) + T(1, 1)) >> (1 + BAYER_SHIFT); \
+    \
+    B(1, 1) = \
+    B(0, 0) = \
+    B(0, 1) = \
+    B(1, 0) = S(0, 1) >> BAYER_SHIFT;
+#define BAYER_TO_RGB24_INTERPOLATE \
+    R(0, 0) = (T(-1, 0) + T(1, 0)) >> (1 + BAYER_SHIFT); \
+    G(0, 0) =  S(0, 0) >> BAYER_SHIFT; \
+    B(0, 0) = (T(0, -1) + T(0, 1)) >> (1 + BAYER_SHIFT); \
+    \
+    R(0, 1) = (T(-1, 0) + T(-1, 2) + T(1, 0) + T(1, 2)) >> (2 + BAYER_SHIFT); \
+    G(0, 1) = (T(-1, 1) + T(0,  0) + T(0, 2) + T(1, 1)) >> (2 + BAYER_SHIFT); \
+    B(0, 1) =  S(0, 1) >> BAYER_SHIFT; \
+    \
+    R(1, 0) =  S(1, 0) >> BAYER_SHIFT; \
+    G(1, 0) = (T(0, 0)  + T(1, -1) + T(1,  1) + T(2, 0)) >> (2 + BAYER_SHIFT); \
+    B(1, 0) = (T(0, -1) + T(0,  1) + T(2, -1) + T(2, 1)) >> (2 + BAYER_SHIFT); \
+    \
+    R(1, 1) = (T(1, 0) + T(1, 2)) >> (1 + BAYER_SHIFT); \
+    G(1, 1) =  S(1, 1) >> BAYER_SHIFT; \
+    B(1, 1) = (T(0, 1) + T(2, 1)) >> (1 + BAYER_SHIFT);
+#endif
+
+/**
+ * invoke ff_rgb24toyv12 for 2x2 pixels
+ */
+#define rgb24toyv12_2x2(src, dstY, dstU, dstV, luma_stride, src_stride, rgb2yuv) \
+    ff_rgb24toyv12(src, dstY, dstV, dstU, 2, 2, luma_stride, 0, src_stride, rgb2yuv)
+
+static void BAYER_RENAME(rgb24_copy)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width)
+{
+    int i;
+    for (i = 0 ; i < width; i+= 2) {
+        BAYER_TO_RGB24_COPY
+        src += 2 * BAYER_SIZEOF;
+        dst += 6;
+    }
+}
+
+static void BAYER_RENAME(rgb24_interpolate)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width)
+{
+    int i;
+
+    BAYER_TO_RGB24_COPY
+    src += 2 * BAYER_SIZEOF;
+    dst += 6;
+
+    for (i = 2 ; i < width - 2; i+= 2) {
+        BAYER_TO_RGB24_INTERPOLATE
+        src += 2 * BAYER_SIZEOF;
+        dst += 6;
+    }
+
+    if (width > 2) {
+        BAYER_TO_RGB24_COPY
+    }
+}
+
+static void BAYER_RENAME(yv12_copy)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, int32_t *rgb2yuv)
+{
+    uint8_t dst[12];
+    const int dst_stride = 6;
+    int i;
+    for (i = 0 ; i < width; i+= 2) {
+        BAYER_TO_RGB24_COPY
+        rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv);
+        src  += 2 * BAYER_SIZEOF;
+        dstY += 2;
+        dstU++;
+        dstV++;
+    }
+}
+
+static void BAYER_RENAME(yv12_interpolate)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, int32_t *rgb2yuv)
+{
+    uint8_t dst[12];
+    const int dst_stride = 6;
+    int i;
+
+    BAYER_TO_RGB24_COPY
+    rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv);
+    src  += 2 * BAYER_SIZEOF;
+    dstY += 2;
+    dstU++;
+    dstV++;
+
+    for (i = 2 ; i < width - 2; i+= 2) {
+        BAYER_TO_RGB24_INTERPOLATE
+        rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv);
+        src  += 2 * BAYER_SIZEOF;
+        dstY += 2;
+        dstU++;
+        dstV++;
+    }
+
+    if (width > 2) {
+        BAYER_TO_RGB24_COPY
+        rgb24toyv12_2x2(dst, dstY, dstU, dstV, luma_stride, dst_stride, rgb2yuv);
+    }
+}
+
+#undef S
+#undef T
+#undef R
+#undef G
+#undef B
+#undef BAYER_TO_RGB24_COPY
+#undef BAYER_TO_RGB24_INTERPOLATE
+
+#undef BAYER_RENAME
+
+#undef BAYER_R
+#undef BAYER_G
+#undef BAYER_B
+#undef BAYER_READ
+#undef BAYER_SIZEOF
+#undef BAYER_SHIFT
+
+#if defined(BAYER_BGGR)
+#undef BAYER_BGGR
+#endif
+#if defined(BAYER_RGGB)
+#undef BAYER_RGGB
+#endif
+#if defined(BAYER_GBRG)
+#undef BAYER_GBRG
+#endif
+#if defined(BAYER_GRBG)
+#undef BAYER_GRBG
+#endif
+#if defined(BAYER_8)
+#undef BAYER_8
+#endif
+#if defined(BAYER_16LE)
+#undef BAYER_16LE
+#endif
+#if defined(BAYER_16BE)
+#undef BAYER_16BE
+#endif
index 443615d..c2c23a0 100644 (file)
@@ -749,8 +749,24 @@ static av_always_inline int isRGB(enum AVPixelFormat pix_fmt)
         || (x) == AV_PIX_FMT_BGR24       \
     )
 
+#define isBayer(x) ( \
+           (x)==AV_PIX_FMT_BAYER_BGGR8    \
+        || (x)==AV_PIX_FMT_BAYER_BGGR16LE \
+        || (x)==AV_PIX_FMT_BAYER_BGGR16BE \
+        || (x)==AV_PIX_FMT_BAYER_RGGB8    \
+        || (x)==AV_PIX_FMT_BAYER_RGGB16LE \
+        || (x)==AV_PIX_FMT_BAYER_RGGB16BE \
+        || (x)==AV_PIX_FMT_BAYER_GBRG8    \
+        || (x)==AV_PIX_FMT_BAYER_GBRG16LE \
+        || (x)==AV_PIX_FMT_BAYER_GBRG16BE \
+        || (x)==AV_PIX_FMT_BAYER_GRBG8    \
+        || (x)==AV_PIX_FMT_BAYER_GRBG16LE \
+        || (x)==AV_PIX_FMT_BAYER_GRBG16BE \
+    )
+
 #define isAnyRGB(x) \
     (           \
+          isBayer(x)          ||    \
           isRGBinInt(x)       ||    \
           isBGRinInt(x)       ||    \
           isRGB(x)      \
index 6bcfa3e..16d2de2 100644 (file)
@@ -968,6 +968,160 @@ static int rgbToPlanarRgbWrapper(SwsContext *c, const uint8_t *src[],
     return srcSliceH;
 }
 
+#define BAYER_GBRG
+#define BAYER_8
+#define BAYER_RENAME(x) bayer_gbrg8_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GBRG
+#define BAYER_16LE
+#define BAYER_RENAME(x) bayer_gbrg16le_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GBRG
+#define BAYER_16BE
+#define BAYER_RENAME(x) bayer_gbrg16be_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GRBG
+#define BAYER_8
+#define BAYER_RENAME(x) bayer_grbg8_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GRBG
+#define BAYER_16LE
+#define BAYER_RENAME(x) bayer_grbg16le_to_##x
+#include "bayer_template.c"
+
+#define BAYER_GRBG
+#define BAYER_16BE
+#define BAYER_RENAME(x) bayer_grbg16be_to_##x
+#include "bayer_template.c"
+
+#define BAYER_BGGR
+#define BAYER_8
+#define BAYER_RENAME(x) bayer_bggr8_to_##x
+#include "bayer_template.c"
+
+#define BAYER_BGGR
+#define BAYER_16LE
+#define BAYER_RENAME(x) bayer_bggr16le_to_##x
+#include "bayer_template.c"
+
+#define BAYER_BGGR
+#define BAYER_16BE
+#define BAYER_RENAME(x) bayer_bggr16be_to_##x
+#include "bayer_template.c"
+
+#define BAYER_RGGB
+#define BAYER_8
+#define BAYER_RENAME(x) bayer_rggb8_to_##x
+#include "bayer_template.c"
+
+#define BAYER_RGGB
+#define BAYER_16LE
+#define BAYER_RENAME(x) bayer_rggb16le_to_##x
+#include "bayer_template.c"
+
+#define BAYER_RGGB
+#define BAYER_16BE
+#define BAYER_RENAME(x) bayer_rggb16be_to_##x
+#include "bayer_template.c"
+
+static int bayer_to_rgb24_wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
+                                  int srcSliceH, uint8_t* dst[], int dstStride[])
+{
+    uint8_t *dstPtr= dst[0];
+    const uint8_t *srcPtr= src[0];
+    int i;
+    void (*copy)       (const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width);
+    void (*interpolate)(const uint8_t *src, int src_stride, uint8_t *dst, int dst_stride, int width);
+
+    switch(c->srcFormat) {
+#define CASE(pixfmt, prefix) \
+    case pixfmt: copy        = bayer_##prefix##_to_rgb24_copy; \
+                 interpolate = bayer_##prefix##_to_rgb24_interpolate; \
+                 break;
+    CASE(AV_PIX_FMT_BAYER_BGGR8,    bggr8)
+    CASE(AV_PIX_FMT_BAYER_BGGR16LE, bggr16le)
+    CASE(AV_PIX_FMT_BAYER_BGGR16BE, bggr16be)
+    CASE(AV_PIX_FMT_BAYER_RGGB8,    rggb8)
+    CASE(AV_PIX_FMT_BAYER_RGGB16LE, rggb16le)
+    CASE(AV_PIX_FMT_BAYER_RGGB16BE, rggb16be)
+    CASE(AV_PIX_FMT_BAYER_GBRG8,    gbrg8)
+    CASE(AV_PIX_FMT_BAYER_GBRG16LE, gbrg16le)
+    CASE(AV_PIX_FMT_BAYER_GBRG16BE, gbrg16be)
+    CASE(AV_PIX_FMT_BAYER_GRBG8,    grbg8)
+    CASE(AV_PIX_FMT_BAYER_GRBG16LE, grbg16le)
+    CASE(AV_PIX_FMT_BAYER_GRBG16BE, grbg16be)
+#undef CASE
+    default: return 0;
+    }
+
+    copy(srcPtr, srcStride[0], dstPtr, dstStride[0], c->srcW);
+    srcPtr += 2 * srcStride[0];
+    dstPtr += 2 * dstStride[0];
+
+    for (i = 2; i < srcSliceH - 2; i += 2) {
+        interpolate(srcPtr, srcStride[0], dstPtr, dstStride[0], c->srcW);
+        srcPtr += 2 * srcStride[0];
+        dstPtr += 2 * dstStride[0];
+    }
+
+    copy(srcPtr, srcStride[0], dstPtr, dstStride[0], c->srcW);
+    return srcSliceH;
+}
+
+static int bayer_to_yv12_wrapper(SwsContext *c, const uint8_t* src[], int srcStride[], int srcSliceY,
+                                 int srcSliceH, uint8_t* dst[], int dstStride[])
+{
+    const uint8_t *srcPtr= src[0];
+    uint8_t *dstY= dst[0];
+    uint8_t *dstU= dst[1];
+    uint8_t *dstV= dst[2];
+    int i;
+    void (*copy)       (const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, int32_t *rgb2yuv);
+    void (*interpolate)(const uint8_t *src, int src_stride, uint8_t *dstY, uint8_t *dstU, uint8_t *dstV, int luma_stride, int width, int32_t *rgb2yuv);
+
+    switch(c->srcFormat) {
+#define CASE(pixfmt, prefix) \
+    case pixfmt: copy        = bayer_##prefix##_to_yv12_copy; \
+                 interpolate = bayer_##prefix##_to_yv12_interpolate; \
+                 break;
+    CASE(AV_PIX_FMT_BAYER_BGGR8,    bggr8)
+    CASE(AV_PIX_FMT_BAYER_BGGR16LE, bggr16le)
+    CASE(AV_PIX_FMT_BAYER_BGGR16BE, bggr16be)
+    CASE(AV_PIX_FMT_BAYER_RGGB8,    rggb8)
+    CASE(AV_PIX_FMT_BAYER_RGGB16LE, rggb16le)
+    CASE(AV_PIX_FMT_BAYER_RGGB16BE, rggb16be)
+    CASE(AV_PIX_FMT_BAYER_GBRG8,    gbrg8)
+    CASE(AV_PIX_FMT_BAYER_GBRG16LE, gbrg16le)
+    CASE(AV_PIX_FMT_BAYER_GBRG16BE, gbrg16be)
+    CASE(AV_PIX_FMT_BAYER_GRBG8,    grbg8)
+    CASE(AV_PIX_FMT_BAYER_GRBG16LE, grbg16le)
+    CASE(AV_PIX_FMT_BAYER_GRBG16BE, grbg16be)
+#undef CASE
+    default: return 0;
+    }
+
+    copy(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->srcW, c->input_rgb2yuv_table);
+    srcPtr += 2 * srcStride[0];
+    dstY   += 2 * dstStride[0];
+    dstU   +=     dstStride[1];
+    dstV   +=     dstStride[1];
+
+    for (i = 2; i < srcSliceH - 2; i += 2) {
+        interpolate(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->srcW, c->input_rgb2yuv_table);
+        srcPtr += 2 * srcStride[0];
+        dstY   += 2 * dstStride[0];
+        dstU   +=     dstStride[1];
+        dstV   +=     dstStride[1];
+    }
+
+    copy(srcPtr, srcStride[0], dstY, dstU, dstV, dstStride[0], c->srcW, c->input_rgb2yuv_table);
+    return srcSliceH;
+}
+
 #define isRGBA32(x) (            \
            (x) == AV_PIX_FMT_ARGB   \
         || (x) == AV_PIX_FMT_RGBA   \
@@ -1491,8 +1645,23 @@ void ff_get_unscaled_swscale(SwsContext *c)
         isPackedRGB(srcFormat) && dstFormat == AV_PIX_FMT_GBRP)
         c->swscale = rgbToPlanarRgbWrapper;
 
+    if (isBayer(srcFormat)) {
+        if (dstFormat == AV_PIX_FMT_RGB24)
+            c->swscale = bayer_to_rgb24_wrapper;
+        else if (dstFormat == AV_PIX_FMT_YUV420P)
+            c->swscale = bayer_to_yv12_wrapper;
+        else if (!isBayer(dstFormat)) {
+            av_log(c, AV_LOG_ERROR, "unsupported bayer conversion\n");
+            av_assert0(0);
+        }
+    }
+
     /* bswap 16 bits per pixel/component packed formats */
-    if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR444) ||
+    if (IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_BGGR16) ||
+        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_RGGB16) ||
+        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_GBRG16) ||
+        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BAYER_GRBG16) ||
+        IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR444) ||
         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR48)  ||
         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGRA64) ||
         IS_DIFFERENT_ENDIANESS(srcFormat, dstFormat, AV_PIX_FMT_BGR555) ||
index b8b95a9..4e73853 100644 (file)
@@ -207,6 +207,18 @@ static const FormatEntry format_entries[AV_PIX_FMT_NB] = {
     [AV_PIX_FMT_GBRAP]       = { 1, 1 },
     [AV_PIX_FMT_GBRAP16LE]   = { 1, 0 },
     [AV_PIX_FMT_GBRAP16BE]   = { 1, 0 },
+    [AV_PIX_FMT_BAYER_BGGR8] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_RGGB8] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_GBRG8] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_GRBG8] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_BGGR16LE] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_BGGR16BE] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_RGGB16LE] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_RGGB16BE] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_GBRG16LE] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_GBRG16BE] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_GRBG16LE] = { 1, 0 },
+    [AV_PIX_FMT_BAYER_GRBG16BE] = { 1, 0 },
 };
 
 int sws_isSupportedInput(enum AVPixelFormat pix_fmt)