[MPlayer-dev-eng] AC3-surround patch

Stephen Davies steve at daviesfam.org
Mon Nov 26 19:39:49 CET 2001


Hi developers,

Here's my patch for adding full multichannel AC3 decoding to mplayer.

The patch adds '-ac ac3surround'.  I included some documentation updates
too.  I will write a "sound-ac3.html" which needs to be added to the cvs.

The code would probably benefit from optimization - especially
stream_sample_6ch_to_s16 in libac3/imdct.c - but I think others should try
the code before that.  I don't think there's anything too tricky in the
code.  I did change the semantics of ao_data.channels in ao_oss.c to be
the actual number of channels rather than channels-1.

Output to the soundcard driver will always be 6 channels - Left, Right,
Left-Surround, Right-Surround, Centre and low-frequency-effects.  The
channels are output just as they are in the original file.  Channels not
present in the AC3 stream are output as silence - ie a "5.0" AC3 stream
will have silence on the LFE channel.

(There are all sorts of downmix, dynamic range reduction things that could
be added later, but probably we should get merged with liba52 first).

I've tested with various DVDs with 3/2.1, 3/2, 2/1, 2/0 AC3 streams, and
with the Dolby Digital trailers (wow).  Iffy-est piece of the code is the
new LFE decoding I added, but I think thats right.

For it to work you'll need an OSS soundcard driver that supports
SNDCTL_DSP_CHANNELS with channels==6.  For example, a recent emu10k1
driver for the SB Live.

http://opensource.creative.com/ has the development emu10k1 driver - you
can fetch the cvs version from there.  The emu10k1 driver in 2.4.10
kernel, at least, seems to have the >2 channel support, but I recommend to
get the cvs stuff.

You'll need a file with an ac3 soundtrack.  Most DVDs, for example.

Some configuration work will probably be necessary on the SB Live side,
too.  To do this you will need the emu-config and emu-dspmgr programs.  
Perhaps best to get them from the emu10k1 driver CVS (via
opensource.creative.com).  Also, in the emu10k1 source tree, read
docs/multichannel.txt, which provides background info on how the driver's
multichannel support works.  Importantly, if you want to hear anything you
need to use emu-dspmgr to map the fx8 through fx13 dsp channels to
somewhere.

For instance, if you have 6 speaker output, you probably want to:

  emu-config -a
  emu-dspmgr -a"fx8:Front L"
  emu-dspmgr -a"fx9:Front R"
  emu-dspmgr -a"fx10:Rear L"
  emu-dspmgr -a"fx11:Rear R"
  emu-dspmgr -a"fx12:Analog Center"
  emu-dspmgr -a"fx13:Analog LFE"

This will map all the outputs to the right places.

If you have 4 speakers only, then you probably want:

  emu-config -a
  emu-dspmgr -a"fx8:Front L"
  emu-dspmgr -a"fx9:Front R"
  emu-dspmgr -a"fx10:Rear L"
  emu-dspmgr -a"fx11:Rear R"
  emu-dspmgr -a"fx12:Front"
  emu-dspmgr -a"fx13:Front"

This will map the left, right, left-surround and right-surround, to your 4
speakers, then send the centre and the lfe channels equally to the two
front channels.

You might need "emu-dspmgr -x -z" at the start to get rid of old routes.

There is an emu-script provided with the emu10k1 driver that can help get
this stuff configured for you.

All sorts of other things are possible with the emu10k1 DSP stuff - but
this should get things started.

