audioconvert: Add dithering-threshold property
authorSebastian Dröge <sebastian@centricular.com>
Wed, 16 Feb 2022 16:49:52 +0000 (18:49 +0200)
committerGStreamer Marge Bot <gitlab-merge-bot@gstreamer-foundation.org>
Fri, 25 Feb 2022 19:32:28 +0000 (19:32 +0000)
By default, no dithering is applied if the target bit depth is above 20
bits. This new property allows to apply dithering nonetheless in these
cases.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1730>

subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json
subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.c
subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.h
subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.c
subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.h

index 80ac33a..e02131d 100644 (file)
                         "type": "GstAudioDitherMethod",
                         "writable": true
                     },
+                    "dithering-threshold": {
+                        "blurb": "Threshold for the output bit depth at/below which to apply dithering.",
+                        "conditionally-available": false,
+                        "construct": false,
+                        "construct-only": false,
+                        "controllable": false,
+                        "default": "20",
+                        "max": "32",
+                        "min": "0",
+                        "mutable": "null",
+                        "readable": true,
+                        "type": "guint",
+                        "writable": true
+                    },
                     "mix-matrix": {
                         "blurb": "Transformation matrix for input/output channels",
                         "conditionally-available": false,
index 65396aa..e607a50 100644 (file)
@@ -263,7 +263,6 @@ audio_chain_get_samples (AudioChain * chain, gsize * avail)
   return res;
 }
 
-/*
 static guint
 get_opt_uint (GstAudioConverter * convert, const gchar * opt, guint def)
 {
@@ -272,7 +271,6 @@ get_opt_uint (GstAudioConverter * convert, const gchar * opt, guint def)
     res = def;
   return res;
 }
-*/
 
 static gint
 get_opt_enum (GstAudioConverter * convert, const gchar * opt, GType type,
@@ -292,6 +290,7 @@ get_opt_value (GstAudioConverter * convert, const gchar * opt)
 
 #define DEFAULT_OPT_RESAMPLER_METHOD GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL
 #define DEFAULT_OPT_DITHER_METHOD GST_AUDIO_DITHER_NONE
+#define DEFAULT_OPT_DITHER_THRESHOLD 20
 #define DEFAULT_OPT_NOISE_SHAPING_METHOD GST_AUDIO_NOISE_SHAPING_NONE
 #define DEFAULT_OPT_QUANTIZATION 1
 
@@ -301,6 +300,8 @@ get_opt_value (GstAudioConverter * convert, const gchar * opt)
 #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
     GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD, \
     DEFAULT_OPT_DITHER_METHOD)
+#define GET_OPT_DITHER_THRESHOLD(c) get_opt_uint(c, \
+    GST_AUDIO_CONVERTER_OPT_DITHER_THRESHOLD, DEFAULT_OPT_DITHER_THRESHOLD)
 #define GET_OPT_NOISE_SHAPING_METHOD(c) get_opt_enum(c, \
     GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, \
     DEFAULT_OPT_NOISE_SHAPING_METHOD)
@@ -951,9 +952,11 @@ chain_quantize (GstAudioConverter * convert, AudioChain * prev)
   gint in_depth, out_depth;
   gboolean in_int, out_int;
   GstAudioDitherMethod dither;
+  guint dither_threshold;
   GstAudioNoiseShapingMethod ns;
 
   dither = GET_OPT_DITHER_METHOD (convert);
+  dither_threshold = GET_OPT_DITHER_THRESHOLD (convert);
   ns = GET_OPT_NOISE_SHAPING_METHOD (convert);
 
   cur_finfo = gst_audio_format_get_info (convert->current_format);
@@ -969,7 +972,7 @@ chain_quantize (GstAudioConverter * convert, AudioChain * prev)
    * as DA converters only can do a SNR up to 20 bits in reality.
    * Also don't dither or apply noise shaping if target depth is larger than
    * source depth. */
