Libav 0.7.1
libavcodec/xan.c
Go to the documentation of this file.
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