[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