[FFmpeg-devel] avcodec/tiff: add support for sub images

Submitted by Paul B Mahol on Oct. 31, 2018, 2:25 p.m.

Details

Message ID 20181031142528.25850-2-onemda@gmail.com
State New
Headers show

Commit Message

Paul B Mahol Oct. 31, 2018, 2:25 p.m.
Signed-off-by: Paul B Mahol <onemda@gmail.com>
---
For ticket #4364. Colors looks wrong with 8bit sample mentioned in trac ticket.
Too greenish, missing yellow. Why?
---
 libavcodec/tiff.c | 46 +++++++++++++++++++++++++++++++++++++++++++++-
 libavcodec/tiff.h |  2 ++
 2 files changed, 47 insertions(+), 1 deletion(-)

Patch hide | download patch | download mbox

diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c
index d42550b4cf..4a82b398af 100644
--- a/libavcodec/tiff.c
+++ b/libavcodec/tiff.c
@@ -37,6 +37,7 @@ 
 #include "libavutil/avstring.h"
 #include "libavutil/intreadwrite.h"
 #include "libavutil/imgutils.h"
+#include "libavutil/opt.h"
 #include "avcodec.h"
 #include "bytestream.h"
 #include "faxcompr.h"
@@ -49,9 +50,12 @@ 
 #include "get_bits.h"
 
 typedef struct TiffContext {
+    AVClass *class;
     AVCodecContext *avctx;
     GetByteContext gb;
 
+    int get_subimage;
+
     int width, height;
     unsigned int bpp, bppcount;
     uint32_t palette[256];
@@ -69,6 +73,8 @@  typedef struct TiffContext {
     int is_bayer;
     uint8_t pattern[4];
 
+    uint32_t sub_ifd;
+
     int strips, rps, sstype;
     int sot;
     int stripsizesoff, stripsize, stripoff, strippos;
@@ -698,6 +704,20 @@  static int init_image(TiffContext *s, ThreadFrame *frame)
     case 81:
         s->avctx->pix_fmt = s->palette_is_set ? AV_PIX_FMT_PAL8 : AV_PIX_FMT_GRAY8;
         break;
+    case 10081:
+        switch (s->pattern[0] | s->pattern[1] << 8 | s->pattern[2] << 16 | s->pattern[3] << 24) {
+        case 0x02010100:
+            s->avctx->pix_fmt = AV_PIX_FMT_BAYER_RGGB8;
+            break;
+        case 0x00010102:
+            s->avctx->pix_fmt = AV_PIX_FMT_BAYER_BGGR8;
+            break;
+        default:
+            av_log(s->avctx, AV_LOG_ERROR, "Unsupported Bayer pattern: 0x%X\n",
+                   s->pattern[0] | s->pattern[1] << 8 | s->pattern[2] << 16 | s->pattern[3] << 24);
+            return AVERROR_PATCHWELCOME;
+        }
+        break;
     case 10121:
         switch (s->pattern[0] | s->pattern[1] << 8 | s->pattern[2] << 16 | s->pattern[3] << 24) {
         case 0x02010100:
@@ -992,6 +1012,9 @@  static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
     case TIFF_PREDICTOR:
         s->predictor = value;
         break;
+    case TIFF_SUB_IFDS:
+        s->sub_ifd = value;
+        break;
     case TIFF_CFA_PATTERN:
         s->is_bayer = 1;
         s->pattern[0] = ff_tget(&s->gb, type, s->le);
@@ -1230,7 +1253,7 @@  static int tiff_decode_tag(TiffContext *s, AVFrame *frame)
     default:
         if (s->avctx->err_recognition & AV_EF_EXPLODE) {
             av_log(s->avctx, AV_LOG_ERROR,
-                   "Unknown or unsupported tag %d/0X%0X\n",
+                   "Unknown or unsupported tag %d/0x%0X\n",
                    tag, tag);
             return AVERROR_INVALIDDATA;
         }
@@ -1282,6 +1305,7 @@  static int decode_frame(AVCodecContext *avctx,
     // Reset these offsets so we can tell if they were set this frame
     s->stripsizesoff = s->strippos = 0;
     /* parse image file directory */
+again:
     bytestream2_seek(&s->gb, off, SEEK_SET);
     entries = ff_tget_short(&s->gb, le);
     if (bytestream2_get_bytes_left(&s->gb) < entries * 12)
@@ -1291,6 +1315,12 @@  static int decode_frame(AVCodecContext *avctx,
             return ret;
     }
 
+    if (s->sub_ifd && s->get_subimage) {
+        off = s->sub_ifd;
+        s->get_subimage = 0;
+        goto again;
+    }
+
     for (i = 0; i<s->geotag_count; i++) {
         const char *keyname = get_geokey_name(s->geotags[i].key);
         if (!keyname) {
@@ -1464,6 +1494,19 @@  static av_cold int tiff_end(AVCodecContext *avctx)
     return 0;
 }
 
+#define OFFSET(x) offsetof(TiffContext, x)
+static const AVOption tiff_options[] = {
+    { "subimage", "decode subimage instead if available", OFFSET(get_subimage), AV_OPT_TYPE_BOOL, {.i64=0},  0, 1, AV_OPT_FLAG_DECODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM },
+    { NULL },
+};
+
+static const AVClass tiff_decoder_class = {
+    .class_name = "TIFF decoder",
+    .item_name  = av_default_item_name,
+    .option     = tiff_options,
+    .version    = LIBAVUTIL_VERSION_INT,
+};
+
 AVCodec ff_tiff_decoder = {
     .name           = "tiff",
     .long_name      = NULL_IF_CONFIG_SMALL("TIFF image"),
@@ -1475,4 +1518,5 @@  AVCodec ff_tiff_decoder = {
     .decode         = decode_frame,
     .init_thread_copy = ONLY_IF_THREADS_ENABLED(tiff_init),
     .capabilities   = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_FRAME_THREADS,
+    .priv_class     = &tiff_decoder_class,
 };
diff --git a/libavcodec/tiff.h b/libavcodec/tiff.h
index ae6622cb0c..57c677c6aa 100644
--- a/libavcodec/tiff.h
+++ b/libavcodec/tiff.h
@@ -70,11 +70,13 @@  enum TiffTags {
     TIFF_TILE_LENGTH        = 0x143,
     TIFF_TILE_OFFSETS       = 0x144,
     TIFF_TILE_BYTE_COUNTS   = 0x145,
+    TIFF_SUB_IFDS           = 0x14A,
     TIFF_EXTRASAMPLES       = 0x152,
     TIFF_YCBCR_COEFFICIENTS = 0x211,
     TIFF_YCBCR_SUBSAMPLING  = 0x212,
     TIFF_YCBCR_POSITIONING  = 0x213,
     TIFF_REFERENCE_BW       = 0x214,
+    TIFF_CFA_PATTERN_DIM    = 0x828D,
     TIFF_CFA_PATTERN        = 0x828E,
     TIFF_COPYRIGHT          = 0x8298,
     TIFF_MODEL_TIEPOINT     = 0x8482,