lavc/tiff: Allow decoding of cmyka (five components).
authorCarl Eugen Hoyos <ceffmpeg@gmail.com>
Wed, 20 Mar 2019 16:50:25 +0000 (17:50 +0100)
committerCarl Eugen Hoyos <ceffmpeg@gmail.com>
Wed, 20 Mar 2019 16:50:25 +0000 (17:50 +0100)
Fixes ticket #7675.

libavcodec/tiff.c

index 828ed9e..29a80a6 100644 (file)
@@ -827,6 +827,10 @@ static int init_image(TiffContext *s, ThreadFrame *frame)
     case 324:
         s->avctx->pix_fmt = s->photometric == TIFF_PHOTOMETRIC_SEPARATED ? AV_PIX_FMT_RGB0 : AV_PIX_FMT_RGBA;
         break;
+    case 405:
+        if (s->photometric == TIFF_PHOTOMETRIC_SEPARATED)
+            s->avctx->pix_fmt = AV_PIX_FMT_RGBA;
+        break;
     case 483:
         s->avctx->pix_fmt = s->le ? AV_PIX_FMT_RGB48LE  : AV_PIX_FMT_RGB48BE;
         break;
@@ -944,7 +948,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
         s->height = value;
         break;
     case TIFF_BPP:
-        if (count > 4U) {
+        if (count > 5U) {
             av_log(s->avctx, AV_LOG_ERROR,
                    "This format is not supported (bpp=%d, %d components)\n",
                    value, count);
@@ -975,7 +979,7 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
                    "Samples per pixel requires a single value, many provided\n");
             return AVERROR_INVALIDDATA;
         }
-        if (value > 4U) {
+        if (value > 5U) {
             av_log(s->avctx, AV_LOG_ERROR,
                    "Samples per pixel %d is too large\n", value);
             return AVERROR_INVALIDDATA;
@@ -1449,10 +1453,19 @@ again:
 
     planes = s->planar ? s->bppcount : 1;
     for (plane = 0; plane < planes; plane++) {
+        uint8_t *five_planes = NULL;
         int remaining = avpkt->size;
         int decoded_height;
         stride = p->linesize[plane];
         dst = p->data[plane];
+        if (s->photometric == TIFF_PHOTOMETRIC_SEPARATED &&
+            s->avctx->pix_fmt == AV_PIX_FMT_RGBA) {
+            stride = stride * 5 / 4;
+            five_planes =
+            dst = av_malloc(stride * s->height);
+            if (!dst)
+                return AVERROR(ENOMEM);
+        }
         for (i = 0; i < s->height; i += s->rps) {
             if (i)
                 dst += s->rps * stride;
@@ -1468,13 +1481,16 @@ again:
 
             if (soff > avpkt->size || ssize > avpkt->size - soff || ssize > remaining) {
                 av_log(avctx, AV_LOG_ERROR, "Invalid strip size/offset\n");
+                av_freep(&five_planes);
                 return AVERROR_INVALIDDATA;
             }
             remaining -= ssize;
             if ((ret = tiff_unpack_strip(s, p, dst, stride, avpkt->data + soff, ssize, i,
                                          FFMIN(s->rps, s->height - i))) < 0) {
-                if (avctx->err_recognition & AV_EF_EXPLODE)
+                if (avctx->err_recognition & AV_EF_EXPLODE) {
+                    av_freep(&five_planes);
                     return ret;
+                }
                 break;
             }
         }
@@ -1485,7 +1501,7 @@ again:
                 av_log(s->avctx, AV_LOG_ERROR, "predictor == 2 with YUV is unsupported");
                 return AVERROR_PATCHWELCOME;
             }
-            dst   = p->data[plane];
+            dst   = five_planes ? five_planes : p->data[plane];
             soff  = s->bpp >> 3;
             if (s->planar)
                 soff  = FFMAX(soff / s->bppcount, 1);
@@ -1532,21 +1548,25 @@ again:
         }
 
         if (s->photometric == TIFF_PHOTOMETRIC_SEPARATED &&
-            s->avctx->pix_fmt == AV_PIX_FMT_RGB0) {
+            (s->avctx->pix_fmt == AV_PIX_FMT_RGB0 || s->avctx->pix_fmt == AV_PIX_FMT_RGBA)) {
+            int x = s->avctx->pix_fmt == AV_PIX_FMT_RGB0 ? 4 : 5;
+            uint8_t *src = five_planes ? five_planes : p->data[plane];
             dst = p->data[plane];
             for (i = 0; i < s->height; i++) {
                 for (j = 0; j < s->width; j++) {
-                    int k =  255 - dst[4 * j + 3];
-                    int r = (255 - dst[4 * j    ]) * k;
-                    int g = (255 - dst[4 * j + 1]) * k;
-                    int b = (255 - dst[4 * j + 2]) * k;
+                    int k =  255 - src[x * j + 3];
+                    int r = (255 - src[x * j    ]) * k;
+                    int g = (255 - src[x * j + 1]) * k;
+                    int b = (255 - src[x * j + 2]) * k;
                     dst[4 * j    ] = r * 257 >> 16;
                     dst[4 * j + 1] = g * 257 >> 16;
                     dst[4 * j + 2] = b * 257 >> 16;
-                    dst[4 * j + 3] = 255;
+                    dst[4 * j + 3] = s->avctx->pix_fmt == AV_PIX_FMT_RGBA ? src[x * j + 4] : 255;
                 }
+                src += stride;
                 dst += p->linesize[plane];
             }
+            av_freep(&five_planes);
         } else if (s->photometric == TIFF_PHOTOMETRIC_SEPARATED &&
             s->avctx->pix_fmt == AV_PIX_FMT_RGBA64BE) {
             dst = p->data[plane];