]> git.sesse.net Git - ffmpeg/blobdiff - libavcodec/tiff.c
Merge commit '345a96c327e8f2a8077189af9f5e8d2b3f4ad5fe'
[ffmpeg] / libavcodec / tiff.c
index e0629dbad888d6bdd94e48f3a27f5da77380c2b7..d864521b364568f08269f84ce9b665bc1af28063 100644 (file)
@@ -53,7 +53,7 @@ typedef struct TiffContext {
     int palette_is_set;
     int le;
     enum TiffCompr compr;
-    int invert;
+    enum TiffPhotometric photometric;
     int planar;
     int fax_opts;
     int predictor;
@@ -383,9 +383,10 @@ static int tiff_unpack_fax(TiffContext *s, uint8_t *dst, int stride,
 static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
                              const uint8_t *src, int size, int lines)
 {
+    PutByteContext pb;
     int c, line, pixels, code, ret;
     const uint8_t *ssrc = src;
-    int width           = ((s->width * s->bpp) + 7) >> 3;
+    int width = ((s->width * s->bpp) + 7) >> 3;
 
     if (s->planar)
         width /= s->bppcount;
@@ -416,21 +417,42 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
             av_log(s->avctx, AV_LOG_ERROR, "Error initializing LZW decoder\n");
             return ret;
         }
+        for (line = 0; line < lines; line++) {
+            pixels = ff_lzw_decode(s->lzw, dst, width);
+            if (pixels < width) {
+                av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n",
+                       pixels, width);
+                return AVERROR_INVALIDDATA;
+            }
+            if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
+                horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0);
+            dst += stride;
+        }
+        return 0;
     }
     if (s->compr == TIFF_CCITT_RLE ||
         s->compr == TIFF_G3        ||
         s->compr == TIFF_G4) {
         return tiff_unpack_fax(s, dst, stride, src, size, width, lines);
     }
