diff --git a/libmpcodecs/ad_a52.c b/libmpcodecs/ad_a52.c new file mode 100644 index 0000000000..ca6eea2398 --- /dev/null +++ b/libmpcodecs/ad_a52.c @@ -0,0 +1,194 @@ +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include "ad_internal.h" + +#include "cpudetect.h" + +#include "../liba52/a52.h" +#include "../liba52/mm_accel.h" + +sample_t * a52_samples; +a52_state_t a52_state; +uint32_t a52_accel=0; +uint32_t a52_flags=0; + +#include "bswap.h" + +static ad_info_t info = +{ + "AC3-liba52", + "liba52", + AFM_A52, + "Nick Kurshev", + "Michel LESPINASSE", + "" +}; + +LIBAD_EXTERN(a52) + +extern int audio_output_channels; + +int a52_fillbuff(sh_audio_t *sh_audio){ +int length=0; +int flags=0; +int sample_rate=0; +int bit_rate=0; + + sh_audio->a_in_buffer_len=0; + /* sync frame:*/ +while(1){ + while(sh_audio->a_in_buffer_len<7){ + int c=demux_getc(sh_audio->ds); + if(c<0) return -1; /* EOF*/ + sh_audio->a_in_buffer[sh_audio->a_in_buffer_len++]=c; + } + length = a52_syncinfo (sh_audio->a_in_buffer, &flags, &sample_rate, &bit_rate); + if(length>=7 && length<=3840) break; /* we're done.*/ + /* bad file => resync*/ + memcpy(sh_audio->a_in_buffer,sh_audio->a_in_buffer+1,6); + --sh_audio->a_in_buffer_len; +} + mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"a52: len=%d flags=0x%X %d Hz %d bit/s\n",length,flags,sample_rate,bit_rate); + sh_audio->samplerate=sample_rate; + sh_audio->i_bps=bit_rate/8; + demux_read_data(sh_audio->ds,sh_audio->a_in_buffer+7,length-7); + + if(crc16_block(sh_audio->a_in_buffer+2,length-2)!=0) + mp_msg(MSGT_DECAUDIO,MSGL_STATUS,"a52: CRC check failed! \n"); + + return length; +} + +/* returns: number of available channels*/ +static int a52_printinfo(sh_audio_t *sh_audio){ +int flags, sample_rate, bit_rate; +char* mode="unknown"; +int channels=0; + a52_syncinfo (sh_audio->a_in_buffer, &flags, &sample_rate, &bit_rate); + switch(flags&A52_CHANNEL_MASK){ + case A52_CHANNEL: mode="channel"; channels=2; break; + case A52_MONO: mode="mono"; channels=1; break; + case A52_STEREO: mode="stereo"; channels=2; break; + case A52_3F: mode="3f";channels=3;break; + case A52_2F1R: mode="2f+1r";channels=3;break; + case A52_3F1R: mode="3f+1r";channels=4;break; + case A52_2F2R: mode="2f+2r";channels=4;break; + case A52_3F2R: mode="3f+2r";channels=5;break; + case A52_CHANNEL1: mode="channel1"; channels=2; break; + case A52_CHANNEL2: mode="channel2"; channels=2; break; + case A52_DOLBY: mode="dolby"; channels=2; break; + } + mp_msg(MSGT_DECAUDIO,MSGL_INFO,"AC3: %d.%d (%s%s) %d Hz %3.1f kbit/s\n", + channels, (flags&A52_LFE)?1:0, + mode, (flags&A52_LFE)?"+lfe":"", + sample_rate, bit_rate*0.001f); + return (flags&A52_LFE) ? (channels+1) : channels; +} + + +static int preinit(sh_audio_t *sh) +{ + /* Dolby AC3 audio: */ + /* however many channels, 2 bytes in a word, 256 samples in a block, 6 blocks in a frame */ + sh->audio_out_minsize=audio_output_channels*2*256*6; + return 1; +} + +static int init(sh_audio_t *sh_audio) +{ + sample_t level=1, bias=384; + int flags=0; + /* Dolby AC3 audio:*/ + if(gCpuCaps.hasSSE) a52_accel|=MM_ACCEL_X86_SSE; + if(gCpuCaps.hasMMX) a52_accel|=MM_ACCEL_X86_MMX; + if(gCpuCaps.hasMMX2) a52_accel|=MM_ACCEL_X86_MMXEXT; + if(gCpuCaps.has3DNow) a52_accel|=MM_ACCEL_X86_3DNOW; + if(gCpuCaps.has3DNowExt) a52_accel|=MM_ACCEL_X86_3DNOWEXT; + a52_samples=a52_init (a52_accel); + if (a52_samples == NULL) { + mp_msg(MSGT_DECAUDIO,MSGL_ERR,"A52 init failed\n"); + return 0; + } + sh_audio->a_in_buffer_size=3840; + sh_audio->a_in_buffer=malloc(sh_audio->a_in_buffer_size); + sh_audio->a_in_buffer_len=0; + if(a52_fillbuff(sh_audio)<0){ + mp_msg(MSGT_DECAUDIO,MSGL_ERR,"A52 sync failed\n"); + return 0; + } + /* 'a52 cannot upmix' hotfix:*/ + a52_printinfo(sh_audio); + sh_audio->channels=audio_output_channels; +while(sh_audio->channels>0){ + switch(sh_audio->channels){ + case 1: a52_flags=A52_MONO; break; +/* case 2: a52_flags=A52_STEREO; break;*/ + case 2: a52_flags=A52_DOLBY; break; +/* case 3: a52_flags=A52_3F; break;*/ + case 3: a52_flags=A52_2F1R; break; + case 4: a52_flags=A52_2F2R; break; /* 2+2*/ + case 5: a52_flags=A52_3F2R; break; + case 6: a52_flags=A52_3F2R|A52_LFE; break; /* 5.1*/ + } + /* test:*/ + flags=a52_flags|A52_ADJUST_LEVEL; + mp_msg(MSGT_DECAUDIO,MSGL_V,"A52 flags before a52_frame: 0x%X\n",flags); + if (a52_frame (&a52_state, sh_audio->a_in_buffer, &flags, &level, bias)){ + mp_msg(MSGT_DECAUDIO,MSGL_ERR,"a52: error decoding frame -> nosound\n"); + return 0; + } + mp_msg(MSGT_DECAUDIO,MSGL_V,"A52 flags after a52_frame: 0x%X\n",flags); + /* frame decoded, let's init resampler:*/ + if(a52_resample_init(a52_accel,flags,sh_audio->channels)) break; + --sh_audio->channels; /* try to decrease no. of channels*/ +} + if(sh_audio->channels<=0){ + mp_msg(MSGT_DECAUDIO,MSGL_ERR,"a52: no resampler. try different channel setup!\n"); + return 0; + } + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + a52_fillbuff(sh); break; // skip AC3 frame + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + sample_t level=1, bias=384; + int flags=a52_flags|A52_ADJUST_LEVEL; + int i,len=-1; + if(!sh_audio->a_in_buffer_len) + if(a52_fillbuff(sh_audio)<0) return len; /* EOF */ + sh_audio->a_in_buffer_len=0; + if (a52_frame (&a52_state, sh_audio->a_in_buffer, &flags, &level, bias)){ + mp_msg(MSGT_DECAUDIO,MSGL_WARN,"a52: error decoding frame\n"); + return len; + } + len=0; + for (i = 0; i < 6; i++) { + if (a52_block (&a52_state, a52_samples)){ + mp_msg(MSGT_DECAUDIO,MSGL_WARN,"a52: error at resampling\n"); + break; + } + len+=2*a52_resample(a52_samples,&buf[len]); + } + return len; +} diff --git a/libmpcodecs/ad_acm.c b/libmpcodecs/ad_acm.c new file mode 100644 index 0000000000..5a74071489 --- /dev/null +++ b/libmpcodecs/ad_acm.c @@ -0,0 +1,76 @@ +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include "ad_internal.h" + +static ad_info_t info = +{ + "Win32 ACM audio decoder", + "msacm", + AFM_ACM, + "Nick Kurshev", + "avifile.sf.net", + "" +}; + +LIBAD_EXTERN(msacm) + +#include "dll_init.h" + +static int init(sh_audio_t *sh_audio) +{ + int ret=acm_decode_audio(sh_audio,sh_audio->a_buffer,4096,sh_audio->a_buffer_size); + if(ret<0){ + mp_msg(MSGT_DECAUDIO,MSGL_INFO,"ACM decoding error: %d\n",ret); + return 0; + } + sh_audio->a_buffer_len=ret; + return 1; +} + +static int preinit(sh_audio_t *sh_audio) +{ + /* Win32 ACM audio codec: */ + if(init_acm_audio_codec(sh_audio)){ + sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec; + sh_audio->channels=sh_audio->o_wf.nChannels; + sh_audio->samplerate=sh_audio->o_wf.nSamplesPerSec; + } else { + mp_msg(MSGT_DECAUDIO,MSGL_ERR,MSGTR_ACMiniterror); + return 0; + } + mp_msg(MSGT_DECVIDEO,MSGL_V,"INFO: Win32/ACM audio codec init OK!\n"); + return 1; +} + +static void uninit(sh_audio_t *sh) +{ + // TODO! +} + +static int control(sh_audio_t *sh_audio,int cmd,void* arg, ...) +{ + int skip; + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + skip=sh_audio->wf->nBlockAlign; + if(skip<16){ + skip=(sh_audio->wf->nAvgBytesPerSec/16)&(~7); + if(skip<16) skip=16; + } + demux_read_data(sh_audio->ds,NULL,skip); + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + return acm_decode_audio(sh_audio,buf,minlen,maxlen); +} diff --git a/libmpcodecs/ad_alaw.c b/libmpcodecs/ad_alaw.c new file mode 100644 index 0000000000..d1a7e4cfe4 --- /dev/null +++ b/libmpcodecs/ad_alaw.c @@ -0,0 +1,73 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" + +static ad_info_t info = +{ + "aLaw/uLaw audio decoder", + "alaw", + AFM_ALAW, + "Nick Kurshev", + "A'rpi", + "" +}; + +LIBAD_EXTERN(alaw) + +#include "alaw.h" + +static int init(sh_audio_t *sh_audio) +{ + /* aLaw audio codec:*/ + if(!sh_audio->wf) return 0; + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + sh_audio->i_bps=sh_audio->channels*sh_audio->samplerate; + return 1; +} + +static int preinit(sh_audio_t *sh) +{ + sh->audio_out_minsize=2048; + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + int skip; + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + skip=sh->i_bps/16; + skip=skip&(~3); + demux_read_data(sh->ds,NULL,skip); + return CONTROL_TRUE; + default: + return CONTROL_UNKNOWN; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + int len; + int l=demux_read_data(sh_audio->ds,buf,minlen/2); + unsigned short *d=(unsigned short *) buf; + unsigned char *s=buf; + len=2*l; + if(sh_audio->format==6){ + /* aLaw */ + while(l>0){ --l; d[l]=alaw2short[s[l]]; } + } else { + /* uLaw */ + while(l>0){ --l; d[l]=ulaw2short[s[l]]; } + } + return len; +} diff --git a/libmpcodecs/ad_dk3adpcm.c b/libmpcodecs/ad_dk3adpcm.c new file mode 100644 index 0000000000..a6de3d96e1 --- /dev/null +++ b/libmpcodecs/ad_dk3adpcm.c @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" + +static ad_info_t info = +{ + "Duck DK3 ADPCM decoder", + "dk3adpcm", + AFM_DK3ADPCM, + "Nick Kurshev", + "Mike Melanson", + "This format number was used by Duck Corp. but not officially registered with Microsoft" +}; + +LIBAD_EXTERN(dk3adpcm) + +#include "adpcm.h" + +static int init(sh_audio_t *sh_audio) +{ + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + sh_audio->i_bps=DK3_ADPCM_BLOCK_SIZE* + (sh_audio->channels*sh_audio->samplerate) / DK3_ADPCM_SAMPLES_PER_BLOCK; + return 1; +} + +static int preinit(sh_audio_t *sh_audio) +{ + sh_audio->audio_out_minsize=DK3_ADPCM_SAMPLES_PER_BLOCK * 4; + sh_audio->ds->ss_div=DK3_ADPCM_SAMPLES_PER_BLOCK; + sh_audio->ds->ss_mul=DK3_ADPCM_BLOCK_SIZE; + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + // TODO! + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + int len=-1; + unsigned char ibuf[DK3_ADPCM_BLOCK_SIZE * 2]; /* bytes / stereo frame */ + if (demux_read_data(sh_audio->ds, ibuf, + DK3_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) != + DK3_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) + return len; /* EOF */ + len = 2 * dk3_adpcm_decode_block( + (unsigned short*)buf,ibuf); + return len; +} diff --git a/libmpcodecs/ad_dk4adpcm.c b/libmpcodecs/ad_dk4adpcm.c new file mode 100644 index 0000000000..c647f984fa --- /dev/null +++ b/libmpcodecs/ad_dk4adpcm.c @@ -0,0 +1,60 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" + +static ad_info_t info = +{ + "Duck DK4 ADPCM (rogue format number) audio decoder", + "dk4adpcm", + AFM_DK4ADPCM, + "Nick Kurshev", + "This format number was used by Duck Corp. but not officially registered with Microsoft" +}; + +LIBAD_EXTERN(dk4adpcm) + +#include "adpcm.h" + +static int init(sh_audio_t *sh_audio) +{ + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + sh_audio->i_bps = sh_audio->wf->nBlockAlign * + (sh_audio->channels*sh_audio->samplerate) / DK4_ADPCM_SAMPLES_PER_BLOCK; + return 1; +} + +static int preinit(sh_audio_t *sh_audio) +{ + sh_audio->audio_out_minsize=DK4_ADPCM_SAMPLES_PER_BLOCK * 4; + sh_audio->ds->ss_div=DK4_ADPCM_SAMPLES_PER_BLOCK; + sh_audio->ds->ss_mul=sh_audio->wf->nBlockAlign; + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + // TODO! + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + int len=-1; + static unsigned char *ibuf = NULL; + if (!ibuf) + ibuf = (unsigned char *)malloc(sh_audio->wf->nBlockAlign); + if (demux_read_data(sh_audio->ds, ibuf, sh_audio->wf->nBlockAlign) != + sh_audio->wf->nBlockAlign) + return len; /* EOF */ + len=2*dk4_adpcm_decode_block((unsigned short*)buf,ibuf, + sh_audio->wf->nChannels, sh_audio->wf->nBlockAlign); + return len; +} diff --git a/libmpcodecs/ad_dshow.c b/libmpcodecs/ad_dshow.c new file mode 100644 index 0000000000..369368e7e2 --- /dev/null +++ b/libmpcodecs/ad_dshow.c @@ -0,0 +1,99 @@ +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include "ad_internal.h" + +static ad_info_t info = +{ + "Win32/DirectShow decoders", + "dshow", + AFM_DSHOW, + "Nick Kurshev", + "avifile.sf.net", + "" +}; + +LIBAD_EXTERN(dshow) + +#include "dshow/DS_AudioDecoder.h" + +static DS_AudioDecoder* ds_adec=NULL; + +static int init(sh_audio_t *sh) +{ + return 1; +} + +static int preinit(sh_audio_t *sh_audio) +{ + if(!(ds_adec=DS_AudioDecoder_Open(sh_audio->codec->dll,&sh_audio->codec->guid,sh_audio->wf))) + { + mp_msg(MSGT_DECAUDIO,MSGL_ERR,MSGTR_MissingDLLcodec,sh_audio->codec->dll); + return 0; + } else { + sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec; + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + sh_audio->audio_in_minsize=2*sh_audio->wf->nBlockAlign; + if(sh_audio->audio_in_minsize<8192) sh_audio->audio_in_minsize=8192; + sh_audio->a_in_buffer_size=sh_audio->audio_in_minsize; + sh_audio->a_in_buffer=malloc(sh_audio->a_in_buffer_size); + sh_audio->a_in_buffer_len=0; + sh_audio->audio_out_minsize=16384; + } + mp_msg(MSGT_DECVIDEO,MSGL_V,"INFO: Win32/DShow audio codec init OK!\n"); + return 1; +} + +static void uninit(sh_audio_t *sh) +{ + // TODO!!! +} + +static int control(sh_audio_t *sh_audio,int cmd,void* arg, ...) +{ + int skip; + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + skip=sh_audio->wf->nBlockAlign; + if(skip<16){ + skip=(sh_audio->wf->nAvgBytesPerSec/16)&(~7); + if(skip<16) skip=16; + } + demux_read_data(sh_audio->ds,NULL,skip); + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ +// int len=-1; + int size_in=0; + int size_out=0; + int srcsize=DS_AudioDecoder_GetSrcSize(ds_adec, maxlen); + mp_msg(MSGT_DECAUDIO,MSGL_DBG3,"DShow says: srcsize=%d (buffsize=%d) out_size=%d\n",srcsize,sh_audio->a_in_buffer_size,maxlen); + if(srcsize>sh_audio->a_in_buffer_size) srcsize=sh_audio->a_in_buffer_size; // !!!!!! + if(sh_audio->a_in_buffer_lena_in_buffer_len+= + demux_read_data(sh_audio->ds,&sh_audio->a_in_buffer[sh_audio->a_in_buffer_len], + srcsize-sh_audio->a_in_buffer_len); + } + DS_AudioDecoder_Convert(ds_adec, sh_audio->a_in_buffer,sh_audio->a_in_buffer_len, + buf,maxlen, &size_in,&size_out); + mp_dbg(MSGT_DECAUDIO,MSGL_DBG2,"DShow: audio %d -> %d converted (in_buf_len=%d of %d) %d\n",size_in,size_out,sh_audio->a_in_buffer_len,sh_audio->a_in_buffer_size,ds_tell_pts(sh_audio->ds)); + if(size_in>=sh_audio->a_in_buffer_len){ + sh_audio->a_in_buffer_len=0; + } else { + sh_audio->a_in_buffer_len-=size_in; + memcpy(sh_audio->a_in_buffer,&sh_audio->a_in_buffer[size_in],sh_audio->a_in_buffer_len); + } +// len=size_out; + return size_out; +} diff --git a/libmpcodecs/ad_dvdpcm.c b/libmpcodecs/ad_dvdpcm.c new file mode 100644 index 0000000000..3a08db8588 --- /dev/null +++ b/libmpcodecs/ad_dvdpcm.c @@ -0,0 +1,64 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" + +static ad_info_t info = +{ + "Uncompressed DVD PCM audio decoder", + "dvdpcm", + AFM_DVDPCM, + "Nick Kurshev", + "A'rpi", + "" +}; + +LIBAD_EXTERN(dvdpcm) + +static int init(sh_audio_t *sh) +{ +/* DVD PCM Audio:*/ + sh->channels=2; + sh->samplerate=48000; + sh->i_bps=2*2*48000; +/* sh_audio->pcm_bswap=1;*/ + return 1; +} + +static int preinit(sh_audio_t *sh) +{ + sh->audio_out_minsize=2048; + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + int skip; + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + skip=sh->i_bps/16; + skip=skip&(~3); + demux_read_data(sh->ds,NULL,skip); + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + int j,len; + len=demux_read_data(sh_audio->ds,buf,(minlen+3)&(~3)); + for(j=0;j +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include "ad_internal.h" + +#include "bswap.h" + +static ad_info_t info = +{ + "FFmpeg audio decoders", + "ffmpeg", + AFM_FFMPEG, + "Nick Kurshev", + "ffmpeg.sf.net", + "" +}; + +LIBAD_EXTERN(ffmpeg) + +#define assert(x) +#include "../libavcodec/avcodec.h" + +static AVCodec *lavc_codec=NULL; +static AVCodecContext lavc_context; +extern int avcodec_inited; + +static int preinit(sh_audio_t *sh) +{ + sh->audio_out_minsize=AVCODEC_MAX_AUDIO_FRAME_SIZE; + return 1; +} + +static int init(sh_audio_t *sh_audio) +{ + int x; + mp_msg(MSGT_DECAUDIO,MSGL_V,"FFmpeg's libavcodec audio codec\n"); + if(!avcodec_inited){ + avcodec_init(); + avcodec_register_all(); + avcodec_inited=1; + } + lavc_codec = (AVCodec *)avcodec_find_decoder_by_name(sh_audio->codec->dll); + if(!lavc_codec){ + mp_msg(MSGT_DECAUDIO,MSGL_ERR,MSGTR_MissingLAVCcodec,sh_audio->codec->dll); + return 0; + } + memset(&lavc_context, 0, sizeof(lavc_context)); + /* open it */ + if (avcodec_open(&lavc_context, lavc_codec) < 0) { + mp_msg(MSGT_DECAUDIO,MSGL_ERR, MSGTR_CantOpenCodec); + return 0; + } + mp_msg(MSGT_DECAUDIO,MSGL_V,"INFO: libavcodec init OK!\n"); + + // Decode at least 1 byte: (to get header filled) + x=decode_audio(sh_audio,sh_audio->a_buffer,1,sh_audio->a_buffer_size); + if(x>0) sh_audio->a_buffer_len=x; + +#if 1 + sh_audio->channels=lavc_context.channels; + sh_audio->samplerate=lavc_context.sample_rate; + sh_audio->i_bps=lavc_context.bit_rate/8; +#else + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec; +#endif + return 1; +} + +static void uninit(sh_audio_t *sh) +{ + avcodec_close(&lavc_context); +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + // TODO ??? + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + unsigned char *start=NULL; + int y,len=-1; + while(lends,&start); + if(x<=0) break; // error + y=avcodec_decode_audio(&lavc_context,(INT16*)buf,&len2,start,x); + if(y<0){ mp_msg(MSGT_DECAUDIO,MSGL_V,"lavc_audio: error\n");break; } + if(yds->buffer_pos+=y-x; // put back data (HACK!) + if(len2>0){ + //len=len2;break; + if(len<0) len=len2; else len+=len2; + buf+=len2; + } + mp_dbg(MSGT_DECAUDIO,MSGL_DBG2,"Decoded %d -> %d \n",y,len2); + } + return len; +} diff --git a/libmpcodecs/ad_hwac3.c b/libmpcodecs/ad_hwac3.c new file mode 100644 index 0000000000..fb92d5b593 --- /dev/null +++ b/libmpcodecs/ad_hwac3.c @@ -0,0 +1,88 @@ +#include +#include +#include + +#include "config.h" +#include "mp_msg.h" +#include "help_mp.h" + +#include "ad_internal.h" + +#include "../liba52/a52.h" +#include "../ac3-iec958.h" + +extern int a52_fillbuff(sh_audio_t *sh_audio); + +static ad_info_t info = +{ + "AC3 through SPDIF", + "hwac3", + AFM_HWAC3, + "Nick Kurshev", + "???", + "" +}; + +LIBAD_EXTERN(hwac3) + +static int preinit(sh_audio_t *sh) +{ + /* Dolby AC3 audio: */ + sh->audio_out_minsize=4*256*6; + sh->channels=2; + return 1; +} + +static int init(sh_audio_t *sh_audio) +{ + /* Dolby AC3 passthrough:*/ + sample_t *a52_samples=a52_init(0); + if (a52_samples == NULL) { + mp_msg(MSGT_DECAUDIO,MSGL_ERR,"A52 init failed\n"); + return 0; + } + sh_audio->a_in_buffer_size=3840; + sh_audio->a_in_buffer=malloc(sh_audio->a_in_buffer_size); + sh_audio->a_in_buffer_len=0; + if(a52_fillbuff(sh_audio)<0) { + mp_msg(MSGT_DECAUDIO,MSGL_ERR,"A52 sync failed\n"); + return 0; + } + /* + sh_audio->samplerate=ai.samplerate; // SET by a52_fillbuff() + sh_audio->samplesize=ai.framesize; + sh_audio->i_bps=ai.bitrate*(1000/8); // SET by a52_fillbuff() + sh_audio->ac3_frame=malloc(6144); + sh_audio->o_bps=sh_audio->i_bps; // XXX FIXME!!! XXX + + o_bps is calculated from samplesize*channels*samplerate + a single ac3 frame is always translated to 6144 byte packet. (zero padding)*/ + sh_audio->channels=2; + sh_audio->samplesize=2; /* 2*2*(6*256) = 6144 (very TRICKY!)*/ + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + a52_fillbuff(sh); break; // skip AC3 frame + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + int len=-1; + if(!sh_audio->a_in_buffer_len) + if((len=a52_fillbuff(sh_audio))<0) return len; /*EOF*/ + sh_audio->a_in_buffer_len=0; + len = ac3_iec958_build_burst(len, 0x01, 1, sh_audio->a_in_buffer, buf); + return len; +} diff --git a/libmpcodecs/ad_imaadpcm.c b/libmpcodecs/ad_imaadpcm.c new file mode 100644 index 0000000000..eca064d6c5 --- /dev/null +++ b/libmpcodecs/ad_imaadpcm.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" + +#include "../adpcm.h" + +static ad_info_t info = +{ + "IMA ADPCM audio decoder", + "imaadpcm", + AFM_IMAADPCM, + "Nick Kurshev", + "Mike Melanson", + "ima4 (MOV files)" +}; + +LIBAD_EXTERN(imaadpcm) + +static int init(sh_audio_t *sh_audio) +{ + /* IMA-ADPCM 4:1 audio codec:*/ + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + /* decodes 34 byte -> 64 short*/ + sh_audio->i_bps=IMA_ADPCM_BLOCK_SIZE*(sh_audio->channels*sh_audio->samplerate)/ + IMA_ADPCM_SAMPLES_PER_BLOCK; /* 1:4 */ + return 1; +} + +static int preinit(sh_audio_t *sh_audio) +{ + sh_audio->audio_out_minsize=4096; + sh_audio->ds->ss_div=IMA_ADPCM_SAMPLES_PER_BLOCK; + sh_audio->ds->ss_mul=IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels; + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + // TODO!!! + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + unsigned char ibuf[IMA_ADPCM_BLOCK_SIZE * 2]; /* bytes / stereo frame */ + if (demux_read_data(sh_audio->ds, ibuf, + IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) != + IMA_ADPCM_BLOCK_SIZE * sh_audio->wf->nChannels) + return -1; + return 2*ima_adpcm_decode_block((unsigned short*)buf,ibuf, sh_audio->wf->nChannels); +} diff --git a/libmpcodecs/ad_internal.h b/libmpcodecs/ad_internal.h new file mode 100644 index 0000000000..e5b67f5844 --- /dev/null +++ b/libmpcodecs/ad_internal.h @@ -0,0 +1,25 @@ + +#include "codec-cfg.h" +#include "../libao2/afmt.h" + +#include "stream.h" +#include "demuxer.h" +#include "stheader.h" + +#include "ad.h" + +static int init(sh_audio_t *sh); +static int preinit(sh_audio_t *sh); +static void uninit(sh_audio_t *sh); +static int control(sh_audio_t *sh,int cmd,void* arg, ...); +static int decode_audio(sh_audio_t *sh,unsigned char *buffer,int minlen,int maxlen); + +#define LIBAD_EXTERN(x) ad_functions_t mpcodecs_ad_##x = {\ + &info,\ + preinit,\ + init,\ + uninit,\ + control,\ + decode_audio\ +}; + diff --git a/libmpcodecs/ad_mp3.c b/libmpcodecs/ad_mp3.c new file mode 100644 index 0000000000..683ce09771 --- /dev/null +++ b/libmpcodecs/ad_mp3.c @@ -0,0 +1,79 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" + +static ad_info_t info = +{ + "MPEG layer-2, layer-3", + "mp3lib", + AFM_MPEG, + "Nick Kurshev", + "mpg123", + "Optimized to MMX/SSE/3Dnow!" +}; + +LIBAD_EXTERN(mp3) + +#include "../mp3lib/mp3.h" + +extern int fakemono; + +static sh_audio_t* dec_audio_sh=NULL; + +// MP3 decoder buffer callback: +int mplayer_audio_read(char *buf,int size){ + return demux_read_data(dec_audio_sh->ds,buf,size); +} + +static int preinit(sh_audio_t *sh) +{ + sh->audio_out_minsize=32*36*2*2; //4608; + return 1; +} + +static int init(sh_audio_t *sh) +{ + // MPEG Audio: + dec_audio_sh=sh; // save sh_audio for the callback: +// MP3_Init(fakemono,mplayer_accel,&mplayer_audio_read); // TODO!!! +#ifdef USE_FAKE_MONO + MP3_Init(fakemono); +#else + MP3_Init(); +#endif + MP3_samplerate=MP3_channels=0; + sh->a_buffer_len=MP3_DecodeFrame(sh->a_buffer,-1); + sh->channels=2; // hack + sh->samplerate=MP3_samplerate; + sh->i_bps=MP3_bitrate*(1000/8); + MP3_PrintHeader(); + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + switch(cmd) + { + case ADCTRL_RESYNC_STREAM: + MP3_DecodeFrame(NULL,-2); // resync + MP3_DecodeFrame(NULL,-2); // resync + MP3_DecodeFrame(NULL,-2); // resync + return CONTROL_TRUE; + case ADCTRL_SKIP_FRAME: + MP3_DecodeFrame(NULL,-2); // skip MPEG frame + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + return MP3_DecodeFrame(buf,-1); +} diff --git a/libmpcodecs/ad_msadpcm.c b/libmpcodecs/ad_msadpcm.c new file mode 100644 index 0000000000..046307b30f --- /dev/null +++ b/libmpcodecs/ad_msadpcm.c @@ -0,0 +1,62 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" + +static ad_info_t info = +{ + "MS ADPCM audio decoder", + "msadpcm", + AFM_MSADPCM, + "Nick Kurshev", + "Mike Melanson", + "" +}; + +LIBAD_EXTERN(msadpcm) + +#include "../adpcm.h" + +static int init(sh_audio_t *sh_audio) +{ + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + sh_audio->i_bps = sh_audio->wf->nBlockAlign * + (sh_audio->channels*sh_audio->samplerate) / MS_ADPCM_SAMPLES_PER_BLOCK; + return 1; +} + +static int preinit(sh_audio_t *sh_audio) +{ + sh_audio->audio_out_minsize=sh_audio->wf->nBlockAlign * 8; + sh_audio->ds->ss_div = MS_ADPCM_SAMPLES_PER_BLOCK; + sh_audio->ds->ss_mul = sh_audio->wf->nBlockAlign; + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + // TODO!!! + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + static unsigned char *ibuf = NULL; // FIXME!!! TODO!!! use sh->a_in_buffer! + if (!ibuf) + ibuf = (unsigned char *)malloc + (sh_audio->wf->nBlockAlign * sh_audio->wf->nChannels); + if (demux_read_data(sh_audio->ds, ibuf, + sh_audio->wf->nBlockAlign) != + sh_audio->wf->nBlockAlign) + return -1; /* EOF */ + return 2 * ms_adpcm_decode_block( + (unsigned short*)buf,ibuf, sh_audio->wf->nChannels, + sh_audio->wf->nBlockAlign); +} diff --git a/libmpcodecs/ad_pcm.c b/libmpcodecs/ad_pcm.c new file mode 100644 index 0000000000..67ce5cba5a --- /dev/null +++ b/libmpcodecs/ad_pcm.c @@ -0,0 +1,66 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" + +static ad_info_t info = +{ + "Uncompressed PCM audio decoder", + "pcm", + AFM_PCM, + "Nick Kurshev", + "A'rpi", + "" +}; + +LIBAD_EXTERN(pcm) + +static int init(sh_audio_t *sh_audio) +{ + WAVEFORMATEX *h=sh_audio->wf; + sh_audio->i_bps=h->nAvgBytesPerSec; + sh_audio->channels=h->nChannels; + sh_audio->samplerate=h->nSamplesPerSec; + sh_audio->samplesize=(h->wBitsPerSample+7)/8; + switch(sh_audio->format){ /* hardware formats: */ + case 0x6: sh_audio->sample_format=AFMT_A_LAW;break; + case 0x7: sh_audio->sample_format=AFMT_MU_LAW;break; + case 0x11: sh_audio->sample_format=AFMT_IMA_ADPCM;break; + case 0x50: sh_audio->sample_format=AFMT_MPEG;break; + case 0x736F7774: sh_audio->sample_format=AFMT_S16_LE;sh_audio->codec->driver=AFM_DVDPCM;break; +/* case 0x2000: sh_audio->sample_format=AFMT_AC3; */ + default: sh_audio->sample_format=(sh_audio->samplesize==2)?AFMT_S16_LE:AFMT_U8; + } + return 1; +} + +static int preinit(sh_audio_t *sh) +{ + sh->audio_out_minsize=2048; + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + int skip; + switch(cmd) + { + case ADCTRL_SKIP_FRAME: + skip=sh->i_bps/16; + skip=skip&(~3); + demux_read_data(sh->ds,NULL,skip); + return CONTROL_TRUE; + } + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + return demux_read_data(sh_audio->ds,buf,minlen); +} diff --git a/libmpcodecs/ad_roqaudio.c b/libmpcodecs/ad_roqaudio.c new file mode 100644 index 0000000000..51fc5af14e --- /dev/null +++ b/libmpcodecs/ad_roqaudio.c @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "config.h" +#include "ad_internal.h" +#include "../roqav.h" +//#include "../adpcm.h" + +static ad_info_t info = +{ + "Id RoQ File Audio Decoder", + "roqaudio", + AFM_ROQAUDIO, + "Nick Kurshev", + "Mike Melanson ???" + "RoQA is an internal MPlayer FOURCC" +}; + +LIBAD_EXTERN(roqaudio) + +static int init(sh_audio_t *sh_audio) +{ + sh_audio->channels=sh_audio->wf->nChannels; + sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; + sh_audio->i_bps = (sh_audio->channels * 22050) / 2; + return 1; +} + +static int preinit(sh_audio_t *sh_audio) +{ + /* minsize was stored in wf->nBlockAlign by the RoQ demuxer */ + sh_audio->audio_out_minsize=sh_audio->wf->nBlockAlign; + sh_audio->context = roq_decode_audio_init(); + return 1; +} + +static void uninit(sh_audio_t *sh) +{ +} + +static int control(sh_audio_t *sh,int cmd,void* arg, ...) +{ + // TODO!!! + return CONTROL_UNKNOWN; +} + +static int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) +{ + static unsigned char *ibuf = NULL; + unsigned char header_data[6]; + int read_len; + +// TODO!! FIXME!!! + 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) return -1; /* 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) return -1; + return 2 * roq_decode_audio((unsigned short *)buf, ibuf, + read_len, sh_audio->channels, sh_audio->context); +}