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

Thomas Guillem thomas at gllm.fr
Wed Aug 26 09:56:06 CEST 2020



On Tue, Aug 25, 2020, at 19:08, Alexandre Janniaux wrote:
> Hi,
> 
> Thank you for the contributions! Here are a few improvement
> points, though only a quick review:
> 
> On Tue, Aug 25, 2020 at 05:39:26PM +0530, Vedanta Nayak wrote:
> > Hi,
> >
> > This patch adds support for decoding Dolby Prologic II and adds
> > surround delay for Dolby Surround and Dolby Prologic II to
> > implement the precedence effect.
> >
> > ---
> >  modules/audio_filter/channel_mixer/dolby.c | 395 ++++++++++++++++++---
> >  1 file changed, 355 insertions(+), 40 deletions(-)
> >
> > diff --git a/modules/audio_filter/channel_mixer/dolby.c b/modules/audio_filter/channel_mixer/dolby.c
> > index 8d5c63c256..44be02d96d 100644
> > --- a/modules/audio_filter/channel_mixer/dolby.c
> > +++ b/modules/audio_filter/channel_mixer/dolby.c
> > @@ -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( "decoding-matrix", "prologic", MATRIX_TEXT,
> > +            MATRIX_LONGTEXT, false)
> > +        change_integer_list( matrix_list , matrix_list_text )
> 
> Maybe Thomas can suggest a better way here, like exposing
> different submodules reacting to different chanmode? I'm
> not entirely sure it's the best we can do here but it's fine
> in the current form otherwise.


The big question is how we choose DPL, from DPLii, from DoWork. Is it only defined by the user ? Or can it be detected from the input ?


> 
> However, if we keep a variable, it must be prefixed (for example
> by "dolby-"). Same for the second one.
> 
> > +    add_integer_with_range("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;         //samples to 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,137 @@ static int Create( vlc_object_t *p_this )
> >          ++i;
> >      }
> >
> > -    p_filter->pf_audio_filter = DoWork;
> > -
> > +    size_t matrix = var_CreateGetInteger( vlc_object_parent(p_filter),
> > +              "decoding-matrix" );
> > +    size_t delay = var_CreateGetInteger( vlc_object_parent(p_filter),
> > +             "surround-delay");
> 
> If you don't add callbacks on those values, var_InheritInteger
> should be enough.
> 
> > +    if (delay)
> > +    {
> > +        p_sys->i_delay = delay *
> > +                ((p_filter->fmt_in.audio.i_rate+999)/1000);
> 
> A comment would help here, the rounding is not trivial to read. :)
> 
> > +    }
> > +    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 )
> > +            {
> > +                size_t buffer_size = head->i_buffer/(2 *sizeof(float));
> > +                size_t nb_samples = (buffer_size + i_samples_delayed >
> > +                    i_nb_samples)? i_nb_samples : buffer_size;
> 
> Ternary condition + comparision is not very readable, you can probably
> improve by splitting here + adding a comment.
> 
> > +                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)
> > +                {
> > +                    i_samples_delayed = i_nb_samples;
> > +                    head->p_buffer += 2 * j;
> > +                    head->i_buffer -= 2 * j * sizeof(float);
> > +                    break;
> > +                }
> > +                else
> > +                {
> > +                    i_samples_delayed += nb_samples;
> > +                    block_t *consumed = head;
> > +                    head = head->p_next;
> > +                    block_Release(consumed);
> > +                }
> > +            }
> > +            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 +312,235 @@ 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)
> > +        {
> > +            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 ( 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:
> > +    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 )
> > +            {
> > +                size_t buffer_size = head->i_buffer/(2 *sizeof(float));
> > +                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)
> > +                {
> > +                    i_samples_delayed = i_nb_samples;
> > +                    head->p_buffer += 2 * j;
> > +                    head->i_buffer -= 2 * j * sizeof(float);
> > +                    break;
> > +                }
> > +                else
> > +                {
> > +                    i_samples_delayed += nb_samples;
> > +                    block_t *consumed = head;
> > +                    head = head->p_next;
> > +                    block_Release(consumed);
> > +                }
> > +            }
> > +            p_sys->firstblock = head;
> > +         }
> > +        else
> > +        {
> > +            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_rear_left ] = f_rear;
> > +            p_out [ i * i_nb_channels + p_sys->i_right ] =
> > +                f_left * 0.073144 + f_right * 0.412956;
> >          }
> > -        if( p_sys->i_rear_center >= 0 )
> > +        if (p_sys->i_center >= 0)
> >          {
> > -            p_out[ i * i_nb_channels + p_sys->i_rear_center ] = f_rear;
> > +            p_out [ i * i_nb_channels + p_sys->i_center ] =
> > +                (f_left + f_right) * 0.343724;
> >          }
> > -        if( p_sys->i_rear_right >= 0 )
> > +        if (i_nb_rear > 0)
> >          {
> > -            p_out[ i * i_nb_channels + p_sys->i_rear_right ] = f_rear;
> > +            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;
> >  }
> > --
> > _______________________________________________
> > vlc-devel mailing list
> > To unsubscribe or modify your subscription options:
> > https://mailman.videolan.org/listinfo/vlc-devel
> _______________________________________________
> vlc-devel mailing list
> To unsubscribe or modify your subscription options:
> https://mailman.videolan.org/listinfo/vlc-devel


More information about the vlc-devel mailing list