+
+    bytestream2_init(&s->gb, src, size);
+    bytestream2_init_writer(&pb, dst, stride * lines);
+
     for (line = 0; line < lines; line++) {
         if (src - ssrc > size) {
             av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n");
             return AVERROR_INVALIDDATA;
         }
+
+        if (bytestream2_get_bytes_left(&s->gb) == 0 || bytestream2_get_eof(&pb))
+            break;
+        bytestream2_seek_p(&pb, stride * line, SEEK_SET);
         switch (s->compr) {
         case TIFF_RAW:
             if (ssrc + size - src < width)
                 return AVERROR_INVALIDDATA;
+
             if (!s->fill_order) {
                 horizontal_fill(s->bpp * (s->avctx->pix_fmt == AV_PIX_FMT_PAL8),
                                 dst, 1, src, 0, width, 0);
@@ -479,16 +501,6 @@ static int tiff_unpack_strip(TiffContext *s, uint8_t *dst, int stride,
                     dst[i] = ff_reverse[dst[i]];
             }
             break;
-        case TIFF_LZW:
-            pixels = ff_lzw_decode(s->lzw, dst, width);
-            if (pixels < width) {
-                av_log(s->avctx, AV_LOG_ERROR, "Decoded only %i bytes of %i\n",
-                       pixels, width);
-                return AVERROR_INVALIDDATA;
-            }
-            if (s->bpp < 8 && s->avctx->pix_fmt == AV_PIX_FMT_PAL8)
-                horizontal_fill(s->bpp, dst, 1, dst, 0, width, 0);
-            break;
         }
         dst += stride;
     }
@@ -580,9 +592,9 @@ static void set_sar(TiffContext *s, unsigned tag, unsigned num, unsigned den)
 static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
 {
     unsigned tag, type, count, off, value = 0, value2 = 0;
-    int i, j, k, pos, start;
+    int i, start;
+    int j, k, pos;
     int ret;
-    uint32_t *pal;
     double *dp;
 
     ret = ff_tread_tag(&s->gb, s->le, &tag, &type, &count, &start);
@@ -691,46 +703,31 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
         }
         break;
     case TIFF_ROWSPERSTRIP:
-        if (type == TIFF_LONG && value == UINT_MAX)
+        if (!value || (type == TIFF_LONG && value == UINT_MAX))
             value = s->height;
-        if (value < 1) {
-            av_log(s->avctx, AV_LOG_ERROR,
-                   "Incorrect value of rows per strip\n");
-            return AVERROR_INVALIDDATA;
-        }
-        s->rps = value;
+        s->rps = FFMIN(value, s->height);
         break;
     case TIFF_STRIP_OFFS:
         if (count == 1) {
-            s->strippos  = 0;
-            s->stripoff  = value;
+            s->strippos = 0;
+            s->stripoff = value;
         } else
             s->strippos = off;
         s->strips = count;
         if (s->strips == 1)
             s->rps = s->height;
         s->sot = type;
-        if (s->strippos > bytestream2_size(&s->gb)) {
-            av_log(s->avctx, AV_LOG_ERROR,
-                   "Tag referencing position outside the image\n");
-            return AVERROR_INVALIDDATA;
-        }
         break;
     case TIFF_STRIP_SIZE:
         if (count == 1) {
             s->stripsizesoff = 0;
-            s->stripsize  = value;
-            s->strips     = 1;
+            s->stripsize     = value;
+            s->strips        = 1;
         } else {
             s->stripsizesoff = off;
         }
         s->strips = count;
         s->sstype = type;
-        if (s->stripsizesoff > bytestream2_size(&s->gb)) {
-            av_log(s->avctx, AV_LOG_ERROR,
-                   "Tag referencing position outside the image\n");
-            return AVERROR_INVALIDDATA;
-        }
         break;
     case TIFF_XRES:
     case TIFF_YRES:
@@ -746,20 +743,31 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
     case TIFF_PREDICTOR:
         s->predictor = value;
         break;
-    case TIFF_INVERT:
+    case TIFF_PHOTOMETRIC:
         switch (value) {
-        case 0:
-            s->invert = 1;
-            break;
-        case 1:
-            s->invert = 0;
-            break;
-        case 2:
-        case 3:
+        case TIFF_PHOTOMETRIC_WHITE_IS_ZERO:
+        case TIFF_PHOTOMETRIC_BLACK_IS_ZERO:
+        case TIFF_PHOTOMETRIC_RGB:
+        case TIFF_PHOTOMETRIC_PALETTE:
+            s->photometric = value;
             break;
+        case TIFF_PHOTOMETRIC_ALPHA_MASK:
+        case TIFF_PHOTOMETRIC_SEPARATED:
+        case TIFF_PHOTOMETRIC_YCBCR:
+        case TIFF_PHOTOMETRIC_CIE_LAB:
+        case TIFF_PHOTOMETRIC_ICC_LAB:
+        case TIFF_PHOTOMETRIC_ITU_LAB:
+        case TIFF_PHOTOMETRIC_CFA:
+        case TIFF_PHOTOMETRIC_LOG_L:
+        case TIFF_PHOTOMETRIC_LOG_LUV:
+        case TIFF_PHOTOMETRIC_LINEAR_RAW:
+            avpriv_report_missing_feature(s->avctx,
+                                          "PhotometricInterpretation 0x%04X",
+                                          value);
+            return AVERROR_PATCHWELCOME;
         default:
-            av_log(s->avctx, AV_LOG_ERROR, "Color mode %d is not supported\n",
-                   value);
+            av_log(s->avctx, AV_LOG_ERROR, "PhotometricInterpretation %u is "
+                   "unknown\n", value);
             return AVERROR_INVALIDDATA;
         }
         break;
@@ -771,22 +779,28 @@ static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
         }
         s->fill_order = value - 1;
         break;
