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 libavcodec/xan.c 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#include <unistd.h> 35 36#include "libavutil/intreadwrite.h" 37#include "avcodec.h" 38 39typedef struct XanContext { 40 41 AVCodecContext *avctx; 42 AVFrame last_frame; 43 AVFrame current_frame; 44 45 const unsigned char *buf; 46 int size; 47 48 /* scratch space */ 49 unsigned char *buffer1; 50 int buffer1_size; 51 unsigned char *buffer2; 52 int buffer2_size; 53 54 int frame_size; 55 56} XanContext; 57 58static av_cold int xan_decode_init(AVCodecContext *avctx) 59{ 60 XanContext *s = avctx->priv_data; 61 62 s->avctx = avctx; 63 s->frame_size = 0; 64 65 if ((avctx->codec->id == CODEC_ID_XAN_WC3) && 66 (s->avctx->palctrl == NULL)) { 67 av_log(avctx, AV_LOG_ERROR, " WC3 Xan video: palette expected.\n"); 68 return -1; 69 } 70 71 avctx->pix_fmt = PIX_FMT_PAL8; 72 73 if(avcodec_check_dimensions(avctx, avctx->width, avctx->height)) 74 return -1; 75 76 s->buffer1_size = avctx->width * avctx->height; 77 s->buffer1 = av_malloc(s->buffer1_size); 78 s->buffer2_size = avctx->width * avctx->height; 79 s->buffer2 = av_malloc(s->buffer2_size); 80 if (!s->buffer1 || !s->buffer2) 81 return -1; 82 83 return 0; 84} 85 86/* This function is used in lieu of memcpy(). This decoder cannot use 87 * memcpy because the memory locations often overlap and 88 * memcpy doesn't like that; it's not uncommon, for example, for 89 * dest = src+1, to turn byte A into pattern AAAAAAAA. 90 * This was originally repz movsb in Intel x86 ASM. */ 91static inline void bytecopy(unsigned char *dest, const unsigned char *src, int count) 92{ 93 int i; 94 95 for (i = 0; i < count; i++) 96 dest[i] = src[i]; 97} 98 99static int xan_huffman_decode(unsigned char *dest, const unsigned char *src, 100 int dest_len) 101{ 102 unsigned char byte = *src++; 103 unsigned char ival = byte + 0x16; 104 const unsigned char * ptr = src + byte*2; 105 unsigned char val = ival; 106 int counter = 0; 107 unsigned char *dest_end = dest + dest_len; 108 109 unsigned char bits = *ptr++; 110 111 while ( val != 0x16 ) { 112 if ( (1 << counter) & bits ) 113 val = src[byte + val - 0x17]; 114 else 115 val = src[val - 0x17]; 116 117 if ( val < 0x16 ) { 118 if (dest + 1 > dest_end) 119 return 0; 120 *dest++ = val; 121 val = ival; 122 } 123 124 if (counter++ == 7) { 125 counter = 0; 126 bits = *ptr++; 127 } 128 } 129 130 return 0; 131} 132 133static void xan_unpack(unsigned char *dest, const unsigned char *src, int dest_len) 134{ 135 unsigned char opcode; 136 int size; 137 int offset; 138 int byte1, byte2, byte3; 139 unsigned char *dest_end = dest + dest_len; 140 141 for (;;) { 142 opcode = *src++; 143 144 if ( (opcode & 0x80) == 0 ) { 145 146 offset = *src++; 147 148 size = opcode & 3; 149 if (dest + size > dest_end) 150 return; 151 bytecopy(dest, src, size); dest += size; src += size; 152 153 size = ((opcode & 0x1c) >> 2) + 3; 154 if (dest + size > dest_end) 155 return; 156 bytecopy (dest, dest - (((opcode & 0x60) << 3) + offset + 1), size); 157 dest += size; 158 159 } else if ( (opcode & 0x40) == 0 ) { 160 161 byte1 = *src++; 162 byte2 = *src++; 163 164 size = byte1 >> 6; 165 if (dest + size > dest_end) 166 return; 167 bytecopy (dest, src, size); dest += size; src += size; 168 169 size = (opcode & 0x3f) + 4; 170 if (dest + size > dest_end) 171 return; 172 bytecopy (dest, dest - (((byte1 & 0x3f) << 8) + byte2 + 1), size); 173 dest += size; 174 175 } else if ( (opcode & 0x20) == 0 ) { 176 177 byte1 = *src++; 178 byte2 = *src++; 179 byte3 = *src++; 180 181 size = opcode & 3; 182 if (dest + size > dest_end) 183 return; 184 bytecopy (dest, src, size); dest += size; src += size; 185 186 size = byte3 + 5 + ((opcode & 0xc) << 6); 187 if (dest + size > dest_end) 188 return; 189 bytecopy (dest, 190 dest - ((((opcode & 0x10) >> 4) << 0x10) + 1 + (byte1 << 8) + byte2), 191 size); 192 dest += size; 193 } else { 194 size = ((opcode & 0x1f) << 2) + 4; 195 196 if (size > 0x70) 197 break; 198 199 if (dest + size > dest_end) 200 return; 201 bytecopy (dest, src, size); dest += size; src += size; 202 } 203 } 204 205 size = opcode & 3; 206 bytecopy(dest, src, size); dest += size; src += size; 207} 208 209static inline void xan_wc3_output_pixel_run(XanContext *s, 210 const unsigned char *pixel_buffer, int x, int y, int pixel_count) 211{ 212 int stride; 213 int line_inc; 214 int index; 215 int current_x; 216 int width = s->avctx->width; 217 unsigned char *palette_plane; 218 219 palette_plane = s->current_frame.data[0]; 220 stride = s->current_frame.linesize[0]; 221 line_inc = stride - width; 222 index = y * stride + x; 223 current_x = x; 224 while((pixel_count--) && (index < s->frame_size)) { 225 226 /* don't do a memcpy() here; keyframes generally copy an entire 227 * frame of data and the stride needs to be accounted for */ 228 palette_plane[index++] = *pixel_buffer++; 229 230 current_x++; 231 if (current_x >= width) { 232 index += line_inc; 233 current_x = 0; 234 } 235 } 236} 237 238static inline void xan_wc3_copy_pixel_run(XanContext *s, 239 int x, int y, int pixel_count, int motion_x, int motion_y) 240{ 241 int stride; 242 int line_inc; 243 int curframe_index, prevframe_index; 244 int curframe_x, prevframe_x; 245 int width = s->avctx->width; 246 unsigned char *palette_plane, *prev_palette_plane; 247 248 palette_plane = s->current_frame.data[0]; 249 prev_palette_plane = s->last_frame.data[0]; 250 stride = s->current_frame.linesize[0]; 251 line_inc = stride - width; 252 curframe_index = y * stride + x; 253 curframe_x = x; 254 prevframe_index = (y + motion_y) * stride + x + motion_x; 255 prevframe_x = x + motion_x; 256 while((pixel_count--) && (curframe_index < s->frame_size)) { 257 258 palette_plane[curframe_index++] = 259 prev_palette_plane[prevframe_index++]; 260 261 curframe_x++; 262 if (curframe_x >= width) { 263 curframe_index += line_inc; 264 curframe_x = 0; 265 } 266 267 prevframe_x++; 268 if (prevframe_x >= width) { 269 prevframe_index += line_inc; 270 prevframe_x = 0; 271 } 272 } 273} 274 275static void xan_wc3_decode_frame(XanContext *s) { 276 277 int width = s->avctx->width; 278 int height = s->avctx->height; 279 int total_pixels = width * height; 280 unsigned char opcode; 281 unsigned char flag = 0; 282 int size = 0; 283 int motion_x, motion_y; 284 int x, y; 285 286 unsigned char *opcode_buffer = s->buffer1; 287 int opcode_buffer_size = s->buffer1_size; 288 const unsigned char *imagedata_buffer = s->buffer2; 289 290 /* pointers to segments inside the compressed chunk */ 291 const unsigned char *huffman_segment; 292 const unsigned char *size_segment; 293 const unsigned char *vector_segment; 294 const unsigned char *imagedata_segment; 295 296 huffman_segment = s->buf + AV_RL16(&s->buf[0]); 297 size_segment = s->buf + AV_RL16(&s->buf[2]); 298 vector_segment = s->buf + AV_RL16(&s->buf[4]); 299 imagedata_segment = s->buf + AV_RL16(&s->buf[6]); 300 301 xan_huffman_decode(opcode_buffer, huffman_segment, opcode_buffer_size); 302 303 if (imagedata_segment[0] == 2) 304 xan_unpack(s->buffer2, &imagedata_segment[1], s->buffer2_size); 305 else 306 imagedata_buffer = &imagedata_segment[1]; 307 308 /* use the decoded data segments to build the frame */ 309 x = y = 0; 310 while (total_pixels) { 311 312 opcode = *opcode_buffer++; 313 size = 0; 314 315 switch (opcode) { 316 317 case 0: 318 flag ^= 1; 319 continue; 320 321 case 1: 322 case 2: 323 case 3: 324 case 4: 325 case 5: 326 case 6: 327 case 7: 328 case 8: 329 size = opcode; 330 break; 331 332 case 12: 333 case 13: 334 case 14: 335 case 15: 336 case 16: 337 case 17: 338 case 18: 339 size += (opcode - 10); 340 break; 341 342 case 9: 343 case 19: 344 size = *size_segment++; 345 break; 346 347 case 10: 348 case 20: 349 size = AV_RB16(&size_segment[0]); 350 size_segment += 2; 351 break; 352 353 case 11: 354 case 21: 355 size = AV_RB24(size_segment); 356 size_segment += 3; 357 break; 358 } 359 360 if (opcode < 12) { 361 flag ^= 1; 362 if (flag) { 363 /* run of (size) pixels is unchanged from last frame */ 364 xan_wc3_copy_pixel_run(s, x, y, size, 0, 0); 365 } else { 366 /* output a run of pixels from imagedata_buffer */ 367 xan_wc3_output_pixel_run(s, imagedata_buffer, x, y, size); 368 imagedata_buffer += size; 369 } 370 } else { 371 /* run-based motion compensation from last frame */ 372 motion_x = (*vector_segment >> 4) & 0xF; 373 motion_y = *vector_segment & 0xF; 374 vector_segment++; 375 376 /* sign extension */ 377 if (motion_x & 0x8) 378 motion_x |= 0xFFFFFFF0; 379 if (motion_y & 0x8) 380 motion_y |= 0xFFFFFFF0; 381 382 /* copy a run of pixels from the previous frame */ 383 xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y); 384 385 flag = 0; 386 } 387 388 /* coordinate accounting */ 389 total_pixels -= size; 390 while (size) { 391 if (x + size >= width) { 392 y++; 393 size -= (width - x); 394 x = 0; 395 } else { 396 x += size; 397 size = 0; 398 } 399 } 400 } 401} 402 403static void xan_wc4_decode_frame(XanContext *s) { 404} 405 406static int xan_decode_frame(AVCodecContext *avctx, 407 void *data, int *data_size, 408 const uint8_t *buf, int buf_size) 409{ 410 XanContext *s = avctx->priv_data; 411 AVPaletteControl *palette_control = avctx->palctrl; 412 413 if (avctx->get_buffer(avctx, &s->current_frame)) { 414 av_log(s->avctx, AV_LOG_ERROR, " Xan Video: get_buffer() failed\n"); 415 return -1; 416 } 417 s->current_frame.reference = 3; 418 419 if (!s->frame_size) 420 s->frame_size = s->current_frame.linesize[0] * s->avctx->height; 421 422 palette_control->palette_changed = 0; 423 memcpy(s->current_frame.data[1], palette_control->palette, 424 AVPALETTE_SIZE); 425 s->current_frame.palette_has_changed = 1; 426 427 s->buf = buf; 428 s->size = buf_size; 429 430 if (avctx->codec->id == CODEC_ID_XAN_WC3) 431 xan_wc3_decode_frame(s); 432 else if (avctx->codec->id == CODEC_ID_XAN_WC4) 433 xan_wc4_decode_frame(s); 434 435 /* release the last frame if it is allocated */ 436 if (s->last_frame.data[0]) 437 avctx->release_buffer(avctx, &s->last_frame); 438 439 *data_size = sizeof(AVFrame); 440 *(AVFrame*)data = s->current_frame; 441 442 /* shuffle frames */ 443 FFSWAP(AVFrame, s->current_frame, s->last_frame); 444 445 /* always report that the buffer was completely consumed */ 446 return buf_size; 447} 448 449static av_cold int xan_decode_end(AVCodecContext *avctx) 450{ 451 XanContext *s = avctx->priv_data; 452 453 /* release the frames */ 454 if (s->last_frame.data[0]) 455 avctx->release_buffer(avctx, &s->last_frame); 456 if (s->current_frame.data[0]) 457 avctx->release_buffer(avctx, &s->current_frame); 458 459 av_free(s->buffer1); 460 av_free(s->buffer2); 461 462 return 0; 463} 464 465AVCodec xan_wc3_decoder = { 466 "xan_wc3", 467 CODEC_TYPE_VIDEO, 468 CODEC_ID_XAN_WC3, 469 sizeof(XanContext), 470 xan_decode_init, 471 NULL, 472 xan_decode_end, 473 xan_decode_frame, 474 CODEC_CAP_DR1, 475 .long_name = NULL_IF_CONFIG_SMALL("Wing Commander III / Xan"), 476}; 477 478/* 479AVCodec xan_wc4_decoder = { 480 "xan_wc4", 481 CODEC_TYPE_VIDEO, 482 CODEC_ID_XAN_WC4, 483 sizeof(XanContext), 484 xan_decode_init, 485 NULL, 486 xan_decode_end, 487 xan_decode_frame, 488 CODEC_CAP_DR1, 489}; 490*/ 491