[vlc-devel] [PATCH v2] audio_filter:add DPLii support and surround delay

Vedanta Nayak vedantnayak2 at gmail.com
Tue Aug 25 21:11:41 CEST 2020


Hi,

I have made the suggested changes. :)

---
 modules/audio_filter/channel_mixer/dolby.c | 422 +++++++++++++++++++--
 1 file changed, 381 insertions(+), 41 deletions(-)

diff --git a/modules/audio_filter/channel_mixer/dolby.c b/modules/audio_filter/channel_mixer/dolby.c
index 8d5c63c256..34c696cc56 100644
--- a/modules/audio_filter/channel_mixer/dolby.c
+++ b/modules/audio_filter/channel_mixer/dolby.c
@@ -4,7 +4,7 @@
  * Copyright (C) 2005-2009 the VideoLAN team
  *
  * Authors: Boris Dorès <babal at via.ecp.fr>
- *
+ *          Vedanta Nayak <vedantnayak2 at gmail.com>
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU Lesser General Public License as published by
  * the Free Software Foundation; either version 2.1 of the License, or
@@ -33,23 +33,48 @@
 #include <vlc_aout.h>
 #include <vlc_filter.h>
 
+#define MATRIX_TEXT N_( "Decoding Matrix" )
+#define MATRIX_LONGTEXT N_( "Decoding matrix to use for the equalizer." )
+
+#define DELAY_TEXT N_( "Surround delay" )
+#define DELAY_LONGTEXT N_( "Delay to be applied to the rear channels "\
+        "for Dolby Prologic II. Maximum is 100. Default is 0." )
+
+enum {
+    DOLBY_PROLOGIC,
+    DOLBY_PROLOGICII
+};
+
+static const int matrix_list[] = {
+    DOLBY_PROLOGIC   ,
+    DOLBY_PROLOGICII
+};
+static const char *const matrix_list_text[] = {
+    N_("Dolby Prologic"), N_("Dolby Prologic II")
+};
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
 static int  Create    ( vlc_object_t * );
 static void Destroy   ( vlc_object_t * );
 
-static block_t *DoWork( filter_t *, block_t * );
+static block_t *DPL   ( filter_t *, block_t * );
+static block_t *DPLii ( filter_t *, block_t * );
 
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
 vlc_module_begin ()
-    set_description( N_("Simple decoder for Dolby Surround encoded streams") )
+    set_description( N_("Simple decoder for Dolby Surround/Prologic II encoded streams") )
     set_shortname( N_("Dolby Surround decoder") )
     set_category( CAT_INPUT )
     set_subcategory( SUBCAT_INPUT_ACODEC )
     set_capability( "audio converter", 5 )
+    add_integer( "dolby-decoding-matrix", 0, MATRIX_TEXT,
+            MATRIX_LONGTEXT, false)
+        change_integer_list( matrix_list , matrix_list_text )
+    add_integer_with_range("dolby-surround-delay",0,0,100,
+            DELAY_TEXT, DELAY_LONGTEXT, false)
     set_callbacks( Create, Destroy )
 vlc_module_end ()
 
@@ -64,10 +89,14 @@ typedef struct
     int i_rear_left;
     int i_rear_center;
     int i_rear_right;
-} filter_sys_t;
+    int i_delay;
+    size_t i_nb_rear;
+    block_t *firstblock;
+    block_t **block_chain;
+}filter_sys_t;
 
 /*****************************************************************************
- * Create: allocate headphone downmixer
+ * Create: allocate filter resources
  *****************************************************************************/
 static int Create( vlc_object_t *p_this )
 {
@@ -107,6 +136,10 @@ static int Create( vlc_object_t *p_this )
     p_sys->i_rear_left = -1;
     p_sys->i_rear_center = -1;
     p_sys->i_rear_right = -1;
+    p_sys->i_nb_rear = 0;
+    p_sys->i_delay = -1;
+    p_sys->firstblock = NULL;
+    p_sys->block_chain = &p_sys->firstblock;
 
     while ( pi_vlc_chan_order_wg4[i] )
     {
@@ -125,12 +158,15 @@ static int Create( vlc_object_t *p_this )
                     break;
                 case AOUT_CHAN_REARLEFT:
                     p_sys->i_rear_left = i_offset;
+                    p_sys->i_nb_rear++;
                     break;
                 case AOUT_CHAN_REARCENTER:
                     p_sys->i_rear_center = i_offset;
+                    p_sys->i_nb_rear++;
                     break;
                 case AOUT_CHAN_REARRIGHT:
                     p_sys->i_rear_right = i_offset;
+                    p_sys->i_nb_rear++;
                     break;
             }
             ++i_offset;
@@ -138,69 +174,151 @@ static int Create( vlc_object_t *p_this )
         ++i;
     }
 
