diff options
-rw-r--r-- | cfg-common.h | 4 | ||||
-rw-r--r-- | cfg-mplayer.h | 4 | ||||
-rw-r--r-- | libmpcodecs/dec_audio.c | 138 | ||||
-rw-r--r-- | libmpcodecs/dec_audio.h | 5 | ||||
-rw-r--r-- | libmpdemux/stheader.h | 12 | ||||
-rw-r--r-- | mencoder.c | 57 | ||||
-rw-r--r-- | mplayer.c | 35 |
7 files changed, 218 insertions, 37 deletions
diff --git a/cfg-common.h b/cfg-common.h index 6fa1478c0b..8071ec876a 100644 --- a/cfg-common.h +++ b/cfg-common.h @@ -91,6 +91,7 @@ // force video/audio rate: {"fps", &force_fps, CONF_TYPE_FLOAT, CONF_MIN, 0, 0, NULL}, {"srate", &force_srate, CONF_TYPE_INT, CONF_RANGE, 1000, 8*48000, NULL}, + {"channels", &audio_output_channels, CONF_TYPE_INT, CONF_RANGE, 1, 6, NULL}, // ------------------------- codec/vfilter options -------------------- @@ -187,6 +188,9 @@ extern float movie_aspect; extern int softzoom; extern int flip; +/* from dec_audio, currently used for ac3surround decoder only */ +extern int audio_output_channels; + #ifdef STREAMING /* defined in network.c */ extern char *network_username; diff --git a/cfg-mplayer.h b/cfg-mplayer.h index f2e583f9a9..4fdf346371 100644 --- a/cfg-mplayer.h +++ b/cfg-mplayer.h @@ -111,9 +111,6 @@ extern int nortc; /* from libvo/aspect.c */ extern float monitor_aspect; -/* from dec_audio, currently used for ac3surround decoder only */ -extern int audio_output_channels; - /* Options related to audio out plugins */ struct config ao_plugin_conf[]={ {"list", &ao_plugin_cfg.plugin_list, CONF_TYPE_STRING, 0, 0, 0, NULL}, @@ -173,7 +170,6 @@ static config_t mplayer_opts[]={ {"dsp", "Use -ao oss:dsp_path!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0, NULL}, {"mixer", &mixer_device, CONF_TYPE_STRING, 0, 0, 0, NULL}, {"master", "Option -master has been removed, use -aop list=volume instead.\n", CONF_TYPE_PRINT, 0, 0, 0, NULL}, - {"channels", &audio_output_channels, CONF_TYPE_INT, CONF_RANGE, 2, 6, NULL}, // override audio buffer size (used only by -ao oss, anyway obsolete...) {"abs", &ao_data.buffersize, CONF_TYPE_INT, CONF_MIN, 0, 0, NULL}, diff --git a/libmpcodecs/dec_audio.c b/libmpcodecs/dec_audio.c index 29ceefbf5b..51353ed0b2 100644 --- a/libmpcodecs/dec_audio.c +++ b/libmpcodecs/dec_audio.c @@ -18,6 +18,8 @@ extern int verbose; // defined in mplayer.c #include "ad.h" #include "../libao2/afmt.h" +#include "../libaf/af.h" + #ifdef USE_FAKE_MONO int fakemono=0; #endif @@ -118,6 +120,10 @@ int init_audio_codec(sh_audio_t *sh_audio) sh_audio->samplerate,sh_audio->channels, sh_audio->samplesize*8,sh_audio->sample_format, sh_audio->i_bps,sh_audio->o_bps,sh_audio->i_bps*8*0.001); + + sh_audio->a_out_buffer_size=sh_audio->a_buffer_size; + sh_audio->a_out_buffer=sh_audio->a_buffer; + sh_audio->a_out_buffer_len=sh_audio->a_buffer_len; return 1; } @@ -210,23 +216,149 @@ return 1; // success void uninit_audio(sh_audio_t *sh_audio) { + if(sh_audio->afilter){ + mp_msg(MSGT_DECAUDIO,MSGL_V,"Uninit audio filters...\n"); + af_uninit(sh_audio->afilter); + sh_audio->afilter=NULL; + } if(sh_audio->inited){ mp_msg(MSGT_DECAUDIO,MSGL_V,MSGTR_UninitAudioStr,sh_audio->codec->drv); mpadec->uninit(sh_audio); sh_audio->inited=0; } + if(sh_audio->a_out_buffer!=sh_audio->a_buffer) free(sh_audio->a_out_buffer); + sh_audio->a_out_buffer=NULL; if(sh_audio->a_buffer) free(sh_audio->a_buffer); sh_audio->a_buffer=NULL; if(sh_audio->a_in_buffer) free(sh_audio->a_in_buffer); sh_audio->a_in_buffer=NULL; } + /* Init audio filters */ +int init_audio_filters(sh_audio_t *sh_audio, + int in_samplerate, int in_channels, int in_format, int in_bps, + int out_samplerate, int out_channels, int out_format, int out_bps, + int out_minsize, int out_maxsize){ + af_stream_t* afs=malloc(sizeof(af_stream_t)); + memset(afs,0,sizeof(af_stream_t)); + + // input format: same as codec's output format: + afs->input.rate = in_samplerate; + afs->input.nch = in_channels; + afs->input.format = in_format; + afs->input.bps = in_bps; + + // output format: same as ao driver's input format (if missing, fallback to input) + afs->output.rate = out_samplerate ? out_samplerate : afs->input.rate; + afs->output.nch = out_channels ? out_channels : afs->input.nch; + afs->output.format = out_format ? out_format : afs->input.format; + afs->output.bps = out_bps ? out_bps : afs->input.bps; + + // filter config: + afs->cfg.force = 0; + afs->cfg.list = NULL; + + mp_msg(MSGT_DECAUDIO, MSGL_INFO, "Building audio filter chain for %dHz/%dch/%dbit -> %dHz/%dch/%dbit...\n", + afs->input.rate,afs->input.nch,afs->input.bps*8, + afs->output.rate,afs->output.nch,afs->output.bps*8); + + // let's autoprobe it! + if(0 != af_init(afs)){ + free(afs); + return 0; // failed :( + } + + // allocate the a_out_* buffers: + if(out_maxsize<out_minsize) out_maxsize=out_minsize; + if(out_maxsize<8192) out_maxsize=MAX_OUTBURST; // not sure this is ok + + sh_audio->a_out_buffer_size=out_maxsize; + sh_audio->a_out_buffer=malloc(sh_audio->a_out_buffer_size); + memset(sh_audio->a_out_buffer,0,sh_audio->a_out_buffer_size); + sh_audio->a_out_buffer_len=0; + + // ok! + sh_audio->afilter=(void*)afs; + return 1; +} + int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int maxlen) { - if(sh_audio->inited) - return mpadec->decode_audio(sh_audio,buf,minlen,maxlen); + int declen; + af_data_t afd; // filter input + af_data_t* pafd; // filter output + + if(!sh_audio->inited) return -1; // no codec + if(!sh_audio->afilter){ + // no filter, just decode: + // FIXME: don't drop initial decoded data in a_buffer! + return mpadec->decode_audio(sh_audio,buf,minlen,maxlen); + } + +// declen=af_inputlen(sh_audio->afilter,minlen); + declen=af_calc_insize_constrained(sh_audio->afilter,minlen,maxlen, + sh_audio->a_buffer_size-sh_audio->audio_out_minsize); + + mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"\ndecaudio: minlen=%d maxlen=%d declen=%d (max=%d)\n", + minlen, maxlen, declen, sh_audio->a_buffer_size); + + if(declen<=0) return -1; // error! + + // limit declen to buffer size: - DONE by af_calc_insize_constrained +// if(declen>sh_audio->a_buffer_size) declen=sh_audio->a_buffer_size; + + // decode if needed: + while(declen>sh_audio->a_buffer_len){ + int len=declen-sh_audio->a_buffer_len; + int maxlen=sh_audio->a_buffer_size-sh_audio->a_buffer_len; + + mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"decaudio: decoding %d bytes, max: %d (%d)\n", + len, maxlen, sh_audio->audio_out_minsize); + + if(maxlen<sh_audio->audio_out_minsize) break; // don't overflow buffer! + // not enough decoded data waiting, decode 'len' bytes more: + len=mpadec->decode_audio(sh_audio, + sh_audio->a_buffer+sh_audio->a_buffer_len, len, maxlen); + if(len<=0) break; // EOF? + sh_audio->a_buffer_len+=len; + } + if(declen>sh_audio->a_buffer_len) + declen=sh_audio->a_buffer_len; // still no enough data (EOF) :( + + // round to whole samples: +// declen/=sh_audio->samplesize*sh_audio->channels; +// declen*=sh_audio->samplesize*sh_audio->channels; + + // run the filters: + afd.audio=sh_audio->a_buffer; + afd.len=declen; + afd.rate=sh_audio->samplerate; + afd.nch=sh_audio->channels; + afd.format=sh_audio->sample_format; + afd.bps=sh_audio->samplesize; + //pafd=&afd; +// printf("\nAF: %d --> ",declen); + pafd=af_play(sh_audio->afilter,&afd); +// printf("%d \n",pafd->len); + + if(!pafd) return -1; // error + + mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"decaudio: declen=%d out=%d (max %d)\n", + declen, pafd->len, maxlen); + + // copy filter==>out: + if(maxlen < pafd->len) + mp_msg(MSGT_DECAUDIO,MSGL_WARN,"%i bytes of audio data lost due to buffer overflow, len = %i", pafd->len - maxlen,pafd->len); else - return -1; + maxlen=pafd->len; + memmove(buf, pafd->audio, maxlen); + + // remove processed data from decoder buffer: + sh_audio->a_buffer_len-=declen; + if(sh_audio->a_buffer_len>0) + memmove(sh_audio->a_buffer, sh_audio->a_buffer+declen, sh_audio->a_buffer_len); + + return maxlen; } void resync_audio_stream(sh_audio_t *sh_audio) diff --git a/libmpcodecs/dec_audio.h b/libmpcodecs/dec_audio.h index d4d5b67917..cc44607dab 100644 --- a/libmpcodecs/dec_audio.h +++ b/libmpcodecs/dec_audio.h @@ -9,3 +9,8 @@ extern int decode_audio(sh_audio_t *sh_audio,unsigned char *buf,int minlen,int m extern void resync_audio_stream(sh_audio_t *sh_audio); extern void skip_audio_frame(sh_audio_t *sh_audio); extern void uninit_audio(sh_audio_t *sh_audio); + +extern int init_audio_filters(sh_audio_t *sh_audio, + int in_samplerate, int in_channels, int in_format, int in_bps, + int out_samplerate, int out_channels, int out_format, int out_bps, + int out_minsize, int out_maxsize);
\ No newline at end of file diff --git a/libmpdemux/stheader.h b/libmpdemux/stheader.h index 559af7d67f..12dff42c10 100644 --- a/libmpdemux/stheader.h +++ b/libmpdemux/stheader.h @@ -55,15 +55,21 @@ typedef struct { int o_bps; // == samplerate*samplesize*channels (uncompr. bytes/sec) int i_bps; // == bitrate (compressed bytes/sec) // in buffers: - int audio_in_minsize; + int audio_in_minsize; // max. compressed packet size (== min. in buffer size) char* a_in_buffer; int a_in_buffer_len; int a_in_buffer_size; - // out buffers: - int audio_out_minsize; + // decoder buffers: + int audio_out_minsize; // max. uncompressed packet size (==min. out buffsize) char* a_buffer; int a_buffer_len; int a_buffer_size; + // output buffers: + char* a_out_buffer; + int a_out_buffer_len; + int a_out_buffer_size; +// void* audio_out; // the audio_out handle, used for this audio stream + void* afilter; // the audio filter stream // win32-compatible codec parameters: AVIStreamHeader audio; WAVEFORMATEX* wf; diff --git a/mencoder.c b/mencoder.c index d2ad95705c..ff283af118 100644 --- a/mencoder.c +++ b/mencoder.c @@ -45,6 +45,8 @@ static char* banner_text= #include "libvo/video_out.h" +#include "libao2/afmt.h" + #include "libmpcodecs/mp_image.h" #include "libmpcodecs/dec_audio.h" #include "libmpcodecs/dec_video.h" @@ -249,19 +251,19 @@ static int dec_audio(sh_audio_t *sh_audio,unsigned char* buffer,int total){ while(size<total && !at_eof){ int len=total-size; if(len>MAX_OUTBURST) len=MAX_OUTBURST; - if(len>sh_audio->a_buffer_size) len=sh_audio->a_buffer_size; - if(len>sh_audio->a_buffer_len){ + if(len>sh_audio->a_out_buffer_size) len=sh_audio->a_out_buffer_size; + if(len>sh_audio->a_out_buffer_len){ int ret=decode_audio(sh_audio, - &sh_audio->a_buffer[sh_audio->a_buffer_len], - len-sh_audio->a_buffer_len, - sh_audio->a_buffer_size-sh_audio->a_buffer_len); - if(ret>0) sh_audio->a_buffer_len+=ret; else at_eof=1; + &sh_audio->a_out_buffer[sh_audio->a_out_buffer_len], + len-sh_audio->a_out_buffer_len, + sh_audio->a_out_buffer_size-sh_audio->a_out_buffer_len); + if(ret>0) sh_audio->a_out_buffer_len+=ret; else at_eof=1; } - if(len>sh_audio->a_buffer_len) len=sh_audio->a_buffer_len; - memcpy(buffer+size,sh_audio->a_buffer,len); - sh_audio->a_buffer_len-=len; size+=len; - if(sh_audio->a_buffer_len>0) - memcpy(sh_audio->a_buffer,&sh_audio->a_buffer[len],sh_audio->a_buffer_len); + if(len>sh_audio->a_out_buffer_len) len=sh_audio->a_out_buffer_len; + memcpy(buffer+size,sh_audio->a_out_buffer,len); + sh_audio->a_out_buffer_len-=len; size+=len; + if(sh_audio->a_out_buffer_len>0) + memcpy(sh_audio->a_out_buffer,&sh_audio->a_out_buffer[len],sh_audio->a_out_buffer_len); } return size; } @@ -694,15 +696,25 @@ case ACODEC_PCM: printf("CBR PCM audio selected\n"); mux_a->h.dwSampleSize=2*sh_audio->channels; mux_a->h.dwScale=1; - mux_a->h.dwRate=sh_audio->samplerate; + mux_a->h.dwRate=force_srate?force_srate:sh_audio->samplerate; mux_a->wf=malloc(sizeof(WAVEFORMATEX)); mux_a->wf->nBlockAlign=mux_a->h.dwSampleSize; mux_a->wf->wFormatTag=0x1; // PCM - mux_a->wf->nChannels=sh_audio->channels; - mux_a->wf->nSamplesPerSec=sh_audio->samplerate; + mux_a->wf->nChannels=audio_output_channels?audio_output_channels:sh_audio->channels; + mux_a->wf->nSamplesPerSec=mux_a->h.dwRate; mux_a->wf->nAvgBytesPerSec=mux_a->h.dwSampleSize*mux_a->wf->nSamplesPerSec; mux_a->wf->wBitsPerSample=16; mux_a->wf->cbSize=0; // FIXME for l3codeca.acm + // setup filter: + if(!init_audio_filters(sh_audio, + sh_audio->samplerate, + sh_audio->channels, sh_audio->sample_format, sh_audio->samplesize, + mux_a->wf->nSamplesPerSec, mux_a->wf->nChannels, + (mux_a->wf->wBitsPerSample==8)? AFMT_U8:AFMT_S16_LE, + mux_a->wf->wBitsPerSample/8, + 16384, mux_a->wf->nAvgBytesPerSec)){ + mp_msg(MSGT_CPLAYER,MSGL_ERR,"Couldn't find matching filter / ao format!\n"); + } break; case ACODEC_VBRMP3: printf("MP3 audio selected\n"); @@ -712,8 +724,9 @@ case ACODEC_VBRMP3: if(sizeof(MPEGLAYER3WAVEFORMAT)!=30) mp_msg(MSGT_MENCODER,MSGL_WARN,"sizeof(MPEGLAYER3WAVEFORMAT)==%d!=30, maybe broken C compiler?\n",sizeof(MPEGLAYER3WAVEFORMAT)); mux_a->wf=malloc(sizeof(MPEGLAYER3WAVEFORMAT)); // should be 30 mux_a->wf->wFormatTag=0x55; // MP3 - mux_a->wf->nChannels= sh_audio->channels; - mux_a->wf->nSamplesPerSec=force_srate?force_srate:sh_audio->samplerate; + mux_a->wf->nChannels= (lame_param_mode<0) ? sh_audio->channels : + ((lame_param_mode==3) ? 1 : 2); + mux_a->wf->nSamplesPerSec=mux_a->h.dwRate; mux_a->wf->nAvgBytesPerSec=192000/8; // FIXME! mux_a->wf->nBlockAlign=(mux_a->h.dwRate<32000)?576:1152; // required for l3codeca.acm + WMP 6.4 mux_a->wf->wBitsPerSample=0; //16; @@ -724,6 +737,15 @@ case ACODEC_VBRMP3: ((MPEGLAYER3WAVEFORMAT*)(mux_a->wf))->nBlockSize=(mux_a->h.dwRate<32000)?576:1152; // ??? ((MPEGLAYER3WAVEFORMAT*)(mux_a->wf))->nFramesPerBlock=1; ((MPEGLAYER3WAVEFORMAT*)(mux_a->wf))->nCodecDelay=0; + // setup filter: + if(!init_audio_filters(sh_audio, + sh_audio->samplerate, + sh_audio->channels, sh_audio->sample_format, sh_audio->samplesize, + mux_a->wf->nSamplesPerSec, mux_a->wf->nChannels, + AFMT_S16_LE, 2, + 4608, mux_a->h.dwRate*mux_a->wf->nChannels*2)){ + mp_msg(MSGT_CPLAYER,MSGL_ERR,"Couldn't find matching filter / ao format!\n"); + } break; } @@ -748,7 +770,8 @@ case ACODEC_VBRMP3: lame=lame_init(); lame_set_bWriteVbrTag(lame,0); -lame_set_in_samplerate(lame,sh_audio->samplerate); +lame_set_in_samplerate(lame,mux_a->wf->nSamplesPerSec); +//lame_set_in_samplerate(lame,sh_audio->samplerate); // if resampling done by lame lame_set_num_channels(lame,mux_a->wf->nChannels); lame_set_out_samplerate(lame,mux_a->wf->nSamplesPerSec); lame_set_quality(lame,lame_param_algqual); // 0 = best q @@ -1237,6 +1237,7 @@ if(sh_audio){ if(!(audio_out=init_best_audio_out(audio_driver_list, (ao_plugin_cfg.plugin_list), // plugin flag force_srate?force_srate:sh_audio->samplerate, + audio_output_channels?audio_output_channels: sh_audio->channels,sh_audio->sample_format,0))){ // FAILED: mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_CannotInitAO); @@ -1244,7 +1245,7 @@ if(sh_audio){ } else { // SUCCESS: inited_flags|=INITED_AO; - mp_msg(MSGT_CPLAYER,MSGL_INFO,"AO: [%s] %iHz %dch %s\n", + mp_msg(MSGT_CPLAYER,MSGL_INFO,"AO: [%s] %dHz %dch %s\n", audio_out->info->short_name, force_srate?force_srate:sh_audio->samplerate, sh_audio->channels, @@ -1253,6 +1254,19 @@ if(sh_audio){ audio_out->info->name, audio_out->info->author); if(strlen(audio_out->info->comment) > 0) mp_msg(MSGT_CPLAYER,MSGL_V,MSGTR_AOComment, audio_out->info->comment); + // init audio filters: +#if 1 + current_module="af_init"; + if(!init_audio_filters(sh_audio, + sh_audio->samplerate, + sh_audio->channels, sh_audio->sample_format, sh_audio->samplesize, + ao_data.samplerate, ao_data.channels, ao_data.format, + audio_out_format_bits(ao_data.format)/8, /* ao_data.bps, */ + ao_data.outburst*4, ao_data.buffersize)){ + mp_msg(MSGT_CPLAYER,MSGL_ERR,"Couldn't find matching filter / ao format, -> nosound\n"); + sh_audio=d_audio->sh=NULL; // -> nosound + } +#endif } } @@ -1338,24 +1352,25 @@ while(sh_audio){ // Fill buffer if needed: current_module="decode_audio"; // Enter AUDIO decoder module t=GetTimer(); - while(sh_audio->a_buffer_len<playsize && !d_audio->eof){ - int ret=decode_audio(sh_audio,&sh_audio->a_buffer[sh_audio->a_buffer_len], - playsize-sh_audio->a_buffer_len,sh_audio->a_buffer_size-sh_audio->a_buffer_len); + while(sh_audio->a_out_buffer_len<playsize && !d_audio->eof){ + int ret=decode_audio(sh_audio,&sh_audio->a_out_buffer[sh_audio->a_out_buffer_len], + playsize-sh_audio->a_out_buffer_len,sh_audio->a_out_buffer_size-sh_audio->a_out_buffer_len); if(ret<=0) break; // EOF? - sh_audio->a_buffer_len+=ret; + sh_audio->a_out_buffer_len+=ret; } t=GetTimer()-t; tt = t*0.000001f; audio_time_usage+=tt; - if(playsize>sh_audio->a_buffer_len) playsize=sh_audio->a_buffer_len; + if(playsize>sh_audio->a_out_buffer_len) playsize=sh_audio->a_out_buffer_len; // play audio: current_module="play_audio"; - playsize=audio_out->play(sh_audio->a_buffer,playsize,0); + playsize=audio_out->play(sh_audio->a_out_buffer,playsize,0); if(playsize>0){ - sh_audio->a_buffer_len-=playsize; - memmove(sh_audio->a_buffer,&sh_audio->a_buffer[playsize],sh_audio->a_buffer_len); - sh_audio->timer+=playsize/(float)(sh_audio->o_bps); + sh_audio->a_out_buffer_len-=playsize; + memmove(sh_audio->a_out_buffer,&sh_audio->a_out_buffer[playsize],sh_audio->a_out_buffer_len); + sh_audio->timer+=playsize/((float)((ao_data.bps && sh_audio->afilter) ? + ao_data.bps : sh_audio->o_bps)); } break; |