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

Giacomo Comes comes at naic.edu
Tue Oct 31 15:44:04 CET 2006


On Mon, Oct 30, 2006 at 10:18:09PM -0800, Corey Hickey wrote:
> Dominik 'Rathann' Mierzejewski wrote:
> >>> 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
> >> That makes sense, since mplayer is outputting 6 channels, and on your 
> >> system the last two aren't hooked up to anything. One thing, though: do 
> >> you have channels=6 in your config file, or did you specify -channels 6 
> >> on your command line? If not, then I'm confused, since as far as I know 
> >> mplayer tells libfaad to downmix to 2 channels be default.
> > 
> > I have channels=4.
> 
> Ok, that'll do it too.
> 
> >> For some reason I have a nagging feeling that somebody else proposed a 
> >> different approach and that it might have been committed, but I can't 
> >> dig up the patch. Maybe I'm imagining things.
> > 
> > I can't recall any such thing.
> 
> Giacomo pointed out enough for me to go by. See the following, and lots
> of replies in that thread.
> 
> To: mplayer-dev-eng at mplayerhq.hu
> From: Alexander 'Lazy Ranma' Ponyatikh
> Subject: [MPlayer-dev-eng] [PATCH] channel reordering for 6ch audio
> Date: Sat, 29 Jul 2006 20:39:44 +0400


I have been working on extending the patches submitted some time ago
by Alexander in order to support in the correct order 4/5/6 channels sound stream.
6 channels is easy because you can only have 3f+2r+lfe.
With 5 channels there are more combinations: 3f+2r, 2f+2r+lfe, 3f+1r+lfe
and with 4 channels: 2f+2r, 3f+1r, 3f+lfe, 2f+1r+lfe

Currently there is no way in mplayer/mencoder (and in libavcodec) to specify the number of
front/rear/lfe channels, you can only specify the sum of them with the option -channels.
For this reason the patches currently assume the following configurations:
6ch 3f+2r+lfe
5ch 3f+2r
4ch 2f+2r
because this is what you get with libavcodec ac3 encoder.

The changes to ad_faad.c, ad_pcm.c, ae_lavc.c, ae_pcm.c and ao_pcm.c
are just extension of the previous patches. Assuming that the original patches
were correct, they should also be. The changes to ae_faac.c instead are completly 
new, check them carefully.

I was planning to submit the patch before rc1 was released, but I didn't have the time.
Also as Corey has noticed, channel reordering introduces some overhead.
May be we can add an option like -nochanreorder the tell mplayer/mencoder to not
do channels reordering (keeping maximum speed in case it is required).

Corey, can you integrate the ideas of this patch in yours?

Giacomo
-------------- next part --------------
diff -Nraub mplayer.ori/libmpcodecs/ad_faad.c mplayer/libmpcodecs/ad_faad.c
--- mplayer.ori/libmpcodecs/ad_faad.c	2006-10-08 15:58:28.000000000 -0400
+++ mplayer/libmpcodecs/ad_faad.c	2006-10-10 12:10:09.000000000 -0400
@@ -277,7 +277,20 @@
       /* XXX: samples already multiplied by channels! */
       mp_msg(MSGT_DECAUDIO,MSGL_DBG2,"FAAD: Successfully decoded frame (%ld Bytes)!\n",
       sh->samplesize*faac_finfo.samples);
+      
+      if (sh->channels == 6 || sh->channels == 5) {
+         //Source channel order: C L R  SL SR LFE
+         //We want:              L R SL SR C  LFE
+         int i;
+         for (i = 0; i < faac_finfo.samples; i += sh->channels) {
+            memcpy(buf+len+(i+0)*sh->samplesize,faac_sample_buffer+(i+1)*sh->samplesize, sh->samplesize*4);     // L R SL SR
+            memcpy(buf+len+(i+4)*sh->samplesize,faac_sample_buffer+(i+0)*sh->samplesize, sh->samplesize*1);     // C
+            if (sh->channels == 6)
+                memcpy(buf+len+(i+5)*sh->samplesize,faac_sample_buffer+(i+5)*sh->samplesize, sh->samplesize*1); // LFE
+         }
+      } else {      
       memcpy(buf+len,faac_sample_buffer, sh->samplesize*faac_finfo.samples);
+      }
       last_dec_len = sh->samplesize*faac_finfo.samples;
       len += last_dec_len;
       sh->pts_bytes += last_dec_len;