-  if (out_depth > 20 || (in_int && out_depth >= in_depth)) {
+  if (out_depth > dither_threshold || (in_int && out_depth >= in_depth)) {
     dither = GST_AUDIO_DITHER_NONE;
     ns = GST_AUDIO_NOISE_SHAPING_NONE;
     GST_INFO ("using no dither and noise shaping");
index 083bda4..ef5ac9a 100644 (file)
@@ -107,6 +107,17 @@ typedef struct _GstAudioConverter GstAudioConverter;
 #define GST_AUDIO_CONVERTER_OPT_MIX_MATRIX   "GstAudioConverter.mix-matrix"
 
 /**
+ * GST_AUDIO_CONVERTER_OPT_DITHER_THRESHOLD:
+ *
+ * Threshold for the output bit depth at/below which to apply dithering.
+ *
+ * Default is 20 bit.
+ *
+ * Since: 1.22
+ */
+#define GST_AUDIO_CONVERTER_OPT_DITHER_THRESHOLD   "GstAudioConverter.dither-threshold"
+
+/**
  * GstAudioConverterFlags:
  * @GST_AUDIO_CONVERTER_FLAG_NONE: no flag
  * @GST_AUDIO_CONVERTER_FLAG_IN_WRITABLE: the input sample arrays are writable and can be
index 3b6f409..48f15bf 100644 (file)
@@ -157,6 +157,7 @@ enum
   PROP_DITHERING,
   PROP_NOISE_SHAPING,
   PROP_MIX_MATRIX,
+  PROP_DITHERING_THRESHOLD
 };
 
 #define DEBUG_INIT \
@@ -224,6 +225,18 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass)
               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
 
+  /**
+   * GstAudioConvert:dithering-threshold:
+   *
+   * Threshold for the output bit depth at/below which to apply dithering.
+   *
+   * Since: 1.22
+   */
+  g_object_class_install_property (gobject_class, PROP_DITHERING_THRESHOLD,
+      g_param_spec_uint ("dithering-threshold", "Dithering Threshold",
+          "Threshold for the output bit depth at/below which to apply dithering.",
+          0, 32, 20, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
   gst_element_class_add_static_pad_template (element_class,
       &gst_audio_convert_src_template);
   gst_element_class_add_static_pad_template (element_class,
@@ -260,6 +273,7 @@ static void
 gst_audio_convert_init (GstAudioConvert * this)
 {
   this->dither = GST_AUDIO_DITHER_TPDF;
+  this->dither_threshold = 20;
   this->ns = GST_AUDIO_NOISE_SHAPING_NONE;
   g_value_init (&this->mix_matrix, GST_TYPE_ARRAY);
 
@@ -765,6 +779,8 @@ gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
   config = gst_structure_new ("GstAudioConverterConfig",
       GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD,
       this->dither,
+      GST_AUDIO_CONVERTER_OPT_DITHER_THRESHOLD, G_TYPE_UINT,
+      this->dither_threshold,
       GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD,
       GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, this->ns, NULL);
 
@@ -978,6 +994,9 @@ gst_audio_convert_set_property (GObject * object, guint prop_id,
     case PROP_NOISE_SHAPING:
       this->ns = g_value_get_enum (value);
       break;
+    case PROP_DITHERING_THRESHOLD:
+      this->dither_threshold = g_value_get_uint (value);
+      break;
     case PROP_MIX_MATRIX:
       if (!gst_value_array_get_size (value)) {
         this->mix_matrix_is_set = FALSE;
@@ -1014,6 +1033,9 @@ gst_audio_convert_get_property (GObject * object, guint prop_id,
     case PROP_NOISE_SHAPING:
       g_value_set_enum (value, this->ns);
       break;
+    case PROP_DITHERING_THRESHOLD:
+      g_value_set_uint (value, this->dither_threshold);
+      break;
     case PROP_MIX_MATRIX:
       if (this->mix_matrix_is_set)
         g_value_copy (&this->mix_matrix, value);
index 336bef2..0413d91 100644 (file)
@@ -41,6 +41,7 @@ struct _GstAudioConvert
 
   /* properties */
   GstAudioDitherMethod dither;
+  guint dither_threshold;
   GstAudioNoiseShapingMethod ns;
   GValue mix_matrix;
   gboolean mix_matrix_is_set;