[FFmpeg-devel,v11,13/14] lavc/tiff: Support DNGs with striped (non-tiled) JPEGs images

Submitted by velocityra@gmail.com on Aug. 8, 2019, 8:52 p.m.

Details

Message ID 20190808205233.16368-13-velocityra@gmail.com
State New
Headers show

Commit Message

velocityra@gmail.com Aug. 8, 2019, 8:52 p.m.
From: Nick Renieris <velocityra@gmail.com>

DNG samples here can now be decoded:
- https://www.photographyblog.com/previews/pentax_k1_photos

Signed-off-by: Nick Renieris <velocityra@gmail.com>
---
 libavcodec/tiff.c | 73 +++++++++++++++++++++++++++--------------------
 1 file changed, 42 insertions(+), 31 deletions(-)

Patch hide | download patch | download mbox

diff --git a/libavcodec/tiff.c b/libavcodec/tiff.c
index 7855c36aa7..47140cddbc 100644
--- a/libavcodec/tiff.c
+++ b/libavcodec/tiff.c
@@ -550,6 +550,8 @@  static int tiff_unpack_fax(TiffContext *s, uint8_t *dst, int stride,
     return ret;
 }
 
+static int dng_decode_strip(AVCodecContext *avctx, AVFrame *frame);
+
 static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int stride,
                              const uint8_t *src, int size, int strip_start, int lines)
 {
@@ -665,6 +667,17 @@  static int tiff_unpack_strip(TiffContext *s, AVFrame *p, uint8_t *dst, int strid
 
     is_dng = (s->tiff_type == TIFF_TYPE_DNG || s->tiff_type == TIFF_TYPE_CINEMADNG);
 
+    /* Decode JPEG-encoded DNGs with strips */
+    if (s->compr == TIFF_NEWJPEG && is_dng) {
+        if (s->strips > 1) {
+            av_log(s->avctx, AV_LOG_ERROR, "More than one DNG JPEG strips unsupported\n");
+            return AVERROR_PATCHWELCOME;
+        }
+        if ((ret = dng_decode_strip(s->avctx, p)) < 0)
+            return ret;
+        return 0;
+    }
+
     for (line = 0; line < lines; line++) {
         if (src - ssrc > size) {
             av_log(s->avctx, AV_LOG_ERROR, "Source data overread\n");
@@ -859,8 +872,8 @@  static void dng_blit(TiffContext *s, uint8_t *dst, int dst_stride,
     }
 }
 
-static int dng_decode_jpeg_tile(AVCodecContext *avctx, AVFrame *frame,
-                                int tile_byte_count, int x, int y, int w, int h)
+static int dng_decode_jpeg(AVCodecContext *avctx, AVFrame *frame,
+                           int tile_byte_count, int dst_x, int dst_y, int w, int h)
 {
     TiffContext *s = avctx->priv_data;
     AVPacket jpkt;
@@ -905,7 +918,7 @@  static int dng_decode_jpeg_tile(AVCodecContext *avctx, AVFrame *frame,
         return AVERROR_PATCHWELCOME;
     }
 
-    dst_offset = x + frame->linesize[0] * y / pixel_size;
+    dst_offset = dst_x + frame->linesize[0] * dst_y / pixel_size;
     dst_data = frame->data[0] + dst_offset * pixel_size;
     src_data = s->jpgframe->data[0];
 
@@ -924,7 +937,7 @@  static int dng_decode_jpeg_tile(AVCodecContext *avctx, AVFrame *frame,
     return 0;
 }
 
-static int dng_decode_tiles(AVCodecContext *avctx, AVFrame *frame)
+static int dng_decode_tiles(AVCodecContext *avctx, AVFrame *frame, AVPacket *avpkt)
 {
     TiffContext *s = avctx->priv_data;
     int tile_idx;
@@ -937,6 +950,12 @@  static int dng_decode_tiles(AVCodecContext *avctx, AVFrame *frame)
     int pos_x = 0, pos_y = 0;
     int ret;
 
+    s->jpgframe->width  = s->tile_width;
+    s->jpgframe->height = s->tile_length;
+
+    s->avctx_mjpeg->width = s->tile_width;
+    s->avctx_mjpeg->height = s->tile_length;
+
     has_width_leftover = (s->width % s->tile_width != 0);
     has_height_leftover = (s->height % s->tile_length != 0);
 
@@ -973,7 +992,7 @@  static int dng_decode_tiles(AVCodecContext *avctx, AVFrame *frame)
         bytestream2_seek(&s->gb, tile_offset, SEEK_SET);
 
         /* Decode JPEG tile and copy it in the reference frame */
-        ret = dng_decode_jpeg_tile(avctx, frame, tile_byte_count, pos_x, pos_y, tile_width, tile_length);
+        ret = dng_decode_jpeg(avctx, frame, tile_byte_count, pos_x, pos_y, tile_width, tile_length);
 
         if (ret < 0)
             return ret;
@@ -986,30 +1005,24 @@  static int dng_decode_tiles(AVCodecContext *avctx, AVFrame *frame)
         }
     }
 
-    return 0;
-}
+    /* Frame is ready to be output */
+    frame->pict_type = AV_PICTURE_TYPE_I;
+    frame->key_frame = 1;
 
-static int dng_decode(AVCodecContext *avctx, AVFrame *frame, AVPacket *avpkt) {
-    int ret;
+    return avpkt->size;
+}
 
+static int dng_decode_strip(AVCodecContext *avctx, AVFrame *frame)
+{
     TiffContext *s = avctx->priv_data;
 
-    s->jpgframe->width  = s->tile_width;
-    s->jpgframe->height = s->tile_length;
-
-    s->avctx_mjpeg->width = s->tile_width;
-    s->avctx_mjpeg->height = s->tile_length;
-
-    /* Decode all tiles in a frame */
-    ret = dng_decode_tiles(avctx, frame);
-    if (ret < 0)
-        return ret;
+    s->jpgframe->width  = s->width;
+    s->jpgframe->height = s->height;
 
-    /* Frame is ready to be output */
-    frame->pict_type = AV_PICTURE_TYPE_I;
-    frame->key_frame = 1;
+    s->avctx_mjpeg->width = s->width;
+    s->avctx_mjpeg->height = s->height;
 
-    return avpkt->size;
+    return dng_decode_jpeg(avctx, frame, s->stripsize, 0, 0, s->width, s->height);
 }
 
 static int init_image(TiffContext *s, ThreadFrame *frame)
@@ -1873,17 +1886,15 @@  again:
 
     /* Handle DNG images with JPEG-compressed tiles */
 
-    if (s->tiff_type == TIFF_TYPE_DNG || s->tiff_type == TIFF_TYPE_CINEMADNG) {
-        if (!s->is_jpeg && s->is_tiled) {
+    if ((s->tiff_type == TIFF_TYPE_DNG || s->tiff_type == TIFF_TYPE_CINEMADNG) && s->is_tiled) {
+        if (!s->is_jpeg) {
             avpriv_report_missing_feature(avctx, "DNG uncompressed tiled images");
             return AVERROR_PATCHWELCOME;
-        }
-        if (s->is_jpeg && !s->is_bayer) {
-            avpriv_report_missing_feature(avctx, "DNG JPG-compressed non-bayer-encoded images");
+        } else if (!s->is_bayer) {
+            avpriv_report_missing_feature(avctx, "DNG JPG-compressed tiled non-bayer-encoded images");
             return AVERROR_PATCHWELCOME;
-        }
-        if (s->is_jpeg && s->is_bayer) {
-            if ((ret = dng_decode(avctx, (AVFrame*)data, avpkt)) > 0)
+        } else {
+            if ((ret = dng_decode_tiles(avctx, (AVFrame*)data, avpkt)) > 0)
                 *got_frame = 1;
             return ret;
         }