-    p_filter->pf_audio_filter = DoWork;
-
+    size_t matrix = var_InheritInteger( vlc_object_parent(p_filter),
+              "dolby-decoding-matrix" );
+    size_t delay = var_InheritInteger( vlc_object_parent(p_filter),
+             "dolby-surround-delay");
+    if (delay)
+    {
+        /* Calculate the number of samples to delay. Done in two steps:
+         * 1) Find number of samples every millisecond by rounding off
+         *     (adding 999) and dividing by 1000.
+         * 2) Multiply with the number of milliseconds to delay. */
+        p_sys->i_delay = delay *
+                ((p_filter->fmt_in.audio.i_rate+999)/1000);
+    }
+    switch(matrix)
+    {
+        case DOLBY_PROLOGIC:
+            p_filter->pf_audio_filter = DPL;
+            break;
+        case DOLBY_PROLOGICII:
+            p_filter->pf_audio_filter = DPLii;
+            break;
+    }
     return VLC_SUCCESS;
 }
 
 /*****************************************************************************
- * Destroy: deallocate resources associated with headphone downmixer
+ * Destroy: deallocate resources associated with filter
  *****************************************************************************/
 static void Destroy( vlc_object_t *p_this )
 {
     filter_t * p_filter = (filter_t *)p_this;
-    free( p_filter->p_sys );
+    filter_sys_t * p_sys= p_filter->p_sys;
+    block_ChainRelease(p_sys->firstblock);
+    free(p_sys);
 }
 
-/*****************************************************************************
- * DoWork: convert a buffer
- *****************************************************************************/
-static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
+/* The decoding matrix used for DPL is :
+ * __|_____Lt_____|_____Rt_____|
+ * L |     1      |      0     |
+ * R |     0      |      1     |
+ * C |  0.707107  |  0.707107  |
+ * S |  0.707107  | -0.707107  |
+ * ------------------------------ */
+static block_t *DPL ( filter_t * p_filter, block_t * p_in_buf)
 {
     filter_sys_t * p_sys = p_filter->p_sys;
     float * p_in = (float*) p_in_buf->p_buffer;
     size_t i_nb_samples = p_in_buf->i_nb_samples;
     size_t i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_out.audio );
-    size_t i_nb_rear = 0;
-    size_t i;
-    block_t *p_out_buf = block_Alloc(
-                                sizeof(float) * i_nb_samples * i_nb_channels );
+    size_t i_nb_rear = p_sys->i_nb_rear;
+    int delay = p_sys->i_delay;
+    block_t *p_out_buf = block_Alloc(sizeof(float) *
+            i_nb_samples * i_nb_channels );
     if( !p_out_buf )
         goto out;
 
+    /*No of samples delayed in current block*/
+    size_t i_samples_delayed = 0;
+    block_t *head = p_sys->firstblock;
+
     float * p_out = (float*) p_out_buf->p_buffer;
     p_out_buf->i_nb_samples = i_nb_samples;
     p_out_buf->i_dts        = p_in_buf->i_dts;
     p_out_buf->i_pts        = p_in_buf->i_pts;
     p_out_buf->i_length     = p_in_buf->i_length;
-
     memset( p_out, 0, p_out_buf->i_buffer );
 
