Dominik 'Rathann' Mierzejewski wrote:
Reviving an old, forgotten patch...
All right, here's an update. I'm sleepy by now, so there might be something wrong that's easily spotted with fresh eyes. I'll take a closer look tomorrow, but it should be testable. New stuff: * a little cleaner; better error checking * remapping for 6-channel WMA (in ad_dmo.c) This is UNTESTED. I won't apply it without testing later, but somebody else can test it now if they want to. * remapping for 6-channel PCM (see below) On 2006-07-30, Alexander 'Lazy Ranma' Ponyatikh sent a patch for decoding 6-channel PCM directly into each correct channel. I benchmarked it, and it seems a bit slower than using af_channels, probably because it calls demux_read_data() repeatedly and only reads two samples at a time. I tested on a 6-channel wav file made from The Matrix DVD. It is 8177.3 seconds long. Each number is the user-time average of three tests, but there really wasn't much variation. The command is: $ time mplayer -ao pcm:fast:file=/dev/null -channels 6 audiodump.wav method user time % of play time ------------------------------------------------------------ original (incorrect channels): 9.099s 0.11127% using af_channels to remap: 15.057s 0.18413% reading into each channel: 30.296s 0.37048% By the way, Alexander, if you're reading this, don't think I'm denigrating your work; the information you sent is helpful and I might end up applying your ae_*.c patches. Also, if you come up with a faster approach for ad_pcm, feel free to submit it and we can consider using that instead of af_channels for PCM decoding. -Corey Index: libmpcodecs/ad_pcm.c =================================================================== --- libmpcodecs/ad_pcm.c (revision 20547) +++ libmpcodecs/ad_pcm.c (working copy) @@ -22,6 +22,21 @@ 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: /* no action needed */ + case 2: /* no action needed */ + /* more mappings should be added when documentation or samples are found */ + case 3: /* unknown? */ + case 4: /* unknown? */ + case 5: /* unknown? */ + break; + case 6: + sh_audio->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 20547) +++ libmpcodecs/ad_faad.c (working copy) @@ -152,6 +152,23 @@ 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) { + default: + case 1: /* no action needed */ + case 2: /* no action needed */ + case 3: /* no suitable default behavior? */ + case 4: /* no suitable default behavior? */ + break; + case 5: /* mplayer treats this like 6-channel */ + case 6: + sh->chan_map = "04" "10" "21" "32" "43" "55"; + break; + case 7: /* not supported by mplayer? */ + 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 20547) +++ libmpcodecs/ad_dmo.c (working copy) @@ -40,6 +40,21 @@ } sh_audio->i_bps=sh_audio->wf->nAvgBytesPerSec; sh_audio->channels=chans; + /* re-map channels */ + switch (chans) { + case 1: /* no action needed */ + case 2: /* no action needed */ + /* more mappings should be added when documentation or samples are found */ + case 3: /* unknown? */ + case 4: /* unknown? */ + case 5: /* unknown? */ + break; + case 6: + sh_audio->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 20547) +++ libmpcodecs/dec_audio.c (working copy) @@ -311,6 +311,7 @@ // filter config: memcpy(&afs->cfg,&af_cfg,sizeof(af_cfg_t)); + afs->chan_map = sh_audio->chan_map; mp_msg(MSGT_DECAUDIO, MSGL_V, MSGTR_BuildingAudioFilterChain, afs->input.rate,afs->input.nch,af_fmt2str_short(afs->input.format), Index: libmpdemux/stheader.h =================================================================== --- libmpdemux/stheader.h (revision 20547) +++ libmpdemux/stheader.h (working copy) @@ -19,6 +19,7 @@ int samplerate; int samplesize; int channels; + char *chan_map; int o_bps; // == samplerate*samplesize*channels (uncompr. bytes/sec) int i_bps; // == bitrate (compressed bytes/sec) // in buffers: Index: libaf/af.c =================================================================== --- libaf/af.c (revision 20547) +++ libaf/af.c (working copy) @@ -359,17 +359,47 @@ // Check if this is the first call if(!s->first){ + + /* remap channels if the codec/demuxer provides a channel map */ + if (s->chan_map) { + int *routes; + af_control_ext_t arg; + arg.ch = s->input.nch; + af_instance_t *af = NULL; + af = af_append(s, s->first, "channels"); + /* check/set up the routes */ + if (! (routes = af_set_channel_map(s->input.nch, s->chan_map)) ) + return -1; + /* set up af_channels to route */ + if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS_ROUTER, &s->input.nch))) + return -1; + if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS_NR, &s->input.nch))) + return -1; + /* pass each route to af_channels */ + for (arg.ch = 0; arg.ch < s->input.nch; ++arg.ch) { + arg.arg = routes + 2*arg.ch; /* two by two... */ + if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS_ROUTING, &arg))) + return -1; + } + /* try it! */ + if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS, &s->input.nch))) + return -1; + if (AF_OK != af_reinit(s,af)) + 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; } } + // To make automatic format conversion work + if (!s->first){ + if(!af_append(s,s->first,"dummy")) + return -1; + } } // Init filters @@ -709,3 +739,22 @@ { data->bps = af_fmt2bits(data->format)/8; } + +int *af_set_channel_map(int channels, char *chan_map){ + int *routes, *ptr; + if (strlen(chan_map) != 2*channels) { + af_msg(AF_MSG_ERROR, "channel map: incorrect num. of routes in channel map\n"); + return NULL; + } + ptr = routes = malloc(2 * channels * sizeof(int)); + if (!chan_map) { + mp_msg(MSGT_DEMUX, MSGL_ERR, "set_channel_map: cannot malloc for %d channels\n", channels); + return 0; + } + while (channels-- > 0) { + /* two by two... */ + *ptr++ = *chan_map++ - '0'; + *ptr++ = *chan_map++ - '0'; + } + return routes; +} Index: libaf/af.h =================================================================== --- libaf/af.h (revision 20547) +++ libaf/af.h (working copy) @@ -104,6 +104,7 @@ af_data_t output; // Configuration for this stream af_cfg_t cfg; + char *chan_map; }af_stream_t; /********************************************* @@ -329,6 +330,17 @@ */ void af_fix_parameters(af_data_t *data); +/** + * \brief set up channel remapping + * \param number of output channels + * \param string of from-to routes + * \return int array of routes, NULL if error + * + * Makes an int array from a string of provided routes. + * Checks that number of routes matches channels. + */ +int *af_set_channel_map(int channels, 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.