[MPlayer-dev-eng] AC3-surround - patch version 2

Stephen Davies steve at daviesfam.org
Tue Nov 27 23:08:47 CET 2001


Hi,

Here's a second version of the ac3-surround patch.

I've added a 4 channel downmix.  To use it:

  "-ac ac3surround -ac3channels 4"

I haven't done anything about the overflow problem with the canyon clip in
6 channel mode - I could just scale everything down a bit but I'm a bit
reluctant to add all those extra float multiplies.  I didn't hear the
problem with my other "real life" ac3 streams, and Felix already notes it
doesn't happen with a52dec.

Because of the scaling done in mixing the centre channel to the front, the
4 channel downmix only has the overflow issue in the rear channels.

I'd like to put this all in the CVS - at least as a "taster" for the
liba52 stuff to come.  Agreed?

One last question though - with the addition of the -ac3channels option,
there is no need for the "separate" ac3surround codec.  The only
difference between the two is that the number of channels is forced to 2
for the ac3 case, allowed to be 2..6 for the ac3surround case.  Shall I
merge the two together?  Then users can just add "-ac3channels 4|6" and
ac3 streams will automatically play in surround without affecting others.

Steve
-------------- next part --------------
? fibmap_mplayer
? DOCS/sound-ac3.html
Index: cfg-mplayer.h
===================================================================
RCS file: /cvsroot/mplayer/main/cfg-mplayer.h,v
retrieving revision 1.104
diff -u -r1.104 cfg-mplayer.h
--- cfg-mplayer.h	25 Nov 2001 14:29:50 -0000	1.104
+++ cfg-mplayer.h	27 Nov 2001 22:03:00 -0000
@@ -74,6 +74,9 @@
 /* from libvo/aspect.c */
 extern float monitor_aspect;
 
+/* from dec_audio, currently used for ac3surround decoder only */
+extern int audio_output_channels;
+
 /*
  * CONF_TYPE_FUNC_FULL :
  * allows own implemtations for passing the params
@@ -103,6 +106,7 @@
 	{"dsp", "Use -ao oss:dsp_path!\n", CONF_TYPE_PRINT, CONF_NOCFG, 0, 0},
         {"mixer", &mixer_device, CONF_TYPE_STRING, 0, 0, 0},
         {"master", &mixer_usemaster, CONF_TYPE_FLAG, 0, 0, 1},
+	{"ac3channels", &audio_output_channels, CONF_TYPE_INT, CONF_RANGE, 2, 6},
 #ifdef HAVE_X11
 	{"display", &mDisplayName, CONF_TYPE_STRING, 0, 0, 0},
 #endif
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	27 Nov 2001 22:03:02 -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	27 Nov 2001 22:03:02 -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.52
diff -u -r1.52 dec_audio.c
--- dec_audio.c	26 Nov 2001 21:55:22 -0000	1.52
+++ dec_audio.c	27 Nov 2001 22:03:04 -0000
@@ -83,6 +83,9 @@
 static struct mad_frame  mad_frame;
 static struct mad_synth  mad_synth;
 
+/* used for ac3surround decoder - set using -channels option */
+int audio_output_channels = 6;
+
 
 // ensure buffer is filled with some data
 static void mad_prepare_buffer(sh_audio_t* sh_audio, struct mad_stream* ms, int length)
@@ -228,7 +231,12 @@
   break;
 case AFM_AC3:
   // Dolby AC3 audio:
-  sh_audio->audio_out_minsize=4*256*6;
+  audio_output_channels = 2;
+  /* fallthrough: */
+case AFM_AC3SURROUND:
+  // Dolby AC3 audio, but not necessarily stereo downmix
+  // however many channels, 2 bytes in a word, 256 samples in a block, 6 blocks in a frame
+  sh_audio->audio_out_minsize=audio_output_channels*2*256*6;
   break;
 case AFM_HWAC3:
   // Dolby AC3 audio:
