swscale: add support for planar RGB input.
authorRonald S. Bultje <rsbultje@gmail.com>
Thu, 24 Nov 2011 18:40:05 +0000 (10:40 -0800)
committerRonald S. Bultje <rsbultje@gmail.com>
Thu, 24 Nov 2011 18:40:05 +0000 (10:40 -0800)
libswscale/swscale.c
libswscale/swscale_internal.h
libswscale/swscale_unscaled.c
libswscale/utils.c

index ac06731..98daf22 100644 (file)
@@ -1807,6 +1807,91 @@ static void rgb24ToUV_half_c(uint8_t *dstU, uint8_t *dstV, const uint8_t *src1,
     }
 }
 
     }
 }
 
+static void planar_rgb_to_y(uint8_t *dst, const uint8_t *src[4], int width)
+{
+    int i;
+    for (i = 0; i < width; i++) {
+        int g = src[0][i];
+        int b = src[1][i];
+        int r = src[2][i];
+
+        dst[i] = ((RY * r + GY * g + BY * b + (33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+    }
+}
+
+static void planar_rgb16le_to_y(uint8_t *_dst, const uint8_t *_src[4], int width)
+{
+    int i;
+    const uint16_t **src = (const uint16_t **) _src;
+    uint16_t *dst = (uint16_t *) _dst;
+    for (i = 0; i < width; i++) {
+        int g = AV_RL16(src[0] + i);
+        int b = AV_RL16(src[1] + i);
+        int r = AV_RL16(src[2] + i);
+
+        dst[i] = ((RY * r + GY * g + BY * b + (33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+    }
+}
+
+static void planar_rgb16be_to_y(uint8_t *_dst, const uint8_t *_src[4], int width)
+{
+    int i;
+    const uint16_t **src = (const uint16_t **) _src;
+    uint16_t *dst = (uint16_t *) _dst;
+    for (i = 0; i < width; i++) {
+        int g = AV_RB16(src[0] + i);
+        int b = AV_RB16(src[1] + i);
+        int r = AV_RB16(src[2] + i);
+
+        dst[i] = ((RY * r + GY * g + BY * b + (33 << (RGB2YUV_SHIFT - 1))) >> RGB2YUV_SHIFT);
+    }
+}
+
+static void planar_rgb_to_uv(uint8_t *dstU, uint8_t *dstV, const uint8_t *src[4], int width)
+{
+    int i;
+    for (i = 0; i < width; i++) {
+        int g = src[0][i];
+        int b = src[1][i];
+        int r = src[2][i];
+
+        dstU[i] = (RU * r + GU * g + BU * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
+        dstV[i] = (RV * r + GV * g + BV * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
+    }
+}
+
+static void planar_rgb16le_to_uv(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *_src[4], int width)
+{
+    int i;
+    const uint16_t **src = (const uint16_t **) _src;
+    uint16_t *dstU = (uint16_t *) _dstU;
+    uint16_t *dstV = (uint16_t *) _dstV;
+    for (i = 0; i < width; i++) {
+        int g = AV_RL16(src[0] + i);
+        int b = AV_RL16(src[1] + i);
+        int r = AV_RL16(src[2] + i);
+
+        dstU[i] = (RU * r + GU * g + BU * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
+        dstV[i] = (RV * r + GV * g + BV * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
+    }
+}
+
+static void planar_rgb16be_to_uv(uint8_t *_dstU, uint8_t *_dstV, const uint8_t *_src[4], int width)
+{
+    int i;
+    const uint16_t **src = (const uint16_t **) _src;
+    uint16_t *dstU = (uint16_t *) _dstU;
+    uint16_t *dstV = (uint16_t *) _dstV;
+    for (i = 0; i < width; i++) {
+        int g = AV_RB16(src[0] + i);
+        int b = AV_RB16(src[1] + i);
+        int r = AV_RB16(src[2] + i);
+
+        dstU[i] = (RU * r + GU * g + BU * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
+        dstV[i] = (RV * r + GV * g + BV * b + (257 << RGB2YUV_SHIFT)) >> (RGB2YUV_SHIFT + 1);
+    }
+}
+
 static void hScale16To19_c(SwsContext *c, int16_t *_dst, int dstW, const uint8_t *_src,
                            const int16_t *filter,
                            const int16_t *filterPos, int filterSize)
 static void hScale16To19_c(SwsContext *c, int16_t *_dst, int dstW, const uint8_t *_src,
                            const int16_t *filter,
                            const int16_t *filterPos, int filterSize)
@@ -1970,7 +2055,7 @@ static void hyscale_fast_c(SwsContext *c, int16_t *dst, int dstWidth,
 
 // *** horizontal scale Y line to temp buffer
 static av_always_inline void hyscale(SwsContext *c, int16_t *dst, int dstWidth,
 
 // *** horizontal scale Y line to temp buffer
 static av_always_inline void hyscale(SwsContext *c, int16_t *dst, int dstWidth,
-                                     const uint8_t *src, int srcW, int xInc,
+                                     const uint8_t *src_in[4], int srcW, int xInc,
                                      const int16_t *hLumFilter,
                                      const int16_t *hLumFilterPos, int hLumFilterSize,
                                      uint8_t *formatConvBuffer,
                                      const int16_t *hLumFilter,
                                      const int16_t *hLumFilterPos, int hLumFilterSize,
                                      uint8_t *formatConvBuffer,
@@ -1978,10 +2063,14 @@ static av_always_inline void hyscale(SwsContext *c, int16_t *dst, int dstWidth,
 {
     void (*toYV12)(uint8_t *, const uint8_t *, int, uint32_t *) = isAlpha ? c->alpToYV12 : c->lumToYV12;
     void (*convertRange)(int16_t *, int) = isAlpha ? NULL : c->lumConvertRange;
 {
     void (*toYV12)(uint8_t *, const uint8_t *, int, uint32_t *) = isAlpha ? c->alpToYV12 : c->lumToYV12;
     void (*convertRange)(int16_t *, int) = isAlpha ? NULL : c->lumConvertRange;
+    const uint8_t *src = src_in[isAlpha ? 3 : 0];
 
     if (toYV12) {
         toYV12(formatConvBuffer, src, srcW, pal);
         src= formatConvBuffer;
 
     if (toYV12) {
         toYV12(formatConvBuffer, src, srcW, pal);
         src= formatConvBuffer;
+    } else if (c->readLumPlanar && !isAlpha) {
+        c->readLumPlanar(formatConvBuffer, src_in, srcW);
+        src = formatConvBuffer;
     }
 
     if (!c->hyscale_fast) {
     }
 
     if (!c->hyscale_fast) {
@@ -2010,16 +2099,22 @@ static void hcscale_fast_c(SwsContext *c, int16_t *dst1, int16_t *dst2,
 }
 
 static av_always_inline void hcscale(SwsContext *c, int16_t *dst1, int16_t *dst2, int dstWidth,
 }
 
 static av_always_inline void hcscale(SwsContext *c, int16_t *dst1, int16_t *dst2, int dstWidth,
-                                     const uint8_t *src1, const uint8_t *src2,
+                                     const uint8_t *src_in[4],
                                      int srcW, int xInc, const int16_t *hChrFilter,
                                      const int16_t *hChrFilterPos, int hChrFilterSize,
                                      uint8_t *formatConvBuffer, uint32_t *pal)
 {
                                      int srcW, int xInc, const int16_t *hChrFilter,
                                      const int16_t *hChrFilterPos, int hChrFilterSize,
                                      uint8_t *formatConvBuffer, uint32_t *pal)
 {
+    const uint8_t *src1 = src_in[1], *src2 = src_in[2];
     if (c->chrToYV12) {
         uint8_t *buf2 = formatConvBuffer + FFALIGN(srcW * FFALIGN(c->srcBpc, 8) >> 3, 16);
         c->chrToYV12(formatConvBuffer, buf2, src1, src2, srcW, pal);
         src1= formatConvBuffer;
         src2= buf2;
     if (c->chrToYV12) {
         uint8_t *buf2 = formatConvBuffer + FFALIGN(srcW * FFALIGN(c->srcBpc, 8) >> 3, 16);
         c->chrToYV12(formatConvBuffer, buf2, src1, src2, srcW, pal);
         src1= formatConvBuffer;
         src2= buf2;
+    } else if (c->readChrPlanar) {
+        uint8_t *buf2 = formatConvBuffer + FFALIGN(srcW * FFALIGN(c->srcBpc, 8) >> 3, 16);
+        c->readChrPlanar(formatConvBuffer, buf2, src_in, srcW);
+        src1= formatConvBuffer;
+        src2= buf2;
     }
 
     if (!c->hcscale_fast) {
     }
 
     if (!c->hcscale_fast) {
@@ -2420,8 +2515,12 @@ static int swScale(SwsContext *c, const uint8_t* src[],
 
         //Do horizontal scaling
         while(lastInLumBuf < lastLumSrcY) {
 
         //Do horizontal scaling
         while(lastInLumBuf < lastLumSrcY) {
-            const uint8_t *src1= src[0]+(lastInLumBuf + 1 - srcSliceY)*srcStride[0];
-            const uint8_t *src2= src[3]+(lastInLumBuf + 1 - srcSliceY)*srcStride[3];
+            const uint8_t *src1[4] = {
+                src[0] + (lastInLumBuf + 1 - srcSliceY) * srcStride[0],
+                src[1] + (lastInLumBuf + 1 - srcSliceY) * srcStride[1],
+                src[2] + (lastInLumBuf + 1 - srcSliceY) * srcStride[2],
+                src[3] + (lastInLumBuf + 1 - srcSliceY) * srcStride[3],
+            };
             lumBufIndex++;
             assert(lumBufIndex < 2*vLumBufSize);
             assert(lastInLumBuf + 1 - srcSliceY < srcSliceH);
             lumBufIndex++;
             assert(lumBufIndex < 2*vLumBufSize);
             assert(lastInLumBuf + 1 - srcSliceY < srcSliceH);
@@ -2431,7 +2530,7 @@ static int swScale(SwsContext *c, const uint8_t* src[],
                     formatConvBuffer,
                     pal, 0);
             if (CONFIG_SWSCALE_ALPHA && alpPixBuf)
                     formatConvBuffer,
                     pal, 0);
             if (CONFIG_SWSCALE_ALPHA && alpPixBuf)
-                hyscale(c, alpPixBuf[ lumBufIndex ], dstW, src2, srcW,
+                hyscale(c, alpPixBuf[ lumBufIndex ], dstW, src1, srcW,
                         lumXInc, hLumFilter, hLumFilterPos, hLumFilterSize,
                         formatConvBuffer,
                         pal, 1);
                         lumXInc, hLumFilter, hLumFilterPos, hLumFilterSize,
                         formatConvBuffer,
                         pal, 1);
@@ -2440,8 +2539,12 @@ static int swScale(SwsContext *c, const uint8_t* src[],
                                lumBufIndex,    lastInLumBuf);
         }
         while(lastInChrBuf < lastChrSrcY) {
                                lumBufIndex,    lastInLumBuf);
         }
         while(lastInChrBuf < lastChrSrcY) {
-            const uint8_t *src1= src[1]+(lastInChrBuf + 1 - chrSrcSliceY)*srcStride[1];
-            const uint8_t *src2= src[2]+(lastInChrBuf + 1 - chrSrcSliceY)*srcStride[2];
+            const uint8_t *src1[4] = {
+                src[0] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[0],
+                src[1] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[1],
+                src[2] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[2],
+                src[3] + (lastInChrBuf + 1 - chrSrcSliceY) * srcStride[3],
+            };
             chrBufIndex++;
             assert(chrBufIndex < 2*vChrBufSize);
             assert(lastInChrBuf + 1 - chrSrcSliceY < (chrSrcSliceH));
             chrBufIndex++;
             assert(chrBufIndex < 2*vChrBufSize);
             assert(lastInChrBuf + 1 - chrSrcSliceY < (chrSrcSliceH));
@@ -2450,7 +2553,7 @@ static int swScale(SwsContext *c, const uint8_t* src[],
 
             if (c->needs_hcscale)
                 hcscale(c, chrUPixBuf[chrBufIndex], chrVPixBuf[chrBufIndex],
 
             if (c->needs_hcscale)
                 hcscale(c, chrUPixBuf[chrBufIndex], chrVPixBuf[chrBufIndex],
-                          chrDstW, src1, src2, chrSrcW, chrXInc,
+                          chrDstW, src1, chrSrcW, chrXInc,
                           hChrFilter, hChrFilterPos, hChrFilterSize,
                           formatConvBuffer, pal);
             lastInChrBuf++;
                           hChrFilter, hChrFilterPos, hChrFilterSize,
                           formatConvBuffer, pal);
             lastInChrBuf++;
@@ -2580,6 +2683,13 @@ static av_cold void sws_init_swScale_c(SwsContext *c)
         case PIX_FMT_PAL8     :
         case PIX_FMT_BGR4_BYTE:
         case PIX_FMT_RGB4_BYTE: c->chrToYV12 = palToUV_c; break;
         case PIX_FMT_PAL8     :
         case PIX_FMT_BGR4_BYTE:
         case PIX_FMT_RGB4_BYTE: c->chrToYV12 = palToUV_c; break;
+        case PIX_FMT_GBRP9LE:
+        case PIX_FMT_GBRP10LE:
+        case PIX_FMT_GBRP16LE:  c->readChrPlanar = planar_rgb16le_to_uv; break;
+        case PIX_FMT_GBRP9BE:
+        case PIX_FMT_GBRP10BE:
+        case PIX_FMT_GBRP16BE:  c->readChrPlanar = planar_rgb16be_to_uv; break;
+        case PIX_FMT_GBRP:      c->readChrPlanar = planar_rgb_to_uv; break;
 #if HAVE_BIGENDIAN
         case PIX_FMT_YUV444P9LE:
         case PIX_FMT_YUV422P9LE:
 #if HAVE_BIGENDIAN
         case PIX_FMT_YUV444P9LE:
         case PIX_FMT_YUV422P9LE:
@@ -2649,6 +2759,13 @@ static av_cold void sws_init_swScale_c(SwsContext *c)
     c->lumToYV12 = NULL;
     c->alpToYV12 = NULL;
     switch (srcFormat) {
     c->lumToYV12 = NULL;
     c->alpToYV12 = NULL;
     switch (srcFormat) {
+    case PIX_FMT_GBRP9LE:
+    case PIX_FMT_GBRP10LE:
+    case PIX_FMT_GBRP16LE: c->readLumPlanar = planar_rgb16le_to_y; break;
+    case PIX_FMT_GBRP9BE:
+    case PIX_FMT_GBRP10BE:
+    case PIX_FMT_GBRP16BE: c->readLumPlanar = planar_rgb16be_to_y; break;
+    case PIX_FMT_GBRP:     c->readLumPlanar = planar_rgb_to_y; break;
 #if HAVE_BIGENDIAN
     case PIX_FMT_YUV444P9LE:
     case PIX_FMT_YUV422P9LE:
 #if HAVE_BIGENDIAN
     case PIX_FMT_YUV444P9LE:
     case PIX_FMT_YUV422P9LE:
index 7048265..b20e0a3 100644 (file)
@@ -427,6 +427,16 @@ typedef struct SwsContext {
     void (*chrToYV12)(uint8_t *dstU, uint8_t *dstV,
                       const uint8_t *src1, const uint8_t *src2,
                       int width, uint32_t *pal); ///< Unscaled conversion of chroma planes to YV12 for horizontal scaler.
     void (*chrToYV12)(uint8_t *dstU, uint8_t *dstV,
                       const uint8_t *src1, const uint8_t *src2,
                       int width, uint32_t *pal); ///< Unscaled conversion of chroma planes to YV12 for horizontal scaler.
+
+    /**
+      * Functions to read planar input, such as planar RGB, and convert
+      * internally to Y/UV.
+      */
+    /** @{ */
+    void (*readLumPlanar)(uint8_t *dst, const uint8_t *src[4], int width);
+    void (*readChrPlanar)(uint8_t *dstU, uint8_t *dstV, const uint8_t *src[4], int width);
+    /** @} */
+
     /**
      * Scale one horizontal line of input data using a bilinear filter
      * to produce one line of output data. Compared to SwsContext->hScale(),
     /**
      * Scale one horizontal line of input data using a bilinear filter
      * to produce one line of output data. Compared to SwsContext->hScale(),
@@ -594,6 +604,10 @@ const char *sws_format_name(enum PixelFormat format);
     (av_pix_fmt_descriptors[x].nb_components >= 2 && \
      !(av_pix_fmt_descriptors[x].flags & PIX_FMT_PLANAR))
 
     (av_pix_fmt_descriptors[x].nb_components >= 2 && \
      !(av_pix_fmt_descriptors[x].flags & PIX_FMT_PLANAR))
 
+#define isPlanar(x) \
+    (av_pix_fmt_descriptors[x].nb_components >= 2 && \
+     (av_pix_fmt_descriptors[x].flags & PIX_FMT_PLANAR))
+
 #define usePal(x) ((av_pix_fmt_descriptors[x].flags & PIX_FMT_PAL) || (x) == PIX_FMT_Y400A)
 
 extern const uint64_t ff_dither4[2];
 #define usePal(x) ((av_pix_fmt_descriptors[x].flags & PIX_FMT_PAL) || (x) == PIX_FMT_Y400A)
 
 extern const uint64_t ff_dither4[2];
index c7e6a28..86bc5ac 100644 (file)
@@ -779,7 +779,7 @@ static void reset_ptr(const uint8_t* src[], int format)
 {
     if(!isALPHA(format))
         src[3]=NULL;
 {
     if(!isALPHA(format))
         src[3]=NULL;
-    if(!isPlanarYUV(format)) {
+    if (!isPlanar(format)) {
         src[3]=src[2]=NULL;
 
         if (!usePal(format))
         src[3]=src[2]=NULL;
 
         if (!usePal(format))
index 51bec62..7a96986 100644 (file)
@@ -137,6 +137,13 @@ const static FormatEntry format_entries[PIX_FMT_NB] = {
     [PIX_FMT_YUV444P9LE]  = { 1 , 1 },
     [PIX_FMT_YUV444P10BE] = { 1 , 1 },
     [PIX_FMT_YUV444P10LE] = { 1 , 1 },
     [PIX_FMT_YUV444P9LE]  = { 1 , 1 },
     [PIX_FMT_YUV444P10BE] = { 1 , 1 },
     [PIX_FMT_YUV444P10LE] = { 1 , 1 },
+    [PIX_FMT_GBRP]        = { 1 , 0 },
+    [PIX_FMT_GBRP9LE]     = { 1 , 0 },
+    [PIX_FMT_GBRP9BE]     = { 1 , 0 },
+    [PIX_FMT_GBRP10LE]    = { 1 , 0 },
+    [PIX_FMT_GBRP10BE]    = { 1 , 0 },
+    [PIX_FMT_GBRP16LE]    = { 1 , 0 },
+    [PIX_FMT_GBRP16BE]    = { 1 , 0 },
 };
 
 int sws_isSupportedInput(enum PixelFormat pix_fmt)
 };
 
 int sws_isSupportedInput(enum PixelFormat pix_fmt)