[vlc-commits] soxr: use a fixed and a variable-rate SoxR instance

Thomas Guillem git at videolan.org
Tue Nov 3 16:26:45 CET 2015


vlc | branch: master | Thomas Guillem <thomas at gllm.fr> | Tue Nov  3 15:13:34 2015 +0100| [004078f2fe55b616e029e5f64b23bb03c773f135] | committer: Thomas Guillem

soxr: use a fixed and a variable-rate SoxR instance

The SoXR variable-rate engine is slower than the fixed one, so use it only when
it's needed (when the input ratio is changing to catch up a delay).

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=004078f2fe55b616e029e5f64b23bb03c773f135
---

 modules/audio_filter/resampler/soxr.c |  183 ++++++++++++++++++++++++---------
 1 file changed, 135 insertions(+), 48 deletions(-)

diff --git a/modules/audio_filter/resampler/soxr.c b/modules/audio_filter/resampler/soxr.c
index 5c7a9a7..5bbd9a1 100644
--- a/modules/audio_filter/resampler/soxr.c
+++ b/modules/audio_filter/resampler/soxr.c
@@ -33,6 +33,7 @@
 #include <vlc_filter.h>
 #include <vlc_plugin.h>
 
+#include <assert.h>
 #include <math.h>
 #include <soxr.h>
 
@@ -81,7 +82,11 @@ vlc_module_end ()
 struct filter_sys_t
 {
     soxr_t  soxr;
+    soxr_t  vr_soxr;
+    soxr_t  last_soxr;
     double  f_fixed_ratio;
+    size_t  i_last_olen;
+    mtime_t i_last_pts;
 };
 
 static block_t *Resample( filter_t *, block_t * );
@@ -140,15 +145,13 @@ Open( vlc_object_t *p_obj, bool b_change_ratio )
     const unsigned i_channels = aout_FormatNbChannels( &p_filter->fmt_in.audio );
     const double f_ratio = p_filter->fmt_out.audio.i_rate
                            / (double) p_filter->fmt_in.audio.i_rate;
-    /* XXX: Performances are worse with Variable-Rate */
-    const unsigned long i_flags = b_change_ratio ? SOXR_VR : 0;
 
-    p_sys->f_fixed_ratio = b_change_ratio ? 0.0f : f_ratio;
+    p_sys->f_fixed_ratio = f_ratio;
     soxr_error_t error;
     /* IO spec */
     soxr_io_spec_t io_spec = soxr_io_spec( i_itype, i_otype );
     /* Quality spec */
-    soxr_quality_spec_t q_spec = soxr_quality_spec( i_recipe, i_flags );
+    soxr_quality_spec_t q_spec = soxr_quality_spec( i_recipe, 0 );
     /* Create SoXR */
     p_sys->soxr = soxr_create( 1, f_ratio, i_channels,
                                &error, &io_spec, &q_spec, NULL );
@@ -158,8 +161,24 @@ Open( vlc_object_t *p_obj, bool b_change_ratio )
         free( p_sys );
         return VLC_EGENERIC;
     }
+
+    /* Create a 'variable-rate' SoXR if needed: it is slower than the fixed
+     * one, but it will be only used when the input rate is changing (to catch
+     * up a delay).  */
     if( b_change_ratio )
-        soxr_set_io_ratio( p_sys->soxr, 1 / f_ratio, 0 );
+    {
+        soxr_quality_spec_t q_spec = soxr_quality_spec( SOXR_LQ, SOXR_VR );
+        p_sys->vr_soxr = soxr_create( 1, f_ratio, i_channels,
+                                      &error, &io_spec, &q_spec, NULL );
+        if( error )
+        {
+            msg_Err( p_filter, "soxr_create failed: %s", soxr_strerror( error ) );
+            soxr_delete( p_sys->soxr );
+            free( p_sys );
+            return VLC_EGENERIC;
+        }
+        soxr_set_io_ratio( p_sys->vr_soxr, 1 / f_ratio, 0 );
+    }
 
     msg_Dbg( p_filter, "Using SoX Resampler with '%s' engine and '%s' quality "
              "to convert %4.4s/%dHz to %4.4s/%dHz.",
@@ -204,76 +223,144 @@ Close( vlc_object_t *p_obj )
     filter_sys_t *p_sys = p_filter->p_sys;
 
     soxr_delete( p_sys->soxr );
+    if( p_sys->vr_soxr )
+        soxr_delete( p_sys->vr_soxr );
 
     free( p_sys );
 }
 
-static size_t
-SoXR_GetOutLen( size_t i_ilen, double f_ratio )
-{
-    /* Processed output len might be a little bigger than expected. Indeed SoXR
-     * can hold a few samples to meet the need of the resampling filter. */
-    return lrint( ( i_ilen + 2 ) * f_ratio * 11. / 10. );
-}
-
 static block_t *
