[vlc-devel] [PATCH] audio_filter:add DPLii support and surround delay
Alexandre Janniaux
ajanni at videolabs.io
Tue Aug 25 19:08:00 CEST 2020
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.
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
More information about the vlc-devel
mailing list