-------------- next part --------------
diff -Nraub mplayer.ori/libmpcodecs/ad_pcm.c mplayer/libmpcodecs/ad_pcm.c
--- mplayer.ori/libmpcodecs/ad_pcm.c	2006-09-12 11:58:43.000000000 -0400
+++ mplayer/libmpcodecs/ad_pcm.c	2006-10-10 13:15:11.000000000 -0400
@@ -17,6 +17,8 @@
 
 LIBAD_EXTERN(pcm)
 
+static void *tmp_buff = NULL;
+
 static int init(sh_audio_t *sh_audio)
 {
   WAVEFORMATEX *h=sh_audio->wf;
@@ -90,6 +92,8 @@
   }
   if (!sh_audio->samplesize) // this would cause MPlayer to hang later
     sh_audio->samplesize = 2;
+  if (sh_audio->channels == 6 || sh_audio->channels == 5)
+    tmp_buff = malloc(2 * sh_audio->samplesize);
   return 1;
 }
 
@@ -101,6 +105,10 @@
 
 static void uninit(sh_audio_t *sh)
 {
+  if (tmp_buff) {
+    free(tmp_buff);
+    tmp_buff = NULL;
+  }
 }
 
 static int control(sh_audio_t *sh,int cmd,void* arg, ...)
@@ -126,5 +134,15 @@
       // based on channels in preinit()
       return -1;
   len=demux_read_data(sh_audio->ds,buf,len);
+  if (sh_audio->channels == 6 || sh_audio->channels == 5) {
+    //Source channel order: L R C  LFE SL SR   or  L R C  SL SR
+    //We want:              L R SL SR  C  LFE  or  L R SL SR C
+    int i, samples = len / sh_audio->samplesize;
+    for (i = 0; i < samples; i += sh_audio->channels) {
+      memcpy(tmp_buff, buf+(i+2)*sh_audio->samplesize, ((sh_audio->channels+1)%2+1)*sh_audio->samplesize); // C (LFE) -> tmp
+      memcpy(buf+(i+2)*sh_audio->samplesize, buf+(i+(sh_audio->channels+1)%2+3)*sh_audio->samplesize, 2*sh_audio->samplesize); // SL SR -> 2,3
+      memcpy(buf+(i+4)*sh_audio->samplesize, tmp_buff, ((sh_audio->channels+1)%2+1)*sh_audio->samplesize); // C (LFE) -> 4(,5)
+    }
+  }
   return len;
 }
