Index: libmpcodecs/ae_faac.c =================================================================== --- libmpcodecs/ae_faac.c (revision 25055) +++ libmpcodecs/ae_faac.c (working copy) @@ -69,6 +69,23 @@ ((MPEGLAYER3WAVEFORMAT *) (mux_a->wf))->nBlockSize = mux_a->wf->nBlockAlign; ((MPEGLAYER3WAVEFORMAT *) (mux_a->wf))->nFramesPerBlock = 1; ((MPEGLAYER3WAVEFORMAT *) (mux_a->wf))->nCodecDelay = 0; + + /* remap channels */ + switch (mux_a->wf->nChannels) { + case 1: /* FC, no action needed */ + case 2: /* FL FR, no action needed */ + case 3: /* no suitable default behavior? */ + case 4: /* FL FR BL BR, no action needed */ + break; + case 5: /* FC FL FR BL BR */ + encoder->output_chan_map = "40" "01" "12" "23" "34"; + break; + case 6: /* FC FL FR BL BR LFE */ + encoder->output_chan_map = "40" "01" "12" "23" "34" "55"; + break; + default: + break; + } // Fix allocation mux_a->wf = realloc(mux_a->wf, sizeof(WAVEFORMATEX)+mux_a->wf->cbSize); Index: libmpcodecs/ae_pcm.c =================================================================== --- libmpcodecs/ae_pcm.c (revision 25055) +++ libmpcodecs/ae_pcm.c (working copy) @@ -28,6 +28,23 @@ mux_a->wf->wBitsPerSample=16; mux_a->wf->cbSize=0; // FIXME for l3codeca.acm + /* re-map channels */ + switch (mux_a->wf->nChannels) { + case 1: /* FC, no action needed */ + case 2: /* FL FR, no action needed */ + case 3: /* unknown; may not exist */ + case 4: /* FL FR BL BR, no action needed */ + break; + case 5: /* FL FR C BL BR */ + encoder->output_chan_map = "00" "11" "42" "23" "34"; + break; + case 6: /* FL FR C LFE BL BR */ + encoder->output_chan_map = "00" "11" "42" "53" "24" "35"; + break; + default: + break; + } + encoder->input_format = (mux_a->wf->wBitsPerSample==8) ? AF_FORMAT_U8 : AF_FORMAT_S16_LE; encoder->min_buffer_size = 16384; encoder->max_buffer_size = mux_a->wf->nAvgBytesPerSec; Index: libmpcodecs/ad_pcm.c =================================================================== --- libmpcodecs/ad_pcm.c (revision 25055) +++ libmpcodecs/ad_pcm.c (working copy) @@ -22,6 +22,22 @@ WAVEFORMATEX *h=sh_audio->wf; sh_audio->i_bps=h->nAvgBytesPerSec; sh_audio->channels=h->nChannels; + /* re-map channels */ + switch (sh_audio->channels) { + case 1: /* FC, no action needed */ + case 2: /* FL FR, no action needed */ + case 3: /* unknown; may not exist */ + case 4: /* FL FR BL BR, no action needed */ + break; + case 5: /* FL FR C BL BR */ + sh_audio->input_chan_map = "00" "11" "24" "32" "43"; + break; + case 6: /* FL FR C LFE BL BR */ + sh_audio->input_chan_map = "00" "11" "24" "35" "42" "53"; + break; + default: + break; + } sh_audio->samplerate=h->nSamplesPerSec; sh_audio->samplesize=(h->wBitsPerSample+7)/8; sh_audio->sample_format=AF_FORMAT_S16_LE; // default Index: libmpcodecs/ad_faad.c =================================================================== --- libmpcodecs/ad_faad.c (revision 25055) +++ libmpcodecs/ad_faad.c (working copy) @@ -151,6 +151,24 @@ mp_msg(MSGT_DECAUDIO,MSGL_V,"FAAD: Negotiated samplerate: %ldHz channels: %d\n", faac_samplerate, faac_channels); sh->channels = faac_channels; if (audio_output_channels <= 2) sh->channels = faac_channels > 1 ? 2 : 1; + + /* re-map channels */ + switch (sh->channels) { + case 1: /* FC, no action needed */ + case 2: /* FL FR, no action needed */ + case 3: /* no suitable default behavior? */ + case 4: /* FL FR BL BR, no action needed */ + break; + case 5: /* FC FL FR BL BR */ + sh->input_chan_map = "04" "10" "21" "32" "43"; + break; + case 6: /* FC FL FR BL BR LFE */ + sh->input_chan_map = "04" "10" "21" "32" "43" "55"; + break; + default: + break; + } + sh->samplerate = faac_samplerate; sh->samplesize=2; //sh->o_bps = sh->samplesize*faac_channels*faac_samplerate; Index: libmpcodecs/ad_dmo.c =================================================================== --- libmpcodecs/ad_dmo.c (revision 25055) +++ libmpcodecs/ad_dmo.c (working copy) @@ -38,6 +38,22 @@ } sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec; sh_audio->channels=chans; + /* re-map channels */ + switch (chans) { + case 1: /* FC, no action needed */ + case 2: /* FL FR, no action needed */ + case 3: /* apparently does not exist */ + case 4: /* FL FR BL BR, no action needed */ + break; + case 5: /* FL FR FC BL BR */ + sh_audio->input_chan_map = "00" "11" "23" "34" "42"; + break; + case 6: /* FL FR FC LFE BL BR */ + sh_audio->input_chan_map = "00" "11" "24" "35" "42" "53"; + break; + default: + break; + } sh_audio->samplerate=sh_audio->wf->nSamplesPerSec; sh_audio->samplesize=2; sh_audio->audio_in_minsize=4*sh_audio->wf->nBlockAlign; Index: libmpcodecs/dec_audio.c =================================================================== --- libmpcodecs/dec_audio.c (revision 25055) +++ libmpcodecs/dec_audio.c (working copy) @@ -335,6 +335,8 @@ // filter config: memcpy(&afs->cfg, &af_cfg, sizeof(af_cfg_t)); + afs->input_chan_map = sh_audio->input_chan_map; + afs->output_chan_map = sh_audio->output_chan_map; mp_msg(MSGT_DECAUDIO, MSGL_V, MSGTR_BuildingAudioFilterChain, afs->input.rate, afs->input.nch, Index: libmpcodecs/ae.h =================================================================== --- libmpcodecs/ae.h (revision 25055) +++ libmpcodecs/ae.h (working copy) @@ -39,6 +39,7 @@ int (*encode)(struct audio_encoder_s *encoder, uint8_t *dest, void *src, int nsamples, int max_size); void (*fixup)(struct audio_encoder_s *encoder); int (*close)(struct audio_encoder_s *encoder); + char *output_chan_map; } audio_encoder_t; audio_encoder_t *new_audio_encoder(muxer_stream_t *stream, audio_encoding_params_t *params); Index: libmpcodecs/ae_lavc.c =================================================================== --- libmpcodecs/ae_lavc.c (revision 25055) +++ libmpcodecs/ae_lavc.c (working copy) @@ -46,6 +46,22 @@ mux_a->wf->nAvgBytesPerSec = (lavc_actx->bit_rate / 8); mux_a->avg_rate= lavc_actx->bit_rate; mux_a->h.dwRate = mux_a->wf->nAvgBytesPerSec; + /* remap channels */ + switch (lavc_actx->channels) { + case 1: /* FC, no action needed */ + case 2: /* FL FR, no action needed */ + case 3: /* unknown */ + case 4: /* FL FR BL BR, no action needed */ + break; + case 5: /* FL FC FR BL BR */ + encoder->output_chan_map = "00" "21" "32" "43" "14"; + break; + case 6: /* FL FC FR BL BR LFE */ + encoder->output_chan_map = "00" "21" "32" "43" "14" "55"; + break; + default: + break; + } if(lavc_actx->block_align) mux_a->h.dwSampleSize = mux_a->h.dwScale = lavc_actx->block_align; else Index: libao2/ao_pcm.c =================================================================== --- libao2/ao_pcm.c (revision 25055) +++ libao2/ao_pcm.c (working copy) @@ -106,6 +106,23 @@ ao_data.samplerate=rate; ao_data.format=format; ao_data.bps=channels*rate*(bits/8); + + /* re-map channels */ + switch (ao_data.channels) { + case 1: /* FC, no action needed */ + case 2: /* FL FR, no action needed */ + case 3: /* unknown; may not exist */ + case 4: /* FL FR BL BR, no action needed */ + break; + case 5: /* FL FR C BL BR */ + ao_data.output_chan_map = "00" "11" "42" "23" "34"; + break; + case 6: /* FL FR C LFE BL BR */ + ao_data.output_chan_map = "00" "11" "42" "53" "24" "35"; + break; + default: + break; + } wavhdr.riff = le2me_32(WAV_ID_RIFF); wavhdr.wave = le2me_32(WAV_ID_WAVE); Index: libao2/audio_out.h =================================================================== --- libao2/audio_out.h (revision 25055) +++ libao2/audio_out.h (working copy) @@ -39,6 +39,7 @@ int outburst; int buffersize; int pts; + char *output_chan_map; } ao_data_t; extern char *ao_subdevice; Index: DOCS/man/en/mplayer.1 =================================================================== --- DOCS/man/en/mplayer.1 (revision 25055) +++ DOCS/man/en/mplayer.1 (working copy) @@ -1457,6 +1457,14 @@ Always falls back on content-based demuxer selection. . .TP +.B \-noremap-channels +Some audio formats have a different channel order than MPlayer and +MEncoder use internally. +Normally, the channels audio filter is automatically inserted to remap +the channels as necessary. +This option disables the remapping. +. +.TP .B \-passwd (also see \-user) (network only) Specify password for HTTP authentication. . Index: mplayer.c =================================================================== --- mplayer.c (revision 25055) +++ mplayer.c (working copy) @@ -304,6 +304,7 @@ float force_fps=0; static int force_srate=0; +static int remap_channels=1; static int audio_output_format=-1; // AF_FORMAT_UNKNOWN int frame_dropping=0; // option 0=no drop 1= drop vo 2= drop decode static int play_n_frames=-1; @@ -1224,6 +1225,8 @@ playback_speed = (float)new_srate / (float)sh_audio->samplerate; } } + if (!remap_channels) + sh_audio->input_chan_map = sh_audio->output_chan_map = NULL; result = init_audio_filters(sh_audio, new_srate, &ao_data->samplerate, &ao_data->channels, &ao_data->format); mpctx->mixer.afilter = sh_audio->afilter; @@ -1505,6 +1508,8 @@ ao_data.format=audio_output_format; #if 1 // first init to detect best values + if (!remap_channels) + mpctx->sh_audio->input_chan_map = mpctx->sh_audio->output_chan_map = NULL; if(!init_audio_filters(mpctx->sh_audio, // preliminary init // input: mpctx->sh_audio->samplerate, @@ -1541,6 +1546,7 @@ // init audio filters: #if 1 current_module="af_init"; + mpctx->sh_audio->output_chan_map = ao_data.output_chan_map; if(!build_afilter_chain(mpctx->sh_audio, &ao_data)) { mp_msg(MSGT_CPLAYER,MSGL_ERR,MSGTR_NoMatchingFilter); // mp_msg(MSGT_CPLAYER,MSGL_ERR,"Couldn't find matching filter / ao format! -> NOSOUND\n"); Index: cfg-common.h =================================================================== --- cfg-common.h (revision 25055) +++ cfg-common.h (working copy) @@ -173,6 +173,8 @@ {"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}, + {"remap-channels", &remap_channels, CONF_TYPE_FLAG, 0, 0, 1, NULL}, + {"noremap-channels", &remap_channels, CONF_TYPE_FLAG, 0, 1, 0, NULL}, {"format", &audio_output_format, CONF_TYPE_AFMT, 0, 0, 0, NULL}, {"speed", &playback_speed, CONF_TYPE_FLOAT, CONF_RANGE, 0.01, 100.0, NULL}, Index: libmpdemux/stheader.h =================================================================== --- libmpdemux/stheader.h (revision 25055) +++ libmpdemux/stheader.h (working copy) @@ -18,6 +18,8 @@ int samplerate; int samplesize; int channels; + char *input_chan_map; + char *output_chan_map; int o_bps; // == samplerate*samplesize*channels (uncompr. bytes/sec) int i_bps; // == bitrate (compressed bytes/sec) // in buffers: Index: mencoder.c =================================================================== --- mencoder.c (revision 25055) +++ mencoder.c (working copy) @@ -169,6 +169,7 @@ float playback_speed=1.0; static int force_srate=0; +static int remap_channels=1; static int audio_output_format=0; char *vobsub_out=NULL; @@ -407,7 +408,7 @@ int new_srate=0; unsigned int timer_start=0; -ao_data_t ao_data = {0,0,0,0,OUTBURST,-1,0}; +ao_data_t ao_data = {0,0,0,0,OUTBURST,-1,0,NULL}; audio_encoding_params_t aparams; audio_encoder_t *aencoder = NULL; @@ -914,6 +915,8 @@ ao_data.samplerate = force_srate; ao_data.channels = 0; ao_data.format = audio_output_format; +if (!remap_channels) + sh_audio->input_chan_map = sh_audio->output_chan_map = NULL; if(!init_audio_filters(sh_audio, // input: new_srate, @@ -930,6 +933,9 @@ aencoder = new_audio_encoder(mux_a, &aparams); if(!aencoder) mencoder_exit(1, NULL); + sh_audio->output_chan_map = aencoder->output_chan_map; + if (!remap_channels) + sh_audio->input_chan_map = sh_audio->output_chan_map = NULL; if(!init_audio_filters(sh_audio, new_srate, &aparams.sample_rate, &aparams.channels, &aencoder->input_format)) { Index: libaf/af.c =================================================================== --- libaf/af.c (revision 25055) +++ libaf/af.c (working copy) @@ -361,12 +361,12 @@ // Check if this is the first call if(!s->first){ + /* remap input channels if the codec/demuxer provides a map */ + if (s->input_chan_map) + if (AF_OK != af_append_channel_map(s, s->first, s->input_chan_map)) + return -1; // Add all filters in the list (if there are any) - if(!s->cfg.list){ // To make automatic format conversion work - if(!af_append(s,s->first,"dummy")) - return -1; - } - else{ + if (s->cfg.list) { while(s->cfg.list[i]){ if(!af_append(s,s->last,s->cfg.list[i++])) return -1; @@ -374,6 +374,20 @@ } } + /* remap output channels if the codec/ao provides a map */ + if (s->output_chan_map) { + if (AF_OK != af_append_channel_map(s, s->last, s->output_chan_map)) + return -1; + /* make sure we don't append this more than once */ + s->output_chan_map = NULL; + } + + // To make automatic format conversion work + if (!s->first){ + if(!af_append(s,s->first,"dummy")) + return -1; + } + // Init filters if(AF_OK != af_reinit(s,s->first)) return -1; @@ -606,3 +620,36 @@ { data->bps = af_fmt2bits(data->format)/8; } + +int af_append_channel_map(af_stream_t *s, af_instance_t *af_prev, char *chan_map){ + af_control_ext_t arg; + af_instance_t *af = NULL; + int channels, route[2]; + channels = af_prev ? af_prev->data->nch : s->input.nch; + /* check input */ + if (strlen(chan_map) != 2*channels) { + af_msg(AF_MSG_ERROR, "channel map: num. of routes does not match num. of channels\n"); + return AF_ERROR; + } + /* set up af_channels to route */ + af = af_append(s, af_prev, "channels"); + if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS_ROUTER, &channels))) + return AF_ERROR; + if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS_NR, &channels))) + return AF_ERROR; + /* pass each route to af_channels */ + for (arg.ch = 0; arg.ch < channels; ++arg.ch) { + /* two by two... */ + route[0] = *chan_map++ - '0'; + route[1] = *chan_map++ - '0'; + arg.arg = route; + if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS_ROUTING, &arg))) + return AF_ERROR; + } + /* try it! */ + if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS, &channels))) + return AF_ERROR; + if (AF_OK != af_reinit(s,af)) + return AF_ERROR; + return AF_OK; +} Index: libaf/af.h =================================================================== --- libaf/af.h (revision 25055) +++ libaf/af.h (working copy) @@ -100,6 +100,8 @@ af_data_t output; // Configuration for this stream af_cfg_t cfg; + char *input_chan_map; + char *output_chan_map; }af_stream_t; /********************************************* @@ -295,6 +297,18 @@ */ void af_fix_parameters(af_data_t *data); +/** + * \brief set up channel remapping + * \param af_stream + * \param af_instance to append this instance after + * \param string of channel routes + * \return AF_OK if ok, AF_ERROR otherwise + * + * Checks that the number of routes matches channels, and creates an instance + * of af_channels with the routes specified in *chan_map. + */ +int af_append_channel_map(af_stream_t *s, af_instance_t *af_prev, char *chan_map); + /** Memory reallocation macro: if a local buffer is used (i.e. if the filter doesn't operate on the incoming buffer this macro must be called to ensure the buffer is big enough.