[MPlayer-dev-eng] [PATCH] add support for AC3 endianness

Reimar Döffinger Reimar.Doeffinger at stud.uni-karlsruhe.de
Thu Nov 15 13:02:09 CET 2007


Hello,
On Sun, Sep 16, 2007 at 11:50:42AM +0200, Reimar Döffinger wrote:
> attached patch distinguishes between BE and LE AC3, getting rid of the
> duplicate endianness conversion in ad_hwac3.c.
> The disadvantage is a slightly higher CPU because the format filter will
> swap even the 0-bytes at the end.

Some very minor updates.
Complete bugreports welcome.

Greetings,
Reimar Döffinger
-------------- next part --------------
Index: libmpcodecs/ad_hwac3.c
===================================================================
--- libmpcodecs/ad_hwac3.c	(revision 25054)
+++ libmpcodecs/ad_hwac3.c	(working copy)
@@ -20,6 +20,7 @@
 #include "ad_internal.h"
 
 #include "liba52/a52.h"
+#include "libavutil/intreadwrite.h"
 
 
 static int isdts = -1;
@@ -106,7 +107,7 @@
   sh->audio_in_minsize = 8192;
   sh->channels = 2;
   sh->samplesize = 2;
-  sh->sample_format = AF_FORMAT_AC3;
+  sh->sample_format = AF_FORMAT_AC3_BE;
   return 1;
 }
 