I'm interested in results, especially if you have an pre 5.1 SB Live, or
some other multichannel card.  Sounds awesome for me, though now I'll have
to buy some "proper" surround speakers and a subwoofer :-(

Steve
-------------- next part --------------
? fibmap_mplayer
? DOCS/sound-ac3.html
Index: codec-cfg.c
===================================================================
RCS file: /cvsroot/mplayer/main/codec-cfg.c,v
retrieving revision 1.47
diff -u -r1.47 codec-cfg.c
--- codec-cfg.c	14 Nov 2001 11:16:45 -0000	1.47
+++ codec-cfg.c	26 Nov 2001 15:18:37 -0000
@@ -213,6 +213,7 @@
 		"ffmpeg",
 		"libmad",
 		"ima4",
+		"ac3surround",
 		NULL
 	};
 	static char *videodrv[] = {
Index: codec-cfg.h
===================================================================
RCS file: /cvsroot/mplayer/main/codec-cfg.h,v
retrieving revision 1.23
diff -u -r1.23 codec-cfg.h
--- codec-cfg.h	11 Nov 2001 13:35:00 -0000	1.23
+++ codec-cfg.h	26 Nov 2001 15:18:37 -0000
@@ -31,6 +31,7 @@
 #define AFM_FFMPEG 11
 #define AFM_MAD 12
 #define AFM_IMA4 13
+#define AFM_AC3SURROUND 14
 
 #define VFM_MPEG 1
 #define VFM_VFW 2
Index: dec_audio.c
===================================================================
RCS file: /cvsroot/mplayer/main/dec_audio.c,v
retrieving revision 1.51
diff -u -r1.51 dec_audio.c
--- dec_audio.c	30 Oct 2001 17:38:09 -0000	1.51
+++ dec_audio.c	26 Nov 2001 15:18:40 -0000
@@ -228,6 +228,11 @@
   // Dolby AC3 audio:
   sh_audio->audio_out_minsize=4*256*6;
   break;
+case AFM_AC3SURROUND:
+  // Dolby AC3 audio but mixed to 6 channel output rather than downmixed:
+  // 6 blocks in a frame, 2 bytes in a word, 256 samples in a block, 6 channels
+  sh_audio->audio_out_minsize=6*2*256*6;
+  break;
 case AFM_HWAC3:
   // Dolby AC3 audio:
   sh_audio->audio_out_minsize=4*256*6;
@@ -323,11 +328,13 @@
 //    sh_audio->pcm_bswap=1;
     break;
 }
