annotate ffmpeg/libavcodec/smc.c @ 13:844d341cf643 tip

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