-    if( p_sys->i_rear_left >= 0 )
-    {
-        ++i_nb_rear;
-    }
-    if( p_sys->i_rear_center >= 0 )
-    {
-        ++i_nb_rear;
-    }
-    if( p_sys->i_rear_right >= 0 )
+    if ( i_nb_rear > 0 && delay != -1 )
     {
-        ++i_nb_rear;
+        if ( delay < (int)i_nb_samples)
+        {
+            i_samples_delayed = delay;
+            delay = 0;
+            while ( head != NULL )
+            {
+                /* Calculate the size of delay block using i_buffer */
+                size_t buffer_size = head->i_buffer/(2 *sizeof(float));
+                /* Checks if using all samples in current delay block will
+                 * exceed current block's size. If the size of current
+                 * delay block is greater, the maximum, ie i_nb_samples
+                 * is used, else we use the
+                 * entire delay block ie buffer_size */
+                size_t nb_samples = (buffer_size + i_samples_delayed >
+                    i_nb_samples)? i_nb_samples : buffer_size;
+                float *p_delay = (float *) head->p_buffer;
+                size_t j = 0;
+                for ( size_t i = i_samples_delayed ; i < nb_samples;
+                        ++j, ++i )
+                {
+                    float f_left  = p_delay [ j * 2 ];
+                    float f_right = p_delay [ j * 2 + 1 ];
+                    float f_rear  = (f_left - f_right) * 0.707107;
+                    if ( p_sys->i_rear_left >= 0 )
+                    {
+                        p_out[ i * i_nb_channels +
+                                p_sys->i_rear_left] = f_rear;
+                    }
+                    if (p_sys->i_rear_right >= 0)
+                    {
+                        p_out[ i * i_nb_channels +
+                                p_sys->i_rear_right] = f_rear;
+                    }
+                    if (p_sys->i_rear_center >= 0)
+                    {
+                        p_out[ i * i_nb_channels +
+                                p_sys->i_rear_center] = f_rear;
+                    }
+                }
+                if ( nb_samples == i_nb_samples)
+                {
+                    /* If the end of the current block is reached. */
+                    i_samples_delayed = i_nb_samples;
+                    head->p_buffer += 2 * j;
+                    head->i_buffer -= 2 * j * sizeof(float);
+                    break;
+                }
+                else
+                {
+                    /* Update the number of samples delayed in
+                     * current block and go to the next delay block. */
+                    i_samples_delayed += nb_samples;
+                    block_t *consumed = head;
+                    head = head->p_next;
+                    block_Release(consumed);
+                }
+            }
+            /* Update the head of the block_t chain. */
+            p_sys->firstblock = head;
+         }
+        else
+        {
+            delay            -= i_nb_samples;
+            i_samples_delayed = i_nb_samples;
+        }
     }