-case AFM_AC3: {
+case AFM_AC3:
+case AFM_AC3SURROUND: {
   // Dolby AC3 audio:
   dec_audio_sh=sh_audio; // save sh_audio for the callback:
   ac3_config.fill_buffer_callback = ac3_fill_buffer;
-  ac3_config.num_output_ch = 2;
+  //FIXME:SLD: later the desired output channels needs to be configurable beyond 6 or 2
+  ac3_config.num_output_ch = (driver == AFM_AC3SURROUND) ? 6 : 2;
   ac3_config.flags = 0;
 #ifdef HAVE_MMX
   ac3_config.flags |= AC3_MMX_ENABLE;
@@ -340,7 +347,7 @@
   if(sh_audio->ac3_frame){
     ac3_frame_t* fr=(ac3_frame_t*)sh_audio->ac3_frame;
     sh_audio->samplerate=fr->sampling_rate;
-    sh_audio->channels=2;
+    sh_audio->channels=ac3_config.num_output_ch;
     // 1 frame: 6*256 samples     1 sec: sh_audio->samplerate samples
     //sh_audio->i_bps=fr->frame_size*fr->sampling_rate/(6*256);
     sh_audio->i_bps=fr->bit_rate*(1000/8);
@@ -831,6 +838,7 @@
         break;
       }
       case AFM_AC3: // AC3 decoder
+      case AFM_AC3SURROUND: // AC3 decoder - multichannel
         //printf("{1:%d}",avi_header.idx_pos);fflush(stdout);
         if(!sh_audio->ac3_frame) sh_audio->ac3_frame=ac3_decode_frame();
         //printf("{2:%d}",avi_header.idx_pos);fflush(stdout);
@@ -937,6 +945,7 @@
           break;
 #endif
         case AFM_AC3:
+        case AFM_AC3SURROUND:
           ac3_bitstream_reset();    // reset AC3 bitstream buffer
     //      if(verbose){ printf("Resyncing AC3 audio...");fflush(stdout);}
           sh_audio->ac3_frame=ac3_decode_frame(); // resync
@@ -962,7 +971,9 @@
 void skip_audio_frame(sh_audio_t *sh_audio){
               switch(sh_audio->codec->driver){
                 case AFM_MPEG: MP3_DecodeFrame(NULL,-2);break; // skip MPEG frame
-                case AFM_AC3: sh_audio->ac3_frame=ac3_decode_frame();break; // skip AC3 frame
+                case AFM_AC3:
+                case AFM_AC3SURROUND:
+		    sh_audio->ac3_frame=ac3_decode_frame();break; // skip AC3 frame
 		case AFM_ACM:
 		case AFM_DSHOW: {
 		    int skip=sh_audio->wf->nBlockAlign;
Index: DOCS/codecs.html
===================================================================
RCS file: /cvsroot/mplayer/main/DOCS/codecs.html,v
retrieving revision 1.33
diff -u -r1.33 codecs.html
--- DOCS/codecs.html	20 Nov 2001 14:19:31 -0000	1.33
+++ DOCS/codecs.html	26 Nov 2001 15:18:41 -0000
@@ -206,7 +206,36 @@
 option. It may or may not work (experimental). (probably won't...)</P>
 
 
-<P><B><A NAME=2.2.2.2>2.2.2.2.  libmad support</A></B></P>
+<P><B><A NAME=2.2.2.2>2.2.2.2.  Software AC3 decoding to multichannel output</A></B></P>
+
+<P>This decoder provides separate output of all the AC3 channels to
+the soundcard driver, allowing the full "surround sound" experience
+without the external AC3 decoder required to use the hwac3 decoder.
+(In comparison, the standard ac3 codec downmixes the AC3 stream to
+stereo). </P>
+
+<P>Use the '-ac ac3surround' option to use this feature. </P>
+
+<P>To use it, you'll need to be using OSS, and to have a soundcard
+driver that supports setting 6 output channels via the
+SNDCTL_DSP_CHANNELS ioctl.  For example, a version of the emu10k1
+driver (used with the SB Live cards) newer than August 2001 should be
+suitable.  </P>
+
+<P>An SB Live 5.1 card was used for development of this feature.
+Older 4-channel SB Live cards should also work - though you will need
+to use emu-dspmgr to remap some of the channels in order to hear them
+all. </P>
+
+<P>More information, with some tips on using it with an SB Live card
+can be found <a href="sound-ac3.html">here</a>.
+</p>
+
+<P>This feature is currently
+experimental. </P>
+
+
+<P><B><A NAME=2.2.2.3>2.2.2.3.  libmad support</A></B></P>
 
 <P><A HREF="http://mad.sourceforge.net">libmad</A> is a multiplatform MPEG audio
 decoding library. If you don't know why is it good, you probably don't need it.</P>
@@ -215,7 +244,7 @@
 option.</P>
 
 
-<P><B><A NAME=2.2.2.3>2.2.2.3.  VIVO audio</A></B></P>
+<P><B><A NAME=2.2.2.4>2.2.2.4.  VIVO audio</A></B></P>
 
 <P>The audio codec used in VIVO files depends on whether it's a VIVO/1.0 or
 VIVO/2.0 file. VIVO/1.0 files have <B>g.723</B> audio, and VIVO/2.0 files
Index: DOCS/documentation.html
===================================================================
RCS file: /cvsroot/mplayer/main/DOCS/documentation.html,v
retrieving revision 1.119
diff -u -r1.119 documentation.html
--- DOCS/documentation.html	25 Nov 2001 16:27:13 -0000	1.119
+++ DOCS/documentation.html	26 Nov 2001 15:18:45 -0000
@@ -55,8 +55,9 @@
       <LI><A HREF="codecs.html#2.2.2">2.2.2 Audio</A></LI>
       <UL>
 	<LI><A HREF="codecs.html#2.2.2.1">2.2.2.1 Hardware AC3 decoding</A></LI>
-	<LI><A HREF="codecs.html#2.2.2.2">2.2.2.2 libmad support</A></LI>
-	<LI><A HREF="codecs.html#2.2.2.3">2.2.2.3 VIVO audio</A></LI>
+	<LI><A HREF="codecs.html#2.2.2.2">2.2.2.2 Software AC3 decoding to multichannel output</A></LI>
+	<LI><A HREF="codecs.html#2.2.2.3">2.2.2.3 libmad support</A></LI>
+	<LI><A HREF="codecs.html#2.2.2.4">2.2.2.4 VIVO audio</A></LI>
       </UL>
       <LI><A HREF="codecs.html#2.2.3">2.2.3 Win32 codec importing howto</A></LI>
       <UL>
Index: DOCS/mplayer.1
===================================================================
RCS file: /cvsroot/mplayer/main/DOCS/mplayer.1,v
retrieving revision 1.107
diff -u -r1.107 mplayer.1
--- DOCS/mplayer.1	11 Nov 2001 22:52:34 -0000	1.107
+++ DOCS/mplayer.1	26 Nov 2001 15:18:48 -0000
@@ -273,6 +273,8 @@
     -ac ac3        use AC3 codec
     -ac hwac3      enable Hardware AC3 passthrough
                    (see documentation)
+    -ac ac3surround enable full 5.1 AC3 decoding
+    		   (experimental, see documentation)
     -ac vorbis     use libvorbis
     -ac ffmp3      use ffmpeg's MP3 decoder (SLOW)
 
Index: etc/codecs.conf
===================================================================
RCS file: /cvsroot/mplayer/main/etc/codecs.conf,v
retrieving revision 1.89
diff -u -r1.89 codecs.conf
--- etc/codecs.conf	25 Nov 2001 17:32:38 -0000	1.89
+++ etc/codecs.conf	26 Nov 2001 15:18:49 -0000
@@ -757,7 +757,7 @@
   dll "uncompressed"
 
 audiocodec ac3
-  info "AC3"
+  info "AC3 stereo downmix"
   status working
   format 0x2000
   driver libac3
@@ -794,6 +794,13 @@
   format 0x2000
   driver hwac3
   dll "ac3-iec958.c"
+
+audiocodec ac3surround
+  info "AC3 surround"
+  status working
+  format 0x2000
+  driver ac3surround
+  dll "libac3"
 
 audiocodec vorbis
   info "OggVorbis Audio Decoder"
Index: libac3/decode.c
===================================================================
RCS file: /cvsroot/mplayer/main/libac3/decode.c,v
retrieving revision 1.7
diff -u -r1.7 decode.c
--- libac3/decode.c	14 Jul 2001 16:33:11 -0000	1.7
+++ libac3/decode.c	26 Nov 2001 15:18:50 -0000
@@ -62,9 +62,10 @@
 //the floating point samples for one audblk
 static stream_samples_t samples;
 
-//the integer samples for the entire frame (with enough space for 2 ch out)
-//if this size change, be sure to change the size when muting
-static int16_t s16_samples[2 * 6 * 256] __attribute__ ((aligned(16)));
+//the integer samples for the entire frame (with enough space for MAX_OUTPUT_CHANNELS ch out)
+//#define MAX_OUTPUT_CHANNELS 2
+#define MAX_OUTPUT_CHANNELS 6
+static int16_t s16_samples[6 * MAX_OUTPUT_CHANNELS * 256] __attribute__ ((aligned(16)));
 
 // downmix stuff
 static float cmixlev_lut[4] = { 0.707, 0.595, 0.500, 0.707 };
@@ -153,7 +154,7 @@
 decode_mute(void)
 {
 	//mute the frame
-	memset (s16_samples, 0, sizeof(int16_t) * 256 * 2 * 6);
+	memset (s16_samples, 0, sizeof(int16_t) * 256 * MAX_OUTPUT_CHANNELS * 6);
 	error_flag = 0;
 }
 
@@ -172,14 +173,15 @@
 	sanity_check_init(&syncinfo,&bsi,&audblk);
 	decode_mute();
 #if defined(HAVE_SSE)
-	printf("!! libac3"AC3VER": using SSE optimization\n");
+	printf("!! libac3"AC3VER": using SSE optimization");
 #elif defined(HAVE_3DNOWEX)
-	printf("!! libac3"AC3VER": using 3dNow-dsp! optimization\n");
+	printf("!! libac3"AC3VER": using 3dNow-dsp! optimization");
 #elif defined(HAVE_3DNOW)
-	printf("!! libac3"AC3VER": using 3dNow! optimization\n");
+	printf("!! libac3"AC3VER": using 3dNow! optimization");
 #else
-	printf("!! libac3"AC3VER": using FPU optimization\n");
+	printf("!! libac3"AC3VER": using FPU optimization");
 #endif
+	printf(", mixing to %d output channels\n", ac3_config.num_output_ch);
 }
 
 static ac3_frame_t ac3_frame;
@@ -205,8 +207,7 @@
 			done_banner = 1;
 		}
 
-		// compute downmix parameters
-		// downmix to tow channels for now
+		// compute downmix parameters - to be used for downmix to two channels
 		dm_par.clev = 0.0; dm_par.slev = 0.0; dm_par.unit = 1.0;
 		if (bsi.acmod & 0x1)	// have center
 			dm_par.clev = cmixlev_lut[bsi.cmixlev];
@@ -243,7 +244,11 @@
 				rematrix (&audblk,samples);
 
 			// Convert the frequency samples into time samples 
-			imdct (&bsi,&audblk,samples, &s16_samples[i * 2 * 256], &dm_par);
+			// Downmix at the same time...
+			imdct (&bsi,&audblk,samples,
+			       ac3_config.num_output_ch,
+			       &s16_samples[i*ac3_config.num_output_ch*256],
+			       &dm_par);
 
 			// Downmix into the requested number of channels
 			// and convert floating point to int16_t
@@ -262,4 +267,3 @@
 
 	return &ac3_frame;
 }
-
Index: libac3/imdct.c
===================================================================
RCS file: /cvsroot/mplayer/main/libac3/imdct.c,v
retrieving revision 1.8
diff -u -r1.8 imdct.c
--- libac3/imdct.c	10 Jul 2001 08:27:49 -0000	1.8
+++ libac3/imdct.c	26 Nov 2001 15:18:52 -0000
@@ -20,6 +20,9 @@
  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. 
  *
  *
+ *  Updated 2001-11-25 - Steve Davies <steve at daviesfam.org>:
+ *    - Added full 5.1 output
+ *    - Added decoding of lfe channel
  */
 
 #include <stdlib.h>
@@ -57,6 +60,9 @@
 static float delay[6][256] __attribute__((aligned(16)));
 static float delay1[6][256] __attribute__((aligned(16)));
 
+/* Buffer full of "silence" for output channels to be muted */
+static float silence[256] = {0.0};
+
 /* Windowing function for Modified DCT - Thank you acroread */
 static float window[] __attribute__((aligned(16))) = {
 	0.00014, 0.00024, 0.00037, 0.00051, 0.00067, 0.00086, 0.00107, 0.00130,
@@ -493,7 +499,30 @@
 ///#include <sys/time.h>
 //FIXME remove
 
-void imdct (bsi_t *bsi,audblk_t *audblk, stream_samples_t samples, int16_t *s16_samples, dm_par_t* dm_par)
+//FIXME:SLD:Optimize - specially for <5.1 cases - and all those pointers will mean too few
+//registers to go round (check generated code...)...
+void stream_sample_6ch_to_s16(int16_t *s16_samples,
+			      float *left, float *right,
+			      float *left_s, float *right_s,
+			      float *centre, float *lfe,
+			      float *delay_left, float *delay_right,
+			      float *delay_left_s, float *delay_right_s,
+			      float *delay_centre, float *delay_lfe)
+{
+  int i;
+
+  for (i=0; i<256; i++) {
+    *s16_samples++ = (int16_t)(*left++ + *delay_left++);
+    *s16_samples++ = (int16_t)(*right++ + *delay_right++);
+    *s16_samples++ = (int16_t)(*left_s++ + *delay_left_s++);
+    *s16_samples++ = (int16_t)(*right_s++ + *delay_right_s++);
+    *s16_samples++ = (int16_t)(*centre++ + *delay_centre++);
+    *s16_samples++ = (int16_t)(*lfe++ + *delay_lfe++);
+  }
+}
+
+void imdct (bsi_t *bsi,audblk_t *audblk, stream_samples_t samples,
+	    int num_output_channels, int16_t *s16_samples, dm_par_t* dm_par)
 {
 	int i;
 	int doable = 0;
@@ -501,21 +530,26 @@
 	float *delay_left, *delay_right;
 	float *delay1_left, *delay1_right, *delay1_center, *delay1_sr, *delay1_sl;
 	float right_tmp, left_tmp;
-	void (*do_imdct)(float data[], float deley[]);
+	float *lfe_samples, *lfe_delay;
+	void (*do_imdct)(float data[], float delay[]);
 
-	// test if dm in frequency is doable
-	if (!(doable = audblk->blksw[0]))
-		do_imdct = imdct_do_512;
-	else
-		do_imdct = imdct_do_256;
-
-	// downmix in the frequency domain if all the channels
-	// use the same imdct
-	for (i=0; i < bsi->nfchans; i++) {
-		if (doable != audblk->blksw[i]) {
-			do_imdct = NULL;
-			break;
-		}
+	if (num_output_channels > 2)
+		do_imdct = NULL;
+	else {
+		// test if dm in frequency is doable
+	  	if (!(doable = audblk->blksw[0]))
+			do_imdct = imdct_do_512;
+	  	else
+	        	do_imdct = imdct_do_256;
+
+		// downmix in the frequency domain if all the channels
+	  	// use the same imdct
+	  	for (i=0; i < bsi->nfchans; i++) {
+	    		if (doable != audblk->blksw[i]) {
+	      			do_imdct = NULL;
+	      			break;
+	    		}
+	  	}
 	}
 
 	if (do_imdct) {
@@ -565,7 +599,106 @@
 			else
 				imdct_do_512_nol (samples[i],delay1[i]);
 		}
-
+		//FIXME:SLD:Seems to get something.  Hard to tell if its right with few
+		//FIXME:SLD:5.1 disks and without a proper subwoofer.
+		if (bsi->lfeon && num_output_channels > 5) {
+		  //lfe channel:
+		  //Here's what liba52 does:
+		  //	if (state->output & A52_LFE) {
+		  //	    coeff_get (samples - 256, state->lf_exp, state->lfe_bap,
+		  //		       &quantizer, state->dynrng, 0, 7);
+		  //	    for (i = 7; i < 256; i++)
+		  //		(samples-256)[i] = 0;
+		  //	    imdct_512 (samples - 256, samples + 1536 - 256, state->bias);
+		  //We should already have top of the samples buffer as 0s 'cos its cleared above
+		  //presumably samples+1536 is equivalent of the delay buffer
+		  //So I think we want...:
+		  imdct_do_512_nol(samples[5], delay1[5]);
+		  lfe_samples = samples[5];  lfe_delay = delay[5];
+		}
+		else
+		  lfe_samples = lfe_delay = silence;
+		  
+
+		if (num_output_channels > 2) {
+		  if (num_output_channels != 6) {
+		    fprintf(stderr, "ac3surround: Error: no support yet for %d channel mix\n",
+			    num_output_channels);
+		    return;
+		  }
+		  // Upmix to 5.1
+		  switch(bsi->acmod) {
+		  case 7:	// 3/2
+		    stream_sample_6ch_to_s16(s16_samples,
+					     samples[0], samples[2],
+					     samples[3], samples[4],
+					     samples[1], lfe_samples,
+					     delay[0],   delay[2],
+					     delay[3],   delay[4],
+					     delay[1],   lfe_delay);
+		    break;
+		  case 6:	// 2/2
+		    stream_sample_6ch_to_s16(s16_samples,
+					     samples[0], samples[1],
+					     samples[2], samples[3],
+					     silence,    lfe_samples,
+					     delay[0],   delay[1],
+					     delay[2],   delay[3],
+					     silence,    lfe_delay);
+		    break;
+		  case 5:	// 3/1
+		    stream_sample_6ch_to_s16(s16_samples,
+					     samples[0], samples[2],
+					     samples[3], samples[3], //FIXME: Should one be inverted?
+					     samples[1], lfe_samples,
+					     delay[0],   delay[2],
+					     delay[3],   delay[3], //FIXME: Should one be inverted?
+					     delay[1],   lfe_delay);
+		    break;
+		  case 4:	// 2/1
+		    stream_sample_6ch_to_s16(s16_samples,
+					     samples[0], samples[1],
+					     samples[2], samples[2], //FIXME: Invert one?
+					     silence,    lfe_samples,
+					     delay[0],   delay[1],
+					     delay[2],   delay[2], //FIXME: Invert one?
+					     silence,    lfe_delay);
+		    break;
+		  case 3:	// 3/0
+		    stream_sample_6ch_to_s16(s16_samples,
+					     samples[0], samples[2],
+					     silence,    silence,
+					     samples[1], lfe_samples,
+					     delay[0],   delay[2],
+					     silence,    silence,
+					     delay[1],   lfe_delay);
+		    break;
+		  case 2:	// 2/0
+		    stream_sample_6ch_to_s16(s16_samples,
+					     samples[0], samples[1],
+					     silence,    silence,
+					     silence,    lfe_samples,
+					     delay[0],   delay[1],
+					     silence,    silence,
+					     silence,    lfe_delay);
+		    break;
+		  default:	// 1/0 or dual language
+		    {
+		      int i = (bsi->acmod) ? 0 : ac3_config.dual_mono_ch_sel;
+		      stream_sample_6ch_to_s16(s16_samples,
+					       samples[i], samples[i],
+					       silence,    silence,
+					       silence,    lfe_samples,
+					       delay[i],   delay[i],
+					       silence,    silence,
+					       silence,    lfe_delay);
+		    }
+		  }
+		  // And copy the delays  (optimize?)
+		  memcpy(&delay[0], &delay1[0], sizeof(float)*6*256);
+		}
+		else {
+	  	// Downmix to stereo:
 		// mix the sample, overlap
 		switch(bsi->acmod) {
 		case 7:		// 3/2
@@ -588,7 +721,7 @@
 				*s16_samples++ = (int16_t)(left_tmp + *delay_left);
 				*s16_samples++ = (int16_t)(right_tmp + *delay_right);
 				*delay_left++ = dm_par->unit * *delay1_left++  + dm_par->clev * *delay1_center  + dm_par->slev * *delay1_sl++;
-				*delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++ + dm_par->slev * *delay1_sr++;
+				*delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *delay1_center++ + dm_par->slev * *delay1_sr++;
 			}
 			break;
 		case 6:		// 2/2
@@ -630,7 +763,7 @@
 				*s16_samples++ = (int16_t)(left_tmp + *delay_left);
 				*s16_samples++ = (int16_t)(right_tmp + *delay_right);
 				*delay_left++ = dm_par->unit * *delay1_left++  + dm_par->clev * *delay1_center  + dm_par->slev * *delay1_sl;
-				*delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++ + dm_par->slev * *delay1_sl++;
+				*delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *delay1_center++ + dm_par->slev * *delay1_sl++;
 			}
 			break;
 		case 4:		// 2/1
@@ -668,12 +801,14 @@
 				*s16_samples++ = (int16_t)(left_tmp + *delay_left);
 				*s16_samples++ = (int16_t)(right_tmp + *delay_right);
 				*delay_left++ = dm_par->unit * *delay1_left++  + dm_par->clev * *delay1_center;
-				*delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *center++;
+				*delay_right++ = dm_par->unit * *delay1_right++ + dm_par->clev * *delay1_center++;
 			}
 			break;
 		case 2:		// copy to output
+			//FIXME:SLD:Don't think this is right - doesn't add in the delay1[] values...
 			stream_sample_2ch_to_s16(s16_samples,samples[0],samples[1]);
 			break;
-		}
-	}
+		} /* switch */
+		} /* else of if num_output_channels > 2 */
+	} /* else of if (do_imdct) */
 }
