Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Quicktime Video (RPZA) Video Decoder
  3.  * Copyright (c) 2003 The FFmpeg Project
  4.  *
  5.  * This file is part of FFmpeg.
  6.  *
  7.  * FFmpeg is free software; you can redistribute it and/or
  8.  * modify it under the terms of the GNU Lesser General Public
  9.  * License as published by the Free Software Foundation; either
  10.  * version 2.1 of the License, or (at your option) any later version.
  11.  *
  12.  * FFmpeg is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.  * Lesser General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU Lesser General Public
  18.  * License along with FFmpeg; if not, write to the Free Software
  19.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20.  */
  21.  
  22. /**
  23.  * @file
  24.  * QT RPZA Video Decoder by Roberto Togni
  25.  * For more information about the RPZA format, visit:
  26.  *   http://www.pcisys.net/~melanson/codecs/
  27.  *
  28.  * The RPZA decoder outputs RGB555 colorspace data.
  29.  *
  30.  * Note that this decoder reads big endian RGB555 pixel values from the
  31.  * bytestream, arranges them in the host's endian order, and outputs
  32.  * them to the final rendered map in the same host endian order. This is
  33.  * intended behavior as the libavcodec documentation states that RGB555
  34.  * pixels shall be stored in native CPU endianness.
  35.  */
  36.  
  37. #include <stdint.h>
  38. #include <stdio.h>
  39. #include <stdlib.h>
  40. #include <string.h>
  41.  
  42. #include "libavutil/internal.h"
  43. #include "avcodec.h"
  44. #include "bytestream.h"
  45. #include "internal.h"
  46.  
  47. typedef struct RpzaContext {
  48.  
  49.     AVCodecContext *avctx;
  50.     AVFrame *frame;
  51.  
  52.     GetByteContext gb;
  53. } RpzaContext;
  54.  
  55. #define ADVANCE_BLOCK() \
  56. { \
  57.     pixel_ptr += 4; \
  58.     if (pixel_ptr >= width) \
  59.     { \
  60.         pixel_ptr = 0; \
  61.         row_ptr += stride * 4; \
  62.     } \
  63.     total_blocks--; \
  64.     if (total_blocks < 0) \
  65.     { \
  66.         av_log(s->avctx, AV_LOG_ERROR, "warning: block counter just went negative (this should not happen)\n"); \
  67.         return; \
  68.     } \
  69. }
  70.  
  71. static void rpza_decode_stream(RpzaContext *s)
  72. {
  73.     int width = s->avctx->width;
  74.     int stride = s->frame->linesize[0] / 2;
  75.     int row_inc = stride - 4;
  76.     int chunk_size;
  77.     uint16_t colorA = 0, colorB;
  78.     uint16_t color4[4];
  79.     uint16_t ta, tb;
  80.     uint16_t *pixels = (uint16_t *)s->frame->data[0];
  81.  
  82.     int row_ptr = 0;
  83.     int pixel_ptr = -4;
  84.     int block_ptr;
  85.     int pixel_x, pixel_y;
  86.     int total_blocks;
  87.  
  88.     /* First byte is always 0xe1. Warn if it's different */
  89.     if (bytestream2_peek_byte(&s->gb) != 0xe1)
  90.         av_log(s->avctx, AV_LOG_ERROR, "First chunk byte is 0x%02x instead of 0xe1\n",
  91.                bytestream2_peek_byte(&s->gb));
  92.  
  93.     /* Get chunk size, ingnoring first byte */
  94.     chunk_size = bytestream2_get_be32(&s->gb) & 0x00FFFFFF;
  95.  
  96.     /* If length mismatch use size from MOV file and try to decode anyway */
  97.     if (chunk_size != bytestream2_get_bytes_left(&s->gb) + 4)
  98.         av_log(s->avctx, AV_LOG_WARNING,
  99.                "MOV chunk size %d != encoded chunk size %d\n",
  100.                chunk_size,
  101.                bytestream2_get_bytes_left(&s->gb) + 4
  102.               );
  103.  
  104.     /* Number of 4x4 blocks in frame. */
  105.     total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
  106.  
  107.     /* Process chunk data */
  108.     while (bytestream2_get_bytes_left(&s->gb)) {
  109.         uint8_t opcode = bytestream2_get_byte(&s->gb); /* Get opcode */
  110.  
  111.         int n_blocks = (opcode & 0x1f) + 1; /* Extract block counter from opcode */
  112.  
  113.         /* If opcode MSbit is 0, we need more data to decide what to do */
  114.         if ((opcode & 0x80) == 0) {
  115.             colorA = (opcode << 8) | bytestream2_get_byte(&s->gb);
  116.             opcode = 0;
  117.             if ((bytestream2_peek_byte(&s->gb) & 0x80) != 0) {
  118.                 /* Must behave as opcode 110xxxxx, using colorA computed
  119.                  * above. Use fake opcode 0x20 to enter switch block at
  120.                  * the right place */
  121.                 opcode = 0x20;
  122.                 n_blocks = 1;
  123.             }
  124.         }
  125.  
  126.         n_blocks = FFMIN(n_blocks, total_blocks);
  127.  
  128.         switch (opcode & 0xe0) {
  129.  
  130.         /* Skip blocks */
  131.         case 0x80:
  132.             while (n_blocks--) {
  133.               ADVANCE_BLOCK();
  134.             }
  135.             break;
  136.  
  137.         /* Fill blocks with one color */
  138.         case 0xa0:
  139.             colorA = bytestream2_get_be16(&s->gb);
  140.             while (n_blocks--) {
  141.                 ADVANCE_BLOCK()
  142.                 block_ptr = row_ptr + pixel_ptr;
  143.                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
  144.                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
  145.                         pixels[block_ptr] = colorA;
  146.                         block_ptr++;
  147.                     }
  148.                     block_ptr += row_inc;
  149.                 }
  150.             }
  151.             break;
  152.  
  153.         /* Fill blocks with 4 colors */
  154.         case 0xc0:
  155.             colorA = bytestream2_get_be16(&s->gb);
  156.         case 0x20:
  157.             colorB = bytestream2_get_be16(&s->gb);
  158.  
  159.             /* sort out the colors */
  160.             color4[0] = colorB;
  161.             color4[1] = 0;
  162.             color4[2] = 0;
  163.             color4[3] = colorA;
  164.  
  165.             /* red components */
  166.             ta = (colorA >> 10) & 0x1F;
  167.             tb = (colorB >> 10) & 0x1F;
  168.             color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;
  169.             color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;
  170.  
  171.             /* green components */
  172.             ta = (colorA >> 5) & 0x1F;
  173.             tb = (colorB >> 5) & 0x1F;
  174.             color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;
  175.             color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;
  176.  
  177.             /* blue components */
  178.             ta = colorA & 0x1F;
  179.             tb = colorB & 0x1F;
  180.             color4[1] |= ((11 * ta + 21 * tb) >> 5);
  181.             color4[2] |= ((21 * ta + 11 * tb) >> 5);
  182.  
  183.             if (bytestream2_get_bytes_left(&s->gb) < n_blocks * 4)
  184.                 return;
  185.             while (n_blocks--) {
  186.                 ADVANCE_BLOCK();
  187.                 block_ptr = row_ptr + pixel_ptr;
  188.                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
  189.                     uint8_t index = bytestream2_get_byteu(&s->gb);
  190.                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
  191.                         uint8_t idx = (index >> (2 * (3 - pixel_x))) & 0x03;
  192.                         pixels[block_ptr] = color4[idx];
  193.                         block_ptr++;
  194.                     }
  195.                     block_ptr += row_inc;
  196.                 }
  197.             }
  198.             break;
  199.  
  200.         /* Fill block with 16 colors */
  201.         case 0x00:
  202.             if (bytestream2_get_bytes_left(&s->gb) < 30)
  203.                 return;
  204.             ADVANCE_BLOCK();
  205.             block_ptr = row_ptr + pixel_ptr;
  206.             for (pixel_y = 0; pixel_y < 4; pixel_y++) {
  207.                 for (pixel_x = 0; pixel_x < 4; pixel_x++){
  208.                     /* We already have color of upper left pixel */
  209.                     if ((pixel_y != 0) || (pixel_x != 0))
  210.                         colorA = bytestream2_get_be16u(&s->gb);
  211.                     pixels[block_ptr] = colorA;
  212.                     block_ptr++;
  213.                 }
  214.                 block_ptr += row_inc;
  215.             }
  216.             break;
  217.  
  218.         /* Unknown opcode */
  219.         default:
  220.             av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk."
  221.                  " Skip remaining %d bytes of chunk data.\n", opcode,
  222.                  bytestream2_get_bytes_left(&s->gb));
  223.             return;
  224.         } /* Opcode switch */
  225.     }
  226. }
  227.  
  228. static av_cold int rpza_decode_init(AVCodecContext *avctx)
  229. {
  230.     RpzaContext *s = avctx->priv_data;
  231.  
  232.     s->avctx = avctx;
  233.     avctx->pix_fmt = AV_PIX_FMT_RGB555;
  234.  
  235.     s->frame = av_frame_alloc();
  236.     if (!s->frame)
  237.         return AVERROR(ENOMEM);
  238.  
  239.     return 0;
  240. }
  241.  
  242. static int rpza_decode_frame(AVCodecContext *avctx,
  243.                              void *data, int *got_frame,
  244.                              AVPacket *avpkt)
  245. {
  246.     RpzaContext *s = avctx->priv_data;
  247.     int ret;
  248.  
  249.     bytestream2_init(&s->gb, avpkt->data, avpkt->size);
  250.  
  251.     if ((ret = ff_reget_buffer(avctx, s->frame)) < 0)
  252.         return ret;
  253.  
  254.     rpza_decode_stream(s);
  255.  
  256.     if ((ret = av_frame_ref(data, s->frame)) < 0)
  257.         return ret;
  258.  
  259.     *got_frame      = 1;
  260.  
  261.     /* always report that the buffer was completely consumed */
  262.     return avpkt->size;
  263. }
  264.  
  265. static av_cold int rpza_decode_end(AVCodecContext *avctx)
  266. {
  267.     RpzaContext *s = avctx->priv_data;
  268.  
  269.     av_frame_free(&s->frame);
  270.  
  271.     return 0;
  272. }
  273.  
  274. AVCodec ff_rpza_decoder = {
  275.     .name           = "rpza",
  276.     .long_name      = NULL_IF_CONFIG_SMALL("QuickTime video (RPZA)"),
  277.     .type           = AVMEDIA_TYPE_VIDEO,
  278.     .id             = AV_CODEC_ID_RPZA,
  279.     .priv_data_size = sizeof(RpzaContext),
  280.     .init           = rpza_decode_init,
  281.     .close          = rpza_decode_end,
  282.     .decode         = rpza_decode_frame,
  283.     .capabilities   = AV_CODEC_CAP_DR1,
  284. };
  285.