Optimized libmad_output() for smoother sound. It is still not optimal.
authorJean-Paul Saman <jpsaman@videolan.org>
Sun, 6 Jan 2002 14:46:40 +0000 (14:46 +0000)
committerJean-Paul Saman <jpsaman@videolan.org>
Sun, 6 Jan 2002 14:46:40 +0000 (14:46 +0000)
plugins/mad/mad_adec.c
plugins/mad/mad_libmad.c

index b3190f8..d84fad2 100644 (file)
@@ -69,7 +69,7 @@ MODULE_CONFIG_STOP
 
 MODULE_INIT_START
     SET_DESCRIPTION( "Libmad MPEG 1/2/3 audio decoder library" )
-    ADD_CAPABILITY( DECODER, 50 )
+    ADD_CAPABILITY( DECODER, 950 )
 MODULE_INIT_STOP
 
 MODULE_ACTIVATE_START
@@ -180,10 +180,10 @@ static int InitThread( mad_adec_thread_t * p_mad_adec )
     mad_decoder_init( p_mad_adec->libmad_decoder,
                      p_mad_adec,       /* vlc's thread structure and p_fifo playbuffer */
                      libmad_input,     /* input_func */
-                     libmad_header,    /* header_func */
+                     0,                /* header_func */
                      0,                /* filter */
                      libmad_output,    /* output_func */
-                     0,        /* error */
+                     0,                /* error */
                      0);               /* message */
 
     mad_decoder_options(p_mad_adec->libmad_decoder, MAD_OPTION_IGNORECRC);
@@ -231,9 +231,8 @@ static void EndThread (mad_adec_thread_t * p_mad_adec)
     /* mad_decoder_finish releases the memory allocated inside the struct */
     mad_decoder_finish( p_mad_adec->libmad_decoder );
 
-    /* Unlock the modules */
+    /* Unlock the modules, p_mad_adec->p_config is released by the decoder subsystem  */
     free( p_mad_adec->libmad_decoder );
-//    free( p_mad_adec->p_config ); /* for now a reminder until integration with cvs */
     free( p_mad_adec );
 
     intf_ErrMsg ("mad_adec debug: mad decoder thread %p destroyed", p_mad_adec);
index 8164235..fcd1cbc 100644 (file)
@@ -36,7 +36,6 @@
 /*****************************************************************************
  * Libmad includes files
  *****************************************************************************/
-
 #include <mad.h>
 #include "mad_adec.h"
 #include "mad_libmad.h"
@@ -81,21 +80,18 @@ enum mad_flow libmad_input(void *data, struct mad_stream *p_libmad_stream)
  * libmad_header: this function is called just after the header of a frame is
  * decoded
  *****************************************************************************/
-enum mad_flow libmad_header(void *data, struct mad_header const *p_libmad_header)
-{
-    mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data;
-
-    vlc_mutex_lock (&p_mad_adec->p_aout_fifo->data_lock);
-/*
-    intf_ErrMsg( "mad_adec: libmad_header samplerate %d", p_libmad_header->samplerate);
-       intf_DbgMsg( "mad_adec: libmad_header bitrate %d", p_libmad_header->bitrate);   
-*/
-    p_mad_adec->p_aout_fifo->l_rate = p_libmad_header->samplerate;
-    vlc_cond_signal (&p_mad_adec->p_aout_fifo->data_wait);
-    vlc_mutex_unlock (&p_mad_adec->p_aout_fifo->data_lock);
-
-    return MAD_FLOW_CONTINUE;
-}
+/* enum mad_flow libmad_header(void *data, struct mad_header const *p_libmad_header)
+ * {
+ *   mad_adec_thread_t *p_mad_adec = (mad_adec_thread_t *) data;
+ *
+ *   intf_ErrMsg( "mad_adec: libmad_header samplerate %d", p_libmad_header->samplerate);
+ *   intf_DbgMsg( "mad_adec: libmad_header bitrate %d", p_libmad_header->bitrate);     
+ *
+ *   p_mad_adec->p_aout_fifo->l_rate = p_libmad_header->samplerate;
+ *
+ *   return MAD_FLOW_CONTINUE;
+ * }
+ */
 
 /*****************************************************************************
  * lib_mad_filter: this function is called to filter data of a frame
@@ -106,6 +102,8 @@ enum mad_flow libmad_header(void *data, struct mad_header const *p_libmad_header
  * }
  */
 
+//#define MPG321_ROUTINES     1
+#ifdef MPG321_ROUTINES
 /*****************************************************************************
  * support routines borrowed from mpg321 (file: mad.c), which is distributed
  * under GPL license
@@ -191,6 +189,25 @@ static __inline__ signed long audio_linear_dither(unsigned int bits, mad_fixed_t
     /* scale */
     return output >> scalebits;
 }