Index: libac3/imdct.h
===================================================================
RCS file: /cvsroot/mplayer/main/libac3/imdct.h,v
retrieving revision 1.1.1.1
diff -u -r1.1.1.1 imdct.h
--- libac3/imdct.h	24 Feb 2001 20:29:39 -0000	1.1.1.1
+++ libac3/imdct.h	26 Nov 2001 15:18:52 -0000
@@ -22,5 +22,5 @@
  *
  */
 
-void imdct (bsi_t *bsi,audblk_t *audblk, stream_samples_t samples, int16_t *s16_samples, dm_par_t *dm_par);
+void imdct (bsi_t *bsi,audblk_t *audblk, stream_samples_t samples, int num_output_channels, int16_t *s16_samples, dm_par_t *dm_par);
 void imdct_init(void);
Index: libac3/parse.c
===================================================================
RCS file: /cvsroot/mplayer/main/libac3/parse.c,v
retrieving revision 1.2
diff -u -r1.2 parse.c
--- libac3/parse.c	14 Jul 2001 16:33:11 -0000	1.2
+++ libac3/parse.c	26 Nov 2001 15:18:53 -0000
@@ -382,7 +382,7 @@
 			audblk->cplexps[i] = bitstream_get(7);
 	}
 
-	/* Get the fwb channel exponents */
+	/* Get the fbw channel exponents */
 	for(i=0;i < bsi->nfchans; i++) {
 		if(audblk->chexpstr[i] != EXP_REUSE) {
 			audblk->exps[i][0] = bitstream_get(4);			
@@ -442,7 +442,7 @@
 		}
 	}
 	
