Libav

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