-    case TIFF_PAL:
-        pal = (uint32_t *) s->palette;
+    case TIFF_PAL: {
+        GetByteContext pal_gb[3];
         off = type_sizes[type];
-        if (count / 3 > 256 || bytestream2_get_bytes_left(&s->gb) < count / 3 * off * 3)
+        if (count / 3 > 256 ||
+            bytestream2_get_bytes_left(&s->gb) < count / 3 * off * 3)
             return AVERROR_INVALIDDATA;
+
+        pal_gb[0] = pal_gb[1] = pal_gb[2] = s->gb;
+        bytestream2_skip(&pal_gb[1], count / 3 * off);
+        bytestream2_skip(&pal_gb[2], count / 3 * off * 2);
+
         off = (type_sizes[type] - 1) << 3;
-        for (k = 2; k >= 0; k--) {
-            for (i = 0; i < count / 3; i++) {
-                if (k == 2)
-                    pal[i] = 0xFFU << 24;
-                j =  (ff_tget(&s->gb, type, s->le) >> off) << (k * 8);
-                pal[i] |= j;
-            }
+        for (i = 0; i < count / 3; i++) {
+            uint32_t p = 0xFF000000;
+            p |= (ff_tget(&pal_gb[0], type, s->le) >> off) << 16;
+            p |= (ff_tget(&pal_gb[1], type, s->le) >> off) << 8;
+            p |=  ff_tget(&pal_gb[2], type, s->le) >> off;
+            s->palette[i] = p;
         }
         s->palette_is_set = 1;
         break;
+    }
     case TIFF_PLANAR:
         s->planar = value == 2;
         break;
@@ -966,12 +980,12 @@ static int decode_frame(AVCodecContext *avctx,
         av_log(avctx, AV_LOG_ERROR, "IFD offset is greater than image size\n");
         return AVERROR_INVALIDDATA;
     }
-    s->le         = le;
+    s->le          = le;
     // TIFF_BPP is not a required tag and defaults to 1
-    s->bppcount   = s->bpp = 1;
-    s->invert     = 0;
-    s->compr      = TIFF_RAW;
-    s->fill_order = 0;
+    s->bppcount    = s->bpp = 1;
+    s->photometric = TIFF_PHOTOMETRIC_NONE;
+    s->compr       = TIFF_RAW;
+    s->fill_order  = 0;
     free_geotags(s);
 
     // Reset these offsets so we can tell if they were set this frame
@@ -1019,12 +1033,14 @@ static int decode_frame(AVCodecContext *avctx,
     if (s->stripsizesoff) {
         if (s->stripsizesoff >= (unsigned)avpkt->size)
             return AVERROR_INVALIDDATA;
-        bytestream2_init(&stripsizes, avpkt->data + s->stripsizesoff, avpkt->size - s->stripsizesoff);
+        bytestream2_init(&stripsizes, avpkt->data + s->stripsizesoff,
+                         avpkt->size - s->stripsizesoff);
     }
     if (s->strippos) {
         if (s->strippos >= (unsigned)avpkt->size)
             return AVERROR_INVALIDDATA;
-        bytestream2_init(&stripdata, avpkt->data + s->strippos, avpkt->size - s->strippos);
+        bytestream2_init(&stripdata, avpkt->data + s->strippos,
+                         avpkt->size - s->strippos);
     }
 
     if (s->rps <= 0) {
@@ -1038,12 +1054,12 @@ static int decode_frame(AVCodecContext *avctx,
         dst    = p->data[plane];
     for (i = 0; i < s->height; i += s->rps) {
         if (s->stripsizesoff)
-            ssize = ff_tget(&stripsizes, s->sstype, s->le);
+            ssize = ff_tget(&stripsizes, s->sstype, le);
         else
             ssize = s->stripsize;
 
         if (s->strippos)
-            soff = ff_tget(&stripdata, s->sot, s->le);
+            soff = ff_tget(&stripdata, s->sot, le);
         else
             soff = s->stripoff;
 
@@ -1092,12 +1108,12 @@ static int decode_frame(AVCodecContext *avctx,
         }
     }
 
-    if (s->invert) {
+    if (s->photometric == TIFF_PHOTOMETRIC_WHITE_IS_ZERO) {
         dst = p->data[plane];
         for (i = 0; i < s->height; i++) {
             for (j = 0; j < p->linesize[plane]; j++)
                 dst[j] = (s->avctx->pix_fmt == AV_PIX_FMT_PAL8 ? (1<<s->bpp) - 1 : 255) - dst[j];
-            dst += p->linesize[plane];
+            dst += stride;
         }
     }
     }