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
00035 #include "libavutil/intreadwrite.h"
00036 #include "avcodec.h"
00037 #include "bytestream.h"
00038 #define ALT_BITSTREAM_READER_LE
00039 #include "get_bits.h"
00040
00041 #include "libavutil/lzo.h"
00042
00043 #define RUNTIME_GAMMA 0
00044
00045 #define VGA__TAG MKTAG('V', 'G', 'A', ' ')
00046 #define PALT_TAG MKTAG('P', 'A', 'L', 'T')
00047 #define SHOT_TAG MKTAG('S', 'H', 'O', 'T')
00048 #define PALETTE_COUNT 256
00049 #define PALETTE_SIZE (PALETTE_COUNT * 3)
00050 #define PALETTES_MAX 256
00051
00052 typedef struct XanContext {
00053
00054 AVCodecContext *avctx;
00055 AVFrame last_frame;
00056 AVFrame current_frame;
00057
00058 const unsigned char *buf;
00059 int size;
00060
00061
00062 unsigned char *buffer1;
00063 int buffer1_size;
00064 unsigned char *buffer2;
00065 int buffer2_size;
00066
00067 unsigned *palettes;
00068 int palettes_count;
00069 int cur_palette;
00070
00071 int frame_size;
00072
00073 } XanContext;
00074
00075 static av_cold int xan_decode_init(AVCodecContext *avctx)
00076 {
00077 XanContext *s = avctx->priv_data;
00078
00079 s->avctx = avctx;
00080 s->frame_size = 0;
00081
00082 avctx->pix_fmt = PIX_FMT_PAL8;
00083
00084 s->buffer1_size = avctx->width * avctx->height;
00085 s->buffer1 = av_malloc(s->buffer1_size);
00086 if (!s->buffer1)
00087 return AVERROR(ENOMEM);
00088 s->buffer2_size = avctx->width * avctx->height;
00089 s->buffer2 = av_malloc(s->buffer2_size + 130);
00090 if (!s->buffer2) {
00091 av_freep(&s->buffer1);
00092 return AVERROR(ENOMEM);
00093 }
00094 avcodec_get_frame_defaults(&s->last_frame);
00095 avcodec_get_frame_defaults(&s->current_frame);
00096
00097 return 0;
00098 }
00099
00100 static int xan_huffman_decode(unsigned char *dest, int dest_len,
00101 const unsigned char *src, int src_len)
00102 {
00103 unsigned char byte = *src++;
00104 unsigned char ival = byte + 0x16;
00105 const unsigned char * ptr = src + byte*2;
00106 int ptr_len = src_len - 1 - byte*2;
00107 unsigned char val = ival;
00108 unsigned char *dest_end = dest + dest_len;
00109 GetBitContext gb;
00110
00111 if (ptr_len < 0)
00112 return AVERROR_INVALIDDATA;
00113
00114 init_get_bits(&gb, ptr, ptr_len * 8);
00115
00116 while (val != 0x16) {
00117 unsigned idx = val - 0x17 + get_bits1(&gb) * byte;
00118 if (idx >= 2 * byte)
00119 return -1;
00120 val = src[idx];
00121
00122 if (val < 0x16) {
00123 if (dest >= dest_end)
00124 return 0;
00125 *dest++ = val;
00126 val = ival;
00127 }
00128 }
00129
00130 return 0;
00131 }
00132
00138 static void xan_unpack(unsigned char *dest, int dest_len,
00139 const unsigned char *src, int src_len)
00140 {
00141 unsigned char opcode;
00142 int size;
00143 unsigned char *dest_org = dest;
00144 unsigned char *dest_end = dest + dest_len;
00145 const unsigned char *src_end = src + src_len;
00146
00147 while (dest < dest_end && src < src_end) {
00148 opcode = *src++;
00149
00150 if (opcode < 0xe0) {
00151 int size2, back;
00152 if ((opcode & 0x80) == 0) {
00153 size = opcode & 3;
00154
00155 back = ((opcode & 0x60) << 3) + *src++ + 1;
00156 size2 = ((opcode & 0x1c) >> 2) + 3;
00157 } else if ((opcode & 0x40) == 0) {
00158 size = *src >> 6;
00159
00160 back = (bytestream_get_be16(&src) & 0x3fff) + 1;
00161 size2 = (opcode & 0x3f) + 4;
00162 } else {
00163 size = opcode & 3;
00164
00165 back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
00166 size2 = ((opcode & 0x0c) << 6) + *src++ + 5;
00167 }
00168
00169 if (dest_end - dest < size + size2 ||
00170 dest + size - dest_org < back ||
00171 src_end - src < size)
00172 return;
00173 memcpy(dest, src, size); dest += size; src += size;
00174 av_memcpy_backptr(dest, back, size2);
00175 dest += size2;
00176 } else {
00177 int finish = opcode >= 0xfc;
00178 size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
00179
00180 if (dest_end - dest < size || src_end - src < size)
00181 return;
00182 memcpy(dest, src, size); dest += size; src += size;
00183 if (finish)
00184 return;
00185 }
00186 }
00187 }
00188
00189 static inline void xan_wc3_output_pixel_run(XanContext *s,
00190 const unsigned char *pixel_buffer, int x, int y, int pixel_count)
00191 {
00192 int stride;
00193 int line_inc;
00194 int index;
00195 int current_x;
00196 int width = s->avctx->width;
00197 unsigned char *palette_plane;
00198
00199 palette_plane = s->current_frame.data[0];
00200 stride = s->current_frame.linesize[0];
00201 line_inc = stride - width;
00202 index = y * stride + x;
00203 current_x = x;
00204 while (pixel_count && index < s->frame_size) {
00205 int count = FFMIN(pixel_count, width - current_x);
00206 memcpy(palette_plane + index, pixel_buffer, count);
00207 pixel_count -= count;
00208 index += count;
00209 pixel_buffer += count;
00210 current_x += count;
00211
00212 if (current_x >= width) {
00213 index += line_inc;
00214 current_x = 0;
00215 }
00216 }
00217 }
00218
00219 static inline void xan_wc3_copy_pixel_run(XanContext *s, int x, int y,
00220 int pixel_count, int motion_x,
00221 int motion_y)
00222 {
00223 int stride;
00224 int line_inc;
00225 int curframe_index, prevframe_index;
00226 int curframe_x, prevframe_x;
00227 int width = s->avctx->width;
00228 unsigned char *palette_plane, *prev_palette_plane;
00229
00230 if (y + motion_y < 0 || y + motion_y >= s->avctx->height ||
00231 x + motion_x < 0 || x + motion_x >= s->avctx->width)
00232 return;
00233
00234 palette_plane = s->current_frame.data[0];
00235 prev_palette_plane = s->last_frame.data[0];
00236 if (!prev_palette_plane)
00237 prev_palette_plane = palette_plane;
00238 stride = s->current_frame.linesize[0];
00239 line_inc = stride - width;
00240 curframe_index = y * stride + x;
00241 curframe_x = x;
00242 prevframe_index = (y + motion_y) * stride + x + motion_x;
00243 prevframe_x = x + motion_x;
00244 while (pixel_count &&
00245 curframe_index < s->frame_size &&
00246 prevframe_index < s->frame_size) {
00247 int count = FFMIN3(pixel_count, width - curframe_x,
00248 width - prevframe_x);
00249
00250 memcpy(palette_plane + curframe_index,
00251 prev_palette_plane + prevframe_index, count);
00252 pixel_count -= count;
00253 curframe_index += count;
00254 prevframe_index += count;
00255 curframe_x += count;
00256 prevframe_x += count;
00257
00258 if (curframe_x >= width) {
00259 curframe_index += line_inc;
00260 curframe_x = 0;
00261 }
00262
00263 if (prevframe_x >= width) {
00264 prevframe_index += line_inc;
00265 prevframe_x = 0;
00266 }
00267 }
00268 }
00269
00270 static int xan_wc3_decode_frame(XanContext *s) {
00271
00272 int width = s->avctx->width;
00273 int height = s->avctx->height;
00274 int total_pixels = width * height;
00275 unsigned char opcode;
00276 unsigned char flag = 0;
00277 int size = 0;
00278 int motion_x, motion_y;
00279 int x, y;
00280
00281 unsigned char *opcode_buffer = s->buffer1;
00282 unsigned char *opcode_buffer_end = s->buffer1 + s->buffer1_size;
00283 int opcode_buffer_size = s->buffer1_size;
00284 const unsigned char *imagedata_buffer = s->buffer2;
00285
00286
00287 const unsigned char *huffman_segment;
00288 const unsigned char *size_segment;
00289 const unsigned char *vector_segment;
00290 const unsigned char *imagedata_segment;
00291 int huffman_offset, size_offset, vector_offset, imagedata_offset,
00292 imagedata_size;
00293
00294 if (s->size < 8)
00295 return AVERROR_INVALIDDATA;
00296
00297 huffman_offset = AV_RL16(&s->buf[0]);
00298 size_offset = AV_RL16(&s->buf[2]);
00299 vector_offset = AV_RL16(&s->buf[4]);
00300 imagedata_offset = AV_RL16(&s->buf[6]);
00301
00302 if (huffman_offset >= s->size ||
00303 size_offset >= s->size ||
00304 vector_offset >= s->size ||
00305 imagedata_offset >= s->size)
00306 return AVERROR_INVALIDDATA;
00307
00308 huffman_segment = s->buf + huffman_offset;
00309 size_segment = s->buf + size_offset;
00310 vector_segment = s->buf + vector_offset;
00311 imagedata_segment = s->buf + imagedata_offset;
00312
00313 if (xan_huffman_decode(opcode_buffer, opcode_buffer_size,
00314 huffman_segment, s->size - huffman_offset) < 0)
00315 return AVERROR_INVALIDDATA;
00316
00317 if (imagedata_segment[0] == 2) {
00318 xan_unpack(s->buffer2, s->buffer2_size,
00319 &imagedata_segment[1], s->size - imagedata_offset - 1);
00320 imagedata_size = s->buffer2_size;
00321 } else {
00322 imagedata_size = s->size - imagedata_offset - 1;
00323 imagedata_buffer = &imagedata_segment[1];
00324 }
00325
00326
00327 x = y = 0;
00328 while (total_pixels && opcode_buffer < opcode_buffer_end) {
00329
00330 opcode = *opcode_buffer++;
00331 size = 0;
00332
00333 switch (opcode) {
00334
00335 case 0:
00336 flag ^= 1;
00337 continue;
00338
00339 case 1:
00340 case 2:
00341 case 3:
00342 case 4:
00343 case 5:
00344 case 6:
00345 case 7:
00346 case 8:
00347 size = opcode;
00348 break;
00349
00350 case 12:
00351 case 13:
00352 case 14:
00353 case 15:
00354 case 16:
00355 case 17:
00356 case 18:
00357 size += (opcode - 10);
00358 break;
00359
00360 case 9:
00361 case 19:
00362 size = *size_segment++;
00363 break;
00364
00365 case 10:
00366 case 20:
00367 size = AV_RB16(&size_segment[0]);
00368 size_segment += 2;
00369 break;
00370
00371 case 11:
00372 case 21:
00373 size = AV_RB24(size_segment);
00374 size_segment += 3;
00375 break;
00376 }
00377
00378 if (size > total_pixels)
00379 break;
00380
00381 if (opcode < 12) {
00382 flag ^= 1;
00383 if (flag) {
00384
00385 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
00386 } else {
00387
00388 if (imagedata_size < size)
00389 break;
00390 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
00391 imagedata_buffer += size;
00392 imagedata_size -= size;
00393 }
00394 } else {
00395
00396 motion_x = sign_extend(*vector_segment >> 4, 4);
00397 motion_y = sign_extend(*vector_segment & 0xF, 4);
00398 vector_segment++;
00399
00400
00401 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
00402
00403 flag = 0;
00404 }
00405
00406
00407 total_pixels -= size;
00408 y += (x + size) / width;
00409 x = (x + size) % width;
00410 }
00411 return 0;
00412 }
00413
00414 #if RUNTIME_GAMMA
00415 static inline unsigned mul(unsigned a, unsigned b)
00416 {
00417 return (a * b) >> 16;
00418 }
00419
00420 static inline unsigned pow4(unsigned a)
00421 {
00422 unsigned square = mul(a, a);
00423 return mul(square, square);
00424 }
00425
00426 static inline unsigned pow5(unsigned a)
00427 {
00428 return mul(pow4(a), a);
00429 }
00430
00431 static uint8_t gamma_corr(uint8_t in) {
00432 unsigned lo, hi = 0xff40, target;
00433 int i = 15;
00434 in = (in << 2) | (in >> 6);
00435
00436
00437
00438
00439
00440 lo = target = in << 8;
00441 do {
00442 unsigned mid = (lo + hi) >> 1;
00443 unsigned pow = pow5(mid);
00444 if (pow > target) hi = mid;
00445 else lo = mid;
00446 } while (--i);
00447 return (pow4((lo + hi) >> 1) + 0x80) >> 8;
00448 }
00449 #else
00450
00461 static const uint8_t gamma_lookup[256] = {
00462 0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C,
00463 0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50,
00464 0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71,
00465 0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F,
00466 0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC,
00467 0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8,
00468 0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3,
00469 0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD,
00470 0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D,
00471 0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51,
00472 0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72,
00473 0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90,
00474 0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD,
00475 0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9,
00476 0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4,
00477 0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD,
00478 0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E,
00479 0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52,
00480 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73,
00481 0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91,
00482 0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE,
00483 0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA,
00484 0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4,
00485 0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD,
00486 0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F,
00487 0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53,
00488 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74,
00489 0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92,
00490 0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF,
00491 0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB,
00492 0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5,
00493 0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD
00494 };
00495 #endif
00496
00497 static int xan_decode_frame(AVCodecContext *avctx,
00498 void *data, int *data_size,
00499 AVPacket *avpkt)
00500 {
00501 const uint8_t *buf = avpkt->data;
00502 int ret, buf_size = avpkt->size;
00503 XanContext *s = avctx->priv_data;
00504
00505 if (avctx->codec->id == CODEC_ID_XAN_WC3) {
00506 const uint8_t *buf_end = buf + buf_size;
00507 int tag = 0;
00508 while (buf_end - buf > 8 && tag != VGA__TAG) {
00509 unsigned *tmpptr;
00510 uint32_t new_pal;
00511 int size;
00512 int i;
00513 tag = bytestream_get_le32(&buf);
00514 size = bytestream_get_be32(&buf);
00515 size = FFMIN(size, buf_end - buf);
00516 switch (tag) {
00517 case PALT_TAG:
00518 if (size < PALETTE_SIZE)
00519 return AVERROR_INVALIDDATA;
00520 if (s->palettes_count >= PALETTES_MAX)
00521 return AVERROR_INVALIDDATA;
00522 tmpptr = av_realloc(s->palettes,
00523 (s->palettes_count + 1) * AVPALETTE_SIZE);
00524 if (!tmpptr)
00525 return AVERROR(ENOMEM);
00526 s->palettes = tmpptr;
00527 tmpptr += s->palettes_count * AVPALETTE_COUNT;
00528 for (i = 0; i < PALETTE_COUNT; i++) {
00529 #if RUNTIME_GAMMA
00530 int r = gamma_corr(*buf++);
00531 int g = gamma_corr(*buf++);
00532 int b = gamma_corr(*buf++);
00533 #else
00534 int r = gamma_lookup[*buf++];
00535 int g = gamma_lookup[*buf++];
00536 int b = gamma_lookup[*buf++];
00537 #endif
00538 *tmpptr++ = (r << 16) | (g << 8) | b;
00539 }
00540 s->palettes_count++;
00541 break;
00542 case SHOT_TAG:
00543 if (size < 4)
00544 return AVERROR_INVALIDDATA;
00545 new_pal = bytestream_get_le32(&buf);
00546 if (new_pal < s->palettes_count) {
00547 s->cur_palette = new_pal;
00548 } else
00549 av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n");
00550 break;
00551 case VGA__TAG:
00552 break;
00553 default:
00554 buf += size;
00555 break;
00556 }
00557 }
00558 buf_size = buf_end - buf;
00559 }
00560 if (s->palettes_count <= 0) {
00561 av_log(s->avctx, AV_LOG_ERROR, "No palette found\n");
00562 return AVERROR_INVALIDDATA;
00563 }
00564
00565 if ((ret = avctx->get_buffer(avctx, &s->current_frame))) {
00566 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n");
00567 return ret;
00568 }
00569 s->current_frame.reference = 3;
00570
00571 if (!s->frame_size)
00572 s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
00573
00574 memcpy(s->current_frame.data[1],
00575 s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE);
00576
00577 s->buf = buf;
00578 s->size = buf_size;
00579
00580 if (xan_wc3_decode_frame(s) < 0)
00581 return AVERROR_INVALIDDATA;
00582
00583
00584 if (s->last_frame.data[0])
00585 avctx->release_buffer(avctx, &s->last_frame);
00586
00587 *data_size = sizeof(AVFrame);
00588 *(AVFrame*)data = s->current_frame;
00589
00590
00591 FFSWAP(AVFrame, s->current_frame, s->last_frame);
00592
00593
00594 return buf_size;
00595 }
00596
00597 static av_cold int xan_decode_end(AVCodecContext *avctx)
00598 {
00599 XanContext *s = avctx->priv_data;
00600
00601
00602 if (s->last_frame.data[0])
00603 avctx->release_buffer(avctx, &s->last_frame);
00604 if (s->current_frame.data[0])
00605 avctx->release_buffer(avctx, &s->current_frame);
00606
00607 av_freep(&s->buffer1);
00608 av_freep(&s->buffer2);
00609 av_freep(&s->palettes);
00610
00611 return 0;
00612 }
00613
00614 AVCodec ff_xan_wc3_decoder = {
00615 .name = "xan_wc3",
00616 .type = AVMEDIA_TYPE_VIDEO,
00617 .id = CODEC_ID_XAN_WC3,
00618 .priv_data_size = sizeof(XanContext),
00619 .init = xan_decode_init,
00620 .close = xan_decode_end,
00621 .decode = xan_decode_frame,
00622 .capabilities = CODEC_CAP_DR1,
00623 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
00624 };