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