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 <stdio.h>
  38. #include <stdlib.h>
  39. #include <string.h>
  40.  
  41. #include "libavutil/internal.h"
  42. #include "libavutil/intreadwrite.h"
  43. #include "avcodec.h"
  44. #include "internal.h"
  45.  
  46. typedef struct RpzaContext {
  47.  
  48.     AVCodecContext *avctx;
  49.     AVFrame frame;
  50.  
  51.     const unsigned char *buf;
  52.     int size;
  53.  
  54. } RpzaContext;
  55.  
  56. #define ADVANCE_BLOCK() \
  57. { \
  58.     pixel_ptr += 4; \
  59.     if (pixel_ptr >= width) \
  60.     { \
  61.         pixel_ptr = 0; \
  62.         row_ptr += stride * 4; \
  63.     } \
  64.     total_blocks--; \
  65.     if (total_blocks < 0) \
  66.     { \
  67.         av_log(s->avctx, AV_LOG_ERROR, "warning: block counter just went negative (this should not happen)\n"); \
  68.         return; \
  69.     } \
  70. }
  71.  
  72. static void rpza_decode_stream(RpzaContext *s)
  73. {
  74.     int width = s->avctx->width;
  75.     int stride = s->frame.linesize[0] / 2;
  76.     int row_inc = stride - 4;
  77.     int stream_ptr = 0;
  78.     int chunk_size;
  79.     unsigned char opcode;
  80.     int n_blocks;
  81.     unsigned short colorA = 0, colorB;
  82.     unsigned short color4[4];
  83.     unsigned char index, idx;
  84.     unsigned short ta, tb;
  85.     unsigned short *pixels = (unsigned short *)s->frame.data[0];
  86.  
  87.     int row_ptr = 0;
  88.     int pixel_ptr = -4;
  89.     int block_ptr;
  90.     int pixel_x, pixel_y;
  91.     int total_blocks;
  92.  
  93.     /* First byte is always 0xe1. Warn if it's different */
  94.     if (s->buf[stream_ptr] != 0xe1)
  95.         av_log(s->avctx, AV_LOG_ERROR, "First chunk byte is 0x%02x instead of 0xe1\n",
  96.             s->buf[stream_ptr]);
  97.  
  98.     /* Get chunk size, ingnoring first byte */
  99.     chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF;
  100.     stream_ptr += 4;
  101.  
  102.     /* If length mismatch use size from MOV file and try to decode anyway */
  103.     if (chunk_size != s->size)
  104.         av_log(s->avctx, AV_LOG_ERROR, "MOV chunk size != encoded chunk size; using MOV chunk size\n");
  105.  
  106.     chunk_size = s->size;
  107.  
  108.     /* Number of 4x4 blocks in frame. */
  109.     total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
  110.  
  111.     /* Process chunk data */
  112.     while (stream_ptr < chunk_size) {
  113.         opcode = s->buf[stream_ptr++]; /* Get opcode */
  114.  
  115.         n_blocks = (opcode & 0x1f) + 1; /* Extract block counter from opcode */
  116.  
  117.         /* If opcode MSbit is 0, we need more data to decide what to do */
  118.         if ((opcode & 0x80) == 0) {
  119.             colorA = (opcode << 8) | (s->buf[stream_ptr++]);
  120.             opcode = 0;
  121.             if ((s->buf[stream_ptr] & 0x80) != 0) {
  122.                 /* Must behave as opcode 110xxxxx, using colorA computed
  123.                  * above. Use fake opcode 0x20 to enter switch block at
  124.                  * the right place */
  125.                 opcode = 0x20;
  126.                 n_blocks = 1;
  127.             }
  128.         }
  129.  
  130.         switch (opcode & 0xe0) {
  131.  
  132.         /* Skip blocks */
  133.         case 0x80:
  134.             while (n_blocks--) {
  135.               ADVANCE_BLOCK();
  136.             }
  137.             break;
  138.  
  139.         /* Fill blocks with one color */
  140.         case 0xa0:
  141.             colorA = AV_RB16 (&s->buf[stream_ptr]);
  142.             stream_ptr += 2;
  143.             while (n_blocks--) {
  144.                 ADVANCE_BLOCK()
  145.                 block_ptr = row_ptr + pixel_ptr;
  146.                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
  147.                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
  148.                         pixels[block_ptr] = colorA;
  149.                         block_ptr++;
  150.                     }
  151.                     block_ptr += row_inc;
  152.                 }
  153.             }
  154.             break;
  155.  
  156.         /* Fill blocks with 4 colors */
  157.         case 0xc0:
  158.             colorA = AV_RB16 (&s->buf[stream_ptr]);
  159.             stream_ptr += 2;
  160.         case 0x20:
  161.             colorB = AV_RB16 (&s->buf[stream_ptr]);
  162.             stream_ptr += 2;
  163.  
  164.             /* sort out the colors */
  165.             color4[0] = colorB;
  166.             color4[1] = 0;
  167.             color4[2] = 0;
  168.             color4[3] = colorA;
  169.  
  170.             /* red components */
  171.             ta = (colorA >> 10) & 0x1F;
  172.             tb = (colorB >> 10) & 0x1F;
  173.             color4[1] |= ((11 * ta + 21 * tb) >> 5) << 10;
  174.             color4[2] |= ((21 * ta + 11 * tb) >> 5) << 10;
  175.  
  176.             /* green components */
  177.             ta = (colorA >> 5) & 0x1F;
  178.             tb = (colorB >> 5) & 0x1F;
  179.             color4[1] |= ((11 * ta + 21 * tb) >> 5) << 5;
  180.             color4[2] |= ((21 * ta + 11 * tb) >> 5) << 5;
  181.  
  182.             /* blue components */
  183.             ta = colorA & 0x1F;
  184.             tb = colorB & 0x1F;
  185.             color4[1] |= ((11 * ta + 21 * tb) >> 5);
  186.             color4[2] |= ((21 * ta + 11 * tb) >> 5);
  187.  
  188.             if (s->size - stream_ptr < n_blocks * 4)
  189.                 return;
  190.             while (n_blocks--) {
  191.                 ADVANCE_BLOCK();
  192.                 block_ptr = row_ptr + pixel_ptr;
  193.                 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
  194.                     index = s->buf[stream_ptr++];
  195.                     for (pixel_x = 0; pixel_x < 4; pixel_x++){
  196.                         idx = (index >> (2 * (3 - pixel_x))) & 0x03;
  197.                         pixels[block_ptr] = color4[idx];
  198.                         block_ptr++;
  199.                     }
  200.                     block_ptr += row_inc;
  201.                 }
  202.             }
  203.             break;
  204.  
  205.         /* Fill block with 16 colors */
  206.         case 0x00:
  207.             if (s->size - stream_ptr < 30)
  208.                 return;
  209.             ADVANCE_BLOCK();
  210.             block_ptr = row_ptr + pixel_ptr;
  211.             for (pixel_y = 0; pixel_y < 4; pixel_y++) {
  212.                 for (pixel_x = 0; pixel_x < 4; pixel_x++){
  213.                     /* We already have color of upper left pixel */
  214.                     if ((pixel_y != 0) || (pixel_x !=0)) {
  215.                         colorA = AV_RB16 (&s->buf[stream_ptr]);
  216.                         stream_ptr += 2;
  217.                     }
  218.                     pixels[block_ptr] = colorA;
  219.                     block_ptr++;
  220.                 }
  221.                 block_ptr += row_inc;
  222.             }
  223.             break;
  224.  
  225.         /* Unknown opcode */
  226.         default:
  227.             av_log(s->avctx, AV_LOG_ERROR, "Unknown opcode %d in rpza chunk."
  228.                  " Skip remaining %d bytes of chunk data.\n", opcode,
  229.                  chunk_size - stream_ptr);
  230.             return;
  231.         } /* Opcode switch */
  232.     }
  233. }
  234.  
  235. static av_cold int rpza_decode_init(AVCodecContext *avctx)
  236. {
  237.     RpzaContext *s = avctx->priv_data;
  238.  
  239.     s->avctx = avctx;
  240.     avctx->pix_fmt = AV_PIX_FMT_RGB555;
  241.  
  242.     avcodec_get_frame_defaults(&s->frame);
  243.  
  244.     return 0;
  245. }
  246.  
  247. static int rpza_decode_frame(AVCodecContext *avctx,
  248.                              void *data, int *got_frame,
  249.                              AVPacket *avpkt)
  250. {
  251.     const uint8_t *buf = avpkt->data;
  252.     int buf_size = avpkt->size;
  253.     RpzaContext *s = avctx->priv_data;
  254.     int ret;
  255.  
  256.     s->buf = buf;
  257.     s->size = buf_size;
  258.  
  259.     if ((ret = ff_reget_buffer(avctx, &s->frame)) < 0)
  260.         return ret;
  261.  
  262.     rpza_decode_stream(s);
  263.  
  264.     if ((ret = av_frame_ref(data, &s->frame)) < 0)
  265.         return ret;
  266.  
  267.     *got_frame      = 1;
  268.  
  269.     /* always report that the buffer was completely consumed */
  270.     return buf_size;
  271. }
  272.  
  273. static av_cold int rpza_decode_end(AVCodecContext *avctx)
  274. {
  275.     RpzaContext *s = avctx->priv_data;
  276.  
  277.     av_frame_unref(&s->frame);
  278.  
  279.     return 0;
  280. }
  281.  
  282. AVCodec ff_rpza_decoder = {
  283.     .name           = "rpza",
  284.     .long_name      = NULL_IF_CONFIG_SMALL("QuickTime video (RPZA)"),
  285.     .type           = AVMEDIA_TYPE_VIDEO,
  286.     .id             = AV_CODEC_ID_RPZA,
  287.     .priv_data_size = sizeof(RpzaContext),
  288.     .init           = rpza_decode_init,
  289.     .close          = rpza_decode_end,
  290.     .decode         = rpza_decode_frame,
  291.     .capabilities   = CODEC_CAP_DR1,
  292. };
  293.