1/* 2 * Quicktime Graphics (SMC) 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 SMC Video Decoder by Mike Melanson (melanson@pcisys.net) 25 * For more information about the SMC format, visit: 26 * http://www.pcisys.net/~melanson/codecs/ 27 * 28 * The SMC decoder outputs PAL8 colorspace data. 29 */ 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34 35#include "libavutil/intreadwrite.h" 36#include "avcodec.h" 37#include "bytestream.h" 38#include "codec_internal.h" 39#include "decode.h" 40#include "internal.h" 41 42#define CPAIR 2 43#define CQUAD 4 44#define COCTET 8 45 46#define COLORS_PER_TABLE 256 47 48typedef struct SmcContext { 49 50 AVCodecContext *avctx; 51 AVFrame *frame; 52 53 GetByteContext gb; 54 55 /* SMC color tables */ 56 uint8_t color_pairs[COLORS_PER_TABLE * CPAIR]; 57 uint8_t color_quads[COLORS_PER_TABLE * CQUAD]; 58 uint8_t color_octets[COLORS_PER_TABLE * COCTET]; 59 60 uint32_t pal[256]; 61} SmcContext; 62 63#define GET_BLOCK_COUNT() \ 64 (opcode & 0x10) ? (1 + bytestream2_get_byte(gb)) : 1 + (opcode & 0x0F); 65 66#define ADVANCE_BLOCK() \ 67{ \ 68 pixel_ptr += 4; \ 69 if (pixel_ptr >= width) \ 70 { \ 71 pixel_ptr = 0; \ 72 row_ptr += stride * 4; \ 73 } \ 74 total_blocks--; \ 75 if (total_blocks < !!n_blocks) \ 76 { \ 77 av_log(s->avctx, AV_LOG_ERROR, "block counter just went negative (this should not happen)\n"); \ 78 return AVERROR_INVALIDDATA; \ 79 } \ 80} 81 82static int smc_decode_stream(SmcContext *s) 83{ 84 GetByteContext *gb = &s->gb; 85 int width = s->avctx->width; 86 int height = s->avctx->height; 87 int stride = s->frame->linesize[0]; 88 int i; 89 int chunk_size; 90 int buf_size = bytestream2_size(gb); 91 uint8_t opcode; 92 int n_blocks; 93 unsigned int color_flags; 94 unsigned int color_flags_a; 95 unsigned int color_flags_b; 96 unsigned int flag_mask; 97 98 uint8_t * const pixels = s->frame->data[0]; 99 100 int image_size = height * s->frame->linesize[0]; 101 int row_ptr = 0; 102 int pixel_ptr = 0; 103 int pixel_x, pixel_y; 104 int row_inc = stride - 4; 105 int block_ptr; 106 int prev_block_ptr; 107 int prev_block_ptr1, prev_block_ptr2; 108 int prev_block_flag; 109 int total_blocks; 110 int color_table_index; /* indexes to color pair, quad, or octet tables */ 111 int pixel; 112 113 int color_pair_index = 0; 114 int color_quad_index = 0; 115 int color_octet_index = 0; 116 117 /* make the palette available */ 118 memcpy(s->frame->data[1], s->pal, AVPALETTE_SIZE); 119 120 bytestream2_skip(gb, 1); 121 chunk_size = bytestream2_get_be24(gb); 122 if (chunk_size != buf_size) 123 av_log(s->avctx, AV_LOG_WARNING, "MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n", 124 chunk_size, buf_size); 125 126 chunk_size = buf_size; 127 total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4); 128 129 /* traverse through the blocks */ 130 while (total_blocks) { 131 /* sanity checks */ 132 /* make sure the row pointer hasn't gone wild */ 133 if (row_ptr >= image_size) { 134 av_log(s->avctx, AV_LOG_ERROR, "just went out of bounds (row ptr = %d, height = %d)\n", 135 row_ptr, image_size); 136 return AVERROR_INVALIDDATA; 137 } 138 if (bytestream2_get_bytes_left(gb) < 1) { 139 av_log(s->avctx, AV_LOG_ERROR, "input too small\n"); 140 return AVERROR_INVALIDDATA; 141 } 142 143 opcode = bytestream2_get_byteu(gb); 144 switch (opcode & 0xF0) { 145 /* skip n blocks */ 146 case 0x00: 147 case 0x10: 148 n_blocks = GET_BLOCK_COUNT(); 149 while (n_blocks--) { 150 ADVANCE_BLOCK(); 151 } 152 break; 153 154 /* repeat last block n times */ 155 case 0x20: 156 case 0x30: 157 n_blocks = GET_BLOCK_COUNT(); 158 159 /* sanity check */ 160 if ((row_ptr == 0) && (pixel_ptr == 0)) { 161 av_log(s->avctx, AV_LOG_ERROR, "encountered repeat block opcode (%02X) but no blocks rendered yet\n", 162 opcode & 0xF0); 163 return AVERROR_INVALIDDATA; 164 } 165 166 /* figure out where the previous block started */ 167 if (pixel_ptr == 0) 168 prev_block_ptr1 = 169 (row_ptr - s->avctx->width * 4) + s->avctx->width - 4; 170 else 171 prev_block_ptr1 = row_ptr + pixel_ptr - 4; 172 173 while (n_blocks--) { 174 block_ptr = row_ptr + pixel_ptr; 175 prev_block_ptr = prev_block_ptr1; 176 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 177 for (pixel_x = 0; pixel_x < 4; pixel_x++) { 178 pixels[block_ptr++] = pixels[prev_block_ptr++]; 179 } 180 block_ptr += row_inc; 181 prev_block_ptr += row_inc; 182 } 183 ADVANCE_BLOCK(); 184 } 185 break; 186 187 /* repeat previous pair of blocks n times */ 188 case 0x40: 189 case 0x50: 190 n_blocks = GET_BLOCK_COUNT(); 191 n_blocks *= 2; 192 193 /* sanity check */ 194 if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) { 195 av_log(s->avctx, AV_LOG_ERROR, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n", 196 opcode & 0xF0); 197 return AVERROR_INVALIDDATA; 198 } 199 200 /* figure out where the previous 2 blocks started */ 201 if (pixel_ptr == 0) 202 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + 203 s->avctx->width - 4 * 2; 204 else if (pixel_ptr == 4) 205 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc; 206 else 207 prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2; 208 209 if (pixel_ptr == 0) 210 prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc; 211 else 212 prev_block_ptr2 = row_ptr + pixel_ptr - 4; 213 214 prev_block_flag = 0; 215 while (n_blocks--) { 216 block_ptr = row_ptr + pixel_ptr; 217 if (prev_block_flag) 218 prev_block_ptr = prev_block_ptr2; 219 else 220 prev_block_ptr = prev_block_ptr1; 221 prev_block_flag = !prev_block_flag; 222 223 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 224 for (pixel_x = 0; pixel_x < 4; pixel_x++) { 225 pixels[block_ptr++] = pixels[prev_block_ptr++]; 226 } 227 block_ptr += row_inc; 228 prev_block_ptr += row_inc; 229 } 230 ADVANCE_BLOCK(); 231 } 232 break; 233 234 /* 1-color block encoding */ 235 case 0x60: 236 case 0x70: 237 n_blocks = GET_BLOCK_COUNT(); 238 pixel = bytestream2_get_byte(gb); 239 240 while (n_blocks--) { 241 block_ptr = row_ptr + pixel_ptr; 242 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 243 for (pixel_x = 0; pixel_x < 4; pixel_x++) { 244 pixels[block_ptr++] = pixel; 245 } 246 block_ptr += row_inc; 247 } 248 ADVANCE_BLOCK(); 249 } 250 break; 251 252 /* 2-color block encoding */ 253 case 0x80: 254 case 0x90: 255 n_blocks = (opcode & 0x0F) + 1; 256 257 /* figure out which color pair to use to paint the 2-color block */ 258 if ((opcode & 0xF0) == 0x80) { 259 /* fetch the next 2 colors from bytestream and store in next 260 * available entry in the color pair table */ 261 for (i = 0; i < CPAIR; i++) { 262 pixel = bytestream2_get_byte(gb); 263 color_table_index = CPAIR * color_pair_index + i; 264 s->color_pairs[color_table_index] = pixel; 265 } 266 /* this is the base index to use for this block */ 267 color_table_index = CPAIR * color_pair_index; 268 color_pair_index++; 269 /* wraparound */ 270 if (color_pair_index == COLORS_PER_TABLE) 271 color_pair_index = 0; 272 } else 273 color_table_index = CPAIR * bytestream2_get_byte(gb); 274 275 while (n_blocks--) { 276 color_flags = bytestream2_get_be16(gb); 277 flag_mask = 0x8000; 278 block_ptr = row_ptr + pixel_ptr; 279 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 280 for (pixel_x = 0; pixel_x < 4; pixel_x++) { 281 if (color_flags & flag_mask) 282 pixel = color_table_index + 1; 283 else 284 pixel = color_table_index; 285 flag_mask >>= 1; 286 pixels[block_ptr++] = s->color_pairs[pixel]; 287 } 288 block_ptr += row_inc; 289 } 290 ADVANCE_BLOCK(); 291 } 292 break; 293 294 /* 4-color block encoding */ 295 case 0xA0: 296 case 0xB0: 297 n_blocks = (opcode & 0x0F) + 1; 298 299 /* figure out which color quad to use to paint the 4-color block */ 300 if ((opcode & 0xF0) == 0xA0) { 301 /* fetch the next 4 colors from bytestream and store in next 302 * available entry in the color quad table */ 303 for (i = 0; i < CQUAD; i++) { 304 pixel = bytestream2_get_byte(gb); 305 color_table_index = CQUAD * color_quad_index + i; 306 s->color_quads[color_table_index] = pixel; 307 } 308 /* this is the base index to use for this block */ 309 color_table_index = CQUAD * color_quad_index; 310 color_quad_index++; 311 /* wraparound */ 312 if (color_quad_index == COLORS_PER_TABLE) 313 color_quad_index = 0; 314 } else 315 color_table_index = CQUAD * bytestream2_get_byte(gb); 316 317 while (n_blocks--) { 318 color_flags = bytestream2_get_be32(gb); 319 /* flag mask actually acts as a bit shift count here */ 320 flag_mask = 30; 321 block_ptr = row_ptr + pixel_ptr; 322 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 323 for (pixel_x = 0; pixel_x < 4; pixel_x++) { 324 pixel = color_table_index + 325 ((color_flags >> flag_mask) & 0x03); 326 flag_mask -= 2; 327 pixels[block_ptr++] = s->color_quads[pixel]; 328 } 329 block_ptr += row_inc; 330 } 331 ADVANCE_BLOCK(); 332 } 333 break; 334 335 /* 8-color block encoding */ 336 case 0xC0: 337 case 0xD0: 338 n_blocks = (opcode & 0x0F) + 1; 339 340 /* figure out which color octet to use to paint the 8-color block */ 341 if ((opcode & 0xF0) == 0xC0) { 342 /* fetch the next 8 colors from bytestream and store in next 343 * available entry in the color octet table */ 344 for (i = 0; i < COCTET; i++) { 345 pixel = bytestream2_get_byte(gb); 346 color_table_index = COCTET * color_octet_index + i; 347 s->color_octets[color_table_index] = pixel; 348 } 349 /* this is the base index to use for this block */ 350 color_table_index = COCTET * color_octet_index; 351 color_octet_index++; 352 /* wraparound */ 353 if (color_octet_index == COLORS_PER_TABLE) 354 color_octet_index = 0; 355 } else 356 color_table_index = COCTET * bytestream2_get_byte(gb); 357 358 while (n_blocks--) { 359 /* 360 For this input of 6 hex bytes: 361 01 23 45 67 89 AB 362 Mangle it to this output: 363 flags_a = xx012456, flags_b = xx89A37B 364 */ 365 /* build the color flags */ 366 int val1 = bytestream2_get_be16(gb); 367 int val2 = bytestream2_get_be16(gb); 368 int val3 = bytestream2_get_be16(gb); 369 color_flags_a = ((val1 & 0xFFF0) << 8) | (val2 >> 4); 370 color_flags_b = ((val3 & 0xFFF0) << 8) | 371 ((val1 & 0x0F) << 8) | ((val2 & 0x0F) << 4) | (val3 & 0x0F); 372 373 color_flags = color_flags_a; 374 /* flag mask actually acts as a bit shift count here */ 375 flag_mask = 21; 376 block_ptr = row_ptr + pixel_ptr; 377 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 378 /* reload flags at third row (iteration pixel_y == 2) */ 379 if (pixel_y == 2) { 380 color_flags = color_flags_b; 381 flag_mask = 21; 382 } 383 for (pixel_x = 0; pixel_x < 4; pixel_x++) { 384 pixel = color_table_index + 385 ((color_flags >> flag_mask) & 0x07); 386 flag_mask -= 3; 387 pixels[block_ptr++] = s->color_octets[pixel]; 388 } 389 block_ptr += row_inc; 390 } 391 ADVANCE_BLOCK(); 392 } 393 break; 394 395 /* 16-color block encoding (every pixel is a different color) */ 396 case 0xE0: 397 case 0xF0: 398 n_blocks = (opcode & 0x0F) + 1; 399 400 while (n_blocks--) { 401 block_ptr = row_ptr + pixel_ptr; 402 for (pixel_y = 0; pixel_y < 4; pixel_y++) { 403 for (pixel_x = 0; pixel_x < 4; pixel_x++) { 404 pixels[block_ptr++] = bytestream2_get_byte(gb); 405 } 406 block_ptr += row_inc; 407 } 408 ADVANCE_BLOCK(); 409 } 410 break; 411 } 412 } 413 414 return 0; 415} 416 417static av_cold int smc_decode_init(AVCodecContext *avctx) 418{ 419 SmcContext *s = avctx->priv_data; 420 421 s->avctx = avctx; 422 avctx->pix_fmt = AV_PIX_FMT_PAL8; 423 424 s->frame = av_frame_alloc(); 425 if (!s->frame) 426 return AVERROR(ENOMEM); 427 428 return 0; 429} 430 431static int smc_decode_frame(AVCodecContext *avctx, AVFrame *rframe, 432 int *got_frame, AVPacket *avpkt) 433{ 434 const uint8_t *buf = avpkt->data; 435 int buf_size = avpkt->size; 436 SmcContext *s = avctx->priv_data; 437 int ret; 438 int total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4); 439 440 if (total_blocks / 1024 > avpkt->size) 441 return AVERROR_INVALIDDATA; 442 443 bytestream2_init(&s->gb, buf, buf_size); 444 445 if ((ret = ff_reget_buffer(avctx, s->frame, 0)) < 0) 446 return ret; 447 448 s->frame->palette_has_changed = ff_copy_palette(s->pal, avpkt, avctx); 449 450 ret = smc_decode_stream(s); 451 if (ret < 0) 452 return ret; 453 454 *got_frame = 1; 455 if ((ret = av_frame_ref(rframe, s->frame)) < 0) 456 return ret; 457 458 /* always report that the buffer was completely consumed */ 459 return buf_size; 460} 461 462static av_cold int smc_decode_end(AVCodecContext *avctx) 463{ 464 SmcContext *s = avctx->priv_data; 465 466 av_frame_free(&s->frame); 467 468 return 0; 469} 470 471const FFCodec ff_smc_decoder = { 472 .p.name = "smc", 473 .p.long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"), 474 .p.type = AVMEDIA_TYPE_VIDEO, 475 .p.id = AV_CODEC_ID_SMC, 476 .priv_data_size = sizeof(SmcContext), 477 .init = smc_decode_init, 478 .close = smc_decode_end, 479 FF_CODEC_DECODE_CB(smc_decode_frame), 480 .p.capabilities = AV_CODEC_CAP_DR1, 481 .caps_internal = FF_CODEC_CAP_INIT_THREADSAFE, 482}; 483