+#endif
+
+/*****************************************************************************
+ * s24_to_s16_pcm: Scale a 24 bit pcm sample to a 16 bit pcm sample.
+ *****************************************************************************/
+static __inline__ mad_fixed_t s24_to_s16_pcm(mad_fixed_t sample)
+{
+  /* round */
+  sample += (1L << (MAD_F_FRACBITS - 16));
+
+  /* clip */
+  if (sample >= MAD_F_ONE)
+    sample = MAD_F_ONE - 1;
+  else if (sample < -MAD_F_ONE)
+    sample = -MAD_F_ONE;
+
+  /* quantize */
+  return sample >> (MAD_F_FRACBITS + 1 - 16);
+}
 
 /*****************************************************************************
  * libmad_ouput: this function is called just after the frame is decoded
@@ -201,19 +218,15 @@ enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header
     byte_t *buffer=NULL;
 
     mad_fixed_t const *left_ch = p_libmad_pcm->samples[0], *right_ch = p_libmad_pcm->samples[1];
-    /*
-     * 1152 because that's what mad has as a max; *4 because
-     * there are 4 distinct bytes per sample (in 2 channel case)
-     */
-    static unsigned char stream[ADEC_FRAME_SIZE];
     register int nsamples = p_libmad_pcm->length;
+    mad_fixed_t sample;
+#ifdef MPG321_ROUTINES
     static struct audio_dither dither;
-
-    register char * ptr = stream;
-    register signed int sample;
+#endif
 
     /* Set timestamp to synchronize audio and video decoder fifo's */
     vlc_mutex_lock (&p_mad_adec->p_aout_fifo->data_lock);
+    p_mad_adec->p_aout_fifo->l_rate = p_libmad_header->samplerate;
     p_mad_adec->p_aout_fifo->date[p_mad_adec->p_aout_fifo->l_end_frame] = p_mad_adec->i_pts_save;
 
     buffer = ((byte_t *)p_mad_adec->p_aout_fifo->buffer) + (p_mad_adec->p_aout_fifo->l_end_frame * ADEC_FRAME_SIZE);
@@ -222,47 +235,56 @@ enum mad_flow libmad_output(void *data, struct mad_header const *p_libmad_header
     {
         while (nsamples--)
         {
-            sample = (signed int) audio_linear_dither(16, *left_ch++, &dither);
+#ifdef MPG321_ROUTINES
+            sample = audio_linear_dither(16, *left_ch++, &dither);
+#else
+            sample = s24_to_s16_pcm(*left_ch++);
+#endif
+
 #ifndef WORDS_BIGENDIAN
-            *ptr++ = (unsigned char) (sample >> 0);
-            *ptr++ = (unsigned char) (sample >> 8);
+            *buffer++ = (byte_t) (sample) & 0xFF;
+            *buffer++ = (byte_t) (sample >> 8) & 0xFF;
+#else
+            *buffer++ = (byte_t) (sample >> 8);
+            *buffer++ = (byte_t) (sample);
+#endif
+           /* right audio channel */
+#ifdef MPG321_ROUTINES
+            sample = audio_linear_dither(16, *right_ch++, &dither);
 #else
-            *ptr++ = (unsigned char) (sample >> 8);
-            *ptr++ = (unsigned char) (sample >> 0);
+            sample = s24_to_s16_pcm(*right_ch++);
 #endif
 
-            sample = (signed int) audio_linear_dither(16, *right_ch++, &dither);
 #ifndef WORDS_BIGENDIAN
-            *ptr++ = (unsigned char) (sample >> 0);
-            *ptr++ = (unsigned char) (sample >> 8);
+            *buffer++ = (byte_t) (sample);
+            *buffer++ = (byte_t) (sample >> 8);
 #else
-            *ptr++ = (unsigned char) (sample >> 8);
-            *ptr++ = (unsigned char) (sample >> 0);
+            *buffer++ = (byte_t) (sample >> 8);
+            *buffer++ = (byte_t) (sample);
 #endif                                         
         }
-        buffer = memcpy(buffer,stream,p_libmad_pcm->length*4);
-        vlc_cond_signal (&p_mad_adec->p_aout_fifo->data_wait);
   }
   else
   {
         while (nsamples--)
         {
-            sample = (signed int) audio_linear_dither(16, *left_ch++, &dither);
+#ifdef MPG321_ROUTINES
+            sample = audio_linear_dither(16, *left_ch++, &dither);
+#else
+            sample = s24_to_s16_pcm(*left_ch++);
+#endif
 
 #ifndef WORDS_BIGENDIAN
-            *ptr++ = (unsigned char) (sample >> 0);
-            *ptr++ = (unsigned char) (sample >> 8);
+            *buffer++ = (byte_t) (sample);
+            *buffer++ = (byte_t) (sample >> 8);
 #else
-            *ptr++ = (unsigned char) (sample >> 8);
-            *ptr++ = (unsigned char) (sample >> 0);
+            *buffer++ = (byte_t) (sample >> 8);
+            *buffer++ = (byte_t) (sample);
 #endif                                 
         }
-        buffer = memcpy(buffer,stream,p_libmad_pcm->length*2);
-        vlc_cond_signal (&p_mad_adec->p_aout_fifo->data_wait);
     }
-    vlc_mutex_unlock (&p_mad_adec->p_aout_fifo->data_lock);
 
-    vlc_mutex_lock (&p_mad_adec->p_aout_fifo->data_lock);
+//    vlc_mutex_lock (&p_mad_adec->p_aout_fifo->data_lock);
     p_mad_adec->p_aout_fifo->l_end_frame = (p_mad_adec->p_aout_fifo->l_end_frame + 1) & AOUT_FIFO_SIZE;
     vlc_cond_signal (&p_mad_adec->p_aout_fifo->data_wait);
     vlc_mutex_unlock (&p_mad_adec->p_aout_fifo->data_lock);