Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * QuickDraw (qdrw) codec
  3.  * Copyright (c) 2004 Konstantin Shishkov
  4.  * Copyright (c) 2015 Vittorio Giovara
  5.  *
  6.  * This file is part of FFmpeg.
  7.  *
  8.  * FFmpeg is free software; you can redistribute it and/or
  9.  * modify it under the terms of the GNU Lesser General Public
  10.  * License as published by the Free Software Foundation; either
  11.  * version 2.1 of the License, or (at your option) any later version.
  12.  *
  13.  * FFmpeg is distributed in the hope that it will be useful,
  14.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.  * Lesser General Public License for more details.
  17.  *
  18.  * You should have received a copy of the GNU Lesser General Public
  19.  * License along with FFmpeg; if not, write to the Free Software
  20.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21.  */
  22.  
  23. /**
  24.  * @file
  25.  * Apple QuickDraw codec.
  26.  * https://developer.apple.com/legacy/library/documentation/mac/QuickDraw/QuickDraw-461.html
  27.  */
  28.  
  29. #include "libavutil/common.h"
  30. #include "libavutil/intreadwrite.h"
  31. #include "avcodec.h"
  32. #include "bytestream.h"
  33. #include "internal.h"
  34.  
  35. enum QuickdrawOpcodes {
  36.     PACKBITSRECT = 0x0098,
  37.     PACKBITSRGN,
  38.     DIRECTBITSRECT,
  39.     DIRECTBITSRGN,
  40.  
  41.     EOP = 0x00FF,
  42. };
  43.  
  44. static int parse_palette(AVCodecContext *avctx, GetByteContext *gbc,
  45.                          uint32_t *pal, int colors)
  46. {
  47.     int i;
  48.  
  49.     for (i = 0; i <= colors; i++) {
  50.         uint8_t r, g, b;
  51.         unsigned int idx = bytestream2_get_be16(gbc); /* color index */
  52.         if (idx > 255) {
  53.             av_log(avctx, AV_LOG_WARNING,
  54.                    "Palette index out of range: %u\n", idx);
  55.             bytestream2_skip(gbc, 6);
  56.             continue;
  57.         }
  58.         r = bytestream2_get_byte(gbc);
  59.         bytestream2_skip(gbc, 1);
  60.         g = bytestream2_get_byte(gbc);
  61.         bytestream2_skip(gbc, 1);
  62.         b = bytestream2_get_byte(gbc);
  63.         bytestream2_skip(gbc, 1);
  64.         pal[idx] = (0xFFU << 24) | (r << 16) | (g << 8) | b;
  65.     }
  66.     return 0;
  67. }
  68.  
  69. static int decode_rle(AVCodecContext *avctx, AVFrame *p, GetByteContext *gbc,
  70.                       int step)
  71. {
  72.     int i, j;
  73.     int offset = avctx->width * step;
  74.     uint8_t *outdata = p->data[0];
  75.  
  76.     for (i = 0; i < avctx->height; i++) {
  77.         int size, left, code, pix;
  78.         uint8_t *out = outdata;
  79.         int pos = 0;
  80.  
  81.         /* size of packed line */
  82.         size = left = bytestream2_get_be16(gbc);
  83.         if (bytestream2_get_bytes_left(gbc) < size)
  84.             return AVERROR_INVALIDDATA;
  85.  
  86.         /* decode line */
  87.         while (left > 0) {
  88.             code = bytestream2_get_byte(gbc);
  89.             if (code & 0x80 ) { /* run */
  90.                 pix = bytestream2_get_byte(gbc);
  91.                 for (j = 0; j < 257 - code; j++) {
  92.                     out[pos] = pix;
  93.                     pos += step;
  94.                     if (pos >= offset) {
  95.                         pos -= offset;
  96.                         pos++;
  97.                     }
  98.                     if (pos >= offset)
  99.                         return AVERROR_INVALIDDATA;
  100.                 }
  101.                 left  -= 2;
  102.             } else { /* copy */
  103.                 for (j = 0; j < code + 1; j++) {
  104.                     out[pos] = bytestream2_get_byte(gbc);
  105.                     pos += step;
  106.                     if (pos >= offset) {
  107.                         pos -= offset;
  108.                         pos++;
  109.                     }
  110.                     if (pos >= offset)
  111.                         return AVERROR_INVALIDDATA;
  112.                 }
  113.                 left  -= 2 + code;
  114.             }
  115.         }
  116.         outdata += p->linesize[0];
  117.     }
  118.     return 0;
  119. }
  120.  
  121. static int check_header(const char *buf, int buf_size)
  122. {
  123.     unsigned w, h, v0, v1;
  124.  
  125.     if (buf_size < 40)
  126.         return 0;
  127.  
  128.     w = AV_RB16(buf+6);
  129.     h = AV_RB16(buf+8);
  130.     v0 = AV_RB16(buf+10);
  131.     v1 = AV_RB16(buf+12);
  132.  
  133.     if (!w || !h)
  134.         return 0;
  135.  
  136.     if (v0 == 0x1101)
  137.         return 1;
  138.     if (v0 == 0x0011 && v1 == 0x02FF)
  139.         return 2;
  140.     return 0;
  141. }
  142.  
  143.  
  144. static int decode_frame(AVCodecContext *avctx,
  145.                         void *data, int *got_frame,
  146.                         AVPacket *avpkt)
  147. {
  148.     AVFrame * const p      = data;
  149.     GetByteContext gbc;
  150.     int colors;
  151.     int w, h, ret;
  152.     int ver;
  153.  
  154.     bytestream2_init(&gbc, avpkt->data, avpkt->size);
  155.     if (   bytestream2_get_bytes_left(&gbc) >= 552
  156.            &&  check_header(gbc.buffer + 512, bytestream2_get_bytes_left(&gbc) - 512)
  157.        )
  158.         bytestream2_skip(&gbc, 512);
  159.  
  160.     ver = check_header(gbc.buffer, bytestream2_get_bytes_left(&gbc));
  161.  
  162.     /* smallest PICT header */
  163.     if (bytestream2_get_bytes_left(&gbc) < 40) {
  164.         av_log(avctx, AV_LOG_ERROR, "Frame is too small %d\n",
  165.                bytestream2_get_bytes_left(&gbc));
  166.         return AVERROR_INVALIDDATA;
  167.     }
  168.  
  169.     bytestream2_skip(&gbc, 6);
  170.     h = bytestream2_get_be16(&gbc);
  171.     w = bytestream2_get_be16(&gbc);
  172.  
  173.     ret = ff_set_dimensions(avctx, w, h);
  174.     if (ret < 0)
  175.         return ret;
  176.  
  177.     /* version 1 is identified by 0x1101
  178.      * it uses byte-aligned opcodes rather than word-aligned */
  179.     if (ver == 1) {
  180.         avpriv_request_sample(avctx, "QuickDraw version 1");
  181.         return AVERROR_PATCHWELCOME;
  182.     } else if (ver != 2) {
  183.         avpriv_request_sample(avctx, "QuickDraw version unknown (%X)", bytestream2_get_be32(&gbc));
  184.         return AVERROR_PATCHWELCOME;
  185.     }
  186.  
  187.     bytestream2_skip(&gbc, 4+26);
  188.  
  189.     while (bytestream2_get_bytes_left(&gbc) >= 4) {
  190.         int bppcnt, bpp;
  191.         int rowbytes, pack_type;
  192.         int opcode = bytestream2_get_be16(&gbc);
  193.  
  194.         switch(opcode) {
  195.         case PACKBITSRECT:
  196.         case PACKBITSRGN:
  197.             av_log(avctx, AV_LOG_DEBUG, "Parsing Packbit opcode\n");
  198.  
  199.             bytestream2_skip(&gbc, 30);
  200.             bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
  201.             bpp    = bytestream2_get_be16(&gbc); /* cmpSize */
  202.  
  203.             av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
  204.             if (bppcnt == 1 && bpp == 8) {
  205.                 avctx->pix_fmt = AV_PIX_FMT_PAL8;
  206.             } else {
  207.                 av_log(avctx, AV_LOG_ERROR,
  208.                        "Invalid pixel format (bppcnt %d bpp %d) in Packbit\n",
  209.                        bppcnt, bpp);
  210.                 return AVERROR_INVALIDDATA;
  211.             }
  212.  
  213.             /* jump to palette */
  214.             bytestream2_skip(&gbc, 18);
  215.             colors = bytestream2_get_be16(&gbc);
  216.  
  217.             if (colors < 0 || colors > 256) {
  218.                 av_log(avctx, AV_LOG_ERROR,
  219.                        "Error color count - %i(0x%X)\n", colors, colors);
  220.                 return AVERROR_INVALIDDATA;
  221.             }
  222.             if (bytestream2_get_bytes_left(&gbc) < (colors + 1) * 8) {
  223.                 av_log(avctx, AV_LOG_ERROR, "Palette is too small %d\n",
  224.                        bytestream2_get_bytes_left(&gbc));
  225.                 return AVERROR_INVALIDDATA;
  226.             }
  227.             if ((ret = ff_get_buffer(avctx, p, 0)) < 0)
  228.                 return ret;
  229.  
  230.             parse_palette(avctx, &gbc, (uint32_t *)p->data[1], colors);
  231.             p->palette_has_changed = 1;
  232.  
  233.             /* jump to image data */
  234.             bytestream2_skip(&gbc, 18);
  235.  
  236.             if (opcode == PACKBITSRGN) {
  237.                 bytestream2_skip(&gbc, 2 + 8); /* size + rect */
  238.                 avpriv_report_missing_feature(avctx, "Packbit mask region");
  239.             }
  240.  
  241.             ret = decode_rle(avctx, p, &gbc, bppcnt);
  242.             if (ret < 0)
  243.                 return ret;
  244.             *got_frame = 1;
  245.             break;
  246.         case DIRECTBITSRECT:
  247.         case DIRECTBITSRGN:
  248.             av_log(avctx, AV_LOG_DEBUG, "Parsing Directbit opcode\n");
  249.  
  250.             bytestream2_skip(&gbc, 4);
  251.             rowbytes = bytestream2_get_be16(&gbc) & 0x3FFF;
  252.             if (rowbytes <= 250) {
  253.                 avpriv_report_missing_feature(avctx, "Short rowbytes");
  254.                 return AVERROR_PATCHWELCOME;
  255.             }
  256.  
  257.             bytestream2_skip(&gbc, 10);
  258.             pack_type = bytestream2_get_be16(&gbc);
  259.  
  260.             bytestream2_skip(&gbc, 16);
  261.             bppcnt = bytestream2_get_be16(&gbc); /* cmpCount */
  262.             bpp    = bytestream2_get_be16(&gbc); /* cmpSize */
  263.  
  264.             av_log(avctx, AV_LOG_DEBUG, "bppcount %d bpp %d\n", bppcnt, bpp);
  265.             if (bppcnt == 3 && bpp == 8) {
  266.                 avctx->pix_fmt = AV_PIX_FMT_RGB24;
  267.             } else if (bppcnt == 4 && bpp == 8) {
  268.                 avctx->pix_fmt = AV_PIX_FMT_ARGB;
  269.             } else {
  270.                 av_log(avctx, AV_LOG_ERROR,
  271.                        "Invalid pixel format (bppcnt %d bpp %d) in Directbit\n",
  272.                        bppcnt, bpp);
  273.                 return AVERROR_INVALIDDATA;
  274.             }
  275.  
  276.             /* set packing when default is selected */
  277.             if (pack_type == 0)
  278.                 pack_type = bppcnt;
  279.  
  280.             if (pack_type != 3 && pack_type != 4) {
  281.                 avpriv_request_sample(avctx, "Pack type %d", pack_type);
  282.                 return AVERROR_PATCHWELCOME;
  283.             }
  284.             if ((ret = ff_get_buffer(avctx, p, 0)) < 0) {
  285.                 av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n");
  286.                 return ret;
  287.             }
  288.  
  289.             /* jump to data */
  290.             bytestream2_skip(&gbc, 30);
  291.  
  292.             if (opcode == DIRECTBITSRGN) {
  293.                 bytestream2_skip(&gbc, 2 + 8); /* size + rect */
  294.                 avpriv_report_missing_feature(avctx, "DirectBit mask region");
  295.             }
  296.  
  297.             ret = decode_rle(avctx, p, &gbc, bppcnt);
  298.             if (ret < 0)
  299.                 return ret;
  300.             *got_frame = 1;
  301.             break;
  302.         default:
  303.             av_log(avctx, AV_LOG_TRACE, "Unknown 0x%04X opcode\n", opcode);
  304.             break;
  305.         }
  306.         /* exit the loop when a known pixel block has been found */
  307.         if (*got_frame) {
  308.             int eop, trail;
  309.  
  310.             /* re-align to a word */
  311.             bytestream2_skip(&gbc, bytestream2_get_bytes_left(&gbc) % 2);
  312.  
  313.             eop = bytestream2_get_be16(&gbc);
  314.             trail = bytestream2_get_bytes_left(&gbc);
  315.             if (eop != EOP)
  316.                 av_log(avctx, AV_LOG_WARNING,
  317.                        "Missing end of picture opcode (found 0x%04X)\n", eop);
  318.             if (trail)
  319.                 av_log(avctx, AV_LOG_WARNING, "Got %d trailing bytes\n", trail);
  320.             break;
  321.         }
  322.     }
  323.  
  324.     if (*got_frame) {
  325.         p->pict_type = AV_PICTURE_TYPE_I;
  326.         p->key_frame = 1;
  327.  
  328.         return avpkt->size;
  329.     } else {
  330.         av_log(avctx, AV_LOG_ERROR, "Frame contained no usable data\n");
  331.  
  332.         return AVERROR_INVALIDDATA;
  333.     }
  334. }
  335.  
  336. AVCodec ff_qdraw_decoder = {
  337.     .name           = "qdraw",
  338.     .long_name      = NULL_IF_CONFIG_SMALL("Apple QuickDraw"),
  339.     .type           = AVMEDIA_TYPE_VIDEO,
  340.     .id             = AV_CODEC_ID_QDRAW,
  341.     .decode         = decode_frame,
  342.     .capabilities   = AV_CODEC_CAP_DR1,
  343. };
  344.