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