diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libffmpeg/libavcodec/8bps.c | 228 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/flicvideo.c | 399 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/lcl.c | 892 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/smc.c | 500 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/truemotion1.c | 604 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/truemotion1data.h | 813 | ||||
-rw-r--r-- | src/libffmpeg/libavcodec/vmdav.c | 548 |
7 files changed, 3984 insertions, 0 deletions
diff --git a/src/libffmpeg/libavcodec/8bps.c b/src/libffmpeg/libavcodec/8bps.c new file mode 100644 index 000000000..9509f42ad --- /dev/null +++ b/src/libffmpeg/libavcodec/8bps.c @@ -0,0 +1,228 @@ +/* + * Quicktime Planar RGB (8BPS) Video Decoder + * Copyright (C) 2003 Roberto Togni + * + * 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 8bps.c + * QT 8BPS Video Decoder by Roberto Togni <rtogni at bresciaonline dot it> + * For more information about the 8BPS format, visit: + * http://www.pcisys.net/~melanson/codecs/ + * + * Supports: PAL8 (RGB 8bpp, paletted) + * : BGR24 (RGB 24bpp) (can also output it as RGBA32) + * : RGBA32 (RGB 32bpp, 4th plane is probably alpha and it's ignored) + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "common.h" +#include "avcodec.h" + + +const enum PixelFormat pixfmt_rgb24[] = {PIX_FMT_BGR24, PIX_FMT_RGBA32, -1}; + +/* + * Decoder context + */ +typedef struct EightBpsContext { + + AVCodecContext *avctx; + AVFrame pic; + + unsigned char planes; + unsigned char planemap[4]; +} EightBpsContext; + + +/* + * + * Decode a frame + * + */ +static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size) +{ + EightBpsContext * const c = (EightBpsContext *)avctx->priv_data; + unsigned char *encoded = (unsigned char *)buf; + unsigned char *pixptr; + unsigned int height = avctx->height; // Real image height + unsigned int dlen, p, row; + unsigned char *lp, *dp; + unsigned char count; + unsigned int px_inc; + unsigned int planes = c->planes; + unsigned char *planemap = c->planemap; + + + /* no supplementary picture */ + if (buf_size == 0) + return 0; + + if(c->pic.data[0]) + avctx->release_buffer(avctx, &c->pic); + + c->pic.reference = 0; + c->pic.buffer_hints = FF_BUFFER_HINTS_VALID; + if(avctx->get_buffer(avctx, &c->pic) < 0){ + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + + /* Set data pointer after line lengths */ + dp = encoded + planes * (height << 1); + + /* Ignore alpha plane, don't know what to do with it */ + if (planes == 4) + planes--; + + px_inc = planes + (avctx->pix_fmt == PIX_FMT_RGBA32); + + for (p = 0; p < planes; p++) { + /* Lines length pointer for this plane */ + lp = encoded + p * (height << 1); + + /* Decode a plane */ + for(row = 0; row < height; row++) { + pixptr = c->pic.data[0] + row * c->pic.linesize[0] + planemap[p]; + dlen = be2me_16(*(unsigned short *)(lp+row*2)); + /* Decode a row of this plane */ + while(dlen > 0) { + if ((count = *dp++) <= 127) { + count++; + dlen -= count + 1; + while(count--) { + *pixptr = *dp++; + pixptr += px_inc; + } + } else { + count = 257 - count; + while(count--) { + *pixptr = *dp; + pixptr += px_inc; + } + dp++; + dlen -= 2; + } + } + } + } + + if (avctx->palctrl) { + memcpy (c->pic.data[1], avctx->palctrl->palette, AVPALETTE_SIZE); + if (avctx->palctrl->palette_changed) { + c->pic.palette_has_changed = 1; + avctx->palctrl->palette_changed = 0; + } else + c->pic.palette_has_changed = 0; + } + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = c->pic; + + /* always report that the buffer was completely consumed */ + return buf_size; +} + + +/* + * + * Init 8BPS decoder + * + */ +static int decode_init(AVCodecContext *avctx) +{ + EightBpsContext * const c = (EightBpsContext *)avctx->priv_data; + + c->avctx = avctx; + avctx->has_b_frames = 0; + + c->pic.data[0] = NULL; + + switch (avctx->bits_per_sample) { + case 8: + avctx->pix_fmt = PIX_FMT_PAL8; + c->planes = 1; + c->planemap[0] = 0; // 1st plane is palette indexes + if (avctx->palctrl == NULL) { + av_log(avctx, AV_LOG_ERROR, "Error: PAL8 format but no palette from demuxer.\n"); + return -1; + } + break; + case 24: + avctx->pix_fmt = avctx->get_format(avctx, pixfmt_rgb24); + c->planes = 3; + c->planemap[0] = 2; // 1st plane is red + c->planemap[1] = 1; // 2nd plane is green + c->planemap[2] = 0; // 3rd plane is blue + break; + case 32: + avctx->pix_fmt = PIX_FMT_RGBA32; + c->planes = 4; +#ifdef WORDS_BIGENDIAN + c->planemap[0] = 1; // 1st plane is red + c->planemap[1] = 2; // 2nd plane is green + c->planemap[2] = 3; // 3rd plane is blue + c->planemap[3] = 0; // 4th plane is alpha??? +#else + c->planemap[0] = 2; // 1st plane is red + c->planemap[1] = 1; // 2nd plane is green + c->planemap[2] = 0; // 3rd plane is blue + c->planemap[3] = 3; // 4th plane is alpha??? +#endif + break; + default: + av_log(avctx, AV_LOG_ERROR, "Error: Unsupported color depth: %u.\n", avctx->bits_per_sample); + return -1; + } + + return 0; +} + + + + +/* + * + * Uninit 8BPS decoder + * + */ +static int decode_end(AVCodecContext *avctx) +{ + EightBpsContext * const c = (EightBpsContext *)avctx->priv_data; + + if (c->pic.data[0]) + avctx->release_buffer(avctx, &c->pic); + + return 0; +} + + + +AVCodec eightbps_decoder = { + "8bps", + CODEC_TYPE_VIDEO, + CODEC_ID_8BPS, + sizeof(EightBpsContext), + decode_init, + NULL, + decode_end, + decode_frame, + CODEC_CAP_DR1, +}; diff --git a/src/libffmpeg/libavcodec/flicvideo.c b/src/libffmpeg/libavcodec/flicvideo.c new file mode 100644 index 000000000..248fc843a --- /dev/null +++ b/src/libffmpeg/libavcodec/flicvideo.c @@ -0,0 +1,399 @@ +/* + * FLI/FLC Animation Video Decoder + * Copyright (C) 2003, 2004 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 flic.c + * Autodesk Animator FLI/FLC Video Decoder + * by Mike Melanson (melanson@pcisys.net) + * for more information on the .fli/.flc file format and all of its many + * variations, visit: + * http://www.compuphase.com/flic.htm + * + * This decoder outputs PAL8 colorspace data. To use this decoder, be + * sure that your demuxer sends the FLI file header to the decoder via + * the extradata chunk in AVCodecContext. The chunk should be 128 bytes + * large. The only exception is for FLI files from the game "Magic Carpet", + * in which the header is only 12 bytes. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "common.h" +#include "avcodec.h" +#include "bswap.h" + +#define FLI_256_COLOR 4 +#define FLI_DELTA 7 +#define FLI_COLOR 11 +#define FLI_LC 12 +#define FLI_BLACK 13 +#define FLI_BRUN 15 +#define FLI_COPY 16 +#define FLI_MINI 18 + +#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]) + +typedef struct FlicDecodeContext { + AVCodecContext *avctx; + AVFrame frame; + + unsigned int palette[256]; + int new_palette; + int fli_type; /* either 0xAF11 or 0xAF12, affects palette resolution */ +} FlicDecodeContext; + +static int flic_decode_init(AVCodecContext *avctx) +{ + FlicDecodeContext *s = (FlicDecodeContext *)avctx->priv_data; + unsigned char *fli_header = (unsigned char *)avctx->extradata; + + s->avctx = avctx; + avctx->pix_fmt = PIX_FMT_PAL8; + avctx->has_b_frames = 0; + + if (s->avctx->extradata_size == 12) { + /* special case for magic carpet FLIs */ + s->fli_type = 0xAF13; + } else if (s->avctx->extradata_size == 128) { + s->fli_type = LE_16(&fli_header[4]); + } else { + av_log(avctx, AV_LOG_ERROR, "Expected extradata of 12 or 128 bytes\n"); + return -1; + } + + s->frame.data[0] = NULL; + s->new_palette = 0; + + return 0; +} + +static int flic_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + FlicDecodeContext *s = (FlicDecodeContext *)avctx->priv_data; + + int stream_ptr = 0; + int stream_ptr_after_color_chunk; + int pixel_ptr; + int palette_ptr; + unsigned char palette_idx1; + unsigned char palette_idx2; + + unsigned int frame_size; + int num_chunks; + + unsigned int chunk_size; + int chunk_type; + + int i, j; + + int color_packets; + int color_changes; + int color_shift; + unsigned char r, g, b; + + int lines; + int compressed_lines; + int starting_line; + signed short line_packets; + int y_ptr; + signed char byte_run; + int pixel_skip; + int pixel_countdown; + unsigned char *pixels; + + s->frame.reference = 1; + s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | FF_BUFFER_HINTS_REUSABLE; + if (avctx->reget_buffer(avctx, &s->frame) < 0) { + av_log(avctx, AV_LOG_ERROR, "reget_buffer() failed\n"); + return -1; + } + + pixels = s->frame.data[0]; + + frame_size = LE_32(&buf[stream_ptr]); + stream_ptr += 6; /* skip the magic number */ + num_chunks = LE_16(&buf[stream_ptr]); + stream_ptr += 10; /* skip padding */ + + frame_size -= 16; + + /* iterate through the chunks */ + while ((frame_size > 0) && (num_chunks > 0)) { + chunk_size = LE_32(&buf[stream_ptr]); + stream_ptr += 4; + chunk_type = LE_16(&buf[stream_ptr]); + stream_ptr += 2; + + switch (chunk_type) { + case FLI_256_COLOR: + case FLI_COLOR: + stream_ptr_after_color_chunk = stream_ptr + chunk_size - 6; + s->new_palette = 1; + + /* check special case: If this file is from the Magic Carpet + * game and uses 6-bit colors even though it reports 256-color + * chunks in a 0xAF12-type file (fli_type is set to 0xAF13 during + * initialization) */ + if ((chunk_type == FLI_256_COLOR) && (s->fli_type != 0xAF13)) + color_shift = 0; + else + color_shift = 2; + /* set up the palette */ + color_packets = LE_16(&buf[stream_ptr]); + stream_ptr += 2; + palette_ptr = 0; + for (i = 0; i < color_packets; i++) { + /* first byte is how many colors to skip */ + palette_ptr += buf[stream_ptr++]; + + /* next byte indicates how many entries to change */ + color_changes = buf[stream_ptr++]; + + /* if there are 0 color changes, there are actually 256 */ + if (color_changes == 0) + color_changes = 256; + + for (j = 0; j < color_changes; j++) { + + /* wrap around, for good measure */ + if (palette_ptr >= 256) + palette_ptr = 0; + + r = buf[stream_ptr++] << color_shift; + g = buf[stream_ptr++] << color_shift; + b = buf[stream_ptr++] << color_shift; + s->palette[palette_ptr++] = (r << 16) | (g << 8) | b; + } + } + + /* color chunks sometimes have weird 16-bit alignment issues; + * therefore, take the hardline approach and set the stream_ptr + * to the value calculated w.r.t. the size specified by the color + * chunk header */ + stream_ptr = stream_ptr_after_color_chunk; + + break; + + case FLI_DELTA: + y_ptr = 0; + compressed_lines = LE_16(&buf[stream_ptr]); + stream_ptr += 2; + while (compressed_lines > 0) { + line_packets = LE_16(&buf[stream_ptr]); + stream_ptr += 2; + if (line_packets < 0) { + line_packets = -line_packets; + y_ptr += line_packets * s->frame.linesize[0]; + } else { + compressed_lines--; + pixel_ptr = y_ptr; + pixel_countdown = s->avctx->width; + for (i = 0; i < line_packets; i++) { + /* account for the skip bytes */ + pixel_skip = buf[stream_ptr++]; + pixel_ptr += pixel_skip; + pixel_countdown -= pixel_skip; + byte_run = buf[stream_ptr++]; + if (byte_run < 0) { + byte_run = -byte_run; + palette_idx1 = buf[stream_ptr++]; + palette_idx2 = buf[stream_ptr++]; + for (j = 0; j < byte_run; j++, pixel_countdown -= 2) { + pixels[pixel_ptr++] = palette_idx1; + pixels[pixel_ptr++] = palette_idx2; + } + } else { + for (j = 0; j < byte_run * 2; j++, pixel_countdown--) { + palette_idx1 = buf[stream_ptr++]; + pixels[pixel_ptr++] = palette_idx1; + } + } + } + + y_ptr += s->frame.linesize[0]; + } + } + break; + + case FLI_LC: + /* line compressed */ + starting_line = LE_16(&buf[stream_ptr]); + stream_ptr += 2; + y_ptr = 0; + y_ptr += starting_line * s->frame.linesize[0]; + + compressed_lines = LE_16(&buf[stream_ptr]); + stream_ptr += 2; + while (compressed_lines > 0) { + pixel_ptr = y_ptr; + pixel_countdown = s->avctx->width; + line_packets = buf[stream_ptr++]; + if (line_packets > 0) { + for (i = 0; i < line_packets; i++) { + /* account for the skip bytes */ + pixel_skip = buf[stream_ptr++]; + pixel_ptr += pixel_skip; + pixel_countdown -= pixel_skip; + byte_run = buf[stream_ptr++]; + if (byte_run > 0) { + for (j = 0; j < byte_run; j++, pixel_countdown--) { + palette_idx1 = buf[stream_ptr++]; + pixels[pixel_ptr++] = palette_idx1; + } + } else { + byte_run = -byte_run; + palette_idx1 = buf[stream_ptr++]; + for (j = 0; j < byte_run; j++, pixel_countdown--) { + pixels[pixel_ptr++] = palette_idx1; + } + } + } + } + + y_ptr += s->frame.linesize[0]; + compressed_lines--; + } + break; + + case FLI_BLACK: + /* set the whole frame to color 0 (which is usually black) */ + memset(pixels, 0, + s->frame.linesize[0] * s->avctx->height); + break; + + case FLI_BRUN: + /* Byte run compression: This chunk type only occurs in the first + * FLI frame and it will update the entire frame. */ + y_ptr = 0; + for (lines = 0; lines < s->avctx->height; lines++) { + pixel_ptr = y_ptr; + /* disregard the line packets; instead, iterate through all + * pixels on a row */ + stream_ptr++; + pixel_countdown = s->avctx->width; + while (pixel_countdown > 0) { + byte_run = buf[stream_ptr++]; + if (byte_run > 0) { + palette_idx1 = buf[stream_ptr++]; + for (j = 0; j < byte_run; j++) { + pixels[pixel_ptr++] = palette_idx1; + pixel_countdown--; + if (pixel_countdown < 0) + av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", + pixel_countdown); + } + } else { /* copy bytes if byte_run < 0 */ + byte_run = -byte_run; + for (j = 0; j < byte_run; j++) { + palette_idx1 = buf[stream_ptr++]; + pixels[pixel_ptr++] = palette_idx1; + pixel_countdown--; + if (pixel_countdown < 0) + av_log(avctx, AV_LOG_ERROR, "pixel_countdown < 0 (%d)\n", + pixel_countdown); + } + } + } + + y_ptr += s->frame.linesize[0]; + } + break; + + case FLI_COPY: + /* copy the chunk (uncompressed frame) */ + if (chunk_size - 6 > s->avctx->width * s->avctx->height) { + av_log(avctx, AV_LOG_ERROR, "In chunk FLI_COPY : source data (%d bytes) " \ + "bigger than image, skipping chunk\n", chunk_size - 6); + stream_ptr += chunk_size - 6; + } else { + for (y_ptr = 0; y_ptr < s->frame.linesize[0] * s->avctx->height; + y_ptr += s->frame.linesize[0]) { + memcpy(&pixels[y_ptr], &buf[stream_ptr], + s->avctx->width); + stream_ptr += s->avctx->width; + } + } + break; + + case FLI_MINI: + /* some sort of a thumbnail? disregard this chunk... */ + stream_ptr += chunk_size - 6; + break; + + default: + av_log(avctx, AV_LOG_ERROR, "Unrecognized chunk type: %d\n", chunk_type); + break; + } + + frame_size -= chunk_size; + num_chunks--; + } + + /* by the end of the chunk, the stream ptr should equal the frame + * size (minus 1, possibly); if it doesn't, issue a warning */ + if ((stream_ptr != buf_size) && (stream_ptr != buf_size - 1)) + av_log(avctx, AV_LOG_ERROR, "Processed FLI chunk where chunk size = %d " \ + "and final chunk ptr = %d\n", buf_size, stream_ptr); + + /* make the palette available on the way out */ +// if (s->new_palette) { + if (1) { + memcpy(s->frame.data[1], s->palette, AVPALETTE_SIZE); + s->frame.palette_has_changed = 1; + s->new_palette = 0; + } + + *data_size=sizeof(AVFrame); + *(AVFrame*)data = s->frame; + + return buf_size; +} + +static int flic_decode_end(AVCodecContext *avctx) +{ + FlicDecodeContext *s = avctx->priv_data; + + if (s->frame.data[0]) + avctx->release_buffer(avctx, &s->frame); + + return 0; +} + +AVCodec flic_decoder = { + "flic", + CODEC_TYPE_VIDEO, + CODEC_ID_FLIC, + sizeof(FlicDecodeContext), + flic_decode_init, + NULL, + flic_decode_end, + flic_decode_frame, + CODEC_CAP_DR1, + NULL +}; diff --git a/src/libffmpeg/libavcodec/lcl.c b/src/libffmpeg/libavcodec/lcl.c new file mode 100644 index 000000000..9a8591a89 --- /dev/null +++ b/src/libffmpeg/libavcodec/lcl.c @@ -0,0 +1,892 @@ +/* + * LCL (LossLess Codec Library) Codec + * Copyright (c) 2002-2004 Roberto Togni + * + * 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 lcl.c + * LCL (LossLess Codec Library) Video Codec + * Decoder for MSZH and ZLIB codecs + * Experimental encoder for ZLIB RGB24 + * + * Fourcc: MSZH, ZLIB + * + * Original Win32 dll: + * Ver2.23 By Kenji Oshima 2000.09.20 + * avimszh.dll, avizlib.dll + * + * A description of the decoding algorithm can be found here: + * http://www.pcisys.net/~melanson/codecs + * + * Supports: BGR24 (RGB 24bpp) + * + */ + +#include <stdio.h> +#include <stdlib.h> + +#include "common.h" +#include "avcodec.h" + +#ifdef CONFIG_ZLIB +#include <zlib.h> +#endif + + +#define BMPTYPE_YUV 1 +#define BMPTYPE_RGB 2 + +#define IMGTYPE_YUV111 0 +#define IMGTYPE_YUV422 1 +#define IMGTYPE_RGB24 2 +#define IMGTYPE_YUV411 3 +#define IMGTYPE_YUV211 4 +#define IMGTYPE_YUV420 5 + +#define COMP_MSZH 0 +#define COMP_MSZH_NOCOMP 1 +#define COMP_ZLIB_HISPEED 1 +#define COMP_ZLIB_HICOMP 9 +#define COMP_ZLIB_NORMAL -1 + +#define FLAG_MULTITHREAD 1 +#define FLAG_NULLFRAME 2 +#define FLAG_PNGFILTER 4 +#define FLAGMASK_UNUSED 0xf8 + +#define CODEC_MSZH 1 +#define CODEC_ZLIB 3 + +#define FOURCC_MSZH mmioFOURCC('M','S','Z','H') +#define FOURCC_ZLIB mmioFOURCC('Z','L','I','B') + +/* + * Decoder context + */ +typedef struct LclContext { + + AVCodecContext *avctx; + AVFrame pic; + PutBitContext pb; + + // Image type + int imgtype; + // Compression type + int compression; + // Flags + int flags; + // Decompressed data size + unsigned int decomp_size; + // Decompression buffer + unsigned char* decomp_buf; + // Maximum compressed data size + unsigned int max_comp_size; + // Compression buffer + unsigned char* comp_buf; +#ifdef CONFIG_ZLIB + z_stream zstream; +#endif +} LclContext; + + +/* + * + * Helper functions + * + */ +static inline unsigned char fix (int pix14) +{ + int tmp; + + tmp = (pix14 + 0x80000) >> 20; + if (tmp < 0) + return 0; + if (tmp > 255) + return 255; + return tmp; +} + + + +static inline unsigned char get_b (unsigned char yq, signed char bq) +{ + return fix((yq << 20) + bq * 1858076); +} + + + +static inline unsigned char get_g (unsigned char yq, signed char bq, signed char rq) +{ + return fix((yq << 20) - bq * 360857 - rq * 748830); +} + + + +static inline unsigned char get_r (unsigned char yq, signed char rq) +{ + return fix((yq << 20) + rq * 1470103); +} + + + +static int mszh_decomp(unsigned char * srcptr, int srclen, unsigned char * destptr) +{ + unsigned char *destptr_bak = destptr; + unsigned char mask = 0; + unsigned char maskbit = 0; + unsigned int ofs, cnt; + + while (srclen > 0) { + if (maskbit == 0) { + mask = *(srcptr++); + maskbit = 8; + srclen--; + continue; + } + if ((mask & (1 << (--maskbit))) == 0) { + *(int*)destptr = *(int*)srcptr; + srclen -= 4; + destptr += 4; + srcptr += 4; + } else { + ofs = *(srcptr++); + cnt = *(srcptr++); + ofs += cnt * 256;; + cnt = ((cnt >> 3) & 0x1f) + 1; + ofs &= 0x7ff; + srclen -= 2; + cnt *= 4; + for (; cnt > 0; cnt--) { + *(destptr) = *(destptr - ofs); + destptr++; + } + } + } + + return (destptr - destptr_bak); +} + + + + +/* + * + * Decode a frame + * + */ +static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, uint8_t *buf, int buf_size) +{ + LclContext * const c = (LclContext *)avctx->priv_data; + unsigned char *encoded = (unsigned char *)buf; + int pixel_ptr; + int row, col; + unsigned char *outptr; + unsigned int width = avctx->width; // Real image width + unsigned int height = avctx->height; // Real image height + unsigned int mszh_dlen; + unsigned char yq, y1q, uq, vq; + int uqvq; + unsigned int mthread_inlen, mthread_outlen; +#ifdef CONFIG_ZLIB + int zret; // Zlib return code +#endif + int len = buf_size; + + /* no supplementary picture */ + if (buf_size == 0) + return 0; + + if(c->pic.data[0]) + avctx->release_buffer(avctx, &c->pic); + + c->pic.reference = 0; + c->pic.buffer_hints = FF_BUFFER_HINTS_VALID; + if(avctx->get_buffer(avctx, &c->pic) < 0){ + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + + outptr = c->pic.data[0]; // Output image pointer + + /* Decompress frame */ + switch (avctx->codec_id) { + case CODEC_ID_MSZH: + switch (c->compression) { + case COMP_MSZH: + if (c->flags & FLAG_MULTITHREAD) { + mthread_inlen = *((unsigned int*)encoded); + mthread_outlen = *((unsigned int*)(encoded+4)); + mszh_dlen = mszh_decomp(encoded + 8, mthread_inlen, c->decomp_buf); + if (mthread_outlen != mszh_dlen) { + av_log(avctx, AV_LOG_ERROR, "Mthread1 decoded size differs (%d != %d)\n", + mthread_outlen, mszh_dlen); + } + mszh_dlen = mszh_decomp(encoded + 8 + mthread_inlen, len - mthread_inlen, + c->decomp_buf + mthread_outlen); + if ((c->decomp_size - mthread_outlen) != mszh_dlen) { + av_log(avctx, AV_LOG_ERROR, "Mthread2 decoded size differs (%d != %d)\n", + c->decomp_size - mthread_outlen, mszh_dlen); + } + encoded = c->decomp_buf; + len = c->decomp_size; + } else { + mszh_dlen = mszh_decomp(encoded, len, c->decomp_buf); + if (c->decomp_size != mszh_dlen) { + av_log(avctx, AV_LOG_ERROR, "Decoded size differs (%d != %d)\n", + c->decomp_size, mszh_dlen); + } + encoded = c->decomp_buf; + len = mszh_dlen; + } + break; + case COMP_MSZH_NOCOMP: + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown MSZH compression in frame decoder.\n"); + return -1; + } + break; + case CODEC_ID_ZLIB: +#ifdef CONFIG_ZLIB + /* Using the original dll with normal compression (-1) and RGB format + * gives a file with ZLIB fourcc, but frame is really uncompressed. + * To be sure that's true check also frame size */ + if ((c->compression == COMP_ZLIB_NORMAL) && (c->imgtype == IMGTYPE_RGB24) && + (len == width * height * 3)) + break; + zret = inflateReset(&(c->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret); + return -1; + } + if (c->flags & FLAG_MULTITHREAD) { + mthread_inlen = *((unsigned int*)encoded); + mthread_outlen = *((unsigned int*)(encoded+4)); + c->zstream.next_in = encoded + 8; + c->zstream.avail_in = mthread_inlen; + c->zstream.next_out = c->decomp_buf; + c->zstream.avail_out = mthread_outlen; + zret = inflate(&(c->zstream), Z_FINISH); + if ((zret != Z_OK) && (zret != Z_STREAM_END)) { + av_log(avctx, AV_LOG_ERROR, "Mthread1 inflate error: %d\n", zret); + return -1; + } + if (mthread_outlen != (unsigned int)(c->zstream.total_out)) { + av_log(avctx, AV_LOG_ERROR, "Mthread1 decoded size differs (%u != %lu)\n", + mthread_outlen, c->zstream.total_out); + } + zret = inflateReset(&(c->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Mthread2 inflate reset error: %d\n", zret); + return -1; + } + c->zstream.next_in = encoded + 8 + mthread_inlen; + c->zstream.avail_in = len - mthread_inlen; + c->zstream.next_out = c->decomp_buf + mthread_outlen; + c->zstream.avail_out = mthread_outlen; + zret = inflate(&(c->zstream), Z_FINISH); + if ((zret != Z_OK) && (zret != Z_STREAM_END)) { + av_log(avctx, AV_LOG_ERROR, "Mthread2 inflate error: %d\n", zret); + return -1; + } + if ((c->decomp_size - mthread_outlen) != (unsigned int)(c->zstream.total_out)) { + av_log(avctx, AV_LOG_ERROR, "Mthread2 decoded size differs (%d != %lu)\n", + c->decomp_size - mthread_outlen, c->zstream.total_out); + } + } else { + c->zstream.next_in = encoded; + c->zstream.avail_in = len; + c->zstream.next_out = c->decomp_buf; + c->zstream.avail_out = c->decomp_size; + zret = inflate(&(c->zstream), Z_FINISH); + if ((zret != Z_OK) && (zret != Z_STREAM_END)) { + av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", zret); + return -1; + } + if (c->decomp_size != (unsigned int)(c->zstream.total_out)) { + av_log(avctx, AV_LOG_ERROR, "Decoded size differs (%d != %lu)\n", + c->decomp_size, c->zstream.total_out); + } + } + encoded = c->decomp_buf; + len = c->decomp_size;; +#else + av_log(avctx, AV_LOG_ERROR, "BUG! Zlib support not compiled in frame decoder.\n"); + return -1; +#endif + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown codec in frame decoder compression switch.\n"); + return -1; + } + + + /* Apply PNG filter */ + if ((avctx->codec_id == CODEC_ID_ZLIB) && (c->flags & FLAG_PNGFILTER)) { + switch (c->imgtype) { + case IMGTYPE_YUV111: + case IMGTYPE_RGB24: + for (row = 0; row < height; row++) { + pixel_ptr = row * width * 3; + yq = encoded[pixel_ptr++]; + uqvq = encoded[pixel_ptr++]; + uqvq+=(encoded[pixel_ptr++] << 8); + for (col = 1; col < width; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + uqvq -= (encoded[pixel_ptr+1] | (encoded[pixel_ptr+2]<<8)); + encoded[pixel_ptr+1] = (uqvq) & 0xff; + encoded[pixel_ptr+2] = ((uqvq)>>8) & 0xff; + pixel_ptr += 3; + } + } + break; + case IMGTYPE_YUV422: + for (row = 0; row < height; row++) { + pixel_ptr = row * width * 2; + yq = uq = vq =0; + for (col = 0; col < width/4; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1]; + encoded[pixel_ptr+2] = yq -= encoded[pixel_ptr+2]; + encoded[pixel_ptr+3] = yq -= encoded[pixel_ptr+3]; + encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4]; + encoded[pixel_ptr+5] = uq -= encoded[pixel_ptr+5]; + encoded[pixel_ptr+6] = vq -= encoded[pixel_ptr+6]; + encoded[pixel_ptr+7] = vq -= encoded[pixel_ptr+7]; + pixel_ptr += 8; + } + } + break; + case IMGTYPE_YUV411: + for (row = 0; row < height; row++) { + pixel_ptr = row * width / 2 * 3; + yq = uq = vq =0; + for (col = 0; col < width/4; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1]; + encoded[pixel_ptr+2] = yq -= encoded[pixel_ptr+2]; + encoded[pixel_ptr+3] = yq -= encoded[pixel_ptr+3]; + encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4]; + encoded[pixel_ptr+5] = vq -= encoded[pixel_ptr+5]; + pixel_ptr += 6; + } + } + break; + case IMGTYPE_YUV211: + for (row = 0; row < height; row++) { + pixel_ptr = row * width * 2; + yq = uq = vq =0; + for (col = 0; col < width/2; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1]; + encoded[pixel_ptr+2] = uq -= encoded[pixel_ptr+2]; + encoded[pixel_ptr+3] = vq -= encoded[pixel_ptr+3]; + pixel_ptr += 4; + } + } + break; + case IMGTYPE_YUV420: + for (row = 0; row < height/2; row++) { + pixel_ptr = row * width * 3; + yq = y1q = uq = vq =0; + for (col = 0; col < width/2; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1]; + encoded[pixel_ptr+2] = y1q -= encoded[pixel_ptr+2]; + encoded[pixel_ptr+3] = y1q -= encoded[pixel_ptr+3]; + encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4]; + encoded[pixel_ptr+5] = vq -= encoded[pixel_ptr+5]; + pixel_ptr += 6; + } + } + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown imagetype in pngfilter switch.\n"); + return -1; + } + } + + /* Convert colorspace */ + switch (c->imgtype) { + case IMGTYPE_YUV111: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width; col++) { + outptr[pixel_ptr++] = get_b(encoded[0], encoded[1]); + outptr[pixel_ptr++] = get_g(encoded[0], encoded[1], encoded[2]); + outptr[pixel_ptr++] = get_r(encoded[0], encoded[2]); + encoded += 3; + } + } + break; + case IMGTYPE_YUV422: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width/4; col++) { + outptr[pixel_ptr++] = get_b(encoded[0], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[0], encoded[4], encoded[6]); + outptr[pixel_ptr++] = get_r(encoded[0], encoded[6]); + outptr[pixel_ptr++] = get_b(encoded[1], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[1], encoded[4], encoded[6]); + outptr[pixel_ptr++] = get_r(encoded[1], encoded[6]); + outptr[pixel_ptr++] = get_b(encoded[2], encoded[5]); + outptr[pixel_ptr++] = get_g(encoded[2], encoded[5], encoded[7]); + outptr[pixel_ptr++] = get_r(encoded[2], encoded[7]); + outptr[pixel_ptr++] = get_b(encoded[3], encoded[5]); + outptr[pixel_ptr++] = get_g(encoded[3], encoded[5], encoded[7]); + outptr[pixel_ptr++] = get_r(encoded[3], encoded[7]); + encoded += 8; + } + } + break; + case IMGTYPE_RGB24: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width; col++) { + outptr[pixel_ptr++] = encoded[0]; + outptr[pixel_ptr++] = encoded[1]; + outptr[pixel_ptr++] = encoded[2]; + encoded += 3; + } + } + break; + case IMGTYPE_YUV411: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width/4; col++) { + outptr[pixel_ptr++] = get_b(encoded[0], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[0], encoded[4], encoded[5]); + outptr[pixel_ptr++] = get_r(encoded[0], encoded[5]); + outptr[pixel_ptr++] = get_b(encoded[1], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[1], encoded[4], encoded[5]); + outptr[pixel_ptr++] = get_r(encoded[1], encoded[5]); + outptr[pixel_ptr++] = get_b(encoded[2], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[2], encoded[4], encoded[5]); + outptr[pixel_ptr++] = get_r(encoded[2], encoded[5]); + outptr[pixel_ptr++] = get_b(encoded[3], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[3], encoded[4], encoded[5]); + outptr[pixel_ptr++] = get_r(encoded[3], encoded[5]); + encoded += 6; + } + } + break; + case IMGTYPE_YUV211: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width/2; col++) { + outptr[pixel_ptr++] = get_b(encoded[0], encoded[2]); + outptr[pixel_ptr++] = get_g(encoded[0], encoded[2], encoded[3]); + outptr[pixel_ptr++] = get_r(encoded[0], encoded[3]); + outptr[pixel_ptr++] = get_b(encoded[1], encoded[2]); + outptr[pixel_ptr++] = get_g(encoded[1], encoded[2], encoded[3]); + outptr[pixel_ptr++] = get_r(encoded[1], encoded[3]); + encoded += 4; + } + } + break; + case IMGTYPE_YUV420: + for (row = height / 2 - 1; row >= 0; row--) { + pixel_ptr = 2 * row * c->pic.linesize[0]; + for (col = 0; col < width/2; col++) { + outptr[pixel_ptr] = get_b(encoded[0], encoded[4]); + outptr[pixel_ptr+1] = get_g(encoded[0], encoded[4], encoded[5]); + outptr[pixel_ptr+2] = get_r(encoded[0], encoded[5]); + outptr[pixel_ptr+3] = get_b(encoded[1], encoded[4]); + outptr[pixel_ptr+4] = get_g(encoded[1], encoded[4], encoded[5]); + outptr[pixel_ptr+5] = get_r(encoded[1], encoded[5]); + outptr[pixel_ptr-c->pic.linesize[0]] = get_b(encoded[2], encoded[4]); + outptr[pixel_ptr-c->pic.linesize[0]+1] = get_g(encoded[2], encoded[4], encoded[5]); + outptr[pixel_ptr-c->pic.linesize[0]+2] = get_r(encoded[2], encoded[5]); + outptr[pixel_ptr-c->pic.linesize[0]+3] = get_b(encoded[3], encoded[4]); + outptr[pixel_ptr-c->pic.linesize[0]+4] = get_g(encoded[3], encoded[4], encoded[5]); + outptr[pixel_ptr-c->pic.linesize[0]+5] = get_r(encoded[3], encoded[5]); + pixel_ptr += 6; + encoded += 6; + } + } + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown imagetype in image decoder.\n"); + return -1; + } + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = c->pic; + + /* always report that the buffer was completely consumed */ + return buf_size; +} + + + +/* + * + * Encode a frame + * + */ +static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){ + LclContext *c = avctx->priv_data; + AVFrame *pict = data; + AVFrame * const p = &c->pic; + int i; + int zret; // Zlib return code + +#ifndef CONFIG_ZLIB + av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled in.\n"); + return -1; +#else + + init_put_bits(&c->pb, buf, buf_size); + + *p = *pict; + p->pict_type= FF_I_TYPE; + p->key_frame= 1; + + if(avctx->pix_fmt != PIX_FMT_BGR24){ + av_log(avctx, AV_LOG_ERROR, "Format not supported!\n"); + return -1; + } + + zret = deflateReset(&(c->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Deflate reset error: %d\n", zret); + return -1; + } + c->zstream.next_in = p->data[0]; + c->zstream.avail_in = c->decomp_size; + c->zstream.next_out = c->comp_buf; + c->zstream.avail_out = c->max_comp_size; + + zret = deflate(&(c->zstream), Z_FINISH); + if ((zret != Z_OK) && (zret != Z_STREAM_END)) { + av_log(avctx, AV_LOG_ERROR, "Deflate error: %d\n", zret); + return -1; + } + + for (i = 0; i < c->zstream.total_out; i++) + put_bits(&c->pb, 8, c->comp_buf[i]); + flush_put_bits(&c->pb); + + return c->zstream.total_out; +#endif +} + + + +/* + * + * Init lcl decoder + * + */ +static int decode_init(AVCodecContext *avctx) +{ + LclContext * const c = (LclContext *)avctx->priv_data; + int basesize = avctx->width * avctx->height; + int zret; // Zlib return code + + c->avctx = avctx; + avctx->has_b_frames = 0; + + c->pic.data[0] = NULL; + +#ifdef CONFIG_ZLIB + // Needed if zlib unused or init aborted before inflateInit + memset(&(c->zstream), 0, sizeof(z_stream)); +#endif + + if (avctx->extradata_size < 8) { + av_log(avctx, AV_LOG_ERROR, "Extradata size too small.\n"); + return 1; + } + + /* Check codec type */ + if (((avctx->codec_id == CODEC_ID_MSZH) && (*((char *)avctx->extradata + 7) != CODEC_MSZH)) || + ((avctx->codec_id == CODEC_ID_ZLIB) && (*((char *)avctx->extradata + 7) != CODEC_ZLIB))) { + av_log(avctx, AV_LOG_ERROR, "Codec id and codec type mismatch. This should not happen.\n"); + } + + /* Detect image type */ + switch (c->imgtype = *((char *)avctx->extradata + 4)) { + case IMGTYPE_YUV111: + c->decomp_size = basesize * 3; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 1:1:1.\n"); + break; + case IMGTYPE_YUV422: + c->decomp_size = basesize * 2; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:2:2.\n"); + break; + case IMGTYPE_RGB24: + c->decomp_size = basesize * 3; + av_log(avctx, AV_LOG_INFO, "Image type is RGB 24.\n"); + break; + case IMGTYPE_YUV411: + c->decomp_size = basesize / 2 * 3; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:1:1.\n"); + break; + case IMGTYPE_YUV211: + c->decomp_size = basesize * 2; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 2:1:1.\n"); + break; + case IMGTYPE_YUV420: + c->decomp_size = basesize / 2 * 3; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:2:0.\n"); + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported image format %d.\n", c->imgtype); + return 1; + } + + /* Detect compression method */ + c->compression = *((char *)avctx->extradata + 5); + switch (avctx->codec_id) { + case CODEC_ID_MSZH: + switch (c->compression) { + case COMP_MSZH: + av_log(avctx, AV_LOG_INFO, "Compression enabled.\n"); + break; + case COMP_MSZH_NOCOMP: + c->decomp_size = 0; + av_log(avctx, AV_LOG_INFO, "No compression.\n"); + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported compression format for MSZH (%d).\n", c->compression); + return 1; + } + break; + case CODEC_ID_ZLIB: +#ifdef CONFIG_ZLIB + switch (c->compression) { + case COMP_ZLIB_HISPEED: + av_log(avctx, AV_LOG_INFO, "High speed compression.\n"); + break; + case COMP_ZLIB_HICOMP: + av_log(avctx, AV_LOG_INFO, "High compression.\n"); + break; + case COMP_ZLIB_NORMAL: + av_log(avctx, AV_LOG_INFO, "Normal compression.\n"); + break; + default: + if ((c->compression < Z_NO_COMPRESSION) || (c->compression > Z_BEST_COMPRESSION)) { + av_log(avctx, AV_LOG_ERROR, "Unusupported compression level for ZLIB: (%d).\n", c->compression); + return 1; + } + av_log(avctx, AV_LOG_INFO, "Compression level for ZLIB: (%d).\n", c->compression); + } +#else + av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n"); + return 1; +#endif + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown codec in compression switch.\n"); + return 1; + } + + /* Allocate decompression buffer */ + /* 4*8 max overflow space for mszh decomp algorithm */ + if (c->decomp_size) { + if ((c->decomp_buf = av_malloc(c->decomp_size+4*8)) == NULL) { + av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); + return 1; + } + } + + /* Detect flags */ + c->flags = *((char *)avctx->extradata + 6); + if (c->flags & FLAG_MULTITHREAD) + av_log(avctx, AV_LOG_INFO, "Multithread encoder flag set.\n"); + if (c->flags & FLAG_NULLFRAME) + av_log(avctx, AV_LOG_INFO, "Nullframe insertion flag set.\n"); + if ((avctx->codec_id == CODEC_ID_ZLIB) && (c->flags & FLAG_PNGFILTER)) + av_log(avctx, AV_LOG_INFO, "PNG filter flag set.\n"); + if (c->flags & FLAGMASK_UNUSED) + av_log(avctx, AV_LOG_ERROR, "Unknown flag set (%d).\n", c->flags); + + /* If needed init zlib */ + if (avctx->codec_id == CODEC_ID_ZLIB) { +#ifdef CONFIG_ZLIB + c->zstream.zalloc = Z_NULL; + c->zstream.zfree = Z_NULL; + c->zstream.opaque = Z_NULL; + zret = inflateInit(&(c->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); + return 1; + } +#else + av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n"); + return 1; +#endif + } + + avctx->pix_fmt = PIX_FMT_BGR24; + + return 0; +} + + + +/* + * + * Init lcl encoder + * + */ +static int encode_init(AVCodecContext *avctx) +{ + LclContext *c = avctx->priv_data; + int zret; // Zlib return code + +#ifndef CONFIG_ZLIB + av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n"); + return 1; +#else + + c->avctx= avctx; + + assert(avctx->width && avctx->height); + + avctx->extradata= av_mallocz(8); + avctx->coded_frame= &c->pic; + + // Will be user settable someday + c->compression = 6; + c->flags = 0; + + switch(avctx->pix_fmt){ + case PIX_FMT_BGR24: + c->imgtype = IMGTYPE_RGB24; + c->decomp_size = avctx->width * avctx->height * 3; + avctx->bits_per_sample= 24; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Format %d not supported\n", avctx->pix_fmt); + return -1; + } + + ((uint8_t*)avctx->extradata)[0]= 4; + ((uint8_t*)avctx->extradata)[1]= 0; + ((uint8_t*)avctx->extradata)[2]= 0; + ((uint8_t*)avctx->extradata)[3]= 0; + ((uint8_t*)avctx->extradata)[4]= c->imgtype; + ((uint8_t*)avctx->extradata)[5]= c->compression; + ((uint8_t*)avctx->extradata)[6]= c->flags; + ((uint8_t*)avctx->extradata)[7]= 0; + c->avctx->extradata_size= 8; + + c->zstream.zalloc = Z_NULL; + c->zstream.zfree = Z_NULL; + c->zstream.opaque = Z_NULL; + zret = deflateInit(&(c->zstream), c->compression); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Deflate init error: %d\n", zret); + return 1; + } + + /* Conservative upper bound taken from zlib v1.2.1 source */ + c->max_comp_size = c->decomp_size + ((c->decomp_size + 7) >> 3) + + ((c->decomp_size + 63) >> 6) + 11; + if ((c->comp_buf = av_malloc(c->max_comp_size)) == NULL) { + av_log(avctx, AV_LOG_ERROR, "Can't allocate compression buffer.\n"); + return 1; + } + + return 0; +#endif +} + + + + + +/* + * + * Uninit lcl decoder + * + */ +static int decode_end(AVCodecContext *avctx) +{ + LclContext * const c = (LclContext *)avctx->priv_data; + + if (c->pic.data[0]) + avctx->release_buffer(avctx, &c->pic); +#ifdef CONFIG_ZLIB + inflateEnd(&(c->zstream)); +#endif + + return 0; +} + + + +/* + * + * Uninit lcl encoder + * + */ +static int encode_end(AVCodecContext *avctx) +{ + LclContext *c = avctx->priv_data; + + av_freep(&avctx->extradata); + av_freep(c->comp_buf); +#ifdef CONFIG_ZLIB + deflateEnd(&(c->zstream)); +#endif + + return 0; +} + +AVCodec mszh_decoder = { + "mszh", + CODEC_TYPE_VIDEO, + CODEC_ID_MSZH, + sizeof(LclContext), + decode_init, + NULL, + decode_end, + decode_frame, + CODEC_CAP_DR1, +}; + + +AVCodec zlib_decoder = { + "zlib", + CODEC_TYPE_VIDEO, + CODEC_ID_ZLIB, + sizeof(LclContext), + decode_init, + NULL, + decode_end, + decode_frame, + CODEC_CAP_DR1, +}; + +#ifdef CONFIG_ENCODERS + +AVCodec zlib_encoder = { + "zlib", + CODEC_TYPE_VIDEO, + CODEC_ID_ZLIB, + sizeof(LclContext), + encode_init, + encode_frame, + encode_end, +// .options = lcl_options, +}; + +#endif //CONFIG_ENCODERS diff --git a/src/libffmpeg/libavcodec/smc.c b/src/libffmpeg/libavcodec/smc.c new file mode 100644 index 000000000..be02b162d --- /dev/null +++ b/src/libffmpeg/libavcodec/smc.c @@ -0,0 +1,500 @@ +/* + * Quicktime Graphics (SMC) 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 smc.c + * QT SMC Video Decoder by Mike Melanson (melanson@pcisys.net) + * For more information about the SMC format, visit: + * http://www.pcisys.net/~melanson/codecs/ + * + * The SMC decoder outputs PAL8 colorspace data. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "common.h" +#include "avcodec.h" +#include "dsputil.h" + +#define CPAIR 2 +#define CQUAD 4 +#define COCTET 8 + +#define COLORS_PER_TABLE 256 + +typedef struct SmcContext { + + AVCodecContext *avctx; + DSPContext dsp; + AVFrame frame; + + unsigned char *buf; + int size; + + /* SMC color tables */ + unsigned char color_pairs[COLORS_PER_TABLE * CPAIR]; + unsigned char color_quads[COLORS_PER_TABLE * CQUAD]; + unsigned char color_octets[COLORS_PER_TABLE * COCTET]; + +} SmcContext; + +#define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) +#define BE_32(x) ((((uint8_t*)(x))[0] << 24) | \ + (((uint8_t*)(x))[1] << 16) | \ + (((uint8_t*)(x))[2] << 8) | \ + ((uint8_t*)(x))[3]) +#define GET_BLOCK_COUNT() \ + (opcode & 0x10) ? (1 + s->buf[stream_ptr++]) : 1 + (opcode & 0x0F); + +#define ADVANCE_BLOCK() \ +{ \ + pixel_ptr += 4; \ + if (pixel_ptr >= width) \ + { \ + pixel_ptr = 0; \ + row_ptr += stride * 4; \ + } \ + total_blocks--; \ + if (total_blocks < 0) \ + { \ + printf("warning: block counter just went negative (this should not happen)\n"); \ + return; \ + } \ +} + +static void smc_decode_stream(SmcContext *s) +{ + int width = s->avctx->width; + int height = s->avctx->height; + int stride = s->frame.linesize[0]; + int i; + int stream_ptr = 0; + int chunk_size; + unsigned char opcode; + int n_blocks; + unsigned int color_flags; + unsigned int color_flags_a; + unsigned int color_flags_b; + unsigned int flag_mask; + + unsigned char *pixels = s->frame.data[0]; + + int image_size = height * s->frame.linesize[0]; + int row_ptr = 0; + int pixel_ptr = 0; + int pixel_x, pixel_y; + int row_inc = stride - 4; + int block_ptr; + int prev_block_ptr; + int prev_block_ptr1, prev_block_ptr2; + int prev_block_flag; + int total_blocks; + int color_table_index; /* indexes to color pair, quad, or octet tables */ + int pixel; + + int color_pair_index = 0; + int color_quad_index = 0; + int color_octet_index = 0; + + /* make the palette available */ + memcpy(s->frame.data[1], s->avctx->palctrl->palette, AVPALETTE_SIZE); + if (s->avctx->palctrl->palette_changed) { + s->frame.palette_has_changed = 1; + s->avctx->palctrl->palette_changed = 0; + } + + chunk_size = BE_32(&s->buf[stream_ptr]) & 0x00FFFFFF; + stream_ptr += 4; + if (chunk_size != s->size) + printf("warning: MOV chunk size != encoded chunk size (%d != %d); using MOV chunk size\n", + chunk_size, s->size); + + chunk_size = s->size; + total_blocks = (s->avctx->width * s->avctx->height) / (4 * 4); + + /* traverse through the blocks */ + while (total_blocks) { + /* sanity checks */ + /* make sure stream ptr hasn't gone out of bounds */ + if (stream_ptr > chunk_size) { + printf("SMC decoder just went out of bounds (stream ptr = %d, chunk size = %d)\n", + stream_ptr, chunk_size); + return; + } + /* make sure the row pointer hasn't gone wild */ + if (row_ptr >= image_size) { + printf("SMC decoder just went out of bounds (row ptr = %d, height = %d)\n", + row_ptr, image_size); + return; + } + + opcode = s->buf[stream_ptr++]; + switch (opcode & 0xF0) { + /* skip n blocks */ + case 0x00: + case 0x10: + n_blocks = GET_BLOCK_COUNT(); + while (n_blocks--) { + ADVANCE_BLOCK(); + } + break; + + /* repeat last block n times */ + case 0x20: + case 0x30: + n_blocks = GET_BLOCK_COUNT(); + + /* sanity check */ + if ((row_ptr == 0) && (pixel_ptr == 0)) { + printf("encountered repeat block opcode (%02X) but no blocks rendered yet\n", + opcode & 0xF0); + break; + } + + /* figure out where the previous block started */ + if (pixel_ptr == 0) + prev_block_ptr1 = + (row_ptr - s->avctx->width * 4) + s->avctx->width - 4; + else + prev_block_ptr1 = row_ptr + pixel_ptr - 4; + + while (n_blocks--) { + block_ptr = row_ptr + pixel_ptr; + prev_block_ptr = prev_block_ptr1; + for (pixel_y = 0; pixel_y < 4; pixel_y++) { + for (pixel_x = 0; pixel_x < 4; pixel_x++) { + pixels[block_ptr++] = pixels[prev_block_ptr++]; + } + block_ptr += row_inc; + prev_block_ptr += row_inc; + } + ADVANCE_BLOCK(); + } + break; + + /* repeat previous pair of blocks n times */ + case 0x40: + case 0x50: + n_blocks = GET_BLOCK_COUNT(); + n_blocks *= 2; + + /* sanity check */ + if ((row_ptr == 0) && (pixel_ptr < 2 * 4)) { + printf("encountered repeat block opcode (%02X) but not enough blocks rendered yet\n", + opcode & 0xF0); + break; + } + + /* figure out where the previous 2 blocks started */ + if (pixel_ptr == 0) + prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + + s->avctx->width - 4 * 2; + else if (pixel_ptr == 4) + prev_block_ptr1 = (row_ptr - s->avctx->width * 4) + row_inc; + else + prev_block_ptr1 = row_ptr + pixel_ptr - 4 * 2; + + if (pixel_ptr == 0) + prev_block_ptr2 = (row_ptr - s->avctx->width * 4) + row_inc; + else + prev_block_ptr2 = row_ptr + pixel_ptr - 4; + + prev_block_flag = 0; + while (n_blocks--) { + block_ptr = row_ptr + pixel_ptr; + if (prev_block_flag) + prev_block_ptr = prev_block_ptr2; + else + prev_block_ptr = prev_block_ptr1; + prev_block_flag = !prev_block_flag; + + for (pixel_y = 0; pixel_y < 4; pixel_y++) { + for (pixel_x = 0; pixel_x < 4; pixel_x++) { + pixels[block_ptr++] = pixels[prev_block_ptr++]; + } + block_ptr += row_inc; + prev_block_ptr += row_inc; + } + ADVANCE_BLOCK(); + } + break; + + /* 1-color block encoding */ + case 0x60: + case 0x70: + n_blocks = GET_BLOCK_COUNT(); + pixel = s->buf[stream_ptr++]; + + while (n_blocks--) { + block_ptr = row_ptr + pixel_ptr; + for (pixel_y = 0; pixel_y < 4; pixel_y++) { + for (pixel_x = 0; pixel_x < 4; pixel_x++) { + pixels[block_ptr++] = pixel; + } + block_ptr += row_inc; + } + ADVANCE_BLOCK(); + } + break; + + /* 2-color block encoding */ + case 0x80: + case 0x90: + n_blocks = (opcode & 0x0F) + 1; + + /* figure out which color pair to use to paint the 2-color block */ + if ((opcode & 0xF0) == 0x80) { + /* fetch the next 2 colors from bytestream and store in next + * available entry in the color pair table */ + for (i = 0; i < CPAIR; i++) { + pixel = s->buf[stream_ptr++]; + color_table_index = CPAIR * color_pair_index + i; + s->color_pairs[color_table_index] = pixel; + } + /* this is the base index to use for this block */ + color_table_index = CPAIR * color_pair_index; + color_pair_index++; + /* wraparound */ + if (color_pair_index == COLORS_PER_TABLE) + color_pair_index = 0; + } else + color_table_index = CPAIR * s->buf[stream_ptr++]; + + while (n_blocks--) { + color_flags = BE_16(&s->buf[stream_ptr]); + stream_ptr += 2; + flag_mask = 0x8000; + block_ptr = row_ptr + pixel_ptr; + for (pixel_y = 0; pixel_y < 4; pixel_y++) { + for (pixel_x = 0; pixel_x < 4; pixel_x++) { + if (color_flags & flag_mask) + pixel = color_table_index + 1; + else + pixel = color_table_index; + flag_mask >>= 1; + pixels[block_ptr++] = s->color_pairs[pixel]; + } + block_ptr += row_inc; + } + ADVANCE_BLOCK(); + } + break; + + /* 4-color block encoding */ + case 0xA0: + case 0xB0: + n_blocks = (opcode & 0x0F) + 1; + + /* figure out which color quad to use to paint the 4-color block */ + if ((opcode & 0xF0) == 0xA0) { + /* fetch the next 4 colors from bytestream and store in next + * available entry in the color quad table */ + for (i = 0; i < CQUAD; i++) { + pixel = s->buf[stream_ptr++]; + color_table_index = CQUAD * color_quad_index + i; + s->color_quads[color_table_index] = pixel; + } + /* this is the base index to use for this block */ + color_table_index = CQUAD * color_quad_index; + color_quad_index++; + /* wraparound */ + if (color_quad_index == COLORS_PER_TABLE) + color_quad_index = 0; + } else + color_table_index = CQUAD * s->buf[stream_ptr++]; + + while (n_blocks--) { + color_flags = BE_32(&s->buf[stream_ptr]); + stream_ptr += 4; + /* flag mask actually acts as a bit shift count here */ + flag_mask = 30; + block_ptr = row_ptr + pixel_ptr; + for (pixel_y = 0; pixel_y < 4; pixel_y++) { + for (pixel_x = 0; pixel_x < 4; pixel_x++) { + pixel = color_table_index + + ((color_flags >> flag_mask) & 0x03); + flag_mask -= 2; + pixels[block_ptr++] = s->color_quads[pixel]; + } + block_ptr += row_inc; + } + ADVANCE_BLOCK(); + } + break; + + /* 8-color block encoding */ + case 0xC0: + case 0xD0: + n_blocks = (opcode & 0x0F) + 1; + + /* figure out which color octet to use to paint the 8-color block */ + if ((opcode & 0xF0) == 0xC0) { + /* fetch the next 8 colors from bytestream and store in next + * available entry in the color octet table */ + for (i = 0; i < COCTET; i++) { + pixel = s->buf[stream_ptr++]; + color_table_index = COCTET * color_octet_index + i; + s->color_octets[color_table_index] = pixel; + } + /* this is the base index to use for this block */ + color_table_index = COCTET * color_octet_index; + color_octet_index++; + /* wraparound */ + if (color_octet_index == COLORS_PER_TABLE) + color_octet_index = 0; + } else + color_table_index = COCTET * s->buf[stream_ptr++]; + + while (n_blocks--) { + /* + For this input of 6 hex bytes: + 01 23 45 67 89 AB + Mangle it to this output: + flags_a = xx012456, flags_b = xx89A37B + */ + /* build the color flags */ + color_flags_a = color_flags_b = 0; + color_flags_a = + (s->buf[stream_ptr + 0] << 16) | + ((s->buf[stream_ptr + 1] & 0xF0) << 8) | + ((s->buf[stream_ptr + 2] & 0xF0) << 4) | + ((s->buf[stream_ptr + 2] & 0x0F) << 4) | + ((s->buf[stream_ptr + 3] & 0xF0) >> 4); + color_flags_b = + (s->buf[stream_ptr + 4] << 16) | + ((s->buf[stream_ptr + 5] & 0xF0) << 8) | + ((s->buf[stream_ptr + 1] & 0x0F) << 8) | + ((s->buf[stream_ptr + 3] & 0x0F) << 4) | + (s->buf[stream_ptr + 5] & 0x0F); + stream_ptr += 6; + + color_flags = color_flags_a; + /* flag mask actually acts as a bit shift count here */ + flag_mask = 21; + block_ptr = row_ptr + pixel_ptr; + for (pixel_y = 0; pixel_y < 4; pixel_y++) { + /* reload flags at third row (iteration pixel_y == 2) */ + if (pixel_y == 2) { + color_flags = color_flags_b; + flag_mask = 21; + } + for (pixel_x = 0; pixel_x < 4; pixel_x++) { + pixel = color_table_index + + ((color_flags >> flag_mask) & 0x07); + flag_mask -= 3; + pixels[block_ptr++] = s->color_octets[pixel]; + } + block_ptr += row_inc; + } + ADVANCE_BLOCK(); + } + break; + + /* 16-color block encoding (every pixel is a different color) */ + case 0xE0: + n_blocks = (opcode & 0x0F) + 1; + + while (n_blocks--) { + block_ptr = row_ptr + pixel_ptr; + for (pixel_y = 0; pixel_y < 4; pixel_y++) { + for (pixel_x = 0; pixel_x < 4; pixel_x++) { + pixels[block_ptr++] = s->buf[stream_ptr++]; + } + block_ptr += row_inc; + } + ADVANCE_BLOCK(); + } + break; + + case 0xF0: + printf("0xF0 opcode seen in SMC chunk (xine developers would like to know)\n"); + break; + } + } +} + +static int smc_decode_init(AVCodecContext *avctx) +{ + SmcContext *s = (SmcContext *)avctx->priv_data; + + s->avctx = avctx; + avctx->pix_fmt = PIX_FMT_PAL8; + avctx->has_b_frames = 0; + dsputil_init(&s->dsp, avctx); + + s->frame.data[0] = NULL; + + return 0; +} + +static int smc_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + SmcContext *s = (SmcContext *)avctx->priv_data; + + /* no supplementary picture */ + if (buf_size == 0) + return 0; + + s->buf = buf; + s->size = buf_size; + + s->frame.reference = 1; + s->frame.buffer_hints = FF_BUFFER_HINTS_VALID | FF_BUFFER_HINTS_PRESERVE | + FF_BUFFER_HINTS_REUSABLE | FF_BUFFER_HINTS_READABLE; + if (avctx->reget_buffer(avctx, &s->frame)) { + printf ("reget_buffer() failed\n"); + return -1; + } + + smc_decode_stream(s); + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = s->frame; + + /* always report that the buffer was completely consumed */ + return buf_size; +} + +static int smc_decode_end(AVCodecContext *avctx) +{ + SmcContext *s = (SmcContext *)avctx->priv_data; + + if (s->frame.data[0]) + avctx->release_buffer(avctx, &s->frame); + + return 0; +} + +AVCodec smc_decoder = { + "smc", + CODEC_TYPE_VIDEO, + CODEC_ID_SMC, + sizeof(SmcContext), + smc_decode_init, + NULL, + smc_decode_end, + smc_decode_frame, + CODEC_CAP_DR1, +}; diff --git a/src/libffmpeg/libavcodec/truemotion1.c b/src/libffmpeg/libavcodec/truemotion1.c new file mode 100644 index 000000000..ebd0ad522 --- /dev/null +++ b/src/libffmpeg/libavcodec/truemotion1.c @@ -0,0 +1,604 @@ +/* + * Duck TrueMotion 1.0 Decoder + * Copyright (C) 2003 Alex Beregszaszi & Mike Melanson + * + * 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 truemotion1.c + * Duck TrueMotion v1 Video Decoder by + * Alex Beregszaszi (alex@fsn.hu) and + * Mike Melanson (melanson@pcisys.net) + * + * The TrueMotion v1 decoder presently only decodes 16-bit TM1 data and + * outputs RGB555 data. 24-bit TM1 data is not supported yet. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "common.h" +#include "avcodec.h" +#include "dsputil.h" + +#include "truemotion1data.h" + +#define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) + +typedef struct TrueMotion1Context { + AVCodecContext *avctx; + AVFrame frame; + AVFrame prev_frame; + + unsigned char *buf; + int size; + + unsigned char *mb_change_bits; + int mb_change_bits_row_size; + unsigned char *index_stream; + int index_stream_size; + + int flags; + int x, y, w, h; + + uint32_t y_predictor_table[1024]; + uint32_t c_predictor_table[1024]; + + int compression; + int block_type; + int block_width; + int block_height; + + int16_t *ydt; + int16_t *cdt; + int16_t *fat_ydt; + int16_t *fat_cdt; + + int last_deltaset, last_vectable; + + unsigned int *vert_pred; + +} TrueMotion1Context; + +#define FLAG_SPRITE 32 +#define FLAG_KEYFRAME 16 +#define FLAG_INTERFRAME 8 +#define FLAG_INTERPOLATED 4 + +struct frame_header { + uint8_t header_size; + uint8_t compression; + uint8_t deltaset; + uint8_t vectable; + uint16_t ysize; + uint16_t xsize; + uint16_t checksum; + uint8_t version; + uint8_t header_type; + uint8_t flags; + uint8_t control; + uint16_t xoffset; + uint16_t yoffset; + uint16_t width; + uint16_t height; +}; + +#define ALGO_NOP 0 +#define ALGO_RGB16V 1 +#define ALGO_RGB16H 2 +#define ALGO_RGB24H 3 + +/* these are the various block sizes that can occupy a 4x4 block */ +#define BLOCK_2x2 0 +#define BLOCK_2x4 1 +#define BLOCK_4x2 2 +#define BLOCK_4x4 3 + +typedef struct comp_types { + int algorithm; + int block_width; + int block_height; + int block_type; +} comp_types; + +/* { valid for metatype }, algorithm, num of deltas, horiz res, vert res */ +static comp_types compression_types[17] = { + { ALGO_NOP, 0, 0, 0 }, + + { ALGO_RGB16V, 4, 4, BLOCK_4x4 }, + { ALGO_RGB16H, 4, 4, BLOCK_4x4 }, + { ALGO_RGB16V, 4, 2, BLOCK_4x2 }, + { ALGO_RGB16H, 4, 2, BLOCK_4x2 }, + + { ALGO_RGB16V, 2, 4, BLOCK_2x4 }, + { ALGO_RGB16H, 2, 4, BLOCK_2x4 }, + { ALGO_RGB16V, 2, 2, BLOCK_2x2 }, + { ALGO_RGB16H, 2, 2, BLOCK_2x2 }, + + { ALGO_NOP, 4, 4, BLOCK_4x4 }, + { ALGO_RGB24H, 4, 4, BLOCK_4x4 }, + { ALGO_NOP, 4, 2, BLOCK_4x2 }, + { ALGO_RGB24H, 4, 2, BLOCK_4x2 }, + + { ALGO_NOP, 2, 4, BLOCK_2x4 }, + { ALGO_RGB24H, 2, 4, BLOCK_2x4 }, + { ALGO_NOP, 2, 2, BLOCK_2x2 }, + { ALGO_RGB24H, 2, 2, BLOCK_2x2 } +}; + +static void select_delta_tables(TrueMotion1Context *s, int delta_table_index) +{ + int i; + + if (delta_table_index > 3) + return; + + s->ydt = ydts[delta_table_index]; + s->cdt = cdts[delta_table_index]; + s->fat_ydt = fat_ydts[delta_table_index]; + s->fat_cdt = fat_cdts[delta_table_index]; + + /* Y skinny deltas need to be halved for some reason; maybe the + * skinny Y deltas should be modified */ + for (i = 0; i < 8; i++) + { + /* drop the lsb before dividing by 2-- net effect: round down + * when dividing a negative number (e.g., -3/2 = -2, not -1) */ + s->ydt[i] &= 0xFFFE; + s->ydt[i] /= 2; + } +} + +#ifdef WORDS_BIGENDIAN +static int make_ydt_entry(int p2, int p1, int16_t *ydt) +#else +static int make_ydt_entry(int p1, int p2, int16_t *ydt) +#endif +{ + int lo, hi; + + lo = ydt[p1]; + lo += (lo << 5) + (lo << 10); + hi = ydt[p2]; + hi += (hi << 5) + (hi << 10); + return ((lo + (hi << 16)) << 1); +} + +#ifdef WORDS_BIGENDIAN +static int make_cdt_entry(int p2, int p1, int16_t *cdt) +#else +static int make_cdt_entry(int p1, int p2, int16_t *cdt) +#endif +{ + int r, b, lo; + + b = cdt[p2]; + r = cdt[p1] << 10; + lo = b + r; + return ((lo + (lo << 16)) << 1); +} + +static void gen_vector_table(TrueMotion1Context *s, uint8_t *sel_vector_table) +{ + int len, i, j; + unsigned char delta_pair; + + for (i = 0; i < 1024; i += 4) + { + len = *sel_vector_table++ / 2; + for (j = 0; j < len; j++) + { + delta_pair = *sel_vector_table++; + s->y_predictor_table[i+j] = 0xfffffffe & + make_ydt_entry(delta_pair >> 4, delta_pair & 0xf, s->ydt); + s->c_predictor_table[i+j] = 0xfffffffe & + make_cdt_entry(delta_pair >> 4, delta_pair & 0xf, s->cdt); + } + s->y_predictor_table[i+(j-1)] |= 1; + s->c_predictor_table[i+(j-1)] |= 1; + } +} + +/* Returns the number of bytes consumed from the bytestream. Returns -1 if + * there was an error while decoding the header */ +static int truemotion1_decode_header(TrueMotion1Context *s) +{ + int i; + struct frame_header header; + uint8_t header_buffer[128]; /* logical maximum size of the header */ + uint8_t *sel_vector_table; + + /* There is 1 change bit per 4 pixels, so each change byte represents + * 32 pixels; divide width by 4 to obtain the number of change bits and + * then round up to the nearest byte. */ + s->mb_change_bits_row_size = ((s->avctx->width >> 2) + 7) >> 3; + + header.header_size = ((s->buf[0] >> 5) | (s->buf[0] << 3)) & 0x7f; + if (s->buf[0] < 0x10) + { + printf("invalid header size\n"); + return -1; + } + + /* unscramble the header bytes with a XOR operation */ + memset(header_buffer, 0, 128); + for (i = 1; i < header.header_size; i++) + header_buffer[i - 1] = s->buf[i] ^ s->buf[i + 1]; + header.compression = header_buffer[0]; + header.deltaset = header_buffer[1]; + header.vectable = header_buffer[2]; + header.ysize = LE_16(&header_buffer[3]); + header.xsize = LE_16(&header_buffer[5]); + header.checksum = LE_16(&header_buffer[7]); + header.version = header_buffer[9]; + header.header_type = header_buffer[10]; + header.flags = header_buffer[11]; + header.control = header_buffer[12]; + + /* Version 2 */ + if (header.version >= 2) + { + if (header.header_type > 3) + { + av_log(s->avctx, AV_LOG_ERROR, "truemotion1: invalid header type\n"); + return -1; + } else if ((header.header_type == 2) || (header.header_type == 3)) { + s->flags = header.flags; + if (!(s->flags & FLAG_INTERFRAME)) + s->flags |= FLAG_KEYFRAME; + } else + s->flags = FLAG_KEYFRAME; + } else /* Version 1 */ + s->flags = FLAG_KEYFRAME; + + if (s->flags & FLAG_SPRITE) { + s->w = header.width; + s->h = header.height; + s->x = header.xoffset; + s->y = header.yoffset; + } else { + s->w = header.xsize; + s->h = header.ysize; + if (header.header_type < 2) { + if ((s->w < 213) && (s->h >= 176)) + s->flags |= FLAG_INTERPOLATED; + } + } + + if (header.compression > 17) { + printf("invalid compression type (%d)\n", header.compression); + return -1; + } + + if ((header.deltaset != s->last_deltaset) || + (header.vectable != s->last_vectable)) + select_delta_tables(s, header.deltaset); + + if ((header.compression & 1) && header.header_type) + sel_vector_table = pc_tbl2; + else { + if (header.vectable < 4) + sel_vector_table = tables[header.vectable - 1]; + else { + printf("invalid vector table id (%d)\n", header.vectable); + return -1; + } + } + + if ((header.deltaset != s->last_deltaset) || (header.vectable != s->last_vectable)) + { + if (compression_types[header.compression].algorithm == ALGO_RGB24H) + { + printf("24bit compression not yet supported\n"); + } + else + gen_vector_table(s, sel_vector_table); + } + + /* set up pointers to the other key data chunks */ + s->mb_change_bits = s->buf + header.header_size; + if (s->flags & FLAG_KEYFRAME) { + /* no change bits specified for a keyframe; only index bytes */ + s->index_stream = s->mb_change_bits; + } else { + /* one change bit per 4x4 block */ + s->index_stream = s->mb_change_bits + + (s->mb_change_bits_row_size * (s->avctx->height >> 2)); + } + s->index_stream_size = s->size - (s->index_stream - s->buf); + + s->last_deltaset = header.deltaset; + s->last_vectable = header.vectable; + s->compression = header.compression; + s->block_width = compression_types[header.compression].block_width; + s->block_height = compression_types[header.compression].block_height; + s->block_type = compression_types[header.compression].block_type; + + return header.header_size; +} + +static int truemotion1_decode_init(AVCodecContext *avctx) +{ + TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; + + s->avctx = avctx; + + avctx->pix_fmt = PIX_FMT_RGB555; + avctx->has_b_frames = 0; + s->frame.data[0] = s->prev_frame.data[0] = NULL; + + /* there is a vertical predictor for each pixel in a line; each vertical + * predictor is 0 to start with */ + s->vert_pred = + (unsigned int *)av_malloc(s->avctx->width * sizeof(unsigned short)); + + return 0; +} + +#define GET_NEXT_INDEX() \ +{\ + if (index_stream_index >= s->index_stream_size) { \ + printf (" help! truemotion1 decoder went out of bounds\n"); \ + return; \ + } \ + index = s->index_stream[index_stream_index++] * 4; \ +} + +#define APPLY_C_PREDICTOR() \ + predictor_pair = s->c_predictor_table[index]; \ + horiz_pred += (predictor_pair >> 1); \ + if (predictor_pair & 1) { \ + GET_NEXT_INDEX() \ + if (!index) { \ + GET_NEXT_INDEX() \ + predictor_pair = s->c_predictor_table[index]; \ + horiz_pred += ((predictor_pair >> 1) * 5); \ + if (predictor_pair & 1) \ + GET_NEXT_INDEX() \ + else \ + index++; \ + } \ + } else \ + index++; + +#define APPLY_Y_PREDICTOR() \ + predictor_pair = s->y_predictor_table[index]; \ + horiz_pred += (predictor_pair >> 1); \ + if (predictor_pair & 1) { \ + GET_NEXT_INDEX() \ + if (!index) { \ + GET_NEXT_INDEX() \ + predictor_pair = s->y_predictor_table[index]; \ + horiz_pred += ((predictor_pair >> 1) * 5); \ + if (predictor_pair & 1) \ + GET_NEXT_INDEX() \ + else \ + index++; \ + } \ + } else \ + index++; + +#define OUTPUT_PIXEL_PAIR() \ + *current_pixel_pair = *vert_pred + horiz_pred; \ + *vert_pred++ = *current_pixel_pair++; \ + prev_pixel_pair++; + +static void truemotion1_decode_16bit(TrueMotion1Context *s) +{ + int y; + int pixels_left; /* remaining pixels on this line */ + unsigned int predictor_pair; + unsigned int horiz_pred; + unsigned int *vert_pred; + unsigned int *current_pixel_pair; + unsigned int *prev_pixel_pair; + unsigned char *current_line = s->frame.data[0]; + unsigned char *prev_line = s->prev_frame.data[0]; + int keyframe = s->flags & FLAG_KEYFRAME; + + /* these variables are for managing the stream of macroblock change bits */ + unsigned char *mb_change_bits = s->mb_change_bits; + unsigned char mb_change_byte; + unsigned char mb_change_byte_mask; + int mb_change_index; + + /* these variables are for managing the main index stream */ + int index_stream_index = 0; /* yes, the index into the index stream */ + int index; + + /* clean out the line buffer */ + memset(s->vert_pred, 0, s->avctx->width * sizeof(unsigned short)); + + GET_NEXT_INDEX(); + + for (y = 0; y < s->avctx->height; y++) { + + /* re-init variables for the next line iteration */ + horiz_pred = 0; + current_pixel_pair = (unsigned int *)current_line; + prev_pixel_pair = (unsigned int *)prev_line; + vert_pred = s->vert_pred; + mb_change_index = 0; + mb_change_byte = mb_change_bits[mb_change_index++]; + mb_change_byte_mask = 0x01; + pixels_left = s->avctx->width; + + while (pixels_left > 0) { + + if (keyframe || ((mb_change_byte & mb_change_byte_mask) == 0)) { + + switch (y & 3) { + case 0: + /* if macroblock width is 2, apply C-Y-C-Y; else + * apply C-Y-Y */ + if (s->block_width == 2) { + APPLY_C_PREDICTOR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + APPLY_C_PREDICTOR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + } else { + APPLY_C_PREDICTOR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + } + break; + + case 1: + case 3: + /* always apply 2 Y predictors on these iterations */ + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + break; + + case 2: + /* this iteration might be C-Y-C-Y, Y-Y, or C-Y-Y + * depending on the macroblock type */ + if (s->block_type == BLOCK_2x2) { + APPLY_C_PREDICTOR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + APPLY_C_PREDICTOR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + } else if (s->block_type == BLOCK_4x2) { + APPLY_C_PREDICTOR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + } else { + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + APPLY_Y_PREDICTOR(); + OUTPUT_PIXEL_PAIR(); + } + break; + } + + } else { + + /* skip (copy) four pixels, but reassign the horizontal + * predictor */ + *current_pixel_pair = *prev_pixel_pair++; + *vert_pred++ = *current_pixel_pair++; + *current_pixel_pair = *prev_pixel_pair++; + horiz_pred = *current_pixel_pair - *vert_pred; + *vert_pred++ = *current_pixel_pair++; + + } + + if (!keyframe) { + mb_change_byte_mask <<= 1; + + /* next byte */ + if (!mb_change_byte_mask) { + mb_change_byte = mb_change_bits[mb_change_index++]; + mb_change_byte_mask = 0x01; + } + } + + pixels_left -= 4; + } + + /* next change row */ + if (((y + 1) & 3) == 0) + mb_change_bits += s->mb_change_bits_row_size; + + current_line += s->frame.linesize[0]; + prev_line += s->prev_frame.linesize[0]; + } +} + +static int truemotion1_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; + + s->buf = buf; + s->size = buf_size; + + s->frame.reference = 1; + if (avctx->get_buffer(avctx, &s->frame) < 0) { + fprintf(stderr, "truemotion1: get_buffer() failed\n"); + return -1; + } + + /* no supplementary picture */ + if (buf_size == 0) + return 0; + + *data_size = 0; + + if (truemotion1_decode_header(s) == -1) + return -1; + + /* check for a do-nothing frame and copy the previous frame */ + if (compression_types[s->compression].algorithm == ALGO_NOP) + { + memcpy(s->frame.data[0], s->prev_frame.data[0], + s->frame.linesize[0] * s->avctx->height); + } else if (compression_types[s->compression].algorithm == ALGO_RGB24H) { + printf (" 24-bit Duck TrueMotion decoding not yet implemented\n"); + } else { + truemotion1_decode_16bit(s); + } + + if (s->prev_frame.data[0]) + avctx->release_buffer(avctx, &s->prev_frame); + + /* shuffle frames */ + s->prev_frame = s->frame; + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = s->frame; + + /* report that the buffer was completely consumed */ + return buf_size; +} + +static int truemotion1_decode_end(AVCodecContext *avctx) +{ + TrueMotion1Context *s = (TrueMotion1Context *)avctx->priv_data; + + /* release the last frame */ + if (s->prev_frame.data[0]) + avctx->release_buffer(avctx, &s->prev_frame); + + av_free(s->vert_pred); + + return 0; +} + +AVCodec truemotion1_decoder = { + "truemotion1", + CODEC_TYPE_VIDEO, + CODEC_ID_TRUEMOTION1, + sizeof(TrueMotion1Context), + truemotion1_decode_init, + NULL, + truemotion1_decode_end, + truemotion1_decode_frame, + CODEC_CAP_DR1, +}; diff --git a/src/libffmpeg/libavcodec/truemotion1data.h b/src/libffmpeg/libavcodec/truemotion1data.h new file mode 100644 index 000000000..d56e015a4 --- /dev/null +++ b/src/libffmpeg/libavcodec/truemotion1data.h @@ -0,0 +1,813 @@ +/* + * Duck Truemotion v1 Decoding Tables + * + * Data in this file was originally part of VpVision from On2 which is + * distributed under the GNU GPL. It is redistributed with ffmpeg under the + * GNU LGPL using the common understanding that data tables necessary for + * decoding algorithms are not necessarily licensable. + */ +#ifndef TRUEMOTION1DATA_H +#define TRUEMOTION1DATA_H + +/* Y delta tables, skinny and fat */ +static int16_t ydt1[8] = { 0, -2, 2, -6, 6, -12, 12, -12 }; +static int16_t ydt2[8] = { 0, -2, 2, -6, 6, -12, 12, -12 }; +static int16_t ydt3[8] = { 4, -6, 20, -20, 46, -46, 94, -94 }; +static int16_t fat_ydt3[8] = { 0, -15, 50, -50, 115, -115, 235, -235 }; +static int16_t ydt4[8] = { 0, -4, 4, -16, 16, -36, 36, -80 }; +static int16_t fat_ydt4[8] = { 0, 40, 80, -76, 160, -154, 236, -236 }; + +/* C delta tables, skinny and fat */ +static int16_t cdt1[8] = { 0, -1, 1, -2, 3, -4, 5, -4 }; +static int16_t cdt2[8] = { 0, -4, 3, -16, 20, -32, 36, -32 }; +static int16_t fat_cdt2[8] = { 0, -20, 15, -80, 100, -160, 180, -160 }; +static int16_t cdt3[8] = { 0, -2, 2, -8, 8, -18, 18, -40 }; +/* NOTE: This table breaks the [+,-] pattern that the rest of the + * tables maintain. Is this intentional? */ +static int16_t fat_cdt3[8] = { 0, 40, 80, -76, 160, -154, 236, -236 }; + +/* all the delta tables to choose from, at all 4 delta levels */ +static int16_t *ydts[] = { ydt1, ydt2, ydt3, ydt4, NULL }; +static int16_t *fat_ydts[] = { fat_ydt3, fat_ydt3, fat_ydt3, fat_ydt4, NULL }; +static int16_t *cdts[] = { cdt1, cdt2, cdt3, cdt3, NULL }; +static int16_t *fat_cdts[] = { fat_cdt2, fat_cdt2, fat_cdt2, fat_cdt3, NULL }; + +static uint8_t pc_tbl2[] = { +0x8,0x00,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x00, +0x8,0x10,0x00,0x00,0x00, +0x8,0x01,0x00,0x00,0x00, +0x8,0x00,0x10,0x00,0x00, +0x8,0x00,0x01,0x00,0x00, +0x8,0x00,0x00,0x10,0x00, +0x8,0x00,0x00,0x01,0x00, +0x8,0x00,0x00,0x00,0x10, +0x8,0x00,0x00,0x00,0x01, +0x6,0x00,0x00,0x00, +0x6,0x10,0x00,0x00, +0x6,0x01,0x00,0x00, +0x6,0x00,0x10,0x00, +0x6,0x00,0x01,0x00, +0x6,0x00,0x00,0x01, +0x6,0x00,0x00,0x10, +0x6,0x00,0x00,0x02, +0x6,0x00,0x00,0x20, +0x6,0x20,0x10,0x00, +0x6,0x00,0x02,0x01, +0x6,0x00,0x20,0x10, +0x6,0x02,0x01,0x00, +0x6,0x11,0x00,0x00, +0x6,0x00,0x20,0x00, +0x6,0x00,0x02,0x00, +0x6,0x20,0x00,0x00, +0x6,0x01,0x10,0x00, +0x6,0x02,0x00,0x00, +0x6,0x01,0x00,0x02, +0x6,0x10,0x00,0x20, +0x6,0x00,0x01,0x02, +0x6,0x10,0x01,0x00, +0x6,0x00,0x10,0x20, +0x6,0x10,0x10,0x00, +0x6,0x10,0x00,0x01, +0x6,0x20,0x00,0x10, +0x6,0x02,0x00,0x01, +0x6,0x01,0x01,0x00, +0x6,0x01,0x00,0x10, +0x6,0x00,0x11,0x00, +0x6,0x10,0x00,0x02, +0x6,0x00,0x01,0x10, +0x6,0x00,0x00,0x11, +0x6,0x10,0x00,0x10, +0x6,0x01,0x00,0x01, +0x6,0x00,0x00,0x22, +0x6,0x02,0x01,0x01, +0x6,0x10,0x20,0x10, +0x6,0x01,0x02,0x01, +0x6,0x20,0x10,0x10, +0x6,0x01,0x00,0x20, +0x6,0x00,0x10,0x01, +0x6,0x21,0x10,0x00, +0x6,0x10,0x02,0x01, +0x6,0x12,0x01,0x00, +0x6,0x01,0x20,0x10, +0x6,0x01,0x02,0x00, +0x6,0x10,0x20,0x00, +0x6,0x00,0x10,0x02, +0x6,0x00,0x01,0x20, +0x6,0x00,0x02,0x21, +0x6,0x00,0x02,0x20, +0x6,0x00,0x00,0x12, +0x6,0x00,0x00,0x21, +0x6,0x20,0x11,0x00, +0x6,0x00,0x01,0x01, +0x6,0x11,0x10,0x00, +0x6,0x00,0x20,0x12, +0x6,0x00,0x20,0x11, +0x6,0x20,0x10,0x02, +0x6,0x02,0x01,0x20, +0x6,0x00,0x22,0x11, +0x6,0x00,0x10,0x10, +0x6,0x02,0x11,0x00, +0x6,0x00,0x21,0x10, +0x6,0x00,0x02,0x03, +0x6,0x20,0x10,0x01, +0x6,0x00,0x12,0x01, +0x4,0x11,0x00, +0x4,0x00,0x22, +0x4,0x20,0x00, +0x4,0x01,0x10, +0x4,0x02,0x20, +0x4,0x00,0x20, +0x4,0x02,0x00, +0x4,0x10,0x01, +0x4,0x00,0x11, +0x4,0x02,0x01, +0x4,0x02,0x21, +0x4,0x00,0x02, +0x4,0x20,0x02, +0x4,0x01,0x01, +0x4,0x10,0x10, +0x4,0x10,0x02, +0x4,0x22,0x00, +0x4,0x10,0x00, +0x4,0x01,0x00, +0x4,0x21,0x00, +0x4,0x12,0x00, +0x4,0x00,0x10, +0x4,0x20,0x12, +0x4,0x01,0x11, +0x4,0x00,0x01, +0x4,0x01,0x02, +0x4,0x11,0x02, +0x4,0x11,0x01, +0x4,0x10,0x20, +0x4,0x20,0x01, +0x4,0x22,0x11, +0x4,0x00,0x12, +0x4,0x20,0x10, +0x4,0x22,0x01, +0x4,0x01,0x20, +0x4,0x00,0x21, +0x4,0x10,0x11, +0x4,0x21,0x10, +0x4,0x10,0x22, +0x4,0x02,0x03, +0x4,0x12,0x01, +0x4,0x20,0x11, +0x4,0x11,0x10, +0x4,0x20,0x30, +0x4,0x11,0x20, +0x4,0x02,0x10, +0x4,0x22,0x10, +0x4,0x11,0x11, +0x4,0x30,0x20, +0x4,0x30,0x00, +0x4,0x01,0x22, +0x4,0x01,0x12, +0x4,0x02,0x11, +0x4,0x03,0x02, +0x4,0x03,0x00, +0x4,0x10,0x21, +0x4,0x12,0x20, +0x4,0x00,0x00, +0x4,0x12,0x21, +0x4,0x21,0x11, +0x4,0x02,0x22, +0x4,0x10,0x12, +0x4,0x31,0x00, +0x4,0x20,0x20, +0x4,0x00,0x03, +0x4,0x02,0x02, +0x4,0x22,0x20, +0x4,0x01,0x21, +0x4,0x21,0x02, +0x4,0x21,0x12, +0x4,0x11,0x22, +0x4,0x00,0x30, +0x4,0x12,0x11, +0x4,0x20,0x22, +0x4,0x31,0x20, +0x4,0x21,0x30, +0x4,0x22,0x02, +0x4,0x22,0x22, +0x4,0x20,0x31, +0x4,0x13,0x02, +0x4,0x03,0x10, +0x4,0x11,0x12, +0x4,0x00,0x13, +0x4,0x21,0x01, +0x4,0x12,0x03, +0x4,0x13,0x00, +0x4,0x13,0x10, +0x4,0x02,0x13, +0x4,0x30,0x01, +0x4,0x12,0x10, +0x4,0x22,0x13, +0x4,0x03,0x12, +0x4,0x31,0x01, +0x4,0x30,0x22, +0x4,0x00,0x31, +0x4,0x01,0x31, +0x4,0x02,0x23, +0x4,0x01,0x30, +0x4,0x11,0x21, +0x4,0x22,0x21, +0x4,0x01,0x13, +0x4,0x10,0x03, +0x4,0x22,0x03, +0x4,0x30,0x21, +0x4,0x21,0x31, +0x4,0x33,0x00, +0x4,0x13,0x12, +0x4,0x11,0x31, +0x4,0x30,0x02, +0x4,0x12,0x02, +0x4,0x11,0x13, +0x4,0x12,0x22, +0x4,0x20,0x32, +0x4,0x10,0x13, +0x4,0x22,0x31, +0x4,0x21,0x20, +0x4,0x01,0x33, +0x4,0x33,0x10, +0x4,0x20,0x13, +0x4,0x31,0x22, +0x4,0x13,0x30, +0x4,0x01,0x03, +0x4,0x11,0x33, +0x4,0x20,0x21, +0x4,0x13,0x31, +0x4,0x03,0x22, +0x4,0x31,0x02, +0x4,0x00,0x24, +0x2,0x00, +0x2,0x10, +0x2,0x20, +0x2,0x30, +0x2,0x40, +0x2,0x50, +0x2,0x60, +0x2,0x01, +0x2,0x11, +0x2,0x21, +0x2,0x31, +0x2,0x41, +0x2,0x51, +0x2,0x61, +0x2,0x02, +0x2,0x12, +0x2,0x22, +0x2,0x32, +0x2,0x42, +0x2,0x52, +0x2,0x62, +0x2,0x03, +0x2,0x13, +0x2,0x23, +0x2,0x33, +0x2,0x43, +0x2,0x53, +0x2,0x63, +0x2,0x04, +0x2,0x14, +0x2,0x24, +0x2,0x34, +0x2,0x44, +0x2,0x54, +0x2,0x64, +0x2,0x05, +0x2,0x15, +0x2,0x25, +0x2,0x35, +0x2,0x45, +0x2,0x55, +0x2,0x65, +0x2,0x06, +0x2,0x16, +0x2,0x26, +0x2,0x36, +0x2,0x46, +0x2,0x56, +0x2,0x66 +}; + +static uint8_t pc_tbl3[] = { +0x6,0x00,0x00,0x00, +0x6,0x00,0x00,0x00, +0x6,0x00,0x00,0x01, +0x6,0x00,0x00,0x10, +0x6,0x00,0x00,0x11, +0x6,0x00,0x01,0x00, +0x6,0x00,0x01,0x01, +0x6,0x00,0x01,0x10, +0x6,0x00,0x01,0x11, +0x6,0x00,0x10,0x00, +0x6,0x00,0x10,0x01, +0x6,0x00,0x10,0x10, +0x6,0x00,0x10,0x11, +0x6,0x00,0x11,0x00, +0x6,0x00,0x11,0x01, +0x6,0x00,0x11,0x10, +0x6,0x00,0x11,0x11, +0x6,0x01,0x00,0x00, +0x6,0x01,0x00,0x01, +0x6,0x01,0x00,0x10, +0x6,0x01,0x00,0x11, +0x6,0x01,0x01,0x00, +0x6,0x01,0x01,0x01, +0x6,0x01,0x01,0x10, +0x6,0x01,0x01,0x11, +0x6,0x01,0x10,0x00, +0x6,0x01,0x10,0x01, +0x6,0x01,0x10,0x10, +0x6,0x01,0x10,0x11, +0x6,0x01,0x11,0x00, +0x6,0x01,0x11,0x01, +0x6,0x01,0x11,0x10, +0x6,0x01,0x11,0x11, +0x6,0x10,0x00,0x00, +0x6,0x10,0x00,0x01, +0x6,0x10,0x00,0x10, +0x6,0x10,0x00,0x11, +0x6,0x10,0x01,0x00, +0x6,0x10,0x01,0x01, +0x6,0x10,0x01,0x10, +0x6,0x10,0x01,0x11, +0x6,0x10,0x10,0x00, +0x6,0x10,0x10,0x01, +0x6,0x10,0x10,0x10, +0x6,0x10,0x10,0x11, +0x6,0x10,0x11,0x00, +0x6,0x10,0x11,0x01, +0x6,0x10,0x11,0x10, +0x6,0x10,0x11,0x11, +0x6,0x11,0x00,0x00, +0x6,0x11,0x00,0x01, +0x6,0x11,0x00,0x10, +0x6,0x11,0x00,0x11, +0x6,0x11,0x01,0x00, +0x6,0x11,0x01,0x01, +0x6,0x11,0x01,0x10, +0x6,0x11,0x01,0x11, +0x6,0x11,0x10,0x00, +0x6,0x11,0x10,0x01, +0x6,0x11,0x10,0x10, +0x6,0x11,0x10,0x11, +0x6,0x11,0x11,0x00, +0x6,0x11,0x11,0x01, +0x6,0x11,0x11,0x10, +0x4,0x00,0x00, +0x4,0x00,0x01, +0x4,0x00,0x02, +0x4,0x00,0x03, +0x4,0x00,0x10, +0x4,0x00,0x11, +0x4,0x00,0x12, +0x4,0x00,0x13, +0x4,0x00,0x20, +0x4,0x00,0x21, +0x4,0x00,0x22, +0x4,0x00,0x23, +0x4,0x00,0x30, +0x4,0x00,0x31, +0x4,0x00,0x32, +0x4,0x00,0x33, +0x4,0x01,0x00, +0x4,0x01,0x01, +0x4,0x01,0x02, +0x4,0x01,0x03, +0x4,0x01,0x10, +0x4,0x01,0x11, +0x4,0x01,0x12, +0x4,0x01,0x13, +0x4,0x01,0x20, +0x4,0x01,0x21, +0x4,0x01,0x22, +0x4,0x01,0x23, +0x4,0x01,0x30, +0x4,0x01,0x31, +0x4,0x01,0x32, +0x4,0x01,0x33, +0x4,0x02,0x00, +0x4,0x02,0x01, +0x4,0x02,0x02, +0x4,0x02,0x03, +0x4,0x02,0x10, +0x4,0x02,0x11, +0x4,0x02,0x12, +0x4,0x02,0x13, +0x4,0x02,0x20, +0x4,0x02,0x21, +0x4,0x02,0x22, +0x4,0x02,0x23, +0x4,0x02,0x30, +0x4,0x02,0x31, +0x4,0x02,0x32, +0x4,0x02,0x33, +0x4,0x03,0x00, +0x4,0x03,0x01, +0x4,0x03,0x02, +0x4,0x03,0x03, +0x4,0x03,0x10, +0x4,0x03,0x11, +0x4,0x03,0x12, +0x4,0x03,0x13, +0x4,0x03,0x20, +0x4,0x03,0x21, +0x4,0x03,0x22, +0x4,0x03,0x23, +0x4,0x03,0x30, +0x4,0x03,0x31, +0x4,0x03,0x32, +0x4,0x03,0x33, +0x4,0x10,0x00, +0x4,0x10,0x01, +0x4,0x10,0x02, +0x4,0x10,0x03, +0x4,0x10,0x10, +0x4,0x10,0x11, +0x4,0x10,0x12, +0x4,0x10,0x13, +0x4,0x10,0x20, +0x4,0x10,0x21, +0x4,0x10,0x22, +0x4,0x10,0x23, +0x4,0x10,0x30, +0x4,0x10,0x31, +0x4,0x10,0x32, +0x4,0x10,0x33, +0x4,0x11,0x00, +0x4,0x11,0x01, +0x4,0x11,0x02, +0x4,0x11,0x03, +0x4,0x11,0x10, +0x4,0x11,0x11, +0x4,0x11,0x12, +0x4,0x11,0x13, +0x4,0x11,0x20, +0x4,0x11,0x21, +0x4,0x11,0x22, +0x4,0x11,0x23, +0x4,0x11,0x30, +0x4,0x11,0x31, +0x4,0x11,0x32, +0x4,0x11,0x33, +0x4,0x12,0x00, +0x4,0x12,0x01, +0x4,0x12,0x02, +0x4,0x12,0x03, +0x4,0x12,0x10, +0x4,0x12,0x11, +0x4,0x12,0x12, +0x4,0x12,0x13, +0x4,0x12,0x20, +0x4,0x12,0x21, +0x4,0x12,0x22, +0x4,0x12,0x23, +0x4,0x12,0x30, +0x4,0x12,0x31, +0x4,0x12,0x32, +0x4,0x12,0x33, +0x4,0x13,0x00, +0x4,0x13,0x01, +0x4,0x13,0x02, +0x4,0x13,0x03, +0x4,0x13,0x10, +0x4,0x13,0x11, +0x4,0x13,0x12, +0x4,0x13,0x13, +0x4,0x13,0x20, +0x4,0x13,0x21, +0x4,0x13,0x22, +0x4,0x13,0x23, +0x4,0x13,0x30, +0x4,0x13,0x31, +0x4,0x13,0x32, +0x4,0x13,0x33, +0x2,0x00, +0x2,0x10, +0x2,0x20, +0x2,0x30, +0x2,0x40, +0x2,0x50, +0x2,0x60, +0x2,0x70, +0x2,0x01, +0x2,0x11, +0x2,0x21, +0x2,0x31, +0x2,0x41, +0x2,0x51, +0x2,0x61, +0x2,0x71, +0x2,0x02, +0x2,0x12, +0x2,0x22, +0x2,0x32, +0x2,0x42, +0x2,0x52, +0x2,0x62, +0x2,0x72, +0x2,0x03, +0x2,0x13, +0x2,0x23, +0x2,0x33, +0x2,0x43, +0x2,0x53, +0x2,0x63, +0x2,0x73, +0x2,0x04, +0x2,0x14, +0x2,0x24, +0x2,0x34, +0x2,0x44, +0x2,0x54, +0x2,0x64, +0x2,0x74, +0x2,0x05, +0x2,0x15, +0x2,0x25, +0x2,0x35, +0x2,0x45, +0x2,0x55, +0x2,0x65, +0x2,0x75, +0x2,0x06, +0x2,0x16, +0x2,0x26, +0x2,0x36, +0x2,0x46, +0x2,0x56, +0x2,0x66, +0x2,0x76, +0x2,0x07, +0x2,0x17, +0x2,0x27, +0x2,0x37, +0x2,0x47, +0x2,0x57, +0x2,0x67, +0x2,0x77 +}; + +static uint8_t pc_tbl4[] = { +0x8,0x00,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x00, +0x8,0x20,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x01, +0x8,0x10,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x02, +0x8,0x01,0x00,0x00,0x00, +0x8,0x00,0x00,0x00,0x10, +0x8,0x02,0x00,0x00,0x00, +0x6,0x00,0x00,0x00, +0x6,0x20,0x00,0x00, +0x6,0x00,0x00,0x01, +0x6,0x10,0x00,0x00, +0x6,0x00,0x00,0x02, +0x6,0x00,0x10,0x00, +0x6,0x00,0x20,0x00, +0x6,0x00,0x02,0x00, +0x6,0x00,0x01,0x00, +0x6,0x01,0x00,0x00, +0x6,0x00,0x00,0x20, +0x6,0x02,0x00,0x00, +0x6,0x00,0x00,0x10, +0x6,0x10,0x00,0x20, +0x6,0x01,0x00,0x02, +0x6,0x20,0x00,0x10, +0x6,0x02,0x00,0x01, +0x6,0x20,0x10,0x00, +0x6,0x00,0x12,0x00, +0x6,0x00,0x02,0x01, +0x6,0x02,0x01,0x00, +0x6,0x00,0x21,0x00, +0x6,0x00,0x01,0x02, +0x6,0x00,0x20,0x10, +0x6,0x00,0x00,0x21, +0x6,0x00,0x00,0x12, +0x6,0x00,0x01,0x20, +0x6,0x12,0x00,0x00, +0x6,0x00,0x10,0x20, +0x6,0x01,0x20,0x00, +0x6,0x02,0x10,0x00, +0x6,0x10,0x20,0x00, +0x6,0x01,0x02,0x00, +0x6,0x21,0x00,0x00, +0x6,0x00,0x02,0x10, +0x6,0x20,0x01,0x00, +0x6,0x00,0x22,0x00, +0x6,0x10,0x02,0x00, +0x6,0x00,0x10,0x02, +0x6,0x11,0x00,0x00, +0x6,0x00,0x11,0x00, +0x6,0x22,0x00,0x00, +0x6,0x20,0x00,0x02, +0x6,0x10,0x00,0x01, +0x6,0x00,0x20,0x01, +0x6,0x02,0x20,0x00, +0x6,0x01,0x10,0x00, +0x6,0x01,0x00,0x20, +0x6,0x00,0x20,0x02, +0x6,0x01,0x20,0x02, +0x6,0x10,0x01,0x00, +0x6,0x02,0x00,0x10, +0x6,0x00,0x10,0x01, +0x6,0x10,0x01,0x20, +0x6,0x20,0x02,0x10, +0x6,0x00,0x00,0x22, +0x6,0x10,0x00,0x02, +0x6,0x00,0x02,0x20, +0x6,0x20,0x02,0x00, +0x6,0x00,0x00,0x11, +0x6,0x02,0x10,0x01, +0x6,0x00,0x01,0x10, +0x6,0x00,0x02,0x11, +0x4,0x01,0x02, +0x4,0x02,0x01, +0x4,0x01,0x00, +0x4,0x10,0x20, +0x4,0x20,0x10, +0x4,0x20,0x00, +0x4,0x11,0x00, +0x4,0x02,0x00, +0x4,0x12,0x00, +0x4,0x00,0x21, +0x4,0x22,0x00, +0x4,0x00,0x12, +0x4,0x21,0x00, +0x4,0x02,0x11, +0x4,0x00,0x01, +0x4,0x10,0x02, +0x4,0x02,0x20, +0x4,0x20,0x11, +0x4,0x01,0x10, +0x4,0x21,0x10, +0x4,0x10,0x00, +0x4,0x10,0x22, +0x4,0x20,0x20, +0x4,0x00,0x22, +0x4,0x01,0x22, +0x4,0x20,0x01, +0x4,0x02,0x02, +0x4,0x00,0x20, +0x4,0x00,0x10, +0x4,0x00,0x11, +0x4,0x22,0x01, +0x4,0x11,0x20, +0x4,0x12,0x01, +0x4,0x12,0x20, +0x4,0x11,0x02, +0x4,0x10,0x10, +0x4,0x01,0x01, +0x4,0x02,0x21, +0x4,0x20,0x12, +0x4,0x01,0x12, +0x4,0x22,0x11, +0x4,0x21,0x12, +0x4,0x22,0x10, +0x4,0x21,0x02, +0x4,0x20,0x02, +0x4,0x10,0x01, +0x4,0x00,0x02, +0x4,0x10,0x21, +0x4,0x01,0x20, +0x4,0x11,0x22, +0x4,0x12,0x21, +0x4,0x22,0x20, +0x4,0x02,0x10, +0x4,0x02,0x22, +0x4,0x11,0x10, +0x4,0x22,0x02, +0x4,0x20,0x21, +0x4,0x01,0x11, +0x4,0x11,0x01, +0x4,0x10,0x12, +0x4,0x02,0x12, +0x4,0x20,0x22, +0x4,0x21,0x20, +0x4,0x01,0x21, +0x4,0x12,0x02, +0x4,0x21,0x11, +0x4,0x12,0x22, +0x4,0x12,0x10, +0x4,0x22,0x21, +0x4,0x10,0x11, +0x4,0x21,0x01, +0x4,0x11,0x12, +0x4,0x12,0x11, +0x4,0x66,0x66, +0x4,0x22,0x22, +0x4,0x11,0x21, +0x4,0x11,0x11, +0x4,0x21,0x22, +0x4,0x00,0x00, +0x4,0x22,0x12, +0x4,0x12,0x12, +0x4,0x21,0x21, +0x4,0x42,0x00, +0x4,0x00,0x04, +0x4,0x40,0x00, +0x4,0x30,0x00, +0x4,0x31,0x00, +0x4,0x00,0x03, +0x4,0x00,0x14, +0x4,0x00,0x13, +0x4,0x01,0x24, +0x4,0x20,0x13, +0x4,0x01,0x42, +0x4,0x14,0x20, +0x4,0x42,0x02, +0x4,0x13,0x00, +0x4,0x00,0x24, +0x4,0x31,0x20, +0x4,0x22,0x13, +0x4,0x11,0x24, +0x4,0x12,0x66, +0x4,0x30,0x01, +0x4,0x02,0x13, +0x4,0x12,0x42, +0x4,0x40,0x10, +0x4,0x40,0x02, +0x4,0x01,0x04, +0x4,0x24,0x00, +0x4,0x42,0x10, +0x4,0x21,0x13, +0x4,0x13,0x12, +0x4,0x31,0x21, +0x4,0x21,0x24, +0x4,0x00,0x40, +0x4,0x10,0x24, +0x4,0x10,0x42, +0x4,0x32,0x01, +0x4,0x11,0x42, +0x4,0x20,0x31, +0x4,0x12,0x40, +0x2,0x00, +0x2,0x10, +0x2,0x20, +0x2,0x30, +0x2,0x40, +0x2,0x50, +0x2,0x60, +0x2,0x70, +0x2,0x01, +0x2,0x11, +0x2,0x21, +0x2,0x31, +0x2,0x41, +0x2,0x51, +0x2,0x61, +0x2,0x71, +0x2,0x02, +0x2,0x12, +0x2,0x22, +0x2,0x32, +0x2,0x42, +0x2,0x52, +0x2,0x62, +0x2,0x72, +0x2,0x03, +0x2,0x13, +0x2,0x23, +0x2,0x33, +0x2,0x43, +0x2,0x53, +0x2,0x63, +0x2,0x73, +0x2,0x04, +0x2,0x14, +0x2,0x24, +0x2,0x34, +0x2,0x44, +0x2,0x54, +0x2,0x64, +0x2,0x74, +0x2,0x05, +0x2,0x15, +0x2,0x25, +0x2,0x35, +0x2,0x45, +0x2,0x55, +0x2,0x65, +0x2,0x75, +0x2,0x06, +0x2,0x16, +0x2,0x26, +0x2,0x36, +0x2,0x46, +0x2,0x56, +0x2,0x66, +0x2,0x76, +0x2,0x07, +0x2,0x17, +0x2,0x27, +0x2,0x37, +0x2,0x47, +0x2,0x57, +0x2,0x67, +0x2,0x77 +}; + +static uint8_t *tables[] = { pc_tbl2, pc_tbl3, pc_tbl4 }; +#endif diff --git a/src/libffmpeg/libavcodec/vmdav.c b/src/libffmpeg/libavcodec/vmdav.c new file mode 100644 index 000000000..a5c7f450c --- /dev/null +++ b/src/libffmpeg/libavcodec/vmdav.c @@ -0,0 +1,548 @@ +/* + * Sierra VMD Audio & Video Decoders + * Copyright (C) 2004 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 vmdvideo.c + * Sierra VMD audio & video decoders + * by Vladimir "VAG" Gneushev (vagsoft at mail.ru) + * + * The video decoder outputs PAL8 colorspace data. The decoder expects + * a 0x330-byte VMD file header to be transmitted via extradata during + * codec initialization. Each encoded frame that is sent to this decoder + * is expected to be prepended with the appropriate 16-byte frame + * information record from the VMD file. + * + * The audio decoder, like the video decoder, expects each encoded data + * chunk to be prepended with the approriate 16-byte frame information + * record from the VMD file. It does not require the 0x330-byte VMD file + * header, but it does need the audio setup parameters passed in through + * normal libavcodec API means. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include "common.h" +#include "avcodec.h" +#include "dsputil.h" + +#define VMD_HEADER_SIZE 0x330 +#define PALETTE_COUNT 256 + +#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]) + +/* + * Video Decoder + */ + +typedef struct VmdVideoContext { + + AVCodecContext *avctx; + DSPContext dsp; + AVFrame frame; + AVFrame prev_frame; + + unsigned char *buf; + int size; + + unsigned char palette[PALETTE_COUNT * 4]; + unsigned char *unpack_buffer; + +} VmdVideoContext; + +#define QUEUE_SIZE 0x1000 +#define QUEUE_MASK 0x0FFF + +static void lz_unpack(unsigned char *src, unsigned char *dest) +{ + unsigned char *s; + unsigned char *d; + unsigned char queue[QUEUE_SIZE]; + unsigned int qpos; + unsigned int dataleft; + unsigned int chainofs; + unsigned int chainlen; + unsigned int speclen; + unsigned char tag; + unsigned int i, j; + + s = src; + d = dest; + dataleft = LE_32(s); + s += 4; + memset(queue, QUEUE_SIZE, 0x20); + if (LE_32(s) == 0x56781234) { + s += 4; + qpos = 0x111; + speclen = 0xF + 3; + } else { + qpos = 0xFEE; + speclen = 100; /* no speclen */ + } + + while (dataleft > 0) { + tag = *s++; + if ((tag == 0xFF) && (dataleft > 8)) { + for (i = 0; i < 8; i++) { + queue[qpos++] = *d++ = *s++; + qpos &= QUEUE_MASK; + } + dataleft -= 8; + } else { + for (i = 0; i < 8; i++) { + if (dataleft == 0) + break; + if (tag & 0x01) { + queue[qpos++] = *d++ = *s++; + qpos &= QUEUE_MASK; + dataleft--; + } else { + chainofs = *s++; + chainofs |= ((*s & 0xF0) << 4); + chainlen = (*s++ & 0x0F) + 3; + if (chainlen == speclen) + chainlen = *s++ + 0xF + 3; + for (j = 0; j < chainlen; j++) { + *d = queue[chainofs++ & QUEUE_MASK]; + queue[qpos++] = *d++; + qpos &= QUEUE_MASK; + } + dataleft -= chainlen; + } + tag >>= 1; + } + } + } +} + +static int rle_unpack(unsigned char *src, unsigned char *dest, int len) +{ + unsigned char *ps; + unsigned char *pd; + int i, l; + + ps = src; + pd = dest; + if (len & 1) + *pd++ = *ps++; + + len >>= 1; + i = 0; + do { + l = *ps++; + if (l & 0x80) { + l = (l & 0x7F) * 2; + memcpy(pd, ps, l); + ps += l; + pd += l; + } else { + for (i = 0; i < l; i++) { + *pd++ = ps[0]; + *pd++ = ps[1]; + } + ps += 2; + } + i += l; + } while (i < len); + + return (ps - src); +} + +static void vmd_decode(VmdVideoContext *s) +{ + int i; + unsigned int *palette32; + unsigned char r, g, b; + + /* point to the start of the encoded data */ + unsigned char *p = s->buf + 16; + + unsigned char *pb; + unsigned char meth; + unsigned char *dp; /* pointer to current frame */ + unsigned char *pp; /* pointer to previous frame */ + unsigned char len; + int ofs; + + int frame_x, frame_y; + int frame_width, frame_height; + + frame_x = LE_16(&s->buf[6]); + frame_y = LE_16(&s->buf[8]); + frame_width = LE_16(&s->buf[10]) - frame_x + 1; + frame_height = LE_16(&s->buf[12]) - frame_y + 1; + + /* if only a certain region will be updated, copy the entire previous + * frame before the decode */ + if (frame_x || frame_y || (frame_width != s->avctx->width) || + (frame_height != s->avctx->height)) { + + memcpy(s->frame.data[0], s->prev_frame.data[0], + s->avctx->height * s->frame.linesize[0]); + } + + /* check if there is a new palette */ + if (s->buf[15] & 0x02) { + p += 2; + palette32 = (unsigned int *)s->palette; + for (i = 0; i < PALETTE_COUNT; i++) { + r = *p++ * 4; + g = *p++ * 4; + b = *p++ * 4; + palette32[i] = (r << 16) | (g << 8) | (b); + } + s->size -= (256 * 3 + 2); + } + if (s->size >= 0) { + /* originally UnpackFrame in VAG's code */ + pb = p; + meth = *pb++; + if (meth & 0x80) { + lz_unpack(pb, s->unpack_buffer); + meth &= 0x7F; + pb = s->unpack_buffer; + } + + dp = &s->frame.data[0][frame_y * s->frame.linesize[0] + frame_x]; + pp = &s->prev_frame.data[0][frame_y * s->prev_frame.linesize[0] + frame_x]; + switch (meth) { + case 1: + for (i = 0; i < frame_height; i++) { + ofs = 0; + do { + len = *pb++; + if (len & 0x80) { + len = (len & 0x7F) + 1; + memcpy(&dp[ofs], pb, len); + pb += len; + ofs += len; + } else { + /* interframe pixel copy */ + memcpy(&dp[ofs], &pp[ofs], len + 1); + ofs += len + 1; + } + } while (ofs < frame_width); + if (ofs > frame_width) { + printf (" VMD video: offset > width (%d > %d)\n", + ofs, frame_width); + break; + } + dp += s->frame.linesize[0]; + pp += s->prev_frame.linesize[0]; + } + break; + + case 2: + for (i = 0; i < frame_height; i++) { + memcpy(dp, pb, frame_width); + pb += frame_width; + dp += s->frame.linesize[0]; + pp += s->prev_frame.linesize[0]; + } + break; + + case 3: + for (i = 0; i < frame_height; i++) { + ofs = 0; + do { + len = *pb++; + if (len & 0x80) { + len = (len & 0x7F) + 1; + if (*pb++ == 0xFF) + len = rle_unpack(pb, dp, len); + else + memcpy(&dp[ofs], pb, len); + pb += len; + ofs += len; + } else { + /* interframe pixel copy */ + memcpy(&dp[ofs], &pp[ofs], len + 1); + ofs += len + 1; + } + } while (ofs < frame_width); + if (ofs > frame_width) { + printf (" VMD video: offset > width (%d > %d)\n", + ofs, frame_width); + } + dp += s->frame.linesize[0]; + pp += s->prev_frame.linesize[0]; + } + break; + } + } +} + +static int vmdvideo_decode_init(AVCodecContext *avctx) +{ + VmdVideoContext *s = (VmdVideoContext *)avctx->priv_data; + int i; + unsigned int *palette32; + int palette_index = 0; + unsigned char r, g, b; + unsigned char *vmd_header; + unsigned char *raw_palette; + + s->avctx = avctx; + avctx->pix_fmt = PIX_FMT_PAL8; + avctx->has_b_frames = 0; + dsputil_init(&s->dsp, avctx); + + /* make sure the VMD header made it */ + if (s->avctx->extradata_size != VMD_HEADER_SIZE) { + printf(" VMD video: expected extradata size of %d\n", + VMD_HEADER_SIZE); + return -1; + } + vmd_header = (unsigned char *)avctx->extradata; + + s->unpack_buffer = av_malloc(LE_32(&vmd_header[800])); + if (!s->unpack_buffer) + return -1; + + /* load up the initial palette */ + raw_palette = &vmd_header[28]; + palette32 = (unsigned int *)s->palette; + for (i = 0; i < PALETTE_COUNT; i++) { + r = raw_palette[palette_index++] * 4; + g = raw_palette[palette_index++] * 4; + b = raw_palette[palette_index++] * 4; + palette32[i] = (r << 16) | (g << 8) | (b); + } + + s->frame.data[0] = s->prev_frame.data[0] = NULL; + + return 0; +} + +static int vmdvideo_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + VmdVideoContext *s = (VmdVideoContext *)avctx->priv_data; + + s->buf = buf; + s->size = buf_size; + + s->frame.reference = 1; + if (avctx->get_buffer(avctx, &s->frame)) { + printf (" VMD Video: get_buffer() failed\n"); + return -1; + } + + vmd_decode(s); + + /* make the palette available on the way out */ + memcpy(s->frame.data[1], s->palette, PALETTE_COUNT * 4); + + if (s->prev_frame.data[0]) + avctx->release_buffer(avctx, &s->prev_frame); + + /* shuffle frames */ + s->prev_frame = s->frame; + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = s->frame; + + /* report that the buffer was completely consumed */ + return buf_size; +} + +static int vmdvideo_decode_end(AVCodecContext *avctx) +{ + VmdVideoContext *s = (VmdVideoContext *)avctx->priv_data; + + if (s->prev_frame.data[0]) + avctx->release_buffer(avctx, &s->prev_frame); + av_free(s->unpack_buffer); + + return 0; +} + + +/* + * Audio Decoder + */ + +typedef struct VmdAudioContext { + int channels; + int bits; + int block_align; + unsigned char steps8[16]; + unsigned short steps16[16]; + unsigned short steps128[256]; + short predictors[2]; +} VmdAudioContext; + +static int vmdaudio_decode_init(AVCodecContext *avctx) +{ + VmdAudioContext *s = (VmdAudioContext *)avctx->priv_data; + int i; + + s->channels = avctx->channels; + s->bits = avctx->bits_per_sample; + s->block_align = avctx->block_align; + +printf (" %d channels, %d bits/sample, block align = %d\n", + s->channels, s->bits, s->block_align); + + /* set up the steps8 and steps16 tables */ + for (i = 0; i < 8; i++) { + if (i < 4) + s->steps8[i] = i; + else + s->steps8[i] = s->steps8[i - 1] + i - 1; + + if (i == 0) + s->steps16[i] = 0; + else if (i == 1) + s->steps16[i] = 4; + else if (i == 2) + s->steps16[i] = 16; + else + s->steps16[i] = 1 << (i + 4); + } + + /* set up the step128 table */ + s->steps128[0] = 0; + s->steps128[1] = 8; + for (i = 0x02; i <= 0x20; i++) + s->steps128[i] = (i - 1) << 4; + for (i = 0x21; i <= 0x60; i++) + s->steps128[i] = (i + 0x1F) << 3; + for (i = 0x61; i <= 0x70; i++) + s->steps128[i] = (i - 0x51) << 6; + for (i = 0x71; i <= 0x78; i++) + s->steps128[i] = (i - 0x69) << 8; + for (i = 0x79; i <= 0x7D; i++) + s->steps128[i] = (i - 0x75) << 10; + s->steps128[0x7E] = 0x3000; + s->steps128[0x7F] = 0x4000; + + /* set up the negative half of each table */ + for (i = 0; i < 8; i++) { + s->steps8[i + 8] = -s->steps8[i]; + s->steps16[i + 8] = -s->steps16[i]; + } + for (i = 0; i < 128; i++) + s->steps128[i + 128] = -s->steps128[i]; + + return 0; +} + +static void vmdaudio_decode_audio(VmdAudioContext *s, unsigned char *data, + uint8_t *buf, int ratio) { + +} + +static void vmdaudio_loadsound(VmdAudioContext *s, unsigned char *data, + uint8_t *buf, int silence) +{ + if (s->channels == 2) { + if ((s->block_align & 0x01) == 0) { + if (silence) + memset(data, 0, s->block_align * 2); + else + vmdaudio_decode_audio(s, data, buf, 1); + } else { + if (silence) + memset(data, 0, s->block_align * 2); +// else +// vmdaudio_decode_audio(s, data, buf, 1); + } + } else { + } +} + +static int vmdaudio_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + VmdAudioContext *s = (VmdAudioContext *)avctx->priv_data; + unsigned int sound_flags; + unsigned char *output_samples = (unsigned char *)data; + + /* point to the start of the encoded data */ + unsigned char *p = buf + 16; + unsigned char *p_end = buf + buf_size; + + if (buf[6] == 1) { + /* the chunk contains audio */ + vmdaudio_loadsound(s, output_samples, p, 0); + } else if (buf[6] == 2) { + /* the chunk contains audio and silence mixed together */ + sound_flags = LE_32(p); + p += 4; + + /* do something with extrabufs here? */ + + while (p < p_end) { + if (sound_flags & 0x01) + /* audio */ + vmdaudio_loadsound(s, output_samples, p, 1); + else + /* silence */ + vmdaudio_loadsound(s, output_samples, p, 0); + p += s->block_align; + output_samples += (s->block_align * s->bits / 8); + sound_flags >>= 1; + } + } else if (buf[6] == 3) { + /* silent chunk */ + vmdaudio_loadsound(s, output_samples, p, 1); + } + + +// *datasize = ; + return buf_size; +} + + +/* + * Public Data Structures + */ + +AVCodec vmdvideo_decoder = { + "vmdvideo", + CODEC_TYPE_VIDEO, + CODEC_ID_VMDVIDEO, + sizeof(VmdVideoContext), + vmdvideo_decode_init, + NULL, + vmdvideo_decode_end, + vmdvideo_decode_frame, + CODEC_CAP_DR1, +}; + +AVCodec vmdaudio_decoder = { + "vmdaudio", + CODEC_TYPE_AUDIO, + CODEC_ID_VMDAUDIO, + sizeof(VmdAudioContext), + vmdaudio_decode_init, + NULL, + NULL, + vmdaudio_decode_frame, +}; |