-------------- next part --------------
diff -Nraub mplayer.ori/libmpcodecs/ae_faac.c mplayer/libmpcodecs/ae_faac.c
--- mplayer.ori/libmpcodecs/ae_faac.c	2006-10-08 15:57:44.000000000 -0400
+++ mplayer/libmpcodecs/ae_faac.c	2006-10-12 23:43:25.000000000 -0400
@@ -97,6 +97,25 @@
 
 static int encode_faac(audio_encoder_t *encoder, uint8_t *dest, void *src, int len, int max_size)
 {
+        if (encoder->params.channels == 6 || encoder->params.channels == 5) {
+            //Codec wants: C L R  SL SR LFE
+            //We have:     L R SL SR C  LFE
+            int i;
+            uint16_t tmp16;
+            uint32_t tmp32;
+            for (i = 0; i < len; i += encoder->params.channels*divisor) {
+                if (divisor == 4)
+                    tmp32 = ((uint32_t*)(src+i))[4];
+                else
+                    tmp16 = ((uint16_t*)(src+i))[4];
+                memmove(src+i+divisor, src+i, 4*divisor);
+                if (divisor == 4)
+                    ((uint32_t*)(src+i))[0] = tmp32;
+                else
+                    ((uint16_t*)(src+i))[0] = tmp16;
+            }
+        }
+
 	// len is divided by the number of bytes per sample
 	enc_frame_size = faacEncEncode(faac,  (int32_t*) src,  len / divisor, dest, max_size);
 	
-------------- next part --------------
diff -Nraub mplayer.ori/libmpcodecs/ae_lavc.c mplayer/libmpcodecs/ae_lavc.c
--- mplayer.ori/libmpcodecs/ae_lavc.c	2006-09-12 11:58:52.000000000 -0400
+++ mplayer/libmpcodecs/ae_lavc.c	2006-10-13 22:54:47.000000000 -0400
@@ -102,6 +102,17 @@
 static int encode_lavc(audio_encoder_t *encoder, uint8_t *dest, void *src, int size, int max_size)
 {
 	int n;
+    if (encoder->params.channels == 6 || encoder->params.channels == 5) {
+        //Codec wants: L C R  SL SR LFE
+        //We have:     L R SL SR C  LFE
+        int i;
+        uint16_t tmp;
+        for (i = 0; i < size; i += encoder->params.channels*2) {
+            tmp = ((uint16_t*)(src+i))[4];
+            memmove(src+i+4, src+i+2, 3*2);
+            ((uint16_t*)(src+i))[1] = tmp;
+        }
+    }
 	n = avcodec_encode_audio(lavc_actx, dest, size, src);
         compressed_frame_size = n;
 	return n;
-------------- next part --------------
diff -Nraub mplayer.ori/libmpcodecs/ae_pcm.c mplayer/libmpcodecs/ae_pcm.c
--- mplayer.ori/libmpcodecs/ae_pcm.c	2006-06-05 15:43:08.000000000 -0400
+++ mplayer/libmpcodecs/ae_pcm.c	2006-10-10 23:06:51.000000000 -0400
@@ -37,7 +37,27 @@
 static int encode_pcm(audio_encoder_t *encoder, uint8_t *dest, void *src, int nsamples, int max_size)
 {
 	max_size = min(nsamples, max_size);
+    if (encoder->params.channels == 6 || encoder->params.channels == 5) {
+        //Codec wants: L R C  LFE SL SR        L R C  SL SR
+        //We have:     L R SL SR  C  LFE       L R SL SR  C
+        max_size -= max_size % (2*encoder->params.channels);
+        int i;
+        for (i = 0; i < max_size; i += 2*encoder->params.channels) {
+            if (encoder->params.channels == 6) {
+                ((uint32_t*)(dest+i))[0] = ((uint32_t*)(src+i))[0]; //L R   -> 0,1
+                ((uint32_t*)(dest+i))[1] = ((uint32_t*)(src+i))[2]; //C LFE -> 2,3
+                ((uint32_t*)(dest+i))[2] = ((uint32_t*)(src+i))[1]; //SL SR -> 4,5
+            } else {
+                ((uint16_t*)(dest+i))[0] = ((uint16_t*)(src+i))[0]; //L     -> 0
+                ((uint16_t*)(dest+i))[1] = ((uint16_t*)(src+i))[1]; //R     -> 1
+                ((uint16_t*)(dest+i))[2] = ((uint16_t*)(src+i))[4]; //C     -> 2
+                ((uint16_t*)(dest+i))[3] = ((uint16_t*)(src+i))[2]; //SL    -> 3
+                ((uint16_t*)(dest+i))[4] = ((uint16_t*)(src+i))[3]; //SR    -> 4
+            }
+        }
+    } else {
 	memcpy(dest, src, max_size);
+    }
 	return max_size;
 }
 
-------------- next part --------------
diff -Nraub mplayer.ori/libao2/ao_pcm.c mplayer/libao2/ao_pcm.c
--- mplayer.ori/libao2/ao_pcm.c	2006-06-05 15:46:03.000000000 -0400
+++ mplayer/libao2/ao_pcm.c	2006-10-10 09:48:30.000000000 -0400
@@ -205,8 +205,20 @@
 	}
 #endif 
 
+    if (ao_data.channels == 6 || ao_data.channels == 5) {
+        int i, samplesize = wavhdr.bits/8;
+        for (i = 0; i < len; i += samplesize*ao_data.channels) {
+            //L R SL SR C LFE -> L R C LFE SL SR
+            //L R SL SR C     -> L R C     SL SR
+            fwrite(data+i, samplesize, 2, fp);
+            fwrite(data+i+4*samplesize, samplesize, (ao_data.channels+1)%2+1, fp);
+            fwrite(data+i+2*samplesize, samplesize, 2, fp);
+        }
+        len -= len % (ao_data.channels*samplesize);
+    } else {
 	//printf("PCM: Writing chunk!\n");
 	fwrite(data,len,1,fp);
+    }
 
 	if(ao_pcm_waveheader)
 		wavhdr.data_length += len;


More information about the MPlayer-dev-eng mailing list