00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <string.h>
00034 #include <unistd.h>
00035
00036 #include "libavutil/intreadwrite.h"
00037 #include "avcodec.h"
00038
00039 #define CPAIR 2
00040 #define CQUAD 4
00041 #define COCTET 8
00042
00043 #define COLORS_PER_TABLE 256
00044
00045 typedef struct SmcContext {
00046
00047 AVCodecContext *avctx;
00048 AVFrame frame;
00049
00050 const unsigned char *buf;
00051 int size;
00052
00053
00054 unsigned char color_pairs[COLORS_PER_TABLE * CPAIR];
00055 unsigned char color_quads[COLORS_PER_TABLE * CQUAD];
00056 unsigned char color_octets[COLORS_PER_TABLE * COCTET];
00057
00058 } SmcContext;
00059
00060 #define GET_BLOCK_COUNT() \
00061 (opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F);
00062
00063 #define ADVANCE_BLOCK() \
00064 { \
00065 pixel_ptr += 4; \
00066 if (pixel_ptr >= width) \
00067 { \
00068 pixel_ptr = 0; \
00069 row_ptr += stride * 4; \
00070 } \
00071 total_blocks--; \
00072 if (total_blocks < 0) \
00073 { \
00074 av_log(s->avctx, AV_LOG_INFO, "warning: block counter just went negative (this should not happen)\n"); \
00075 return; \
00076 } \
00077 }
00078
00079 static void smc_decode_stream(SmcContext *s)
00080 {
00081 int width = s->avctx->width;
00082 int height = s->avctx->height;
00083 int stride = s->frame.linesize[0];
00084 int i;
00085 int stream_ptr = 0;
00086 int chunk_size;
00087 unsigned char opcode;
00088 int n_blocks;
00089 unsigned int color_flags;
00090 unsigned int color_flags_a;
00091 unsigned int color_flags_b;
00092 unsigned int flag_mask;
00093
00094 unsigned char *pixels = s->frame.data[0];
00095
00096 int image_size = height * s->frame.linesize[0];
00097 int row_ptr = 0;
00098 int pixel_ptr = 0;
00099 int pixel_x, pixel_y;
00100 int row_inc = stride - 4;
00101 int block_ptr;
00102 int prev_block_ptr;
00103 int prev_block_ptr1, prev_block_ptr2;
00104 int prev_block_flag;
00105 int total_blocks;
00106 int color_table_index;
00107 int pixel;
00108
00109 int color_pair_index = 0;
00110 int color_quad_index = 0;
00111 int color_octet_index = 0;
00112
00113
00114 memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE);
00115 if (s->avctx->palctrl->palette_changed) {
00116 s->frame.palette_has_changed = 1;
00117 s->avctx->palctrl->palette_changed = 0;
00118 }
00119
00120 chunk_size = AV_RB32(&s->buf[stream_ptr]) & 0x00FFFFFF;
00121 stream_ptr += 4;
00122 if (chunk_size != s->size)
00123 av_log(s->avctx, AV_LOG_INFO, "warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n",
00124 chunk_size, s->size);
00125
00126 chunk_size = s->size;
00127 total_blocks = ((s->avctx->width + 3) / 4) * ((s->avctx->height + 3) / 4);
00128
00129
00130 while (total_blocks) {
00131
00132
00133 if (stream_ptr > chunk_size) {
00134 av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n",
00135 stream_ptr, chunk_size);
00136 return;
00137 }
00138
00139 if (row_ptr >= image_size) {
00140 av_log(s->avctx, AV_LOG_INFO, "SMC decoder just went out of bounds (row ptr = %d, height = %d)\n",
00141 row_ptr, image_size);
00142 return;
00143 }
00144
00145 opcode = s->buf[stream_ptr++];
00146 switch (opcode & 0xF0) {
00147
00148 case 0x00:
00149 case 0x10:
00150 n_blocks = GET_BLOCK_COUNT();
00151 while (n_blocks--) {
00152 ADVANCE_BLOCK();
00153 }
00154 break;
00155
00156
00157 case 0x20:
00158 case 0x30:
00159 n_blocks = GET_BLOCK_COUNT();
00160
00161
00162 if ((row_ptr == 0) && (pixel_ptr == 0)) {
00163 av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but no blocks rendered yet\n",
00164 opcode & 0xF0);
00165 break;
00166 }
00167
00168
00169 if (pixel_ptr == 0)
00170 prev_block_ptr1 =
00171 (row_ptr - s->avctx->width * 4) + s->avctx->width - 4;
00172 else
00173 prev_block_ptr1 = row_ptr + pixel_ptr - 4;
00174
00175 while (n_blocks--) {
00176 block_ptr = row_ptr + pixel_ptr;
00177 prev_block_ptr = prev_block_ptr1;
00178 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00179 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
00180 pixels[block_ptr++] = pixels[prev_block_ptr++];
00181 }
00182 block_ptr += row_inc;
00183 prev_block_ptr += row_inc;
00184 }
00185 ADVANCE_BLOCK();
00186 }
00187 break;
00188
00189
00190 case 0x40:
00191 case 0x50:
00192 n_blocks = GET_BLOCK_COUNT();
00193 n_blocks *= 2;
00194
00195
00196 if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) {
00197 av_log(s->avctx, AV_LOG_INFO, "encountered repeat block opcode (%02X) but not enough blocks rendered yet\n",
00198 opcode & 0xF0);
00199 break;
00200 }
00201
00202
00203 if (pixel_ptr == 0)
00204 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) +
00205 s->avctx->width - 4 * 2;
00206 else if (pixel_ptr == 4)
00207 prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc;
00208 else
00209 prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2;
00210
00211 if (pixel_ptr == 0)
00212 prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc;
00213 else
00214 prev_block_ptr2 = row_ptr + pixel_ptr - 4;
00215
00216 prev_block_flag = 0;
00217 while (n_blocks--) {
00218 block_ptr = row_ptr + pixel_ptr;
00219 if (prev_block_flag)
00220 prev_block_ptr = prev_block_ptr2;
00221 else
00222 prev_block_ptr = prev_block_ptr1;
00223 prev_block_flag = !prev_block_flag;
00224
00225 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00226 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
00227 pixels[block_ptr++] = pixels[prev_block_ptr++];
00228 }
00229 block_ptr += row_inc;
00230 prev_block_ptr += row_inc;
00231 }
00232 ADVANCE_BLOCK();
00233 }
00234 break;
00235
00236
00237 case 0x60:
00238 case 0x70:
00239 n_blocks = GET_BLOCK_COUNT();
00240 pixel = s->buf[stream_ptr++];
00241
00242 while (n_blocks--) {
00243 block_ptr = row_ptr + pixel_ptr;
00244 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00245 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
00246 pixels[block_ptr++] = pixel;
00247 }
00248 block_ptr += row_inc;
00249 }
00250 ADVANCE_BLOCK();
00251 }
00252 break;
00253
00254
00255 case 0x80:
00256 case 0x90:
00257 n_blocks = (opcode & 0x0F) + 1;
00258
00259
00260 if ((opcode & 0xF0) == 0x80) {
00261
00262
00263 for (i = 0; i < CPAIR; i++) {
00264 pixel = s->buf[stream_ptr++];
00265 color_table_index = CPAIR * color_pair_index + i;
00266 s->color_pairs[color_table_index] = pixel;
00267 }
00268
00269 color_table_index = CPAIR * color_pair_index;
00270 color_pair_index++;
00271
00272 if (color_pair_index == COLORS_PER_TABLE)
00273 color_pair_index = 0;
00274 } else
00275 color_table_index = CPAIR * s->buf[stream_ptr++];
00276
00277 while (n_blocks--) {
00278 color_flags = AV_RB16(&s->buf[stream_ptr]);
00279 stream_ptr += 2;
00280 flag_mask = 0x8000;
00281 block_ptr = row_ptr + pixel_ptr;
00282 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00283 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
00284 if (color_flags & flag_mask)
00285 pixel = color_table_index + 1;
00286 else
00287 pixel = color_table_index;
00288 flag_mask >>= 1;
00289 pixels[block_ptr++] = s->color_pairs[pixel];
00290 }
00291 block_ptr += row_inc;
00292 }
00293 ADVANCE_BLOCK();
00294 }
00295 break;
00296
00297
00298 case 0xA0:
00299 case 0xB0:
00300 n_blocks = (opcode & 0x0F) + 1;
00301
00302
00303 if ((opcode & 0xF0) == 0xA0) {
00304
00305
00306 for (i = 0; i < CQUAD; i++) {
00307 pixel = s->buf[stream_ptr++];
00308 color_table_index = CQUAD * color_quad_index + i;
00309 s->color_quads[color_table_index] = pixel;
00310 }
00311
00312 color_table_index = CQUAD * color_quad_index;
00313 color_quad_index++;
00314
00315 if (color_quad_index == COLORS_PER_TABLE)
00316 color_quad_index = 0;
00317 } else
00318 color_table_index = CQUAD * s->buf[stream_ptr++];
00319
00320 while (n_blocks--) {
00321 color_flags = AV_RB32(&s->buf[stream_ptr]);
00322 stream_ptr += 4;
00323
00324 flag_mask = 30;
00325 block_ptr = row_ptr + pixel_ptr;
00326 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00327 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
00328 pixel = color_table_index +
00329 ((color_flags >> flag_mask) & 0x03);
00330 flag_mask -= 2;
00331 pixels[block_ptr++] = s->color_quads[pixel];
00332 }
00333 block_ptr += row_inc;
00334 }
00335 ADVANCE_BLOCK();
00336 }
00337 break;
00338
00339
00340 case 0xC0:
00341 case 0xD0:
00342 n_blocks = (opcode & 0x0F) + 1;
00343
00344
00345 if ((opcode & 0xF0) == 0xC0) {
00346
00347
00348 for (i = 0; i < COCTET; i++) {
00349 pixel = s->buf[stream_ptr++];
00350 color_table_index = COCTET * color_octet_index + i;
00351 s->color_octets[color_table_index] = pixel;
00352 }
00353
00354 color_table_index = COCTET * color_octet_index;
00355 color_octet_index++;
00356
00357 if (color_octet_index == COLORS_PER_TABLE)
00358 color_octet_index = 0;
00359 } else
00360 color_table_index = COCTET * s->buf[stream_ptr++];
00361
00362 while (n_blocks--) {
00363
00364
00365
00366
00367
00368
00369
00370 color_flags_a = color_flags_b = 0;
00371 color_flags_a =
00372 (s->buf[stream_ptr + 0] << 16) |
00373 ((s->buf[stream_ptr + 1] & 0xF0) << 8) |
00374 ((s->buf[stream_ptr + 2] & 0xF0) << 4) |
00375 ((s->buf[stream_ptr + 2] & 0x0F) << 4) |
00376 ((s->buf[stream_ptr + 3] & 0xF0) >> 4);
00377 color_flags_b =
00378 (s->buf[stream_ptr + 4] << 16) |
00379 ((s->buf[stream_ptr + 5] & 0xF0) << 8) |
00380 ((s->buf[stream_ptr + 1] & 0x0F) << 8) |
00381 ((s->buf[stream_ptr + 3] & 0x0F) << 4) |
00382 (s->buf[stream_ptr + 5] & 0x0F);
00383 stream_ptr += 6;
00384
00385 color_flags = color_flags_a;
00386
00387 flag_mask = 21;
00388 block_ptr = row_ptr + pixel_ptr;
00389 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00390
00391 if (pixel_y == 2) {
00392 color_flags = color_flags_b;
00393 flag_mask = 21;
00394 }
00395 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
00396 pixel = color_table_index +
00397 ((color_flags >> flag_mask) & 0x07);
00398 flag_mask -= 3;
00399 pixels[block_ptr++] = s->color_octets[pixel];
00400 }
00401 block_ptr += row_inc;
00402 }
00403 ADVANCE_BLOCK();
00404 }
00405 break;
00406
00407
00408 case 0xE0:
00409 n_blocks = (opcode & 0x0F) + 1;
00410
00411 while (n_blocks--) {
00412 block_ptr = row_ptr + pixel_ptr;
00413 for (pixel_y = 0; pixel_y < 4; pixel_y++) {
00414 for (pixel_x = 0; pixel_x < 4; pixel_x++) {
00415 pixels[block_ptr++] = s->buf[stream_ptr++];
00416 }
00417 block_ptr += row_inc;
00418 }
00419 ADVANCE_BLOCK();
00420 }
00421 break;
00422
00423 case 0xF0:
00424 av_log(s->avctx, AV_LOG_INFO, "0xF0 opcode seen in SMC chunk (contact the developers)\n");
00425 break;
00426 }
00427 }
00428 }
00429
00430 static av_cold int smc_decode_init(AVCodecContext *avctx)
00431 {
00432 SmcContext *s = avctx->priv_data;
00433
00434 s->avctx = avctx;
00435 avctx->pix_fmt = PIX_FMT_PAL8;
00436
00437 s->frame.data[0] = NULL;
00438
00439 return 0;
00440 }
00441
00442 static int smc_decode_frame(AVCodecContext *avctx,
00443 void *data, int *data_size,
00444 const uint8_t *buf, int buf_size)
00445 {
00446 SmcContext *s = avctx->priv_data;
00447
00448 s->buf = buf;
00449 s->size = buf_size;
00450
00451 s->frame.reference = 1;
00452 s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE |
00453 FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE;
00454 if (avctx->reget_buffer(avctx, &s->frame)) {
00455 av_log(s->avctx, AV_LOG_ERROR, "reget_buffer() failed\n");
00456 return -1;
00457 }
00458
00459 smc_decode_stream(s);
00460
00461 *data_size = sizeof(AVFrame);
00462 *(AVFrame*)data = s->frame;
00463
00464
00465 return buf_size;
00466 }
00467
00468 static av_cold int smc_decode_end(AVCodecContext *avctx)
00469 {
00470 SmcContext *s = avctx->priv_data;
00471
00472 if (s->frame.data[0])
00473 avctx->release_buffer(avctx, &s->frame);
00474
00475 return 0;
00476 }
00477
00478 AVCodec smc_decoder = {
00479 "smc",
00480 CODEC_TYPE_VIDEO,
00481 CODEC_ID_SMC,
00482 sizeof(SmcContext),
00483 smc_decode_init,
00484 NULL,
00485 smc_decode_end,
00486 smc_decode_frame,
00487 CODEC_CAP_DR1,
00488 .long_name = NULL_IF_CONFIG_SMALL("QuickTime Graphics (SMC)"),
00489 };