📄 xan.c
字号:
/* * Wing Commander/Xan Video Decoder * Copyright (C) 2003 the ffmpeg project * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * *//** * @file xan.c * Xan video decoder for Wing Commander III & IV computer games * by Mario Brito (mbrito@student.dei.uc.pt) * and Mike Melanson (melanson@pcisys.net) * * The xan_wc3 decoder outputs the following colorspaces natively: * PAL8 (default), RGB555, RGB565, RGB24, BGR24, RGBA32, YUV444P */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include "common.h"#include "avcodec.h"#include "dsputil.h"#define PALETTE_COUNT 256#define PALETTE_CONTROL_SIZE ((256 * 3) + 1)typedef struct XanContext { AVCodecContext *avctx; DSPContext dsp; AVFrame last_frame; AVFrame current_frame; unsigned char *buf; int size; unsigned char palette[PALETTE_COUNT * 4]; /* scratch space */ unsigned char *buffer1; unsigned char *buffer2;} XanContext;#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1])#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0])#define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ (((uint8_t*)(x))[2] << 16) | \ (((uint8_t*)(x))[1] << 8) | \ ((uint8_t*)(x))[0])/* RGB -> YUV conversion stuff */#define SCALEFACTOR 65536#define CENTERSAMPLE 128#define COMPUTE_Y(r, g, b) \ (unsigned char) \ ((y_r_table[r] + y_g_table[g] + y_b_table[b]) / SCALEFACTOR)#define COMPUTE_U(r, g, b) \ (unsigned char) \ ((u_r_table[r] + u_g_table[g] + u_b_table[b]) / SCALEFACTOR + CENTERSAMPLE)#define COMPUTE_V(r, g, b) \ (unsigned char) \ ((v_r_table[r] + v_g_table[g] + v_b_table[b]) / SCALEFACTOR + CENTERSAMPLE)#define Y_R (SCALEFACTOR * 0.29900)#define Y_G (SCALEFACTOR * 0.58700)#define Y_B (SCALEFACTOR * 0.11400)#define U_R (SCALEFACTOR * -0.16874)#define U_G (SCALEFACTOR * -0.33126)#define U_B (SCALEFACTOR * 0.50000)#define V_R (SCALEFACTOR * 0.50000)#define V_G (SCALEFACTOR * -0.41869)#define V_B (SCALEFACTOR * -0.08131)/* * Precalculate all of the YUV tables since it requires fewer than * 10 kilobytes to store them. */static int y_r_table[256];static int y_g_table[256];static int y_b_table[256];static int u_r_table[256];static int u_g_table[256];static int u_b_table[256];static int v_r_table[256];static int v_g_table[256];static int v_b_table[256];static int xan_decode_init(AVCodecContext *avctx){ XanContext *s = avctx->priv_data; int i; s->avctx = avctx; if ((avctx->codec->id == CODEC_ID_XAN_WC3) && (s->avctx->palctrl == NULL)) { av_log(avctx, AV_LOG_ERROR, " WC3 Xan video: palette expected.\n"); return -1; } avctx->pix_fmt = PIX_FMT_PAL8; avctx->has_b_frames = 0; dsputil_init(&s->dsp, avctx); /* initialize the RGB -> YUV tables */ for (i = 0; i < 256; i++) { y_r_table[i] = Y_R * i; y_g_table[i] = Y_G * i; y_b_table[i] = Y_B * i; u_r_table[i] = U_R * i; u_g_table[i] = U_G * i; u_b_table[i] = U_B * i; v_r_table[i] = V_R * i; v_g_table[i] = V_G * i; v_b_table[i] = V_B * i; } s->buffer1 = av_malloc(avctx->width * avctx->height); s->buffer2 = av_malloc(avctx->width * avctx->height); if (!s->buffer1 || !s->buffer2) return -1; return 0;}/* This function is used in lieu of memcpy(). This decoder can not use * memcpy because the memory locations often overlap and * memcpy doesn't like that; it's not uncommon, for example, for * dest = src+1, to turn byte A into pattern AAAAAAAA. * This was originally repz movsb in Intel x86 ASM. */static inline void bytecopy(unsigned char *dest, unsigned char *src, int count){ int i; for (i = 0; i < count; i++) dest[i] = src[i];}static int xan_huffman_decode(unsigned char *dest, unsigned char *src){ unsigned char byte = *src++; unsigned char ival = byte + 0x16; unsigned char * ptr = src + byte*2; unsigned char val = ival; int counter = 0; unsigned char bits = *ptr++; while ( val != 0x16 ) { if ( (1 << counter) & bits ) val = src[byte + val - 0x17]; else val = src[val - 0x17]; if ( val < 0x16 ) { *dest++ = val; val = ival; } if (counter++ == 7) { counter = 0; bits = *ptr++; } } return 0;}static void xan_unpack(unsigned char *dest, unsigned char *src){ unsigned char opcode; int size; int offset; int byte1, byte2, byte3; for (;;) { opcode = *src++; if ( (opcode & 0x80) == 0 ) { offset = *src++; size = opcode & 3; bytecopy(dest, src, size); dest += size; src += size; size = ((opcode & 0x1c) >> 2) + 3; bytecopy (dest, dest - (((opcode & 0x60) << 3) + offset + 1), size); dest += size; } else if ( (opcode & 0x40) == 0 ) { byte1 = *src++; byte2 = *src++; size = byte1 >> 6; bytecopy (dest, src, size); dest += size; src += size; size = (opcode & 0x3f) + 4; bytecopy (dest, dest - (((byte1 & 0x3f) << 8) + byte2 + 1), size); dest += size; } else if ( (opcode & 0x20) == 0 ) { byte1 = *src++; byte2 = *src++; byte3 = *src++; size = opcode & 3; bytecopy (dest, src, size); dest += size; src += size; size = byte3 + 5 + ((opcode & 0xc) << 6); bytecopy (dest, dest - ((((opcode & 0x10) >> 4) << 0x10) + 1 + (byte1 << 8) + byte2), size); dest += size; } else { size = ((opcode & 0x1f) << 2) + 4; if (size > 0x70) break; bytecopy (dest, src, size); dest += size; src += size; } } size = opcode & 3; bytecopy(dest, src, size); dest += size; src += size;}static void inline xan_wc3_build_palette(XanContext *s, unsigned int *palette_data){ int i; unsigned char r, g, b; unsigned short *palette16; unsigned int *palette32; unsigned int pal_elem; /* transform the palette passed through the palette control structure * into the necessary internal format depending on colorspace */ switch (s->avctx->pix_fmt) { case PIX_FMT_RGB555: palette16 = (unsigned short *)s->palette; for (i = 0; i < PALETTE_COUNT; i++) { pal_elem = palette_data[i]; r = (pal_elem >> 16) & 0xff; g = (pal_elem >> 8) & 0xff; b = pal_elem & 0xff; palette16[i] = ((r >> 3) << 10) | ((g >> 3) << 5) | ((b >> 3) << 0); } break; case PIX_FMT_RGB565: palette16 = (unsigned short *)s->palette; for (i = 0; i < PALETTE_COUNT; i++) { pal_elem = palette_data[i]; r = (pal_elem >> 16) & 0xff; g = (pal_elem >> 8) & 0xff; b = pal_elem & 0xff; palette16[i] = ((r >> 3) << 11) | ((g >> 2) << 5) | ((b >> 3) << 0); } break; case PIX_FMT_RGB24: for (i = 0; i < PALETTE_COUNT; i++) { pal_elem = palette_data[i]; r = (pal_elem >> 16) & 0xff; g = (pal_elem >> 8) & 0xff; b = pal_elem & 0xff; s->palette[i * 4 + 0] = r; s->palette[i * 4 + 1] = g; s->palette[i * 4 + 2] = b; } break; case PIX_FMT_BGR24: for (i = 0; i < PALETTE_COUNT; i++) { pal_elem = palette_data[i]; r = (pal_elem >> 16) & 0xff; g = (pal_elem >> 8) & 0xff; b = pal_elem & 0xff; s->palette[i * 4 + 0] = b; s->palette[i * 4 + 1] = g; s->palette[i * 4 + 2] = r; } break; case PIX_FMT_PAL8: case PIX_FMT_RGBA32: palette32 = (unsigned int *)s->palette; memcpy (palette32, palette_data, PALETTE_COUNT * sizeof(unsigned int)); break; case PIX_FMT_YUV444P: for (i = 0; i < PALETTE_COUNT; i++) { pal_elem = palette_data[i]; r = (pal_elem >> 16) & 0xff; g = (pal_elem >> 8) & 0xff; b = pal_elem & 0xff; s->palette[i * 4 + 0] = COMPUTE_Y(r, g, b); s->palette[i * 4 + 1] = COMPUTE_U(r, g, b); s->palette[i * 4 + 2] = COMPUTE_V(r, g, b); } break; default: av_log(s->avctx, AV_LOG_ERROR, " Xan WC3: Unhandled colorspace\n"); break; }}/* advance current_x variable; reset accounting variables if current_x * moves beyond width */#define ADVANCE_CURRENT_X() \ current_x++; \ if (current_x >= width) { \ index += line_inc; \ current_x = 0; \ }static void inline xan_wc3_output_pixel_run(XanContext *s, unsigned char *pixel_buffer, int x, int y, int pixel_count){ int stride; int line_inc; int index; int current_x; int width = s->avctx->width; unsigned char pix; unsigned char *palette_plane; unsigned char *y_plane; unsigned char *u_plane; unsigned char *v_plane; unsigned char *rgb_plane; unsigned short *rgb16_plane; unsigned short *palette16; unsigned int *rgb32_plane; unsigned int *palette32; switch (s->avctx->pix_fmt) { case PIX_FMT_PAL8: palette_plane = s->current_frame.data[0]; stride = s->current_frame.linesize[0]; line_inc = stride - width; index = y * stride + x; current_x = x; while(pixel_count--) { /* don't do a memcpy() here; keyframes generally copy an entire * frame of data and the stride needs to be accounted for */ palette_plane[index++] = *pixel_buffer++; ADVANCE_CURRENT_X(); } break; case PIX_FMT_RGB555: case PIX_FMT_RGB565: rgb16_plane = (unsigned short *)s->current_frame.data[0]; palette16 = (unsigned short *)s->palette; stride = s->current_frame.linesize[0] / 2; line_inc = stride - width; index = y * stride + x; current_x = x; while(pixel_count--) { rgb16_plane[index++] = palette16[*pixel_buffer++]; ADVANCE_CURRENT_X(); } break; case PIX_FMT_RGB24: case PIX_FMT_BGR24: rgb_plane = s->current_frame.data[0]; stride = s->current_frame.linesize[0]; line_inc = stride - width * 3; index = y * stride + x * 3; current_x = x; while(pixel_count--) { pix = *pixel_buffer++;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -