quickdraw: Support direct pixel blocks
authorVittorio Giovara <vittorio.giovara@gmail.com>
Sat, 18 Apr 2015 16:25:20 +0000 (17:25 +0100)
committerVittorio Giovara <vittorio.giovara@gmail.com>
Wed, 6 May 2015 13:27:34 +0000 (14:27 +0100)
Data is stored in separated components so rework decode_rle() to support
stepping and offsets.

Changelog
libavcodec/qdrw.c
libavcodec/version.h

index 2fd1583..9d73449 100644 (file)
--- a/Changelog
+++ b/Changelog
@@ -29,6 +29,7 @@ version <next>:
 - DTS decoding through libdcadec
 - Canopus HQ/HQA decoder
 - Automatically rotate videos based on metadata in avconv
+- improved Quickdraw compatibility
 
 
 version 11:
index a70449d..1eb2a76 100644 (file)
@@ -35,6 +35,8 @@
 enum QuickdrawOpcodes {
     PACKBITSRECT = 0x0098,
     PACKBITSRGN,
+    DIRECTBITSRECT,
+    DIRECTBITSRGN,
 
     EOP = 0x00FF,
 };
@@ -64,14 +66,17 @@ static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc,
     return 0;
 }
 
-static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
+static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc,
+                      int step)
 {
-    int i;
+    int i, j;
+    int offset = avctx->width * step;
     uint8_t *outdata = p->data[0];
 
     for (i = 0; i < avctx->height; i++) {
         int size, left, code, pix;
         uint8_t *out = outdata;
+        int pos = 0;
 
         /* size of packed line */
         size = left = bytestream2_get_be16(gbc);
@@ -83,12 +88,24 @@ static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc)
             code = bytestream2_get_byte(gbc);
             if (code & 0x80 ) { /* run */
                 pix = bytestream2_get_byte(gbc);
-                memset(out, pix, 257 - code);
-                out   += 257 - code;
+                for (j = 0; j < 257 - code; j++) {
+                    out[pos] = pix;
+                    pos += step;
+                    if (pos >= offset) {
+                        pos -= offset;
+                        pos++;
+                    }
+                }
                 left  -= 2;
             } else { /* copy */
-                bytestream2_get_buffer(gbc, out, code + 1);
-                out   += code + 1;
+                for (j = 0; j < code + 1; j++) {
+                    out[pos] = bytestream2_get_byte(gbc);
+                    pos += step;
+                    if (pos >= offset) {
+                        pos -= offset;
+                        pos++;
+                    }
+                }
                 left  -= 2 + code;
             }
         }
@@ -134,6 +151,7 @@ static int decode_frame(AVCodecContext *avctx,
 
     while (bytestream2_get_bytes_left(&gbc) >= 4) {
         int bppcnt, bpp;
+        int rowbytes, pack_type;
         int opcode = bytestream2_get_be16(&gbc);
 
         switch(opcode) {
@@ -185,7 +203,63 @@ static int decode_frame(AVCodecContext *avctx,
                 avpriv_report_missing_feature(avctx, "Packbit mask region");
             }
 
-            ret = decode_rle(avctx, p, &gbc);
+            ret = decode_rle(avctx, p, &gbc, bppcnt);
+            if (ret < 0)
+                return ret;
+            *got_frame = 1;
+            break;
+        case DIRECTBITSRECT:
+        case DIRECTBITSRGN:
+            av_log(avctx, AV_LOG_DEBUG, "Parsing Directbit opcode\n");
+
+            bytestream2_skip(&gbc, 4);
+            rowbytes = bytestream2_get_be16(&gbc) & 0x3FFF;
+            if (rowbytes <= 250) {
+                avpriv_report_missing_feature(avctx, "Short rowbytes");
+                return AVERROR_PATCHWELCOME;
+            }
+
+            bytestream2_skip(&gbc, 10);
+            pack_type = bytestream2_get_be16(&gbc);
+
+            bytestream2_skip(&gbc, 16);
+            bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
+            bpp    = bytestream2_get_be16(&gbc); /* cmpSize */
+
+            av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
+            if (bppcnt == 3 && bpp == 8) {
+                avctx->pix_fmt = AV_PIX_FMT_RGB24;
+            } else if (bppcnt == 4 && bpp == 8) {
+                avctx->pix_fmt = AV_PIX_FMT_ARGB;
+            } else {
+                av_log(avctx, AV_LOG_ERROR,
+                       "Invalid pixel format (bppcnt %d bpp %d) in Directbit\n",
+                       bppcnt, bpp);
+                return AVERROR_INVALIDDATA;
+            }
+
+            /* set packing when default is selected */
+            if (pack_type == 0)
+                pack_type = bppcnt;
+
+            if (pack_type != 3 && pack_type != 4) {
+                avpriv_request_sample(avctx, "Pack type %d", pack_type);
+                return AVERROR_PATCHWELCOME;
+            }
+            if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
+                av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
+                return ret;
+            }
+
+            /* jump to data */
+            bytestream2_skip(&gbc, 30);
+
+            if (opcode == DIRECTBITSRGN) {
+                bytestream2_skip(&gbc, 2 + 8); /* size + rect */
+                avpriv_report_missing_feature(avctx, "DirectBit mask region");
+            }
+
+            ret = decode_rle(avctx, p, &gbc, bppcnt);
             if (ret < 0)
                 return ret;
             *got_frame = 1;
index 76020d3..50c2b48 100644 (file)
@@ -30,7 +30,7 @@
 
 #define LIBAVCODEC_VERSION_MAJOR 56
 #define LIBAVCODEC_VERSION_MINOR 23
-#define LIBAVCODEC_VERSION_MICRO  1
+#define LIBAVCODEC_VERSION_MICRO  2
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \