[MPlayer-dev-eng] [RFC] 6-channel AAC and channel reordering

Dominik 'Rathann' Mierzejewski dominik at rangers.eu.org
Mon Oct 30 23:16:10 CET 2006


Reviving an old, forgotten patch...

On Wednesday, 22 February 2006 at 11:01, Corey Hickey wrote:
> The problem: 6-channel AAC has a different channel order than MPlayer
> outputs.
> 
> MPlayer wants:
> 0 - front left
> 1 - front right
> 2 - rear left
> 3 - rear right
> 4 - front center
> 5 - lfe
> 
> MPlayer gets:
> 0 - front center
> 1 - front left
> 2 - front right
> 3 - rear left
> 4 - rear right
> 5 - lfe
> 
> --------------------------------------------------------------------------
> For a test source you can probably use any recent hd trailer from Apple. Or:
> http://movies.apple.com/movies/universal/king_kong/king_kong-tlr_h480p.mov
> 
> This works fine because AAC does the downmixing internally:
> $ mplayer king_kong-tlr_h480p.mov -channels 2
> 
> This sounds odd -- the channels are definitely mixed up:
> $ mplayer king_kong-tlr_h480p.mov -channels 6
> 
> If you don't have a 5.1 speaker setup (I don't either), then you can do
> a quick-n-dirty downmix:
> $ mplayer king_kong-tlr_h480p.mov -channels 6 \
> -af pan=2:0.4:0:0:0.4:0.2:0:0:0.2:0.3:0.3:0.5:0.5
> 
> ...or an hrtf one:
> $ mplayer king_kong-tlr_h480p.mov -channels 6 -af hrtf
> 
> Either way, you'll hear that the channel position isn't right.
> 
> --------------------------------------------------------------------------
> The attached patch uses af_channels to handle the reordering.
> ad_faad.c:init() sets up a routing map and af.c:af_init() uses that map
> to put a channels filter at the beginning of the audio chain. Try the
> above examples with a patched mplayer -- they should work correctly.
> 
> As far as I know the patch doesn't break anything. Probably it does, but
> not that I know of. :)  Anyway, I don't consider it finished. Some notes:
> 
> * It would probably be ideal to have faad handle the reordering, but I
> don't see a way to do that.
> 
> * If this kind of approach seems acceptable, I should switch to af_pan
> to handle upmixing and downmixing where channels have to be split or
> combined.
> 
> * I don't have any code to deal with 3- or 4- channel AAC. With af_pan I
> could probably upmix or downmix these appropriately to match the output
> channel order. Does anyone have a sample?
> 
> * This could be applied to audio formats other than AAC, of course. Does
> anyone have an example of another format that could benefit?
> 
> --------------------------------------------------------------------------
> So, what do you think? Am I barking up the wrong tree or should I keep
> working in this direction?

I've tested it on my 4.0 setup and I didn't hear the front center and lfe
channels until I downmixed it to 4ch:
mplayer -af pan=4:1:0:0:0:0:1:0:0:0:0:1:0:0:0:0:1:0.25:0.25:0:0:0.25:0.25:0:0 \
return,_the_h720p.mov

With that, it seems to be working fine (certainly the trailer sounds better
than without it). Attached a version updated to current SVN, although the
old patch still applies.

OK to apply?

Regards,
R.

-- 
MPlayer developer and RPMs maintainer: http://rpm.greysector.net/mplayer/
There should be a science of discontent. People need hard times and
oppression to develop psychic muscles.
	-- from "Collected Sayings of Muad'Dib" by the Princess Irulan
-------------- next part --------------
--- MPlayer-20538/libmpcodecs/ad_faad.c.chmap	2006-10-02 01:21:07.000000000 +0200
+++ MPlayer-20538/libmpcodecs/ad_faad.c	2006-10-30 21:57:34.000000000 +0100
@@ -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 = af_set_channel_map(6, "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;
--- MPlayer-20538/libmpcodecs/dec_audio.c.chmap	2006-10-08 16:11:51.000000000 +0200
+++ MPlayer-20538/libmpcodecs/dec_audio.c	2006-10-30 21:57:34.000000000 +0100
@@ -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),
--- MPlayer-20538/libaf/af.h.chmap	2006-06-05 19:40:44.000000000 +0200
+++ MPlayer-20538/libaf/af.h	2006-10-30 21:57:34.000000000 +0100
@@ -104,6 +104,7 @@
   af_data_t output;
   // Configuration for this stream
   af_cfg_t cfg;
+  int *chan_map;
 }af_stream_t;
 
 /*********************************************
@@ -329,6 +330,16 @@
  */
 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
+ *
+ * Makes an int array from a string of provided routes.
+ */
+int *af_set_channel_map(int channels, char *routes);
+
 /** 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.
--- MPlayer-20538/libaf/af.c.chmap	2006-09-19 00:59:44.000000000 +0200
+++ MPlayer-20538/libaf/af.c	2006-10-30 21:57:34.000000000 +0100
@@ -359,17 +359,40 @@
 
   // Check if this is the first call
   if(!s->first){
-    // 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; 
+    /* remap channels if the codec/demuxer provides a channel map */
+    if (s->chan_map) {
+      af_control_ext_t arg;
+      arg.ch = s->input.nch;
+      af_instance_t *af = NULL;
+      af=af_append(s, s->first, "channels");
+      /* 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;
+      /* set up each route */
+      for (arg.ch = 0; arg.ch < s->input.nch; ++arg.ch) {
+        arg.arg = s->chan_map + 2*arg.ch; /* two by two... */
+        if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS_ROUTING, &arg)))
+        return -1;
+      }
+      if (!af || (AF_OK != af->control(af, AF_CONTROL_CHANNELS, &s->input.nch)))
+        return -1;
+      if (AF_OK != af_reinit(s,af))
+        return -1;
     }
-    else{
+    // Add all filters in the list (if there are any)
+    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 +732,23 @@
 {
     data->bps = af_fmt2bits(data->format)/8;
 }
+
+int *af_set_channel_map(int channels, char *routes){
+  int *chan_map, *ptr;
+  ptr=chan_map=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) {
+    if (*routes == '\0' || *(routes+1) == '\0') { 
+      mp_msg(MSGT_DEMUX, MSGL_ERR, "set_channel_map: not enough routes\n");
+      free(chan_map);
+      return 0;
+    }
+    /* two by two... */
+    *ptr++ = *routes++ - '0';
+    *ptr++ = *routes++ - '0';
+  }
+  return chan_map;
+}
--- MPlayer-20538/libmpdemux/stheader.h.chmap	2006-08-29 23:20:01.000000000 +0200
+++ MPlayer-20538/libmpdemux/stheader.h	2006-10-30 21:57:34.000000000 +0100
@@ -19,6 +19,7 @@
   int samplerate;
   int samplesize;
   int channels;
+  int *chan_map;
   int o_bps; // == samplerate*samplesize*channels   (uncompr. bytes/sec)
   int i_bps; // == bitrate  (compressed bytes/sec)
   // in buffers:


More information about the MPlayer-dev-eng mailing list