@@ -325,11 +333,12 @@
 //    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;
+  ac3_config.num_output_ch = (driver == AFM_AC3SURROUND) ? audio_output_channels : 2;
   ac3_config.flags = 0;
 if(gCpuCaps.hasMMX){
   ac3_config.flags |= AC3_MMX_ENABLE;
@@ -342,7 +351,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);
@@ -833,6 +842,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);
@@ -939,6 +949,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
@@ -964,7 +975,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: help_mp-en.h
===================================================================
RCS file: /cvsroot/mplayer/main/help_mp-en.h,v
retrieving revision 1.13
diff -u -r1.13 help_mp-en.h
--- help_mp-en.h	25 Nov 2001 00:01:13 -0000	1.13
+++ help_mp-en.h	27 Nov 2001 22:03:08 -0000
@@ -33,6 +33,7 @@
 #ifdef USE_FAKE_MONO
 " -stereo <mode>  select MPEG1 stereo output (0:stereo 1:left 2:right)\n"
 #endif
+" -ac3channels <n> tell ac3surround codec target number of output channels\n"
 " -fs -vm -zoom   fullscreen playing options (fullscr,vidmode chg,softw.scale)\n"
 " -x <x> -y <y>   scale image to <x> * <y> resolution [if -vo driver supports!]\n"
 " -sub <file>     specify subtitle file to use (see also -subfps, -subdelay)\n"
Index: DOCS/codecs.html
===================================================================
RCS file: /cvsroot/mplayer/main/DOCS/codecs.html,v
retrieving revision 1.35
diff -u -r1.35 codecs.html
--- DOCS/codecs.html	27 Nov 2001 18:09:44 -0000	1.35
+++ DOCS/codecs.html	27 Nov 2001 22:03:09 -0000
@@ -217,7 +217,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>
@@ -226,7 +255,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.120
diff -u -r1.120 documentation.html
--- DOCS/documentation.html	27 Nov 2001 18:09:44 -0000	1.120
+++ DOCS/documentation.html	27 Nov 2001 22:03:11 -0000
@@ -56,8 +56,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	27 Nov 2001 22:03:12 -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	27 Nov 2001 22:03:14 -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	27 Nov 2001 22:03:15 -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	27 Nov 2001 22:03:17 -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,42 @@
 ///#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, int num_output_channels, dm_par_t *dm_par,
+			      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;
+
+  if (num_output_channels == 4) {
+    for (i=0; i<256; i++) {
+      *s16_samples++ = (int16_t)( (*left++ + *delay_left++)     * dm_par->unit +
+			          (*centre + *delay_centre)     * dm_par->clev );
+      *s16_samples++ = (int16_t)( (*right++ + *delay_right++)   * dm_par->unit +
+				  (*centre++ + *delay_centre++) * dm_par->clev );
+      *s16_samples++ = (int16_t)(*left_s++ + *delay_left_s++);
+      *s16_samples++ = (int16_t)(*right_s++ + *delay_right_s++);
+    }
+  }
+  else {
+    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 +542,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 +611,105 @@
 			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 != 4 && num_output_channels != 6) {
+		    fprintf(stderr, "*** ERROR: %d channel mix not yet supported ***\n", num_output_channels);
+		    return;
+		  }
+		  //  multichannel mix:
+		  switch(bsi->acmod) {
+		  case 7:	// 3/2
+		    stream_sample_6ch_to_s16(s16_samples, num_output_channels, dm_par,
+					     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, num_output_channels, dm_par,
+					     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, num_output_channels, dm_par,
+					     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, num_output_channels, dm_par,
+					     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, num_output_channels, dm_par,
+					     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, num_output_channels, dm_par,
+					     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, num_output_channels, dm_par,
+					       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 +732,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 +774,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 +812,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	27 Nov 2001 22:03:17 -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	27 Nov 2001 22:03:18 -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	27 Nov 2001 22:03:18 -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