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