diff --git a/dec_audio.c b/dec_audio.c index 1f2d8b00fa..5aba84344b 100644 --- a/dec_audio.c +++ b/dec_audio.c @@ -20,6 +20,8 @@ extern int verbose; // defined in mplayer.c #include "dec_audio.h" +#include "roqav.h" + //========================================================================== #include "libao2/afmt.h" @@ -433,6 +435,13 @@ case AFM_FOX62ADPCM: sh_audio->ds->ss_div=FOX62_ADPCM_SAMPLES_PER_BLOCK; sh_audio->ds->ss_mul=FOX62_ADPCM_BLOCK_SIZE; break; +case AFM_ROQAUDIO: + // minsize was stored in wf->nBlockAlign by the RoQ demuxer + sh_audio->audio_out_minsize=sh_audio->wf->nBlockAlign; + sh_audio->ds->ss_div=FOX62_ADPCM_SAMPLES_PER_BLOCK; + sh_audio->ds->ss_mul=FOX62_ADPCM_BLOCK_SIZE; + sh_audio->context = roq_decode_audio_init(); + break; case AFM_MPEG: // MPEG Audio: sh_audio->audio_out_minsize=4608; @@ -726,6 +735,11 @@ case AFM_FOX62ADPCM: sh_audio->i_bps=FOX62_ADPCM_BLOCK_SIZE* (sh_audio->channels*sh_audio->samplerate) / FOX62_ADPCM_SAMPLES_PER_BLOCK; break; +case AFM_ROQAUDIO: + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + sh_audio->i_bps = (sh_audio->channels * 22050) / 2; + break; case AFM_MPEG: { // MPEG Audio: dec_audio_sh=sh_audio; // save sh_audio for the callback: @@ -1166,6 +1180,27 @@ int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen){ (unsigned short*)buf,ibuf); break; } + case AFM_ROQAUDIO: + { + static unsigned char *ibuf = NULL; + unsigned char header_data[6]; + int read_len; + + if (!ibuf) + ibuf = (unsigned char *)malloc(sh_audio->audio_out_minsize / 2); + + // figure out how much data to read + if (demux_read_data(sh_audio->ds, header_data, 6) != 6) + break; // EOF + read_len = (header_data[5] << 24) | (header_data[4] << 16) | + (header_data[3] << 8) | header_data[2]; + read_len += 2; // 16-bit arguments + if (demux_read_data(sh_audio->ds, ibuf, read_len) != read_len) + break; + len = 2 * roq_decode_audio((unsigned short *)buf, ibuf, + read_len, sh_audio->channels, sh_audio->context); + break; + } #ifdef USE_LIBAC3 case AFM_AC3: // AC3 decoder //printf("{1:%d}",avi_header.idx_pos);fflush(stdout); diff --git a/dec_video.c b/dec_video.c index d9b928d2d5..90980c5bb2 100644 --- a/dec_video.c +++ b/dec_video.c @@ -34,6 +34,8 @@ extern int verbose; // defined in mplayer.c #include "dec_video.h" +#include "roqav.h" + // =================================================================== extern double video_time_usage; @@ -424,6 +426,15 @@ sh_video->image=new_mp_image(sh_video->disp_w,sh_video->disp_h); mp_image_setfmt(sh_video->image,out_fmt); switch(sh_video->codec->driver){ + case VFM_ROQVIDEO: +#ifdef USE_MP_IMAGE + sh_video->image->type=MP_IMGTYPE_STATIC; +#else + sh_video->our_out_buffer = + (char*)memalign(64, sh_video->disp_w * sh_video->disp_h * 1.5); +#endif + sh_video->context = roq_decode_video_init(); + break; case VFM_CINEPAK: { #ifdef USE_MP_IMAGE sh_video->image->type=MP_IMGTYPE_STATIC; @@ -1080,6 +1091,11 @@ if(verbose>1){ sh_video->disp_w, sh_video->disp_h, (out_fmt==IMGFMT_YUY2)?16:(out_fmt&255)); blit_frame = 3; break; + case VFM_ROQVIDEO: + roq_decode_video(start, in_size, sh_video->our_out_buffer, + sh_video->disp_w, sh_video->disp_h, sh_video->context); + blit_frame = 3; + break; } // switch //------------------------ frame decoded. -------------------- diff --git a/roqav.c b/roqav.c index f1bcd51b98..40eac00673 100644 --- a/roqav.c +++ b/roqav.c @@ -1,17 +1,24 @@ /* RoQ A/V decoder for the MPlayer program by Mike Melanson - based on Dr. Tim Ferguson's RoQ document found at: + based on Dr. Tim Ferguson's RoQ document and accompanying source + code found at: http://www.csse.monash.edu.au/~timf/videocodec.html */ #include "config.h" #include "bswap.h" #include +#include #define LE_16(x) (le2me_16(*(unsigned short *)(x))) #define LE_32(x) (le2me_32(*(unsigned int *)(x))) +#define CLAMP_S16(x) if (x < -32768) x = -32768; \ + else if (x > 32767) x = 32767; +#define SE_16BIT(x) if (x & 0x8000) x -= 0x10000; +// sign extend a 4-bit value + void *roq_decode_video_init(void) { } @@ -26,14 +33,62 @@ void roq_decode_video( { } +// Initialize the RoQ audio decoder, which is to say, initialize the table +// of squares. void *roq_decode_audio_init(void) { + short *square_array; + short square; + int i; + + square_array = (short *)malloc(256 * sizeof(short)); + if (!square_array) + return NULL; + + for (i = 0; i < 128; i++) + { + square = i * i; + square_array[i] = square; + square_array[i + 128] = -square; + } + + return square_array; } int roq_decode_audio( unsigned short *output, unsigned char *input, + int encoded_size, int channels, void *context) { + short *square_array = (short *)context; + int i; + int predictor[2]; + int channel_number = 0; + + // prepare the initial predictors + if (channels == 1) + predictor[0] = LE_16(&input[0]); + else + { + predictor[0] = input[1] << 8; + predictor[1] = input[0] << 8; + } + SE_16BIT(predictor[0]); + SE_16BIT(predictor[1]); + + // decode the samples + for (i = 2; i < encoded_size; i++) + { + predictor[channel_number] += square_array[input[i]]; + CLAMP_S16(predictor[channel_number]); + output[i - 2] = predictor[channel_number]; + + // toggle channel + channel_number ^= channels - 1; + } + + // return the number of samples decoded + return (encoded_size - 2); } diff --git a/roqav.h b/roqav.h index a049713e9a..be88916311 100644 --- a/roqav.h +++ b/roqav.h @@ -7,6 +7,6 @@ void roq_decode_video(unsigned char *encoded, int encoded_size, void *roq_decode_audio_init(void); int roq_decode_audio(unsigned short *output, unsigned char *input, - int channels, void *context); + int encoded_size, int channels, void *context); #endif // ROQAV_H