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