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