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