1/* 2 * Wing Commander/Xan Video Decoder 3 * Copyright (C) 2003 the ffmpeg project 4 * 5 * This file is part of FFmpeg. 6 * 7 * FFmpeg is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * FFmpeg is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with FFmpeg; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 20 */ 21 22/** 23 * @file 24 * Xan video decoder for Wing Commander III computer game 25 * by Mario Brito (mbrito@student.dei.uc.pt) 26 * and Mike Melanson (melanson@pcisys.net) 27 * 28 * The xan_wc3 decoder outputs PAL8 data. 29 */ 30 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34 35#include "libavutil/intreadwrite.h" 36#include "avcodec.h" 37#include "bytestream.h" 38#define ALT_BITSTREAM_READER_LE 39#include "get_bits.h" 40// for av_memcpy_backptr 41#include "libavutil/lzo.h" 42 43typedef struct XanContext { 44 45 AVCodecContext *avctx; 46 AVFrame last_frame; 47 AVFrame current_frame; 48 49 const unsigned char *buf; 50 int size; 51 52 /* scratch space */ 53 unsigned char *buffer1; 54 int buffer1_size; 55 unsigned char *buffer2; 56 int buffer2_size; 57 58 int frame_size; 59 60} XanContext; 61 62static av_cold int xan_decode_init(AVCodecContext *avctx) 63{ 64 XanContext *s = avctx->priv_data; 65 66 s->avctx = avctx; 67 s->frame_size = 0; 68 69 if ((avctx->codec->id == CODEC_ID_XAN_WC3) && 70 (s->avctx->palctrl == NULL)) { 71 av_log(avctx, AV_LOG_ERROR, " WC3 Xan video: palette expected.\n"); 72 return -1; 73 } 74 75 avctx->pix_fmt = PIX_FMT_PAL8; 76 77 s->buffer1_size = avctx->width * avctx->height; 78 s->buffer1 = av_malloc(s->buffer1_size); 79 if (!s->buffer1) 80 return -1; 81 s->buffer2_size = avctx->width * avctx->height; 82 s->buffer2 = av_malloc(s->buffer2_size + 130); 83 if (!s->buffer2) { 84 av_freep(&s->buffer1); 85 return -1; 86 } 87 88 return 0; 89} 90 91static int xan_huffman_decode(unsigned char *dest, const unsigned char *src, 92 int dest_len) 93{ 94 unsigned char byte = *src++; 95 unsigned char ival = byte + 0x16; 96 const unsigned char * ptr = src + byte*2; 97 unsigned char val = ival; 98 unsigned char *dest_end = dest + dest_len; 99 GetBitContext gb; 100 101 init_get_bits(&gb, ptr, 0); // FIXME: no src size available 102 103 while ( val != 0x16 ) { 104 val = src[val - 0x17 + get_bits1(&gb) * byte]; 105 106 if ( val < 0x16 ) { 107 if (dest >= dest_end) 108 return 0; 109 *dest++ = val; 110 val = ival; 111 } 112 } 113 114 return 0; 115} 116 117/** 118 * unpack simple compression 119 * 120 * @param dest destination buffer of dest_len, must be padded with at least 130 bytes 121 */ 122static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len) 123{ 124 unsigned char opcode; 125 int size; 126 unsigned char *dest_end = dest + dest_len; 127 128 while (dest < dest_end) { 129 opcode = *src++; 130 131 if (opcode < 0xe0) { 132 int size2, back; 133 if ( (opcode & 0x80) == 0 ) { 134 135 size = opcode & 3; 136 137 back = ((opcode & 0x60) << 3) + *src++ + 1; 138 size2 = ((opcode & 0x1c) >> 2) + 3; 139 140 } else if ( (opcode & 0x40) == 0 ) { 141 142 size = *src >> 6; 143 144 back = (bytestream_get_be16(&src) & 0x3fff) + 1; 145 size2 = (opcode & 0x3f) + 4; 146 147 } else { 148 149 size = opcode & 3; 150 151 back = ((opcode & 0x10) << 12) + bytestream_get_be16(&src) + 1; 152 size2 = ((opcode & 0x0c) << 6) + *src++ + 5; 153 if (size + size2 > dest_end - dest) 154 return; 155 } 156 memcpy(dest, src, size); dest += size; src += size; 157 av_memcpy_backptr(dest, back, size2); 158 dest += size2; 159 } else { 160 int finish = opcode >= 0xfc; 161 size = finish ? opcode & 3 : ((opcode & 0x1f) << 2) + 4; 162 163 memcpy(dest, src, size); dest += size; src += size; 164 if (finish) 165 return; 166 } 167 } 168} 169 170static inline void xan_wc3_output_pixel_run(XanContext *s, 171 const unsigned char *pixel_buffer, int x, int y, int pixel_count) 172{ 173 int stride; 174 int line_inc; 175 int index; 176 int current_x; 177 int width = s->avctx->width; 178 unsigned char *palette_plane; 179 180 palette_plane = s->current_frame.data[0]; 181 stride = s->current_frame.linesize[0]; 182 line_inc = stride - width; 183 index = y * stride + x; 184 current_x = x; 185 while(pixel_count && (index < s->frame_size)) { 186 int count = FFMIN(pixel_count, width - current_x); 187 memcpy(palette_plane + index, pixel_buffer, count); 188 pixel_count -= count; 189 index += count; 190 pixel_buffer += count; 191 current_x += count; 192 193 if (current_x >= width) { 194 index += line_inc; 195 current_x = 0; 196 } 197 } 198} 199 200static inline void xan_wc3_copy_pixel_run(XanContext *s, 201 int x, int y, int pixel_count, int motion_x, int motion_y) 202{ 203 int stride; 204 int line_inc; 205 int curframe_index, prevframe_index; 206 int curframe_x, prevframe_x; 207 int width = s->avctx->width; 208 unsigned char *palette_plane, *prev_palette_plane; 209 210 palette_plane = s->current_frame.data[0]; 211 prev_palette_plane = s->last_frame.data[0]; 212 stride = s->current_frame.linesize[0]; 213 line_inc = stride - width; 214 curframe_index = y * stride + x; 215 curframe_x = x; 216 prevframe_index = (y + motion_y) * stride + x + motion_x; 217 prevframe_x = x + motion_x; 218 while(pixel_count && (curframe_index < s->frame_size)) { 219 int count = FFMIN3(pixel_count, width - curframe_x, width - prevframe_x); 220 221 memcpy(palette_plane + curframe_index, prev_palette_plane + prevframe_index, count); 222 pixel_count -= count; 223 curframe_index += count; 224 prevframe_index += count; 225 curframe_x += count; 226 prevframe_x += count; 227 228 if (curframe_x >= width) { 229 curframe_index += line_inc; 230 curframe_x = 0; 231 } 232 233 if (prevframe_x >= width) { 234 prevframe_index += line_inc; 235 prevframe_x = 0; 236 } 237 } 238} 239 240static void xan_wc3_decode_frame(XanContext *s) { 241 242 int width = s->avctx->width; 243 int height = s->avctx->height; 244 int total_pixels = width * height; 245 unsigned char opcode; 246 unsigned char flag = 0; 247 int size = 0; 248 int motion_x, motion_y; 249 int x, y; 250 251 unsigned char *opcode_buffer = s->buffer1; 252 int opcode_buffer_size = s->buffer1_size; 253 const unsigned char *imagedata_buffer = s->buffer2; 254 255 /* pointers to segments inside the compressed chunk */ 256 const unsigned char *huffman_segment; 257 const unsigned char *size_segment; 258 const unsigned char *vector_segment; 259 const unsigned char *imagedata_segment; 260 261 huffman_segment = s->buf + AV_RL16(&s->buf[0]); 262 size_segment = s->buf + AV_RL16(&s->buf[2]); 263 vector_segment = s->buf + AV_RL16(&s->buf[4]); 264 imagedata_segment = s->buf + AV_RL16(&s->buf[6]); 265 266 xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size); 267 268 if (imagedata_segment[0] == 2) 269 xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size); 270 else 271 imagedata_buffer = &imagedata_segment[1]; 272 273 /* use the decoded data segments to build the frame */ 274 x = y = 0; 275 while (total_pixels) { 276 277 opcode = *opcode_buffer++; 278 size = 0; 279 280 switch (opcode) { 281 282 case 0: 283 flag ^= 1; 284 continue; 285 286 case 1: 287 case 2: 288 case 3: 289 case 4: 290 case 5: 291 case 6: 292 case 7: 293 case 8: 294 size = opcode; 295 break; 296 297 case 12: 298 case 13: 299 case 14: 300 case 15: 301 case 16: 302 case 17: 303 case 18: 304 size += (opcode - 10); 305 break; 306 307 case 9: 308 case 19: 309 size = *size_segment++; 310 break; 311 312 case 10: 313 case 20: 314 size = AV_RB16(&size_segment[0]); 315 size_segment += 2; 316 break; 317 318 case 11: 319 case 21: 320 size = AV_RB24(size_segment); 321 size_segment += 3; 322 break; 323 } 324 325 if (opcode < 12) { 326 flag ^= 1; 327 if (flag) { 328 /* run of (size) pixels is unchanged from last frame */ 329 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0); 330 } else { 331 /* output a run of pixels from imagedata_buffer */ 332 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size); 333 imagedata_buffer += size; 334 } 335 } else { 336 /* run-based motion compensation from last frame */ 337 motion_x = sign_extend(*vector_segment >> 4, 4); 338 motion_y = sign_extend(*vector_segment & 0xF, 4); 339 vector_segment++; 340 341 /* copy a run of pixels from the previous frame */ 342 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y); 343 344 flag = 0; 345 } 346 347 /* coordinate accounting */ 348 total_pixels -= size; 349 y += (x + size) / width; 350 x = (x + size) % width; 351 } 352} 353 354static void xan_wc4_decode_frame(XanContext *s) { 355} 356 357static int xan_decode_frame(AVCodecContext *avctx, 358 void *data, int *data_size, 359 AVPacket *avpkt) 360{ 361 const uint8_t *buf = avpkt->data; 362 int buf_size = avpkt->size; 363 XanContext *s = avctx->priv_data; 364 AVPaletteControl *palette_control = avctx->palctrl; 365 366 if (avctx->get_buffer(avctx, &s->current_frame)) { 367 av_log(s->avctx, AV_LOG_ERROR, " Xan Video: get_buffer() failed\n"); 368 return -1; 369 } 370 s->current_frame.reference = 3; 371 372 if (!s->frame_size) 373 s->frame_size = s->current_frame.linesize[0] * s->avctx->height; 374 375 palette_control->palette_changed = 0; 376 memcpy(s->current_frame.data[1], palette_control->palette, 377 AVPALETTE_SIZE); 378 s->current_frame.palette_has_changed = 1; 379 380 s->buf = buf; 381 s->size = buf_size; 382 383 if (avctx->codec->id == CODEC_ID_XAN_WC3) 384 xan_wc3_decode_frame(s); 385 else if (avctx->codec->id == CODEC_ID_XAN_WC4) 386 xan_wc4_decode_frame(s); 387 388 /* release the last frame if it is allocated */ 389 if (s->last_frame.data[0]) 390 avctx->release_buffer(avctx, &s->last_frame); 391 392 *data_size = sizeof(AVFrame); 393 *(AVFrame*)data = s->current_frame; 394 395 /* shuffle frames */ 396 FFSWAP(AVFrame, s->current_frame, s->last_frame); 397 398 /* always report that the buffer was completely consumed */ 399 return buf_size; 400} 401 402static av_cold int xan_decode_end(AVCodecContext *avctx) 403{ 404 XanContext *s = avctx->priv_data; 405 406 /* release the frames */ 407 if (s->last_frame.data[0]) 408 avctx->release_buffer(avctx, &s->last_frame); 409 if (s->current_frame.data[0]) 410 avctx->release_buffer(avctx, &s->current_frame); 411 412 av_freep(&s->buffer1); 413 av_freep(&s->buffer2); 414 415 return 0; 416} 417 418AVCodec xan_wc3_decoder = { 419 "xan_wc3", 420 AVMEDIA_TYPE_VIDEO, 421 CODEC_ID_XAN_WC3, 422 sizeof(XanContext), 423 xan_decode_init, 424 NULL, 425 xan_decode_end, 426 xan_decode_frame, 427 CODEC_CAP_DR1, 428 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"), 429}; 430 431/* 432AVCodec xan_wc4_decoder = { 433 "xan_wc4", 434 AVMEDIA_TYPE_VIDEO, 435 CODEC_ID_XAN_WC4, 436 sizeof(XanContext), 437 xan_decode_init, 438 NULL, 439 xan_decode_end, 440 xan_decode_frame, 441 CODEC_CAP_DR1, 442 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander IV / Xxan"), 443}; 444*/ 445