Libav 0.7.1
|
00001 /* 00002 * Wing Commander/Xan Video Decoder 00003 * Copyright (C) 2003 the ffmpeg project 00004 * 00005 * This file is part of Libav. 00006 * 00007 * Libav is free software; you can redistribute it and/or 00008 * modify it under the terms of the GNU Lesser General Public 00009 * License as published by the Free Software Foundation; either 00010 * version 2.1 of the License, or (at your option) any later version. 00011 * 00012 * Libav is distributed in the hope that it will be useful, 00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00015 * Lesser General Public License for more details. 00016 * 00017 * You should have received a copy of the GNU Lesser General Public 00018 * License along with Libav; if not, write to the Free Software 00019 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 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 // for av_memcpy_backptr 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 /* scratch space */ 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 00095 return 0; 00096 } 00097 00098 static int xan_huffman_decode(unsigned char *dest, int dest_len, 00099 const unsigned char *src, int src_len) 00100 { 00101 unsigned char byte = *src++; 00102 unsigned char ival = byte + 0x16; 00103 const unsigned char * ptr = src + byte*2; 00104 int ptr_len = src_len - 1 - byte*2; 00105 unsigned char val = ival; 00106 unsigned char *dest_end = dest + dest_len; 00107 GetBitContext gb; 00108 00109 if (ptr_len < 0) 00110 return AVERROR_INVALIDDATA; 00111 00112 init_get_bits(&gb, ptr, ptr_len * 8); 00113 00114 while ( val != 0x16 ) { 00115 val = src[val - 0x17 + get_bits1(&gb) * byte]; 00116 00117 if ( val < 0x16 ) { 00118 if (dest >= dest_end) 00119 return 0; 00120 *dest++ = val; 00121 val = ival; 00122 } 00123 } 00124 00125 return 0; 00126 } 00127 00133 static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len) 00134 { 00135 unsigned char opcode; 00136 int size; 00137 unsigned char *dest_end = dest + dest_len; 00138 00139 while (dest < dest_end) { 00140 opcode = *src++; 00141 00142 if (opcode < 0xe0) { 00143 int size2, back; 00144 if ( (opcode & 0x80) == 0 ) { 00145 00146 size = opcode & 3; 00147 00148 back = ((opcode & 0x60) << 3) + *src++ + 1; 00149 size2 = ((opcode & 0x1c) >> 2) + 3; 00150 00151 } else if ( (opcode & 0x40) == 0 ) { 00152 00153 size = *src >> 6; 00154 00155 back = (bytestream_get_be16(&src) & 0x3fff) + 1; 00156 size2 = (opcode & 0x3f) + 4; 00157 00158 } else { 00159 00160 size = opcode & 3; 00161 00162 back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1; 00163 size2 = ((opcode & 0x0c) << 6) + *src++ + 5; 00164 if (size + size2 > dest_end - dest) 00165 return; 00166 } 00167 memcpy(dest, src, size); dest += size; src += size; 00168 av_memcpy_backptr(dest, back, size2); 00169 dest += size2; 00170 } else { 00171 int finish = opcode >= 0xfc; 00172 size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4; 00173 00174 memcpy(dest, src, size); dest += size; src += size; 00175 if (finish) 00176 return; 00177 } 00178 } 00179 } 00180 00181 static inline void xan_wc3_output_pixel_run(XanContext *s, 00182 const unsigned char *pixel_buffer, int x, int y, int pixel_count) 00183 { 00184 int stride; 00185 int line_inc; 00186 int index; 00187 int current_x; 00188 int width = s->avctx->width; 00189 unsigned char *palette_plane; 00190 00191 palette_plane = s->current_frame.data[0]; 00192 stride = s->current_frame.linesize[0]; 00193 line_inc = stride - width; 00194 index = y * stride + x; 00195 current_x = x; 00196 while(pixel_count && (index < s->frame_size)) { 00197 int count = FFMIN(pixel_count, width - current_x); 00198 memcpy(palette_plane + index, pixel_buffer, count); 00199 pixel_count -= count; 00200 index += count; 00201 pixel_buffer += count; 00202 current_x += count; 00203 00204 if (current_x >= width) { 00205 index += line_inc; 00206 current_x = 0; 00207 } 00208 } 00209 } 00210 00211 static inline void xan_wc3_copy_pixel_run(XanContext *s, 00212 int x, int y, int pixel_count, int motion_x, int motion_y) 00213 { 00214 int stride; 00215 int line_inc; 00216 int curframe_index, prevframe_index; 00217 int curframe_x, prevframe_x; 00218 int width = s->avctx->width; 00219 unsigned char *palette_plane, *prev_palette_plane; 00220 00221 palette_plane = s->current_frame.data[0]; 00222 prev_palette_plane = s->last_frame.data[0]; 00223 stride = s->current_frame.linesize[0]; 00224 line_inc = stride - width; 00225 curframe_index = y * stride + x; 00226 curframe_x = x; 00227 prevframe_index = (y + motion_y) * stride + x + motion_x; 00228 prevframe_x = x + motion_x; 00229 while(pixel_count && (curframe_index < s->frame_size)) { 00230 int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x); 00231 00232 memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count); 00233 pixel_count -= count; 00234 curframe_index += count; 00235 prevframe_index += count; 00236 curframe_x += count; 00237 prevframe_x += count; 00238 00239 if (curframe_x >= width) { 00240 curframe_index += line_inc; 00241 curframe_x = 0; 00242 } 00243 00244 if (prevframe_x >= width) { 00245 prevframe_index += line_inc; 00246 prevframe_x = 0; 00247 } 00248 } 00249 } 00250 00251 static int xan_wc3_decode_frame(XanContext *s) { 00252 00253 int width = s->avctx->width; 00254 int height = s->avctx->height; 00255 int total_pixels = width * height; 00256 unsigned char opcode; 00257 unsigned char flag = 0; 00258 int size = 0; 00259 int motion_x, motion_y; 00260 int x, y; 00261 00262 unsigned char *opcode_buffer = s->buffer1; 00263 int opcode_buffer_size = s->buffer1_size; 00264 const unsigned char *imagedata_buffer = s->buffer2; 00265 00266 /* pointers to segments inside the compressed chunk */ 00267 const unsigned char *huffman_segment; 00268 const unsigned char *size_segment; 00269 const unsigned char *vector_segment; 00270 const unsigned char *imagedata_segment; 00271 int huffman_offset, size_offset, vector_offset, imagedata_offset; 00272 00273 if (s->size < 8) 00274 return AVERROR_INVALIDDATA; 00275 00276 huffman_offset = AV_RL16(&s->buf[0]); 00277 size_offset = AV_RL16(&s->buf[2]); 00278 vector_offset = AV_RL16(&s->buf[4]); 00279 imagedata_offset = AV_RL16(&s->buf[6]); 00280 00281 if (huffman_offset >= s->size || 00282 size_offset >= s->size || 00283 vector_offset >= s->size || 00284 imagedata_offset >= s->size) 00285 return AVERROR_INVALIDDATA; 00286 00287 huffman_segment = s->buf + huffman_offset; 00288 size_segment = s->buf + size_offset; 00289 vector_segment = s->buf + vector_offset; 00290 imagedata_segment = s->buf + imagedata_offset; 00291 00292 if (xan_huffman_decode(opcode_buffer, opcode_buffer_size, 00293 huffman_segment, s->size - huffman_offset) < 0) 00294 return AVERROR_INVALIDDATA; 00295 00296 if (imagedata_segment[0] == 2) 00297 xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size); 00298 else 00299 imagedata_buffer = &imagedata_segment[1]; 00300 00301 /* use the decoded data segments to build the frame */ 00302 x = y = 0; 00303 while (total_pixels) { 00304 00305 opcode = *opcode_buffer++; 00306 size = 0; 00307 00308 switch (opcode) { 00309 00310 case 0: 00311 flag ^= 1; 00312 continue; 00313 00314 case 1: 00315 case 2: 00316 case 3: 00317 case 4: 00318 case 5: 00319 case 6: 00320 case 7: 00321 case 8: 00322 size = opcode; 00323 break; 00324 00325 case 12: 00326 case 13: 00327 case 14: 00328 case 15: 00329 case 16: 00330 case 17: 00331 case 18: 00332 size += (opcode - 10); 00333 break; 00334 00335 case 9: 00336 case 19: 00337 size = *size_segment++; 00338 break; 00339 00340 case 10: 00341 case 20: 00342 size = AV_RB16(&size_segment[0]); 00343 size_segment += 2; 00344 break; 00345 00346 case 11: 00347 case 21: 00348 size = AV_RB24(size_segment); 00349 size_segment += 3; 00350 break; 00351 } 00352 00353 if (opcode < 12) { 00354 flag ^= 1; 00355 if (flag) { 00356 /* run of (size) pixels is unchanged from last frame */ 00357 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0); 00358 } else { 00359 /* output a run of pixels from imagedata_buffer */ 00360 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size); 00361 imagedata_buffer += size; 00362 } 00363 } else { 00364 /* run-based motion compensation from last frame */ 00365 motion_x = sign_extend(*vector_segment >> 4, 4); 00366 motion_y = sign_extend(*vector_segment & 0xF, 4); 00367 vector_segment++; 00368 00369 /* copy a run of pixels from the previous frame */ 00370 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y); 00371 00372 flag = 0; 00373 } 00374 00375 /* coordinate accounting */ 00376 total_pixels -= size; 00377 y += (x + size) / width; 00378 x = (x + size) % width; 00379 } 00380 return 0; 00381 } 00382 00383 #if RUNTIME_GAMMA 00384 static inline unsigned mul(unsigned a, unsigned b) 00385 { 00386 return (a * b) >> 16; 00387 } 00388 00389 static inline unsigned pow4(unsigned a) 00390 { 00391 unsigned square = mul(a, a); 00392 return mul(square, square); 00393 } 00394 00395 static inline unsigned pow5(unsigned a) 00396 { 00397 return mul(pow4(a), a); 00398 } 00399 00400 static uint8_t gamma_corr(uint8_t in) { 00401 unsigned lo, hi = 0xff40, target; 00402 int i = 15; 00403 in = (in << 2) | (in >> 6); 00404 /* equivalent float code: 00405 if (in >= 252) 00406 return 253; 00407 return round(pow(in / 256.0, 0.8) * 256); 00408 */ 00409 lo = target = in << 8; 00410 do { 00411 unsigned mid = (lo + hi) >> 1; 00412 unsigned pow = pow5(mid); 00413 if (pow > target) hi = mid; 00414 else lo = mid; 00415 } while (--i); 00416 return (pow4((lo + hi) >> 1) + 0x80) >> 8; 00417 } 00418 #else 00419 00430 static const uint8_t gamma_lookup[256] = { 00431 0x00, 0x09, 0x10, 0x16, 0x1C, 0x21, 0x27, 0x2C, 00432 0x31, 0x35, 0x3A, 0x3F, 0x43, 0x48, 0x4C, 0x50, 00433 0x54, 0x59, 0x5D, 0x61, 0x65, 0x69, 0x6D, 0x71, 00434 0x75, 0x79, 0x7D, 0x80, 0x84, 0x88, 0x8C, 0x8F, 00435 0x93, 0x97, 0x9A, 0x9E, 0xA2, 0xA5, 0xA9, 0xAC, 00436 0xB0, 0xB3, 0xB7, 0xBA, 0xBE, 0xC1, 0xC5, 0xC8, 00437 0xCB, 0xCF, 0xD2, 0xD5, 0xD9, 0xDC, 0xDF, 0xE3, 00438 0xE6, 0xE9, 0xED, 0xF0, 0xF3, 0xF6, 0xFA, 0xFD, 00439 0x03, 0x0B, 0x12, 0x18, 0x1D, 0x23, 0x28, 0x2D, 00440 0x32, 0x36, 0x3B, 0x40, 0x44, 0x49, 0x4D, 0x51, 00441 0x56, 0x5A, 0x5E, 0x62, 0x66, 0x6A, 0x6E, 0x72, 00442 0x76, 0x7A, 0x7D, 0x81, 0x85, 0x89, 0x8D, 0x90, 00443 0x94, 0x98, 0x9B, 0x9F, 0xA2, 0xA6, 0xAA, 0xAD, 00444 0xB1, 0xB4, 0xB8, 0xBB, 0xBF, 0xC2, 0xC5, 0xC9, 00445 0xCC, 0xD0, 0xD3, 0xD6, 0xDA, 0xDD, 0xE0, 0xE4, 00446 0xE7, 0xEA, 0xED, 0xF1, 0xF4, 0xF7, 0xFA, 0xFD, 00447 0x05, 0x0D, 0x13, 0x19, 0x1F, 0x24, 0x29, 0x2E, 00448 0x33, 0x38, 0x3C, 0x41, 0x45, 0x4A, 0x4E, 0x52, 00449 0x57, 0x5B, 0x5F, 0x63, 0x67, 0x6B, 0x6F, 0x73, 00450 0x77, 0x7B, 0x7E, 0x82, 0x86, 0x8A, 0x8D, 0x91, 00451 0x95, 0x99, 0x9C, 0xA0, 0xA3, 0xA7, 0xAA, 0xAE, 00452 0xB2, 0xB5, 0xB9, 0xBC, 0xBF, 0xC3, 0xC6, 0xCA, 00453 0xCD, 0xD0, 0xD4, 0xD7, 0xDA, 0xDE, 0xE1, 0xE4, 00454 0xE8, 0xEB, 0xEE, 0xF1, 0xF5, 0xF8, 0xFB, 0xFD, 00455 0x07, 0x0E, 0x15, 0x1A, 0x20, 0x25, 0x2A, 0x2F, 00456 0x34, 0x39, 0x3D, 0x42, 0x46, 0x4B, 0x4F, 0x53, 00457 0x58, 0x5C, 0x60, 0x64, 0x68, 0x6C, 0x70, 0x74, 00458 0x78, 0x7C, 0x7F, 0x83, 0x87, 0x8B, 0x8E, 0x92, 00459 0x96, 0x99, 0x9D, 0xA1, 0xA4, 0xA8, 0xAB, 0xAF, 00460 0xB2, 0xB6, 0xB9, 0xBD, 0xC0, 0xC4, 0xC7, 0xCB, 00461 0xCE, 0xD1, 0xD5, 0xD8, 0xDB, 0xDF, 0xE2, 0xE5, 00462 0xE9, 0xEC, 0xEF, 0xF2, 0xF6, 0xF9, 0xFC, 0xFD 00463 }; 00464 #endif 00465 00466 static int xan_decode_frame(AVCodecContext *avctx, 00467 void *data, int *data_size, 00468 AVPacket *avpkt) 00469 { 00470 const uint8_t *buf = avpkt->data; 00471 int ret, buf_size = avpkt->size; 00472 XanContext *s = avctx->priv_data; 00473 00474 if (avctx->codec->id == CODEC_ID_XAN_WC3) { 00475 const uint8_t *buf_end = buf + buf_size; 00476 int tag = 0; 00477 while (buf_end - buf > 8 && tag != VGA__TAG) { 00478 unsigned *tmpptr; 00479 uint32_t new_pal; 00480 int size; 00481 int i; 00482 tag = bytestream_get_le32(&buf); 00483 size = bytestream_get_be32(&buf); 00484 size = FFMIN(size, buf_end - buf); 00485 switch (tag) { 00486 case PALT_TAG: 00487 if (size < PALETTE_SIZE) 00488 return AVERROR_INVALIDDATA; 00489 if (s->palettes_count >= PALETTES_MAX) 00490 return AVERROR_INVALIDDATA; 00491 tmpptr = av_realloc(s->palettes, (s->palettes_count + 1) * AVPALETTE_SIZE); 00492 if (!tmpptr) 00493 return AVERROR(ENOMEM); 00494 s->palettes = tmpptr; 00495 tmpptr += s->palettes_count * AVPALETTE_COUNT; 00496 for (i = 0; i < PALETTE_COUNT; i++) { 00497 #if RUNTIME_GAMMA 00498 int r = gamma_corr(*buf++); 00499 int g = gamma_corr(*buf++); 00500 int b = gamma_corr(*buf++); 00501 #else 00502 int r = gamma_lookup[*buf++]; 00503 int g = gamma_lookup[*buf++]; 00504 int b = gamma_lookup[*buf++]; 00505 #endif 00506 *tmpptr++ = (r << 16) | (g << 8) | b; 00507 } 00508 s->palettes_count++; 00509 break; 00510 case SHOT_TAG: 00511 if (size < 4) 00512 return AVERROR_INVALIDDATA; 00513 new_pal = bytestream_get_le32(&buf); 00514 if (new_pal < s->palettes_count) { 00515 s->cur_palette = new_pal; 00516 } else 00517 av_log(avctx, AV_LOG_ERROR, "Invalid palette selected\n"); 00518 break; 00519 case VGA__TAG: 00520 break; 00521 default: 00522 buf += size; 00523 break; 00524 } 00525 } 00526 buf_size = buf_end - buf; 00527 } 00528 if ((ret = avctx->get_buffer(avctx, &s->current_frame))) { 00529 av_log(s->avctx, AV_LOG_ERROR, "get_buffer() failed\n"); 00530 return ret; 00531 } 00532 s->current_frame.reference = 3; 00533 00534 if (!s->frame_size) 00535 s->frame_size = s->current_frame.linesize[0] * s->avctx->height; 00536 00537 memcpy(s->current_frame.data[1], s->palettes + s->cur_palette * AVPALETTE_COUNT, AVPALETTE_SIZE); 00538 00539 s->buf = buf; 00540 s->size = buf_size; 00541 00542 if (xan_wc3_decode_frame(s) < 0) 00543 return AVERROR_INVALIDDATA; 00544 00545 /* release the last frame if it is allocated */ 00546 if (s->last_frame.data[0]) 00547 avctx->release_buffer(avctx, &s->last_frame); 00548 00549 *data_size = sizeof(AVFrame); 00550 *(AVFrame*)data = s->current_frame; 00551 00552 /* shuffle frames */ 00553 FFSWAP(AVFrame, s->current_frame, s->last_frame); 00554 00555 /* always report that the buffer was completely consumed */ 00556 return buf_size; 00557 } 00558 00559 static av_cold int xan_decode_end(AVCodecContext *avctx) 00560 { 00561 XanContext *s = avctx->priv_data; 00562 00563 /* release the frames */ 00564 if (s->last_frame.data[0]) 00565 avctx->release_buffer(avctx, &s->last_frame); 00566 if (s->current_frame.data[0]) 00567 avctx->release_buffer(avctx, &s->current_frame); 00568 00569 av_freep(&s->buffer1); 00570 av_freep(&s->buffer2); 00571 av_freep(&s->palettes); 00572 00573 return 0; 00574 } 00575 00576 AVCodec ff_xan_wc3_decoder = { 00577 "xan_wc3", 00578 AVMEDIA_TYPE_VIDEO, 00579 CODEC_ID_XAN_WC3, 00580 sizeof(XanContext), 00581 xan_decode_init, 00582 NULL, 00583 xan_decode_end, 00584 xan_decode_frame, 00585 CODEC_CAP_DR1, 00586 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"), 00587 }; 00588