-Resample( filter_t *p_filter, block_t *p_in )
+SoXR_Resample( filter_t *p_filter, soxr_t soxr, block_t *p_in, size_t i_olen )
 {
     filter_sys_t *p_sys = p_filter->p_sys;
-
+    size_t i_idone, i_odone;
     const size_t i_oframesize = p_filter->fmt_out.audio.i_bytes_per_frame;
-    const size_t i_ilen = p_in->i_nb_samples;
-    size_t i_olen, i_idone, i_odone;
-
-    if( p_sys->f_fixed_ratio == 0.0f )
-    {
-        /* "audio resampler" with variable ratio */
-
-        const double f_ratio = p_filter->fmt_out.audio.i_rate
-                             / (double) p_filter->fmt_in.audio.i_rate;
-        if( f_ratio == 1.0f )
-            return p_in;
-
-        i_olen = SoXR_GetOutLen( i_ilen, f_ratio );
-
-        soxr_set_io_ratio( p_sys->soxr, 1 / f_ratio, i_olen );
-    }
-    else
-        i_olen = SoXR_GetOutLen( i_ilen, p_sys->f_fixed_ratio );
+    const size_t i_ilen = p_in ? p_in->i_nb_samples : 0;
 
-    /* Use input buffer as output if there is enough room */
     block_t *p_out = i_ilen >= i_olen ? p_in
                    : block_Alloc( i_olen * i_oframesize );
-    if( unlikely( p_out == NULL ) )
-        goto error;
 
-    /* Process SoXR */
-    soxr_error_t error = soxr_process( p_sys->soxr,
-                                       p_in->p_buffer, i_ilen, &i_idone,
-                                       p_out->p_buffer, i_olen, &i_odone );
+    soxr_error_t error = soxr_process( soxr, p_in ? p_in->p_buffer : NULL,
+                                       i_ilen, &i_idone, p_out->p_buffer,
+                                       i_olen, &i_odone );
     if( error )
     {
         msg_Err( p_filter, "soxr_process failed: %s", soxr_strerror( error ) );
+        block_Release( p_out );
         goto error;
     }
-
     if( unlikely( i_idone < i_ilen ) )
         msg_Err( p_filter, "lost %zd of %zd input frames",
                  i_ilen - i_idone, i_idone);
 
     p_out->i_buffer = i_odone * i_oframesize;
     p_out->i_nb_samples = i_odone;
-    p_out->i_pts = p_in->i_pts;
     p_out->i_length = i_odone * CLOCK_FREQ / p_filter->fmt_out.audio.i_rate;
 
-    if( p_out != p_in )
+    if( p_in )
+    {
+        p_sys->i_last_olen = i_olen;
+        p_sys->last_soxr = soxr;
+    }
+    else
+    {
+        soxr_clear( soxr );
+        p_sys->i_last_olen = 0;
+        p_sys->last_soxr = NULL;
+    }
+
+error:
+    if( p_in && p_out != p_in )
         block_Release( p_in );
+
     return p_out;
+}
 
-error:
+static size_t
+SoXR_GetOutLen( size_t i_ilen, double f_ratio )
+{
+    /* Processed output len might be a little bigger than expected. Indeed SoXR
+     * can hold a few samples to meet the need of the resampling filter. */
+    return lrint( ( i_ilen + 2 ) * f_ratio * 11. / 10. );
+}
 
-    if( p_out && p_out != p_in )
-        block_Release( p_out );
-    block_Release( p_in );
-    return NULL;
+static block_t *
+Resample( filter_t *p_filter, block_t *p_in )
+{
+    filter_sys_t *p_sys = p_filter->p_sys;
+    const mtime_t i_pts = p_in->i_pts;
+
+    if( p_sys->vr_soxr )
+    {
+        /* "audio resampler" with variable ratio: use the fixed resampler when
+         * the ratio is the same than the fixed one, otherwise use the variable
+         * resampler. */
+
+        soxr_t soxr;
+        block_t *p_flushed_out = NULL, *p_out = NULL;
+        const double f_ratio = p_filter->fmt_out.audio.i_rate
+                             / (double) p_filter->fmt_in.audio.i_rate;
+        const size_t i_olen = SoXR_GetOutLen( p_in->i_nb_samples, f_ratio );
+
+        if( f_ratio != p_sys->f_fixed_ratio )
+        {
+            /* using variable resampler */
+            soxr_set_io_ratio( p_sys->vr_soxr, 1 / f_ratio, i_olen );
+            soxr = p_sys->vr_soxr;
+        }
+        else if( f_ratio == 1.0f )
+        {
+            /* not using any resampler */
+            soxr = NULL;
+            p_out = p_in;
+        }
+        else
+        {
+            /* using fixed resampler */
+            soxr = p_sys->soxr;
+        }
+
+        /* If the new soxr is different than the last one, flush it */
+        if( p_sys->last_soxr && soxr != p_sys->last_soxr && p_sys->i_last_olen )
+        {
+            p_flushed_out = SoXR_Resample( p_filter, p_sys->last_soxr,
+                                           NULL, p_sys->i_last_olen );
+            if( soxr )
+                msg_Dbg( p_filter, "Using '%s' engine", soxr_engine( soxr ) );
+        }
+
+        if( soxr )
+        {
+            assert( !p_out );
+            p_out = SoXR_Resample( p_filter, soxr, p_in, i_olen );
+            if( !p_out )
+                return NULL;
+        }
+
+        if( p_flushed_out )
+        {
+            /* Prepend the flushed output data to p_out */
+            const unsigned i_nb_samples = p_flushed_out->i_nb_samples
+                                        + p_out->i_nb_samples;
+
+            block_ChainAppend( &p_flushed_out, p_out );
+            p_out = block_ChainGather( p_flushed_out );
+            if( !p_out )
+                return NULL;
+            p_out->i_nb_samples = i_nb_samples;
+        }
+        p_out->i_pts = i_pts;
+        return p_out;
+    }
+    else
+    {
+        /* "audio converter" with fixed ratio */
+
+        const size_t i_olen = SoXR_GetOutLen( p_in->i_nb_samples,
+                                              p_sys->f_fixed_ratio );
+        block_t *p_out = SoXR_Resample( p_filter, p_sys->soxr, p_in, i_olen );
+        if( p_out )
+            p_out->i_pts = i_pts;
+        return p_out;
+    }
 }



More information about the vlc-commits mailing list