[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