-	/* Get the delta bit alloaction info */
+	/* Get the delta bit allocation info */
 	audblk->deltbaie = bitstream_get(1);	
 	
 	if(audblk->deltbaie) {
Index: libao2/ao_oss.c
===================================================================
RCS file: /cvsroot/mplayer/main/libao2/ao_oss.c,v
retrieving revision 1.13
diff -u -r1.13 ao_oss.c
--- libao2/ao_oss.c	26 Nov 2001 11:30:35 -0000	1.13
+++ libao2/ao_oss.c	26 Nov 2001 15:18:53 -0000
@@ -26,6 +26,8 @@
 	""
 };
 
+/* Support for >2 output channels added 2001-11-25 - Steve Davies <steve at daviesfam.org> */
+
 LIBAO_EXTERN(oss)
 
 static char *dsp="/dev/dsp";
@@ -95,8 +97,8 @@
 // return: 1=success 0=fail
 static int init(int rate,int channels,int format,int flags){
 
-//  printf("ao2: %d Hz  %d chans  %s\n",rate,channels,
-//    audio_out_format_name(format));
+  printf("ao2: %d Hz  %d chans  %s\n",rate,channels,
+    audio_out_format_name(format));
 
   if (ao_subdevice)
     dsp = ao_subdevice;
@@ -124,13 +126,26 @@
     audio_out_format_name(ao_data.format), audio_out_format_name(format));
   
   if(format != AFMT_AC3) {
-  ao_data.channels=channels-1;
-  ioctl (audio_fd, SNDCTL_DSP_STEREO, &ao_data.channels);
-  
-  // set rate
-  ao_data.samplerate=rate;
-  ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
-  printf("audio_setup: using %d Hz samplerate (requested: %d)\n",ao_data.samplerate,rate);
+    // We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
+    ao_data.channels = channels;
+    if (ao_data.channels > 2) {
+      if (ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels) == -1) {
+	printf("audio_setup: Failed to set audio device to %d channels\n", ao_data.channels);
+	return 0;
+      }
+    }
+    else {
+      int c = ao_data.channels-1;
+      if (ioctl (audio_fd, SNDCTL_DSP_STEREO, &c) == -1) {
+	printf("audio_setup: Failed to set audio device to %d channels\n", ao_data.channels);
+	return 0;
+      }
+    }
+    printf("audio_setup: using %d channels (requested: %d)\n", ao_data.channels, ao_data.channels);
+    // set rate
+    ao_data.samplerate=rate;
+    ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
+    printf("audio_setup: using %d Hz samplerate (requested: %d)\n",ao_data.samplerate,rate);
   }
 
   if(ioctl(audio_fd, SNDCTL_DSP_GETOSPACE, &zz)==-1){
@@ -195,8 +210,13 @@
 
   ioctl (audio_fd, SNDCTL_DSP_SETFMT, &ao_data.format);
   if(ao_data.format != AFMT_AC3) {
-  ioctl (audio_fd, SNDCTL_DSP_STEREO, &ao_data.channels);
-  ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
+    if (ao_data.channels > 2)
+      ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels);
+    else {
+      int c = ao_data.channels-1;
+      ioctl (audio_fd, SNDCTL_DSP_STEREO, &c);
+    }
+    ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
   }
 }
 
@@ -267,7 +287,3 @@
   }
   return ((float)ao_data.buffersize)/(float)ao_data.bps;
 }
-
-
-
-
? libavcodec/.depend
? libavcodec/README


More information about the MPlayer-dev-eng mailing list