• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

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 FFmpeg.
00006  *
00007  * FFmpeg 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  * FFmpeg 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 FFmpeg; 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 typedef struct XanContext {
00044 
00045     AVCodecContext *avctx;
00046     AVFrame last_frame;
00047     AVFrame current_frame;
00048 
00049     const unsigned char *buf;
00050     int size;
00051 
00052     /* scratch space */
00053     unsigned char *buffer1;
00054     int buffer1_size;
00055     unsigned char *buffer2;
00056     int buffer2_size;
00057 
00058     int frame_size;
00059 
00060 } XanContext;
00061 
00062 static av_cold int xan_decode_init(AVCodecContext *avctx)
00063 {
00064     XanContext *s = avctx->priv_data;
00065 
00066     s->avctx = avctx;
00067     s->frame_size = 0;
00068 
00069     if ((avctx->codec->id == CODEC_ID_XAN_WC3) &&
00070         (s->avctx->palctrl == NULL)) {
00071         av_log(avctx, AV_LOG_ERROR, " WC3 Xan video: palette expected.\n");
00072         return -1;
00073     }
00074 
00075     avctx->pix_fmt = PIX_FMT_PAL8;
00076 
00077     s->buffer1_size = avctx->width * avctx->height;
00078     s->buffer1 = av_malloc(s->buffer1_size);
00079     if (!s->buffer1)
00080         return -1;
00081     s->buffer2_size = avctx->width * avctx->height;
00082     s->buffer2 = av_malloc(s->buffer2_size + 130);
00083     if (!s->buffer2) {
00084         av_freep(&s->buffer1);
00085         return -1;
00086     }
00087 
00088     return 0;
00089 }
00090 
00091 static int xan_huffman_decode(unsigned char *dest, const unsigned char *src,
00092     int dest_len)
00093 {
00094     unsigned char byte = *src++;
00095     unsigned char ival = byte + 0x16;
00096     const unsigned char * ptr = src + byte*2;
00097     unsigned char val = ival;
00098     unsigned char *dest_end = dest + dest_len;
00099     GetBitContext gb;
00100 
00101     init_get_bits(&gb, ptr, 0); // FIXME: no src size available
00102 
00103     while ( val != 0x16 ) {
00104         val = src[val - 0x17 + get_bits1(&gb) * byte];
00105 
00106         if ( val < 0x16 ) {
00107             if (dest >= dest_end)
00108                 return 0;
00109             *dest++ = val;
00110             val = ival;
00111         }
00112     }
00113 
00114     return 0;
00115 }
00116 
00122 static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len)
00123 {
00124     unsigned char opcode;
00125     int size;
00126     unsigned char *dest_end = dest + dest_len;
00127 
00128     while (dest < dest_end) {
00129         opcode = *src++;
00130 
00131         if (opcode < 0xe0) {
00132             int size2, back;
00133             if ( (opcode & 0x80) == 0 ) {
00134 
00135                 size = opcode & 3;
00136 
00137                 back  = ((opcode & 0x60) << 3) + *src++ + 1;
00138                 size2 = ((opcode & 0x1c) >> 2) + 3;
00139 
00140             } else if ( (opcode & 0x40) == 0 ) {
00141 
00142                 size = *src >> 6;
00143 
00144                 back  = (bytestream_get_be16(&src) & 0x3fff) + 1;
00145                 size2 = (opcode & 0x3f) + 4;
00146 
00147             } else {
00148 
00149                 size = opcode & 3;
00150 
00151                 back  = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1;
00152                 size2 = ((opcode & 0x0c) <<  6) + *src++ + 5;
00153                 if (size + size2 > dest_end - dest)
00154                     return;
00155             }
00156             memcpy(dest, src, size);  dest += size;  src += size;
00157             av_memcpy_backptr(dest, back, size2);
00158             dest += size2;
00159         } else {
00160             int finish = opcode >= 0xfc;
00161             size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4;
00162 
00163             memcpy(dest, src, size);  dest += size;  src += size;
00164             if (finish)
00165                 return;
00166         }
00167     }
00168 }
00169 
00170 static inline void xan_wc3_output_pixel_run(XanContext *s,
00171     const unsigned char *pixel_buffer, int x, int y, int pixel_count)
00172 {
00173     int stride;
00174     int line_inc;
00175     int index;
00176     int current_x;
00177     int width = s->avctx->width;
00178     unsigned char *palette_plane;
00179 
00180     palette_plane = s->current_frame.data[0];
00181     stride = s->current_frame.linesize[0];
00182     line_inc = stride - width;
00183     index = y * stride + x;
00184     current_x = x;
00185     while(pixel_count && (index < s->frame_size)) {
00186         int count = FFMIN(pixel_count, width - current_x);
00187         memcpy(palette_plane + index, pixel_buffer, count);
00188         pixel_count  -= count;
00189         index        += count;
00190         pixel_buffer += count;
00191         current_x    += count;
00192 
00193         if (current_x >= width) {
00194             index += line_inc;
00195             current_x = 0;
00196         }
00197     }
00198 }
00199 
00200 static inline void xan_wc3_copy_pixel_run(XanContext *s,
00201     int x, int y, int pixel_count, int motion_x, int motion_y)
00202 {
00203     int stride;
00204     int line_inc;
00205     int curframe_index, prevframe_index;
00206     int curframe_x, prevframe_x;
00207     int width = s->avctx->width;
00208     unsigned char *palette_plane, *prev_palette_plane;
00209 
00210     palette_plane = s->current_frame.data[0];
00211     prev_palette_plane = s->last_frame.data[0];
00212     stride = s->current_frame.linesize[0];
00213     line_inc = stride - width;
00214     curframe_index = y * stride + x;
00215     curframe_x = x;
00216     prevframe_index = (y + motion_y) * stride + x + motion_x;
00217     prevframe_x = x + motion_x;
00218     while(pixel_count && (curframe_index < s->frame_size)) {
00219         int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x);
00220 
00221         memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count);
00222         pixel_count     -= count;
00223         curframe_index  += count;
00224         prevframe_index += count;
00225         curframe_x      += count;
00226         prevframe_x     += count;
00227 
00228         if (curframe_x >= width) {
00229             curframe_index += line_inc;
00230             curframe_x = 0;
00231         }
00232 
00233         if (prevframe_x >= width) {
00234             prevframe_index += line_inc;
00235             prevframe_x = 0;
00236         }
00237     }
00238 }
00239 
00240 static void xan_wc3_decode_frame(XanContext *s) {
00241 
00242     int width = s->avctx->width;
00243     int height = s->avctx->height;
00244     int total_pixels = width * height;
00245     unsigned char opcode;
00246     unsigned char flag = 0;
00247     int size = 0;
00248     int motion_x, motion_y;
00249     int x, y;
00250 
00251     unsigned char *opcode_buffer = s->buffer1;
00252     int opcode_buffer_size = s->buffer1_size;
00253     const unsigned char *imagedata_buffer = s->buffer2;
00254 
00255     /* pointers to segments inside the compressed chunk */
00256     const unsigned char *huffman_segment;
00257     const unsigned char *size_segment;
00258     const unsigned char *vector_segment;
00259     const unsigned char *imagedata_segment;
00260 
00261     huffman_segment =   s->buf + AV_RL16(&s->buf[0]);
00262     size_segment =      s->buf + AV_RL16(&s->buf[2]);
00263     vector_segment =    s->buf + AV_RL16(&s->buf[4]);
00264     imagedata_segment = s->buf + AV_RL16(&s->buf[6]);
00265 
00266     xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size);
00267 
00268     if (imagedata_segment[0] == 2)
00269         xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size);
00270     else
00271         imagedata_buffer = &imagedata_segment[1];
00272 
00273     /* use the decoded data segments to build the frame */
00274     x = y = 0;
00275     while (total_pixels) {
00276 
00277         opcode = *opcode_buffer++;
00278         size = 0;
00279 
00280         switch (opcode) {
00281 
00282         case 0:
00283             flag ^= 1;
00284             continue;
00285 
00286         case 1:
00287         case 2:
00288         case 3:
00289         case 4:
00290         case 5:
00291         case 6:
00292         case 7:
00293         case 8:
00294             size = opcode;
00295             break;
00296 
00297         case 12:
00298         case 13:
00299         case 14:
00300         case 15:
00301         case 16:
00302         case 17:
00303         case 18:
00304             size += (opcode - 10);
00305             break;
00306 
00307         case 9:
00308         case 19:
00309             size = *size_segment++;
00310             break;
00311 
00312         case 10:
00313         case 20:
00314             size = AV_RB16(&size_segment[0]);
00315             size_segment += 2;
00316             break;
00317 
00318         case 11:
00319         case 21:
00320             size = AV_RB24(size_segment);
00321             size_segment += 3;
00322             break;
00323         }
00324 
00325         if (opcode < 12) {
00326             flag ^= 1;
00327             if (flag) {
00328                 /* run of (size) pixels is unchanged from last frame */
00329                 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0);
00330             } else {
00331                 /* output a run of pixels from imagedata_buffer */
00332                 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size);
00333                 imagedata_buffer += size;
00334             }
00335         } else {
00336             /* run-based motion compensation from last frame */
00337             motion_x = sign_extend(*vector_segment >> 4,  4);
00338             motion_y = sign_extend(*vector_segment & 0xF, 4);
00339             vector_segment++;
00340 
00341             /* copy a run of pixels from the previous frame */
00342             xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y);
00343 
00344             flag = 0;
00345         }
00346 
00347         /* coordinate accounting */
00348         total_pixels -= size;
00349         y += (x + size) / width;
00350         x  = (x + size) % width;
00351     }
00352 }
00353 
00354 static void xan_wc4_decode_frame(XanContext *s) {
00355 }
00356 
00357 static int xan_decode_frame(AVCodecContext *avctx,
00358                             void *data, int *data_size,
00359                             AVPacket *avpkt)
00360 {
00361     const uint8_t *buf = avpkt->data;
00362     int buf_size = avpkt->size;
00363     XanContext *s = avctx->priv_data;
00364     AVPaletteControl *palette_control = avctx->palctrl;
00365 
00366     if (avctx->get_buffer(avctx, &s->current_frame)) {
00367         av_log(s->avctx, AV_LOG_ERROR, "  Xan Video: get_buffer() failed\n");
00368         return -1;
00369     }
00370     s->current_frame.reference = 3;
00371 
00372     if (!s->frame_size)
00373         s->frame_size = s->current_frame.linesize[0] * s->avctx->height;
00374 
00375     palette_control->palette_changed = 0;
00376     memcpy(s->current_frame.data[1], palette_control->palette,
00377            AVPALETTE_SIZE);
00378     s->current_frame.palette_has_changed = 1;
00379 
00380     s->buf = buf;
00381     s->size = buf_size;
00382 
00383     if (avctx->codec->id == CODEC_ID_XAN_WC3)
00384         xan_wc3_decode_frame(s);
00385     else if (avctx->codec->id == CODEC_ID_XAN_WC4)
00386         xan_wc4_decode_frame(s);
00387 
00388     /* release the last frame if it is allocated */
00389     if (s->last_frame.data[0])
00390         avctx->release_buffer(avctx, &s->last_frame);
00391 
00392     *data_size = sizeof(AVFrame);
00393     *(AVFrame*)data = s->current_frame;
00394 
00395     /* shuffle frames */
00396     FFSWAP(AVFrame, s->current_frame, s->last_frame);
00397 
00398     /* always report that the buffer was completely consumed */
00399     return buf_size;
00400 }
00401 
00402 static av_cold int xan_decode_end(AVCodecContext *avctx)
00403 {
00404     XanContext *s = avctx->priv_data;
00405 
00406     /* release the frames */
00407     if (s->last_frame.data[0])
00408         avctx->release_buffer(avctx, &s->last_frame);
00409     if (s->current_frame.data[0])
00410         avctx->release_buffer(avctx, &s->current_frame);
00411 
00412     av_freep(&s->buffer1);
00413     av_freep(&s->buffer2);
00414 
00415     return 0;
00416 }
00417 
00418 AVCodec xan_wc3_decoder = {
00419     "xan_wc3",
00420     AVMEDIA_TYPE_VIDEO,
00421     CODEC_ID_XAN_WC3,
00422     sizeof(XanContext),
00423     xan_decode_init,
00424     NULL,
00425     xan_decode_end,
00426     xan_decode_frame,
00427     CODEC_CAP_DR1,
00428     .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"),
00429 };
00430 
00431 /*
00432 AVCodec xan_wc4_decoder = {
00433     "xan_wc4",
00434     AVMEDIA_TYPE_VIDEO,
00435     CODEC_ID_XAN_WC4,
00436     sizeof(XanContext),
00437     xan_decode_init,
00438     NULL,
00439     xan_decode_end,
00440     xan_decode_frame,
00441     CODEC_CAP_DR1,
00442     .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"),
00443 };
00444 */

Generated on Fri Sep 16 2011 17:17:47 for FFmpeg by  doxygen 1.7.1