@@ -159,22 +160,12 @@
   }
   else if(isdts == 0)
   {
-    uint16_t *buf16 = (uint16_t *)buf;
-    buf16[0] = 0xF872;   // iec 61937 syncword 1
-    buf16[1] = 0x4E1F;   // iec 61937 syncword 2
-    buf16[2] = 0x0001;   // data-type ac3
-    buf16[2] |= (sh_audio->a_in_buffer[5] & 0x7) << 8; // bsmod
-    buf16[3] = len << 3; // number of bits in payload
-#ifdef WORDS_BIGENDIAN
+    AV_WB16(buf    , 0xF872);   // iec 61937 syncword 1
+    AV_WB16(buf + 2, 0x4E1F);   // iec 61937 syncword 2
+    buf[4] = sh_audio->a_in_buffer[5] & 0x7; // bsmod
+    buf[5] = 0x01;              // data-type ac3
+    AV_WB16(buf + 6, len << 3); // number of bits in payload
     memcpy(buf + 8, sh_audio->a_in_buffer, len);
-#else
-    swab(sh_audio->a_in_buffer, buf + 8, len);
-    if (len & 1) {
-      buf[8+len-1] = 0;
-      buf[8+len] = sh_audio->a_in_buffer[len-1];
-      len++;
-    }
-#endif
     memset(buf + 8 + len, 0, 6144 - 8 - len);
 
     return 6144;
@@ -330,7 +321,6 @@
   int sfreq;
   int burst_len;
   int nr_samples;
-  uint16_t *buf16 = (uint16_t *)buf;
 
   fsize = dts_decode_header(indata_ptr, &rate, &nblks, &sfreq);
   if(fsize < 0)
@@ -339,40 +329,31 @@
   burst_len = fsize * 8;
   nr_samples = nblks * 32;
 
-  buf16[0] = 0xf872; /* iec 61937     */
-  buf16[1] = 0x4e1f; /*  syncword     */
+  AV_WB16(buf    , 0xf872); /* iec 61937     */
+  AV_WB16(buf + 2, 0x4e1f); /*  syncword     */
   switch(nr_samples) 
   {
   case 512:
-    buf16[2] = 0x000b;      /* DTS-1 (512-sample bursts) */
+    AV_WB16(buf + 4, 0x000b);      /* DTS-1 (512-sample bursts) */
     break;
   case 1024:
-    buf16[2] = 0x000c;      /* DTS-2 (1024-sample bursts) */
+    AV_WB16(buf + 4, 0x000c);      /* DTS-2 (1024-sample bursts) */
     break;
   case 2048:
-    buf16[2] = 0x000d;      /* DTS-3 (2048-sample bursts) */
+    AV_WB16(buf + 4, 0x000d);      /* DTS-3 (2048-sample bursts) */
     break;
   default:
     mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DTS: %d-sample bursts not supported\n", nr_samples);
-    buf16[2] = 0x0000;
+    AV_WB16(buf + 4, 0x0000);
     break;
   }
-  buf16[3] = burst_len;
+  AV_WB16(buf + 6, burst_len);
  
   if(fsize + 8 > nr_samples * 2 * 2)
   {
     mp_msg(MSGT_DECAUDIO, MSGL_ERR, "DTS: more data than fits\n");
   }
-#ifdef WORDS_BIGENDIAN
   memcpy(&buf[8], indata_ptr, fsize);
-#else
-  swab(indata_ptr, &buf[8], fsize);
-  if (fsize & 1) {
-    buf[8+fsize-1] = 0;
-    buf[8+fsize] = indata_ptr[fsize-1];
-    fsize++;
-  }
-#endif
   memset(&buf[fsize + 8], 0, nr_samples * 2 * 2 - (fsize + 8));
 
   return nr_samples * 2 * 2;
Index: m_option.c
===================================================================
--- m_option.c	(revision 25054)
+++ m_option.c	(working copy)
@@ -1113,7 +1113,9 @@
   {"mulaw", AF_FORMAT_MU_LAW},
   {"alaw", AF_FORMAT_A_LAW},
   {"mpeg2", AF_FORMAT_MPEG2},
-  {"ac3", AF_FORMAT_AC3},
+  {"ac3le", AF_FORMAT_AC3_LE},
+  {"ac3be", AF_FORMAT_AC3_BE},
+  {"ac3ne", AF_FORMAT_AC3_NE},
   {"imaadpcm", AF_FORMAT_IMA_ADPCM},
   // ORIDNARY
   {"u8", AF_FORMAT_U8},
Index: libao2/ao_dxr2.c
===================================================================
--- libao2/ao_dxr2.c	(revision 25054)
+++ libao2/ao_dxr2.c	(working copy)
@@ -181,7 +181,7 @@
   // MPEG and AC3 don't work :-(
     if(ao_data.format==AF_FORMAT_MPEG2)
       send_mpeg_ps_packet (data, len, 0xC0, ao_data.pts, 2, write_dxr2);
-    else if(ao_data.format==AF_FORMAT_AC3)
+    else if(AF_FORMAT_IS_AC3(ao_data.format))
       send_mpeg_ps_packet (data, len, 0x80, ao_data.pts, 2, write_dxr2);
     else {
 	int i;
Index: libao2/ao_alsa.c
===================================================================
--- libao2/ao_alsa.c	(revision 25054)
+++ libao2/ao_alsa.c	(working copy)
@@ -136,7 +136,7 @@
       }
       if(mixer_device) card = mixer_device;
 
-      if(ao_data.format == AF_FORMAT_AC3)
+      if(AF_FORMAT_IS_AC3(ao_data.format))
 	return CONTROL_TRUE;
 
       //allocate simple id
@@ -353,15 +353,11 @@
       case AF_FORMAT_U16_BE:
 	alsa_format = SND_PCM_FORMAT_U16_BE;
 	break;
-#ifndef WORDS_BIGENDIAN
-      case AF_FORMAT_AC3:
-#endif
+      case AF_FORMAT_AC3_LE:
       case AF_FORMAT_S16_LE:
 	alsa_format = SND_PCM_FORMAT_S16_LE;
 	break;
-#ifdef WORDS_BIGENDIAN
-      case AF_FORMAT_AC3:
-#endif
+      case AF_FORMAT_AC3_BE:
       case AF_FORMAT_S16_BE:
 	alsa_format = SND_PCM_FORMAT_S16_BE;
 	break;
@@ -404,7 +400,7 @@
      * while opening the abstract alias for the spdif subdevice
      * 'iec958'
      */
-    if (format == AF_FORMAT_AC3) {
+    if (AF_FORMAT_IS_AC3(format)) {
 	device.str = "iec958";
 	mp_msg(MSGT_AO,MSGL_V,"alsa-spdif-init: playing AC3, %i channels\n", channels);
     }
@@ -491,12 +487,13 @@
     }
 
     if (!alsa_handler) {
+      int isac3 =  AF_FORMAT_IS_AC3(format);
       //modes = 0, SND_PCM_NONBLOCK, SND_PCM_ASYNC
-      if ((err = try_open_device(alsa_device, open_mode, format == AF_FORMAT_AC3)) < 0)
+      if ((err = try_open_device(alsa_device, open_mode, isac3)) < 0)
 	{
 	  if (err != -EBUSY && ao_noblock) {
 	    mp_msg(MSGT_AO,MSGL_INFO,MSGTR_AO_ALSA_OpenInNonblockModeFailed);
-	    if ((err = try_open_device(alsa_device, 0, format == AF_FORMAT_AC3)) < 0) {
+	    if ((err = try_open_device(alsa_device, 0, isac3)) < 0) {
 	      mp_msg(MSGT_AO,MSGL_ERR,MSGTR_AO_ALSA_PlaybackOpenError, snd_strerror(err));
 	      return(0);
 	    }
@@ -539,6 +536,9 @@
          mp_msg(MSGT_AO,MSGL_INFO,
 		MSGTR_AO_ALSA_FormatNotSupportedByHardware, af_fmt2str_short(format));
          alsa_format = SND_PCM_FORMAT_S16_LE;
+         if (AF_FORMAT_IS_AC3(ao_data.format))
+           ao_data.format = AF_FORMAT_AC3_LE;
+         else
          ao_data.format = AF_FORMAT_S16_LE;
       }
 
Index: libao2/ao_dsound.c
===================================================================
--- libao2/ao_dsound.c	(revision 25054)
+++ libao2/ao_dsound.c	(working copy)
@@ -324,7 +324,7 @@
   
   if (SUCCEEDED(res)) 
   {
-  	if( (ao_data.channels == 6) && (ao_data.format!=AF_FORMAT_AC3) ) {
+  	if( (ao_data.channels == 6) && (ao_data.format!=AF_FORMAT_AC3_NE) ) {
   	    // reorder channels while writing to pointers.
   	    // it's this easy because buffer size and len are always
   	    // aligned to multiples of channels*bytespersample
@@ -423,9 +423,11 @@
 	DSBUFFERDESC dsbpridesc;
 	DSBUFFERDESC dsbdesc;
 
+	if (AF_FORMAT_IS_AC3(format))
+	  format = AF_FORMAT_AC3_NE;
 	//check if the format is supported in general
 	switch(format){
-		case AF_FORMAT_AC3:
+		case AF_FORMAT_AC3_NE:
 		case AF_FORMAT_S24_LE:
 		case AF_FORMAT_S16_LE:
 		case AF_FORMAT_S8:
@@ -448,7 +450,7 @@
 	wformat.Format.cbSize          = (channels > 2) ? sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX) : 0;
 	wformat.Format.nChannels       = channels;
 	wformat.Format.nSamplesPerSec  = rate;
-	if (format == AF_FORMAT_AC3) {
+	if (format == AF_FORMAT_AC3_NE) {
 		wformat.Format.wFormatTag      = WAVE_FORMAT_DOLBY_AC3_SPDIF;
 		wformat.Format.wBitsPerSample  = 16;
 		wformat.Format.nBlockAlign     = 4;
Index: libao2/ao_mpegpes.c
===================================================================
--- libao2/ao_mpegpes.c	(revision 25054)
+++ libao2/ao_mpegpes.c	(working copy)
@@ -219,9 +219,12 @@
     switch(format){
 	case AF_FORMAT_S16_BE:
 	case AF_FORMAT_MPEG2:
-	case AF_FORMAT_AC3:
+	case AF_FORMAT_AC3_BE:
 	    ao_data.format=format;
 	    break;
+        case AF_FORMAT_AC3_LE:
+	    ao_data.format=AF_FORMAT_AC3_BE;
+	    break;
 	default:
 	    ao_data.format=AF_FORMAT_S16_BE;
     }
@@ -302,8 +305,6 @@
 	unsigned short *s=data;
 //	if(len>2000) len=2000;
 //	printf("ao_mpegpes: len=%d  \n",len);
-	if(ao_data.format==AF_FORMAT_AC3)
-	    for(i=0;i<len/2;i++) s[i]=(s[i]>>8)|(s[i]<<8); // le<->be
 	send_mpeg_lpcm_packet(data, len, 0xA0, ao_data.pts, freq_id, my_ao_write);
     }
     return len;
Index: libao2/ao_win32.c
===================================================================
--- libao2/ao_win32.c	(revision 25054)
+++ libao2/ao_win32.c	(working copy)
@@ -149,8 +149,10 @@
 	unsigned char* buffer;
 	int i;
    
+        if (AF_FORMAT_IS_AC3(format))
+          format = AF_FORMAT_AC3_NE;
 	switch(format){
-		case AF_FORMAT_AC3:
+		case AF_FORMAT_AC3_NE:
 		case AF_FORMAT_S24_LE:
 		case AF_FORMAT_S16_LE:
 		case AF_FORMAT_S8:
@@ -185,7 +187,7 @@
     wformat.Format.cbSize          = (channels>2)?sizeof(WAVEFORMATEXTENSIBLE)-sizeof(WAVEFORMATEX):0;
     wformat.Format.nChannels       = channels;                
     wformat.Format.nSamplesPerSec  = rate;            
-    if(format == AF_FORMAT_AC3)
+    if(format == AF_FORMAT_AC3_NE)
     {
         wformat.Format.wFormatTag      = WAVE_FORMAT_DOLBY_AC3_SPDIF;
         wformat.Format.wBitsPerSample  = 16;
Index: libao2/ao_oss.c
===================================================================
--- libao2/ao_oss.c	(revision 25054)
+++ libao2/ao_oss.c	(working copy)
@@ -85,7 +85,7 @@
     case AF_FORMAT_MPEG2: return AFMT_MPEG;
 #endif
 #ifdef AFMT_AC3
-    case AF_FORMAT_AC3: return AFMT_AC3;
+    case AF_FORMAT_AC3_NE: return AFMT_AC3;
 #endif
     }
     mp_msg(MSGT_AO, MSGL_V, "OSS: Unknown/not supported internal format: %s\n", af_fmt2str_short(format));
@@ -137,7 +137,7 @@
     case AFMT_MPEG: return AF_FORMAT_MPEG2;
 #endif
 #ifdef AFMT_AC3
-    case AFMT_AC3: return AF_FORMAT_AC3;
+    case AFMT_AC3: return AF_FORMAT_AC3_NE;
 #endif
     }
     mp_msg(MSGT_GLOBAL,MSGL_ERR,MSGTR_AO_OSS_UnknownUnsupportedFormat, format);
@@ -177,7 +177,7 @@
 	    ao_control_vol_t *vol = (ao_control_vol_t *)arg;
 	    int fd, v, devs;
 
-	    if(ao_data.format == AF_FORMAT_AC3)
+	    if(ao_data.format == AF_FORMAT_AC3_NE)
 		return CONTROL_TRUE;
     
 	    if ((fd = open(oss_mixer_device, O_RDONLY)) > 0)
@@ -295,12 +295,14 @@
   fcntl(audio_fd, F_SETFD, FD_CLOEXEC);
 #endif
   
-  if(format == AF_FORMAT_AC3) {
+  if(format == AF_FORMAT_AC3_NE) {
     ao_data.samplerate=rate;
     ioctl (audio_fd, SNDCTL_DSP_SPEED, &ao_data.samplerate);
   }
 
 ac3_retry:  
+  if (AF_FORMAT_IS_AC3(format))
+    format = AF_FORMAT_AC3_NE;
   ao_data.format=format;
   oss_format=format2oss(format);
   if (oss_format == -1) {
@@ -330,7 +332,7 @@
     af_fmt2str_short(ao_data.format), af_fmt2str_short(format));
   
   ao_data.channels = channels;
-  if(format != AF_FORMAT_AC3) {
+  if(format != AF_FORMAT_AC3_NE) {
     // We only use SNDCTL_DSP_CHANNELS for >2 channels, in case some drivers don't have it
     if (ao_data.channels > 2) {
       if ( ioctl(audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels) == -1 ||
@@ -435,7 +437,7 @@
 
   oss_format = format2oss(ao_data.format);
   ioctl (audio_fd, SNDCTL_DSP_SETFMT, &oss_format);
-  if(ao_data.format != AF_FORMAT_AC3) {
+  if(ao_data.format != AF_FORMAT_AC3_NE) {
     if (ao_data.channels > 2)
       ioctl (audio_fd, SNDCTL_DSP_CHANNELS, &ao_data.channels);
     else {
Index: libao2/ao_alsa5.c
===================================================================
--- libao2/ao_alsa5.c	(revision 25054)
+++ libao2/ao_alsa5.c	(working copy)
@@ -87,15 +87,11 @@
 	case AF_FORMAT_U16_BE:
 	    alsa_format.format = SND_PCM_SFMT_U16_BE;
 	    break;
-#ifndef WORDS_BIGENDIAN
-	case AF_FORMAT_AC3:
-#endif
+	case AF_FORMAT_AC3_LE:
 	case AF_FORMAT_S16_LE:
 	    alsa_format.format = SND_PCM_SFMT_S16_LE;
 	    break;
-#ifdef WORDS_BIGENDIAN
-	case AF_FORMAT_AC3:
-#endif
+	case AF_FORMAT_AC3_BE:
 	case AF_FORMAT_S16_BE:
 	    alsa_format.format = SND_PCM_SFMT_S16_BE;
 	    break;
Index: libaf/af_format.c
===================================================================
--- libaf/af_format.c	(revision 25054)
+++ libaf/af_format.c	(working copy)
@@ -91,6 +91,8 @@
        af->data->bps == data->bps)
       return AF_DETACH;
 
+    // Allow trivial AC3-endianness conversion
+    if (!AF_FORMAT_IS_AC3(af->data->format) || !AF_FORMAT_IS_AC3(data->format))
     // Check for errors in configuration
     if((AF_OK != check_bps(data->bps)) ||
        (AF_OK != check_format(data->format)) ||
@@ -145,7 +147,7 @@
   }
   case AF_CONTROL_FORMAT_FMT | AF_CONTROL_SET:{
     // Check for errors in configuration
-    if(AF_OK != check_format(*(int*)arg))
+    if(!AF_FORMAT_IS_AC3(*(int*)arg) && AF_OK != check_format(*(int*)arg))
       return AF_ERROR;
 
     af->data->format = *(int*)arg;
Index: libaf/af_format.h
===================================================================
--- libaf/af_format.h	(revision 25054)
+++ libaf/af_format.h	(working copy)
@@ -66,6 +71,9 @@
 #define AF_FORMAT_FLOAT_LE	(AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_LE)
 #define AF_FORMAT_FLOAT_BE	(AF_FORMAT_F|AF_FORMAT_32BIT|AF_FORMAT_BE)
 
+#define AF_FORMAT_AC3_LE	(AF_FORMAT_AC3|AF_FORMAT_LE)
+#define AF_FORMAT_AC3_BE	(AF_FORMAT_AC3|AF_FORMAT_BE)
+
 #ifdef WORDS_BIGENDIAN
 #define AF_FORMAT_U16_NE AF_FORMAT_U16_BE
 #define AF_FORMAT_S16_NE AF_FORMAT_S16_BE
@@ -74,6 +82,7 @@
 #define AF_FORMAT_U32_NE AF_FORMAT_U32_BE
 #define AF_FORMAT_S32_NE AF_FORMAT_S32_BE
 #define AF_FORMAT_FLOAT_NE AF_FORMAT_FLOAT_BE
+#define AF_FORMAT_AC3_NE AF_FORMAT_AC3_BE
 #else
 #define AF_FORMAT_U16_NE AF_FORMAT_U16_LE
 #define AF_FORMAT_S16_NE AF_FORMAT_S16_LE
@@ -82,10 +91,13 @@
 #define AF_FORMAT_U32_NE AF_FORMAT_U32_LE
 #define AF_FORMAT_S32_NE AF_FORMAT_S32_LE
 #define AF_FORMAT_FLOAT_NE AF_FORMAT_FLOAT_LE
+#define AF_FORMAT_AC3_NE AF_FORMAT_AC3_LE
 #endif
 
 #define AF_FORMAT_UNKNOWN (-1)
 
+#define AF_FORMAT_IS_AC3(fmt) (((fmt) & AF_FORMAT_SPECIAL_MASK) == AF_FORMAT_AC3)
+
 extern int af_str2fmt(const char *str);
 extern int af_str2fmt_short(const char *str);
 extern int af_fmt2bits(int format);
Index: libaf/format.c
===================================================================
--- libaf/format.c	(revision 25054)
+++ libaf/format.c	(working copy)
@@ -64,6 +64,7 @@
 
 int af_fmt2bits(int format)
 {
+    if (AF_FORMAT_IS_AC3(format)) return 16;
     return (format & AF_FORMAT_BITS_MASK)+8;
 //    return (((format & AF_FORMAT_BITS_MASK)>>3)+1) * 8;
 #if 0
@@ -147,7 +148,9 @@
     { "mulaw", AF_FORMAT_MU_LAW },
     { "alaw", AF_FORMAT_A_LAW },
     { "mpeg2", AF_FORMAT_MPEG2 },
-    { "ac3", AF_FORMAT_AC3 },
+    { "ac3le", AF_FORMAT_AC3_LE },
+    { "ac3be", AF_FORMAT_AC3_BE },
+    { "ac3ne", AF_FORMAT_AC3_NE },
     { "imaadpcm", AF_FORMAT_IMA_ADPCM },
 
     { "u8", AF_FORMAT_U8 },


More information about the MPlayer-dev-eng mailing list