Originally committed as revision 2217 to svn://svn.ffmpeg.org/ffmpeg/trunktags/v0.5
| @@ -18,7 +18,7 @@ OBJS= common.o utils.o mem.o allcodecs.o \ | |||||
| ratecontrol.o adpcm.o eval.o dv.o error_resilience.o \ | ratecontrol.o adpcm.o eval.o dv.o error_resilience.o \ | ||||
| fft.o mdct.o mace.o huffyuv.o cyuv.o opts.o raw.o h264.o golomb.o \ | fft.o mdct.o mace.o huffyuv.o cyuv.o opts.o raw.o h264.o golomb.o \ | ||||
| vp3.o asv1.o 4xm.o cabac.o ffv1.o ra144.o ra288.o vcr1.o cljr.o \ | vp3.o asv1.o 4xm.o cabac.o ffv1.o ra144.o ra288.o vcr1.o cljr.o \ | ||||
| roqvideo.o dpcm.o interplayvideo.o | |||||
| roqvideo.o dpcm.o interplayvideo.o xan.o | |||||
| ifeq ($(AMR_NB),yes) | ifeq ($(AMR_NB),yes) | ||||
| ifeq ($(AMR_NB_FIXED),yes) | ifeq ($(AMR_NB_FIXED),yes) | ||||
| @@ -1,6 +1,6 @@ | |||||
| /* | /* | ||||
| * ADPCM codecs | * ADPCM codecs | ||||
| * Copyright (c) 2001 Fabrice Bellard. | |||||
| * Copyright (c) 2001-2003 The ffmpeg Project | |||||
| * | * | ||||
| * This library is free software; you can redistribute it and/or | * This library is free software; you can redistribute it and/or | ||||
| * modify it under the terms of the GNU Lesser General Public | * modify it under the terms of the GNU Lesser General Public | ||||
| @@ -22,11 +22,13 @@ | |||||
| * @file adpcm.c | * @file adpcm.c | ||||
| * ADPCM codecs. | * ADPCM codecs. | ||||
| * First version by Francois Revol revol@free.fr | * First version by Francois Revol revol@free.fr | ||||
| * Fringe ADPCM codecs (e.g., DK3 and DK4) | |||||
| * by Mike Melanson (melanson@pcisys.net) | |||||
| * | * | ||||
| * Features and limitations: | * Features and limitations: | ||||
| * | * | ||||
| * Reference documents: | * Reference documents: | ||||
| * http://www.pcisys.net/~melanson/codecs/adpcm.txt | |||||
| * http://www.pcisys.net/~melanson/codecs/simpleaudio.html | |||||
| * http://www.geocities.com/SiliconValley/8682/aud3.txt | * http://www.geocities.com/SiliconValley/8682/aud3.txt | ||||
| * http://openquicktime.sourceforge.net/plugins.htm | * http://openquicktime.sourceforge.net/plugins.htm | ||||
| * XAnim sources (xa_codec.c) http://www.rasnaimaging.com/people/lapus/download.html | * XAnim sources (xa_codec.c) http://www.rasnaimaging.com/people/lapus/download.html | ||||
| @@ -293,14 +295,10 @@ static inline short adpcm_ima_expand_nibble(ADPCMChannelStatus *c, char nibble) | |||||
| sign = nibble & 8; | sign = nibble & 8; | ||||
| delta = nibble & 7; | delta = nibble & 7; | ||||
| #if 0 | |||||
| diff = step >> 3; | |||||
| if (delta & 4) diff += step; | |||||
| if (delta & 2) diff += step >> 1; | |||||
| if (delta & 1) diff += step >> 2; | |||||
| #else | |||||
| diff = ((2 * delta + 1) * step) >> 3; // no jumps | |||||
| #endif | |||||
| /* perform direct multiplication instead of series of jumps proposed by | |||||
| * the reference ADPCM implementation since modern CPUs can do the mults | |||||
| * quickly enough */ | |||||
| diff = ((2 * delta + 1) * step) >> 3; | |||||
| predictor = c->predictor; | predictor = c->predictor; | ||||
| if (sign) predictor -= diff; | if (sign) predictor -= diff; | ||||
| else predictor += diff; | else predictor += diff; | ||||
| @@ -355,6 +353,21 @@ static inline short adpcm_ms_expand_nibble(ADPCMChannelStatus *c, char nibble) | |||||
| return (short)predictor; | return (short)predictor; | ||||
| } | } | ||||
| /* DK3 ADPCM support macro */ | |||||
| #define DK3_GET_NEXT_NIBBLE() \ | |||||
| if (decode_top_nibble_next) \ | |||||
| { \ | |||||
| nibble = (last_byte >> 4) & 0x0F; \ | |||||
| decode_top_nibble_next = 0; \ | |||||
| } \ | |||||
| else \ | |||||
| { \ | |||||
| last_byte = *src++; \ | |||||
| if (src >= buf + buf_size) break; \ | |||||
| nibble = last_byte & 0x0F; \ | |||||
| decode_top_nibble_next = 1; \ | |||||
| } | |||||
| static int adpcm_decode_frame(AVCodecContext *avctx, | static int adpcm_decode_frame(AVCodecContext *avctx, | ||||
| void *data, int *data_size, | void *data, int *data_size, | ||||
| uint8_t *buf, int buf_size) | uint8_t *buf, int buf_size) | ||||
| @@ -367,6 +380,12 @@ static int adpcm_decode_frame(AVCodecContext *avctx, | |||||
| uint8_t *src; | uint8_t *src; | ||||
| int st; /* stereo */ | int st; /* stereo */ | ||||
| /* DK3 ADPCM accounting variables */ | |||||
| unsigned char last_byte = 0; | |||||
| unsigned char nibble; | |||||
| int decode_top_nibble_next = 0; | |||||
| int diff_channel; | |||||
| samples = data; | samples = data; | ||||
| src = buf; | src = buf; | ||||
| @@ -551,6 +570,94 @@ static int adpcm_decode_frame(AVCodecContext *avctx, | |||||
| src ++; | src ++; | ||||
| } | } | ||||
| break; | break; | ||||
| case CODEC_ID_ADPCM_IMA_DK4: | |||||
| if (buf_size > BLKSIZE) { | |||||
| if (avctx->block_align != 0) | |||||
| buf_size = avctx->block_align; | |||||
| else | |||||
| buf_size = BLKSIZE; | |||||
| } | |||||
| c->status[0].predictor = (src[0] | (src[1] << 8)); | |||||
| c->status[0].step_index = src[2]; | |||||
| src += 4; | |||||
| if(c->status[0].predictor & 0x8000) | |||||
| c->status[0].predictor -= 0x10000; | |||||
| *samples++ = c->status[0].predictor; | |||||
| if (st) { | |||||
| c->status[1].predictor = (src[0] | (src[1] << 8)); | |||||
| c->status[1].step_index = src[2]; | |||||
| src += 4; | |||||
| if(c->status[1].predictor & 0x8000) | |||||
| c->status[1].predictor -= 0x10000; | |||||
| *samples++ = c->status[1].predictor; | |||||
| } | |||||
| while (src < buf + buf_size) { | |||||
| /* take care of the top nibble (always left or mono channel) */ | |||||
| *samples++ = adpcm_ima_expand_nibble(&c->status[0], | |||||
| (src[0] >> 4) & 0x0F); | |||||
| /* take care of the bottom nibble, which is right sample for | |||||
| * stereo, or another mono sample */ | |||||
| if (st) | |||||
| *samples++ = adpcm_ima_expand_nibble(&c->status[1], | |||||
| src[0] & 0x0F); | |||||
| else | |||||
| *samples++ = adpcm_ima_expand_nibble(&c->status[0], | |||||
| src[0] & 0x0F); | |||||
| src++; | |||||
| } | |||||
| break; | |||||
| case CODEC_ID_ADPCM_IMA_DK3: | |||||
| if (buf_size > BLKSIZE) { | |||||
| if (avctx->block_align != 0) | |||||
| buf_size = avctx->block_align; | |||||
| else | |||||
| buf_size = BLKSIZE; | |||||
| } | |||||
| c->status[0].predictor = (src[10] | (src[11] << 8)); | |||||
| c->status[1].predictor = (src[12] | (src[13] << 8)); | |||||
| c->status[0].step_index = src[14]; | |||||
| c->status[1].step_index = src[15]; | |||||
| /* sign extend the predictors */ | |||||
| if(c->status[0].predictor & 0x8000) | |||||
| c->status[0].predictor -= 0x10000; | |||||
| if(c->status[1].predictor & 0x8000) | |||||
| c->status[1].predictor -= 0x10000; | |||||
| src += 16; | |||||
| diff_channel = c->status[1].predictor; | |||||
| /* the DK3_GET_NEXT_NIBBLE macro issues the break statement when | |||||
| * the buffer is consumed */ | |||||
| while (1) { | |||||
| /* for this algorithm, c->status[0] is the sum channel and | |||||
| * c->status[1] is the diff channel */ | |||||
| /* process the first predictor of the sum channel */ | |||||
| DK3_GET_NEXT_NIBBLE(); | |||||
| adpcm_ima_expand_nibble(&c->status[0], nibble); | |||||
| /* process the diff channel predictor */ | |||||
| DK3_GET_NEXT_NIBBLE(); | |||||
| adpcm_ima_expand_nibble(&c->status[1], nibble); | |||||
| /* process the first pair of stereo PCM samples */ | |||||
| diff_channel = (diff_channel + c->status[1].predictor) / 2; | |||||
| *samples++ = c->status[0].predictor + c->status[1].predictor; | |||||
| *samples++ = c->status[0].predictor - c->status[1].predictor; | |||||
| /* process the second predictor of the sum channel */ | |||||
| DK3_GET_NEXT_NIBBLE(); | |||||
| adpcm_ima_expand_nibble(&c->status[0], nibble); | |||||
| /* process the second pair of stereo PCM samples */ | |||||
| diff_channel = (diff_channel + c->status[1].predictor) / 2; | |||||
| *samples++ = c->status[0].predictor + c->status[1].predictor; | |||||
| *samples++ = c->status[0].predictor - c->status[1].predictor; | |||||
| } | |||||
| break; | |||||
| default: | default: | ||||
| *data_size = 0; | *data_size = 0; | ||||
| return -1; | return -1; | ||||
| @@ -583,8 +690,9 @@ AVCodec name ## _decoder = { \ | |||||
| ADPCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); | ADPCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); | ||||
| ADPCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); | ADPCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); | ||||
| ADPCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); | |||||
| ADPCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); | |||||
| ADPCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); | ADPCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); | ||||
| ADPCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); | ADPCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); | ||||
| #undef ADPCM_CODEC | #undef ADPCM_CODEC | ||||
| @@ -123,6 +123,7 @@ void avcodec_register_all(void) | |||||
| register_avcodec(&mdec_decoder); | register_avcodec(&mdec_decoder); | ||||
| register_avcodec(&roq_decoder); | register_avcodec(&roq_decoder); | ||||
| register_avcodec(&interplay_video_decoder); | register_avcodec(&interplay_video_decoder); | ||||
| register_avcodec(&xan_wc3_decoder); | |||||
| #ifdef CONFIG_AC3 | #ifdef CONFIG_AC3 | ||||
| register_avcodec(&ac3_decoder); | register_avcodec(&ac3_decoder); | ||||
| #endif | #endif | ||||
| @@ -130,6 +131,7 @@ void avcodec_register_all(void) | |||||
| register_avcodec(&ra_288_decoder); | register_avcodec(&ra_288_decoder); | ||||
| register_avcodec(&roq_dpcm_decoder); | register_avcodec(&roq_dpcm_decoder); | ||||
| register_avcodec(&interplay_dpcm_decoder); | register_avcodec(&interplay_dpcm_decoder); | ||||
| register_avcodec(&xan_dpcm_decoder); | |||||
| #endif /* CONFIG_DECODERS */ | #endif /* CONFIG_DECODERS */ | ||||
| #ifdef AMR_NB | #ifdef AMR_NB | ||||
| @@ -154,6 +156,8 @@ PCM_CODEC(CODEC_ID_PCM_MULAW, pcm_mulaw); | |||||
| /* adpcm codecs */ | /* adpcm codecs */ | ||||
| PCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); | PCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); | ||||
| PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); | PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); | ||||
| PCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); | |||||
| PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); | |||||
| PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); | PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); | ||||
| PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); | PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); | ||||
| @@ -68,6 +68,8 @@ enum CodecID { | |||||
| CODEC_ID_MDEC, | CODEC_ID_MDEC, | ||||
| CODEC_ID_ROQ, | CODEC_ID_ROQ, | ||||
| CODEC_ID_INTERPLAY_VIDEO, | CODEC_ID_INTERPLAY_VIDEO, | ||||
| CODEC_ID_XAN_WC3, | |||||
| CODEC_ID_XAN_WC4, | |||||
| /* various pcm "codecs" */ | /* various pcm "codecs" */ | ||||
| CODEC_ID_PCM_S16LE, | CODEC_ID_PCM_S16LE, | ||||
| @@ -82,6 +84,8 @@ enum CodecID { | |||||
| /* various adpcm codecs */ | /* various adpcm codecs */ | ||||
| CODEC_ID_ADPCM_IMA_QT, | CODEC_ID_ADPCM_IMA_QT, | ||||
| CODEC_ID_ADPCM_IMA_WAV, | CODEC_ID_ADPCM_IMA_WAV, | ||||
| CODEC_ID_ADPCM_IMA_DK3, | |||||
| CODEC_ID_ADPCM_IMA_DK4, | |||||
| CODEC_ID_ADPCM_MS, | CODEC_ID_ADPCM_MS, | ||||
| CODEC_ID_ADPCM_4XM, | CODEC_ID_ADPCM_4XM, | ||||
| @@ -94,6 +98,7 @@ enum CodecID { | |||||
| /* various DPCM codecs */ | /* various DPCM codecs */ | ||||
| CODEC_ID_ROQ_DPCM, | CODEC_ID_ROQ_DPCM, | ||||
| CODEC_ID_INTERPLAY_DPCM, | CODEC_ID_INTERPLAY_DPCM, | ||||
| CODEC_ID_XAN_DPCM, | |||||
| }; | }; | ||||
| #define CODEC_ID_MPEGVIDEO CODEC_ID_MPEG1VIDEO | #define CODEC_ID_MPEGVIDEO CODEC_ID_MPEG1VIDEO | ||||
| @@ -1356,10 +1361,12 @@ extern AVCodec fourxm_decoder; | |||||
| extern AVCodec mdec_decoder; | extern AVCodec mdec_decoder; | ||||
| extern AVCodec roq_decoder; | extern AVCodec roq_decoder; | ||||
| extern AVCodec interplay_video_decoder; | extern AVCodec interplay_video_decoder; | ||||
| extern AVCodec xan_wc3_decoder; | |||||
| extern AVCodec ra_144_decoder; | extern AVCodec ra_144_decoder; | ||||
| extern AVCodec ra_288_decoder; | extern AVCodec ra_288_decoder; | ||||
| extern AVCodec roq_dpcm_decoder; | extern AVCodec roq_dpcm_decoder; | ||||
| extern AVCodec interplay_dpcm_decoder; | extern AVCodec interplay_dpcm_decoder; | ||||
| extern AVCodec xan_dpcm_decoder; | |||||
| /* pcm codecs */ | /* pcm codecs */ | ||||
| #define PCM_CODEC(id, name) \ | #define PCM_CODEC(id, name) \ | ||||
| @@ -1379,6 +1386,8 @@ PCM_CODEC(CODEC_ID_PCM_MULAW, pcm_mulaw); | |||||
| PCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); | PCM_CODEC(CODEC_ID_ADPCM_IMA_QT, adpcm_ima_qt); | ||||
| PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); | PCM_CODEC(CODEC_ID_ADPCM_IMA_WAV, adpcm_ima_wav); | ||||
| PCM_CODEC(CODEC_ID_ADPCM_IMA_DK3, adpcm_ima_dk3); | |||||
| PCM_CODEC(CODEC_ID_ADPCM_IMA_DK4, adpcm_ima_dk4); | |||||
| PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); | PCM_CODEC(CODEC_ID_ADPCM_MS, adpcm_ms); | ||||
| PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); | PCM_CODEC(CODEC_ID_ADPCM_4XM, adpcm_4xm); | ||||
| @@ -21,8 +21,17 @@ | |||||
| * @file: dpcm.c | * @file: dpcm.c | ||||
| * Assorted DPCM (differential pulse code modulation) audio codecs | * Assorted DPCM (differential pulse code modulation) audio codecs | ||||
| * by Mike Melanson (melanson@pcisys.net) | * by Mike Melanson (melanson@pcisys.net) | ||||
| * Xan DPCM decoder by Mario Brito (mbrito@student.dei.uc.pt) | |||||
| * for more information on the specific data formats, visit: | * for more information on the specific data formats, visit: | ||||
| * http://www.pcisys.net/~melanson/codecs/simpleaudio.html | * http://www.pcisys.net/~melanson/codecs/simpleaudio.html | ||||
| * | |||||
| * Note about using the Xan DPCM decoder: Xan DPCM is used in AVI files | |||||
| * found in the Wing Commander IV computer game. These AVI files contain | |||||
| * WAVEFORMAT headers which report the audio format as 0x01: raw PCM. | |||||
| * Clearly incorrect. To detect Xan DPCM, you will probably have to | |||||
| * special-case your AVI demuxer to use Xan DPCM if the file uses 'Xxan' | |||||
| * (Xan video) for its video codec. Alternately, such AVI files also contain | |||||
| * the fourcc 'Axan' in the 'auds' chunk of the AVI header. | |||||
| */ | */ | ||||
| #include "avcodec.h" | #include "avcodec.h" | ||||
| @@ -115,6 +124,9 @@ static int dpcm_decode_frame(AVCodecContext *avctx, | |||||
| int channel_number = 0; | int channel_number = 0; | ||||
| short *output_samples = data; | short *output_samples = data; | ||||
| int sequence_number; | int sequence_number; | ||||
| int shift[2]; | |||||
| unsigned char byte; | |||||
| short diff; | |||||
| switch(avctx->codec->id) { | switch(avctx->codec->id) { | ||||
| @@ -171,6 +183,40 @@ static int dpcm_decode_frame(AVCodecContext *avctx, | |||||
| s->last_delta[i] = predictor[i]; | s->last_delta[i] = predictor[i]; | ||||
| break; | break; | ||||
| case CODEC_ID_XAN_DPCM: | |||||
| in = 0; | |||||
| shift[0] = shift[1] = 4; | |||||
| predictor[0] = LE_16(&buf[in]); | |||||
| in += 2; | |||||
| SE_16BIT(predictor[0]); | |||||
| if (s->channels == 2) { | |||||
| predictor[1] = LE_16(&buf[in]); | |||||
| in += 2; | |||||
| SE_16BIT(predictor[1]); | |||||
| } | |||||
| while (in < buf_size) { | |||||
| byte = buf[in++]; | |||||
| diff = (byte & 0xFC) << 8; | |||||
| if ((byte & 0x03) == 3) | |||||
| shift[channel_number]++; | |||||
| else | |||||
| shift[channel_number] -= (2 * (byte & 3)); | |||||
| /* saturate the shifter to a lower limit of 0 */ | |||||
| if (shift[channel_number] < 0) | |||||
| shift[channel_number] = 0; | |||||
| diff >>= shift[channel_number]; | |||||
| predictor[channel_number] += diff; | |||||
| SATURATE_S16(predictor[channel_number]); | |||||
| output_samples[out++] = predictor[channel_number]; | |||||
| /* toggle channel */ | |||||
| channel_number ^= s->channels - 1; | |||||
| } | |||||
| break; | |||||
| } | } | ||||
| *data_size = out * sizeof(short); | *data_size = out * sizeof(short); | ||||
| @@ -198,3 +244,14 @@ AVCodec interplay_dpcm_decoder = { | |||||
| NULL, | NULL, | ||||
| dpcm_decode_frame, | dpcm_decode_frame, | ||||
| }; | }; | ||||
| AVCodec xan_dpcm_decoder = { | |||||
| "xan_dpcm", | |||||
| CODEC_TYPE_AUDIO, | |||||
| CODEC_ID_XAN_DPCM, | |||||
| sizeof(DPCMContext), | |||||
| dpcm_decode_init, | |||||
| NULL, | |||||
| NULL, | |||||
| dpcm_decode_frame, | |||||
| }; | |||||
| @@ -0,0 +1,605 @@ | |||||
| /* | |||||
| * Wing Commander/Xan Video Decoder | |||||
| * Copyright (C) 2003 the ffmpeg project | |||||
| * | |||||
| * This library is free software; you can redistribute it and/or | |||||
| * modify it under the terms of the GNU Lesser General Public | |||||
| * License as published by the Free Software Foundation; either | |||||
| * version 2 of the License, or (at your option) any later version. | |||||
| * | |||||
| * This library is distributed in the hope that it will be useful, | |||||
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
| * Lesser General Public License for more details. | |||||
| * | |||||
| * You should have received a copy of the GNU Lesser General Public | |||||
| * License along with this library; if not, write to the Free Software | |||||
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |||||
| * | |||||
| */ | |||||
| /** | |||||
| * @file xan.c | |||||
| * Xan video decoder for Wing Commander III & IV computer games | |||||
| * by Mario Brito (mbrito@student.dei.uc.pt) | |||||
| * and Mike Melanson (melanson@pcisys.net) | |||||
| * For more information about the Xan format, visit: | |||||
| * http://www.pcisys.net/~melanson/codecs/ | |||||
| */ | |||||
| #include <stdio.h> | |||||
| #include <stdlib.h> | |||||
| #include <string.h> | |||||
| #include <unistd.h> | |||||
| #include "common.h" | |||||
| #include "avcodec.h" | |||||
| #include "dsputil.h" | |||||
| #define PALETTE_COUNT 256 | |||||
| #define PALETTE_CONTROL_SIZE ((256 * 3) + 1) | |||||
| typedef struct XanContext { | |||||
| AVCodecContext *avctx; | |||||
| DSPContext dsp; | |||||
| AVFrame last_frame; | |||||
| AVFrame current_frame; | |||||
| unsigned char *buf; | |||||
| int size; | |||||
| unsigned char palette[PALETTE_COUNT * 4]; | |||||
| /* scratch space */ | |||||
| unsigned char *buffer1; | |||||
| unsigned char *buffer2; | |||||
| } XanContext; | |||||
| #define BE_16(x) ((((uint8_t*)(x))[0] << 8) | ((uint8_t*)(x))[1]) | |||||
| #define LE_16(x) ((((uint8_t*)(x))[1] << 8) | ((uint8_t*)(x))[0]) | |||||
| #define LE_32(x) ((((uint8_t*)(x))[3] << 24) | \ | |||||
| (((uint8_t*)(x))[2] << 16) | \ | |||||
| (((uint8_t*)(x))[1] << 8) | \ | |||||
| ((uint8_t*)(x))[0]) | |||||
| /* RGB -> YUV conversion stuff */ | |||||
| #define SCALEFACTOR 65536 | |||||
| #define CENTERSAMPLE 128 | |||||
| #define COMPUTE_Y(r, g, b) \ | |||||
| (unsigned char) \ | |||||
| ((y_r_table[r] + y_g_table[g] + y_b_table[b]) / SCALEFACTOR) | |||||
| #define COMPUTE_U(r, g, b) \ | |||||
| (unsigned char) \ | |||||
| ((u_r_table[r] + u_g_table[g] + u_b_table[b]) / SCALEFACTOR + CENTERSAMPLE) | |||||
| #define COMPUTE_V(r, g, b) \ | |||||
| (unsigned char) \ | |||||
| ((v_r_table[r] + v_g_table[g] + v_b_table[b]) / SCALEFACTOR + CENTERSAMPLE) | |||||
| #define Y_R (SCALEFACTOR * 0.29900) | |||||
| #define Y_G (SCALEFACTOR * 0.58700) | |||||
| #define Y_B (SCALEFACTOR * 0.11400) | |||||
| #define U_R (SCALEFACTOR * -0.16874) | |||||
| #define U_G (SCALEFACTOR * -0.33126) | |||||
| #define U_B (SCALEFACTOR * 0.50000) | |||||
| #define V_R (SCALEFACTOR * 0.50000) | |||||
| #define V_G (SCALEFACTOR * -0.41869) | |||||
| #define V_B (SCALEFACTOR * -0.08131) | |||||
| /* | |||||
| * Precalculate all of the YUV tables since it requires fewer than | |||||
| * 10 kilobytes to store them. | |||||
| */ | |||||
| static int y_r_table[256]; | |||||
| static int y_g_table[256]; | |||||
| static int y_b_table[256]; | |||||
| static int u_r_table[256]; | |||||
| static int u_g_table[256]; | |||||
| static int u_b_table[256]; | |||||
| static int v_r_table[256]; | |||||
| static int v_g_table[256]; | |||||
| static int v_b_table[256]; | |||||
| static int xan_decode_init(AVCodecContext *avctx) | |||||
| { | |||||
| XanContext *s = avctx->priv_data; | |||||
| int i; | |||||
| s->avctx = avctx; | |||||
| if ((avctx->codec->id == CODEC_ID_XAN_WC3) && | |||||
| (s->avctx->extradata_size != PALETTE_CONTROL_SIZE)) { | |||||
| printf (" WC3 Xan video: expected extradata_size of %d\n", | |||||
| PALETTE_CONTROL_SIZE); | |||||
| return -1; | |||||
| } | |||||
| avctx->pix_fmt = PIX_FMT_YUV444P; | |||||
| avctx->has_b_frames = 0; | |||||
| dsputil_init(&s->dsp, avctx); | |||||
| /* initialize the RGB -> YUV tables */ | |||||
| for (i = 0; i < 256; i++) { | |||||
| y_r_table[i] = Y_R * i; | |||||
| y_g_table[i] = Y_G * i; | |||||
| y_b_table[i] = Y_B * i; | |||||
| u_r_table[i] = U_R * i; | |||||
| u_g_table[i] = U_G * i; | |||||
| u_b_table[i] = U_B * i; | |||||
| v_r_table[i] = V_R * i; | |||||
| v_g_table[i] = V_G * i; | |||||
| v_b_table[i] = V_B * i; | |||||
| } | |||||
| s->buffer1 = av_malloc(avctx->width * avctx->height * 4); | |||||
| s->buffer2 = av_malloc(avctx->width * avctx->height * 4); | |||||
| if (!s->buffer1 || !s->buffer2) | |||||
| return -1; | |||||
| return 0; | |||||
| } | |||||
| /* This function is used in lieu of memcpy(). This decoder can not use | |||||
| * memcpy because the memory locations often overlap and | |||||
| * memcpy doesn't like that; it's not uncommon, for example, for | |||||
| * dest = src+1, to turn byte A into pattern AAAAAAAA. | |||||
| * This was originally repz movsb in Intel x86 ASM. */ | |||||
| static inline void bytecopy(unsigned char *dest, unsigned char *src, int count) | |||||
| { | |||||
| int i; | |||||
| for (i = 0; i < count; i++) | |||||
| dest[i] = src[i]; | |||||
| } | |||||
| static int xan_decode_method_1(unsigned char *dest, unsigned char *src) | |||||
| { | |||||
| unsigned char byte = *src++; | |||||
| unsigned char ival = byte + 0x16; | |||||
| unsigned char * ptr = src + byte*2; | |||||
| unsigned char val = ival; | |||||
| int counter = 0; | |||||
| unsigned char bits = *ptr++; | |||||
| while ( val != 0x16 ) { | |||||
| if ( (1 << counter) & bits ) | |||||
| val = src[byte + val - 0x17]; | |||||
| else | |||||
| val = src[val - 0x17]; | |||||
| if ( val < 0x16 ) { | |||||
| *dest++ = val; | |||||
| val = ival; | |||||
| } | |||||
| if (counter++ == 7) { | |||||
| counter = 0; | |||||
| bits = *ptr++; | |||||
| } | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static int xan_decode_method_2(unsigned char *dest, unsigned char *src) | |||||
| { | |||||
| unsigned char opcode; | |||||
| int size; | |||||
| int offset; | |||||
| int byte1, byte2, byte3; | |||||
| for (;;) { | |||||
| opcode = *src++; | |||||
| if ( (opcode & 0x80) == 0 ) { | |||||
| offset = *src++; | |||||
| size = opcode & 3; | |||||
| bytecopy(dest, src, size); dest += size; src += size; | |||||
| size = ((opcode & 0x1c) >> 2) + 3; | |||||
| bytecopy (dest, dest - (((opcode & 0x60) << 3) + offset + 1), size); | |||||
| dest += size; | |||||
| } else if ( (opcode & 0x40) == 0 ) { | |||||
| byte1 = *src++; | |||||
| byte2 = *src++; | |||||
| size = byte1 >> 6; | |||||
| bytecopy (dest, src, size); dest += size; src += size; | |||||
| size = (opcode & 0x3f) + 4; | |||||
| bytecopy (dest, dest - (((byte1 & 0x3f) << 8) + byte2 + 1), size); | |||||
| dest += size; | |||||
| } else if ( (opcode & 0x20) == 0 ) { | |||||
| byte1 = *src++; | |||||
| byte2 = *src++; | |||||
| byte3 = *src++; | |||||
| size = opcode & 3; | |||||
| bytecopy (dest, src, size); dest += size; src += size; | |||||
| size = byte3 + 5 + ((opcode & 0xc) << 6); | |||||
| bytecopy (dest, | |||||
| dest - ((((opcode & 0x10) >> 4) << 0x10) + 1 + (byte1 << 8) + byte2), | |||||
| size); | |||||
| dest += size; | |||||
| } else { | |||||
| size = ((opcode & 0x1f) << 2) + 4; | |||||
| if (size > 0x70) | |||||
| break; | |||||
| bytecopy (dest, src, size); dest += size; src += size; | |||||
| } | |||||
| } | |||||
| size = opcode & 3; | |||||
| bytecopy(dest, src, size); dest += size; src += size; | |||||
| return 0; | |||||
| } | |||||
| static void inline xan_wc3_build_palette(XanContext *s, | |||||
| unsigned char *palette_data) | |||||
| { | |||||
| int i; | |||||
| unsigned char r, g, b; | |||||
| /* transform the palette passed through the palette control structure | |||||
| * into the necessary internal format depending on colorspace */ | |||||
| switch (s->avctx->pix_fmt) { | |||||
| case PIX_FMT_YUV444P: | |||||
| for (i = 0; i < PALETTE_COUNT; i++) { | |||||
| r = *palette_data++; | |||||
| g = *palette_data++; | |||||
| b = *palette_data++; | |||||
| s->palette[i * 4 + 0] = COMPUTE_Y(r, g, b); | |||||
| s->palette[i * 4 + 1] = COMPUTE_U(r, g, b); | |||||
| s->palette[i * 4 + 2] = COMPUTE_V(r, g, b); | |||||
| } | |||||
| break; | |||||
| default: | |||||
| printf (" Xan WC3: Unhandled colorspace\n"); | |||||
| break; | |||||
| } | |||||
| } | |||||
| static void inline xan_wc3_output_pixel_run(XanContext *s, | |||||
| unsigned char *pixel_buffer, int x, int y, int pixel_count) | |||||
| { | |||||
| int stride; | |||||
| int line_inc; | |||||
| int index; | |||||
| int current_x; | |||||
| int width = s->avctx->width; | |||||
| unsigned char pixel; | |||||
| unsigned char *y_plane; | |||||
| unsigned char *u_plane; | |||||
| unsigned char *v_plane; | |||||
| switch (s->avctx->pix_fmt) { | |||||
| case PIX_FMT_YUV444P: | |||||
| y_plane = s->current_frame.data[0]; | |||||
| u_plane = s->current_frame.data[1]; | |||||
| v_plane = s->current_frame.data[2]; | |||||
| stride = s->current_frame.linesize[0]; | |||||
| line_inc = stride - width; | |||||
| index = y * stride + x; | |||||
| current_x = x; | |||||
| while(pixel_count--) { | |||||
| pixel = *pixel_buffer++; | |||||
| y_plane[index] = s->palette[pixel * 4 + 0]; | |||||
| u_plane[index] = s->palette[pixel * 4 + 1]; | |||||
| v_plane[index] = s->palette[pixel * 4 + 2]; | |||||
| index++; | |||||
| current_x++; | |||||
| if (current_x >= width) { | |||||
| /* reset accounting variables */ | |||||
| index += line_inc; | |||||
| current_x = 0; | |||||
| } | |||||
| } | |||||
| break; | |||||
| default: | |||||
| printf (" Xan WC3: Unhandled colorspace\n"); | |||||
| break; | |||||
| } | |||||
| } | |||||
| static void inline xan_wc3_copy_pixel_run(XanContext *s, | |||||
| int x, int y, int pixel_count, int motion_x, int motion_y) | |||||
| { | |||||
| int stride; | |||||
| int line_inc; | |||||
| int curframe_index, prevframe_index; | |||||
| int curframe_x, prevframe_x; | |||||
| int width = s->avctx->width; | |||||
| unsigned char *y_plane, *u_plane, *v_plane; | |||||
| unsigned char *prev_y_plane, *prev_u_plane, *prev_v_plane; | |||||
| switch (s->avctx->pix_fmt) { | |||||
| case PIX_FMT_YUV444P: | |||||
| y_plane = s->current_frame.data[0]; | |||||
| u_plane = s->current_frame.data[1]; | |||||
| v_plane = s->current_frame.data[2]; | |||||
| prev_y_plane = s->last_frame.data[0]; | |||||
| prev_u_plane = s->last_frame.data[1]; | |||||
| prev_v_plane = s->last_frame.data[2]; | |||||
| stride = s->current_frame.linesize[0]; | |||||
| line_inc = stride - width; | |||||
| curframe_index = y * stride + x; | |||||
| curframe_x = x; | |||||
| prevframe_index = (y + motion_x) * stride + x + motion_x; | |||||
| prevframe_x = x + motion_x; | |||||
| while(pixel_count--) { | |||||
| y_plane[curframe_index] = prev_y_plane[prevframe_index]; | |||||
| u_plane[curframe_index] = prev_u_plane[prevframe_index]; | |||||
| v_plane[curframe_index] = prev_v_plane[prevframe_index]; | |||||
| curframe_index++; | |||||
| curframe_x++; | |||||
| if (curframe_x >= width) { | |||||
| /* reset accounting variables */ | |||||
| curframe_index += line_inc; | |||||
| curframe_x = 0; | |||||
| } | |||||
| prevframe_index++; | |||||
| prevframe_x++; | |||||
| if (prevframe_x >= width) { | |||||
| /* reset accounting variables */ | |||||
| prevframe_index += line_inc; | |||||
| prevframe_x = 0; | |||||
| } | |||||
| } | |||||
| break; | |||||
| default: | |||||
| printf (" Xan WC3: Unhandled colorspace\n"); | |||||
| break; | |||||
| } | |||||
| } | |||||
| static void xan_wc3_decode_frame(XanContext *s) { | |||||
| int width = s->avctx->width; | |||||
| int height = s->avctx->height; | |||||
| int total_pixels = width * height; | |||||
| unsigned char opcode; | |||||
| unsigned char flag = 0; | |||||
| int size = 0; | |||||
| int motion_x, motion_y; | |||||
| int x, y; | |||||
| unsigned char *method1_buffer = s->buffer1; | |||||
| unsigned char *method2_buffer = s->buffer2; | |||||
| /* pointers to segments inside the compressed chunk */ | |||||
| unsigned char *method1_segment; | |||||
| unsigned char *size_segment; | |||||
| unsigned char *vector_segment; | |||||
| unsigned char *method2_segment; | |||||
| method1_segment = s->buf + LE_16(&s->buf[0]); | |||||
| size_segment = s->buf + LE_16(&s->buf[2]); | |||||
| vector_segment = s->buf + LE_16(&s->buf[4]); | |||||
| method2_segment = s->buf + LE_16(&s->buf[6]); | |||||
| xan_decode_method_1(method1_buffer, method1_segment); | |||||
| if (method2_segment[0] == 2) | |||||
| xan_decode_method_2(method2_buffer, method2_segment + 1); | |||||
| else | |||||
| method2_buffer = method2_segment + 1; | |||||
| /* use the decoded data segments to build the frame */ | |||||
| x = y = 0; | |||||
| while (total_pixels) { | |||||
| opcode = *method1_buffer++; | |||||
| size = 0; | |||||
| switch (opcode) { | |||||
| case 0: | |||||
| flag ^= 1; | |||||
| continue; | |||||
| case 1: | |||||
| case 2: | |||||
| case 3: | |||||
| case 4: | |||||
| case 5: | |||||
| case 6: | |||||
| case 7: | |||||
| case 8: | |||||
| size = opcode; | |||||
| break; | |||||
| case 12: | |||||
| case 13: | |||||
| case 14: | |||||
| case 15: | |||||
| case 16: | |||||
| case 17: | |||||
| case 18: | |||||
| size += (opcode - 10); | |||||
| break; | |||||
| case 9: | |||||
| case 19: | |||||
| size = *size_segment++; | |||||
| break; | |||||
| case 10: | |||||
| case 20: | |||||
| size = BE_16(&size_segment[0]); | |||||
| size_segment += 2; | |||||
| break; | |||||
| case 11: | |||||
| case 21: | |||||
| size = (size_segment[0] << 16) | (size_segment[1] << 8) | | |||||
| size_segment[2]; | |||||
| size_segment += 3; | |||||
| break; | |||||
| } | |||||
| if (opcode < 12) { | |||||
| flag ^= 1; | |||||
| if (flag) { | |||||
| /* run of (size) pixels is unchanged from last frame */ | |||||
| xan_wc3_copy_pixel_run(s, x, y, size, 0, 0); | |||||
| } else { | |||||
| /* output a run of pixels from method2_buffer */ | |||||
| xan_wc3_output_pixel_run(s, method2_buffer, x, y, size); | |||||
| method2_buffer += size; | |||||
| } | |||||
| } else { | |||||
| /* run-based motion compensation from last frame */ | |||||
| motion_x = (*vector_segment >> 4) & 0xF; | |||||
| motion_y = *vector_segment & 0xF; | |||||
| vector_segment++; | |||||
| /* sign extension */ | |||||
| if (motion_x & 0x8) | |||||
| motion_x |= 0xFFFFFFF0; | |||||
| if (motion_y & 0x8) | |||||
| motion_y |= 0xFFFFFFF0; | |||||
| /* copy a run of pixels from the previous frame */ | |||||
| xan_wc3_copy_pixel_run(s, x, y, size, motion_x, motion_y); | |||||
| flag = 0; | |||||
| } | |||||
| /* coordinate accounting */ | |||||
| total_pixels -= size; | |||||
| while (size) { | |||||
| if (x + size >= width) { | |||||
| y++; | |||||
| size -= (width - x); | |||||
| x = 0; | |||||
| } else { | |||||
| x += size; | |||||
| size = 0; | |||||
| } | |||||
| } | |||||
| } | |||||
| } | |||||
| static void xan_wc4_decode_frame(XanContext *s) { | |||||
| } | |||||
| static int xan_decode_frame(AVCodecContext *avctx, | |||||
| void *data, int *data_size, | |||||
| uint8_t *buf, int buf_size) | |||||
| { | |||||
| XanContext *s = avctx->priv_data; | |||||
| unsigned char *palette_control = avctx->extradata; | |||||
| int keyframe = 0; | |||||
| if (palette_control[0]) { | |||||
| /* load the new palette and reset the palette control */ | |||||
| xan_wc3_build_palette(s, &palette_control[1]); | |||||
| palette_control[0] = 0; | |||||
| keyframe = 1; | |||||
| } | |||||
| if (avctx->get_buffer(avctx, &s->current_frame)) { | |||||
| printf (" Interplay Video: get_buffer() failed\n"); | |||||
| return -1; | |||||
| } | |||||
| s->buf = buf; | |||||
| s->size = buf_size; | |||||
| if (avctx->codec->id == CODEC_ID_XAN_WC3) { | |||||
| // if (keyframe) | |||||
| if (1) | |||||
| xan_wc3_decode_frame(s); | |||||
| else { | |||||
| memcpy(s->current_frame.data[0], s->last_frame.data[0], | |||||
| s->current_frame.linesize[0] * avctx->height); | |||||
| memcpy(s->current_frame.data[1], s->last_frame.data[1], | |||||
| s->current_frame.linesize[1] * avctx->height); | |||||
| memcpy(s->current_frame.data[2], s->last_frame.data[2], | |||||
| s->current_frame.linesize[2] * avctx->height); | |||||
| } | |||||
| } else if (avctx->codec->id == CODEC_ID_XAN_WC4) | |||||
| xan_wc4_decode_frame(s); | |||||
| /* release the last frame if it is allocated */ | |||||
| if (s->last_frame.data[0]) | |||||
| avctx->release_buffer(avctx, &s->last_frame); | |||||
| /* shuffle frames */ | |||||
| s->last_frame = s->current_frame; | |||||
| *data_size = sizeof(AVFrame); | |||||
| *(AVFrame*)data = s->current_frame; | |||||
| /* always report that the buffer was completely consumed */ | |||||
| return buf_size; | |||||
| } | |||||
| static int xan_decode_end(AVCodecContext *avctx) | |||||
| { | |||||
| XanContext *s = avctx->priv_data; | |||||
| /* release the last frame */ | |||||
| avctx->release_buffer(avctx, &s->last_frame); | |||||
| av_free(s->buffer1); | |||||
| av_free(s->buffer2); | |||||
| return 0; | |||||
| } | |||||
| AVCodec xan_wc3_decoder = { | |||||
| "xan_wc3", | |||||
| CODEC_TYPE_VIDEO, | |||||
| CODEC_ID_XAN_WC3, | |||||
| sizeof(XanContext), | |||||
| xan_decode_init, | |||||
| NULL, | |||||
| xan_decode_end, | |||||
| xan_decode_frame, | |||||
| CODEC_CAP_DR1, | |||||
| }; | |||||
| /* | |||||
| AVCodec xan_wc4_decoder = { | |||||
| "xan_wc4", | |||||
| CODEC_TYPE_VIDEO, | |||||
| CODEC_ID_XAN_WC4, | |||||
| sizeof(XanContext), | |||||
| xan_decode_init, | |||||
| NULL, | |||||
| xan_decode_end, | |||||
| xan_decode_frame, | |||||
| CODEC_CAP_DR1, | |||||
| }; | |||||
| */ | |||||