-
-    for( i = 0; i < i_nb_samples; ++i )
+    for( size_t i = 0; i < i_nb_samples; ++i )
     {
-        float f_left = p_in[ i * 2 ];
+        float f_left  = p_in[ i * 2 ];
         float f_right = p_in[ i * 2 + 1 ];
-        float f_rear = ( f_left - f_right ) / i_nb_rear;
 
         if( p_sys->i_center >= 0 )
         {
-            float f_center = f_left + f_right;
+            float f_center = (f_left + f_right) * 0.707107;
             f_left -= f_center / 2;
             f_right -= f_center / 2;
-
             p_out[ i * i_nb_channels + p_sys->i_center ] = f_center;
         }
 
@@ -208,24 +326,246 @@ static block_t *DoWork( filter_t * p_filter, block_t * p_in_buf )
         {
             p_out[ i * i_nb_channels + p_sys->i_left ] = f_left;
         }
+
         if( p_sys->i_right >= 0 )
         {
             p_out[ i * i_nb_channels + p_sys->i_right ] = f_right;
         }
-        if( p_sys->i_rear_left >= 0 )
+
+        if (i_nb_rear > 0)
         {
-            p_out[ i * i_nb_channels + p_sys->i_rear_left ] = f_rear;
+            float f_rear = ( f_left - f_right ) * 0.707107;
+            if (delay == -1)
+            {
+                if( p_sys->i_rear_left >= 0 )
+                {
+                    p_out[ i * i_nb_channels +
+                        p_sys->i_rear_left ] = f_rear;
+                }
+                if( p_sys->i_rear_center >= 0 )
+                {
+                    p_out[ i * i_nb_channels +
+                        p_sys->i_rear_center ] = f_rear;
+                }
+                if( p_sys->i_rear_right >= 0 )
+                {
+                    p_out[ i * i_nb_channels +
+                        p_sys->i_rear_right ] = f_rear;
+                }
+            }
+            else
+            {
+                if ( i < i_nb_samples - i_samples_delayed )
+                {
+                    if( p_sys->i_rear_left >= 0 )
+                    {
+                        p_out[ i * i_nb_channels +
+                            p_sys->i_rear_left ] = f_rear;
+                    }
+                    if( p_sys->i_rear_center >= 0 )
+                    {
+                        p_out[ i * i_nb_channels +
+                            p_sys->i_rear_center ] = f_rear;
+                    }
+                    if( p_sys->i_rear_right >= 0 )
+                    {
+                        p_out[ i * i_nb_channels +
+                            p_sys->i_rear_right ] = f_rear;
+                    }
+                }
+            }
         }
-        if( p_sys->i_rear_center >= 0 )
+    }
+    if ( i_nb_rear > 0 && delay != -1 )
+    {
+        if (i_samples_delayed < i_nb_samples)
         {
-            p_out[ i * i_nb_channels + p_sys->i_rear_center ] = f_rear;
+            p_in_buf->p_buffer += 2 * i_samples_delayed;
+            p_in_buf->i_buffer -= i_samples_delayed * sizeof(float) * 2;
         }
-        if( p_sys->i_rear_right >= 0 )
+        p_sys->i_delay = delay;
+        block_ChainLastAppend(&(p_sys->block_chain),p_in_buf);
+    }
+out:
+    if (delay == -1 || i_nb_rear == 0)
+    {
+        block_Release( p_in_buf );
+    }
+    return p_out_buf;
+}
+
+/* The decoding matrix used for DPLii is :
+ * ___|_____Lt_____|_____Rt_____|
+ * L  |  0.412956  |  0.073144  |
+ * R  |  0.073144  |  0.412956  |
+ * C  |  0.343724  |  0.343724  |
+ * LS | -0.294947  |  0.242277  |
+ * RS | -0.178698  |  0.205033  |
+ * ------------------------------ */
+
+static block_t *DPLii ( filter_t * p_filter, block_t * p_in_buf )
+{
+    filter_sys_t * p_sys = p_filter->p_sys;
+    float * p_in = (float*) p_in_buf->p_buffer;
+    size_t i_nb_samples = p_in_buf->i_nb_samples;
+    int i_nb_channels = aout_FormatNbChannels( &p_filter->fmt_out.audio );
+    size_t i_nb_rear = p_sys->i_nb_rear;
+    int delay = p_sys->i_delay;
+    block_t *p_out_buf = block_Alloc(sizeof(float) *
+            i_nb_samples * i_nb_channels );
+    if( !p_out_buf )
+        goto out;
+
+    float * p_out = (float*) p_out_buf->p_buffer;
+    /*No of samples delayed */
+    size_t i_samples_delayed = 0;
+    block_t *head = p_sys->firstblock;
+
+    p_out_buf->i_nb_samples = i_nb_samples;
+    p_out_buf->i_dts        = p_in_buf->i_dts;
+    p_out_buf->i_pts        = p_in_buf->i_pts;
+    p_out_buf->i_length     = p_in_buf->i_length;
+    memset( p_out, 0, p_out_buf->i_buffer );
+
+    if ( i_nb_rear > 0 && delay != -1 )
+    {
+        if ( delay < (int)i_nb_samples)
+        {
+            i_samples_delayed = delay;
+            delay = 0;
+            while ( head != NULL )
+            {
+                /* Calculate the size of delay block using i_buffer */
+                size_t buffer_size = head->i_buffer/(2 *sizeof(float));
+                /* Checks if using all samples in current delay block will
+                 * exceed current block's size. If the size of current
+                 * delay block is greater, the maximum, ie i_nb_samples
+                 * is used, else we use the
+                 * entire delay block ie buffer_size */
+                size_t nb_samples = (buffer_size + i_samples_delayed >
+                    i_nb_samples)? i_nb_samples :
+                    buffer_size;
+                float *p_delay = (float *) head->p_buffer;
+                size_t j = 0;
+                for ( size_t i = i_samples_delayed ; i < nb_samples;
+                        ++j, ++i )
+                {
+                    float f_left  = p_delay [ j * 2 ];
+                    float f_right = p_delay [ j * 2 + 1 ];
+                    float f_rearleft = f_right * 0.242277 -
+                        f_left * 0.294947 ;
+                    float f_rearright= f_right * 0.205033 -
+                        f_left * 0.178698 ;
+                    if ( p_sys->i_rear_left >= 0 )
+                    {
+                        p_out[ i * i_nb_channels +
+                                p_sys->i_rear_left] = f_rearleft;
+                    }
+                    if (p_sys->i_rear_right >= 0)
+                    {
+                        p_out[ i * i_nb_channels +
+                                p_sys->i_rear_right] = f_rearright;
+                    }
+                }
+                if ( nb_samples == i_nb_samples)
+                {
+                    /* If the end of the current block is reached. */
+                    i_samples_delayed = i_nb_samples;
+                    head->p_buffer += 2 * j;
+                    head->i_buffer -= 2 * j * sizeof(float);
+                    break;
+                }
+                else
+                {
+                    /* Update the number of samples delayed in
+                     * current block and go to the next delay block. */
+                    i_samples_delayed += nb_samples;
+                    block_t *consumed = head;
+                    head = head->p_next;
+                    block_Release(consumed);
+                }
+            }
+            /* Update the head of the block_t chain. */
+            p_sys->firstblock = head;
+         }
+        else
         {
-            p_out[ i * i_nb_channels + p_sys->i_rear_right ] = f_rear;
+            delay            -= i_nb_samples;
+            i_samples_delayed = i_nb_samples;
         }
     }
+    for ( size_t i = 0 ; i < i_nb_samples ; i++ )
+    {
+        float f_left  = p_in[ i * 2     ];
+        float f_right = p_in[ i * 2 + 1 ];
+
+        if (p_sys->i_left >= 0)
+        {
+            p_out [ i * i_nb_channels + p_sys->i_left ] =
+                f_left * 0.412956 + f_right * 0.073144;
+        }
+        if (p_sys->i_right >= 0)
+        {
+            p_out [ i * i_nb_channels + p_sys->i_right ] =
+                f_left * 0.073144 + f_right * 0.412956;
+        }
+        if (p_sys->i_center >= 0)
+        {
+            p_out [ i * i_nb_channels + p_sys->i_center ] =
+                (f_left + f_right) * 0.343724;
+        }
+        if (i_nb_rear > 0)
+        {
+            if ( delay == -1 )
+            {
+                /* If no delay is present */
+                if (p_sys->i_rear_left >= 0)
+                {
+                    p_out [ i * i_nb_channels + p_sys->i_rear_left ] =
+                        f_right * 0.242277 - f_left * 0.294947;
+                }
+                if (p_sys->i_rear_right >= 0)
+                {
+                    p_out [ i * i_nb_channels + p_sys->i_rear_right ] =
+                        f_right * 0.205033 - f_left * 0.178698;
+                }
+            }
+            else
+            {
+                /* If delay is present */
+                if ( i < i_nb_samples - i_samples_delayed )
+                {
+                    if (p_sys->i_rear_left >= 0)
+                    {
+                        p_out [ (i + i_samples_delayed) * i_nb_channels
+                            + p_sys->i_rear_left ] =  f_right * 0.242277
+                            - f_left * 0.294947;
+                    }
+                    if (p_sys->i_rear_right >= 0)
+                    {
+                        p_out [ (i + i_samples_delayed) * i_nb_channels +
+                            p_sys->i_rear_right ] = f_right * 0.205033
+                            - f_left * 0.178698;
+                    }
+                }
+            }
+        }
+    }
+    if ( i_nb_rear > 0 && delay != -1 )
+    {
+        if (i_samples_delayed < i_nb_samples)
+        {
+            p_in_buf->p_buffer += 2 * i_samples_delayed;
+            p_in_buf->i_buffer -= i_samples_delayed * sizeof(float) * 2;
+        }
+        p_sys->i_delay = delay;
+        block_ChainLastAppend(&(p_sys->block_chain),p_in_buf);
+    }
 out:
-    block_Release( p_in_buf );
+    /* Skip block_Release if there is surround delay */
+    if (delay == -1 || i_nb_rear == 0)
+    {
+        block_Release( p_in_buf );
+    }
     return p_out_buf;
 }
-- 


More information about the vlc-devel mailing list