From 3941eb7dbd694f7ae573e67172e7df514cbd5f2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Wed, 16 Feb 2022 18:49:52 +0200 Subject: [PATCH] audioconvert: Add dithering-threshold property 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: --- .../docs/plugins/gst_plugins_cache.json | 14 ++++++++++++ .../gst-libs/gst/audio/audio-converter.c | 9 +++++--- .../gst-libs/gst/audio/audio-converter.h | 11 ++++++++++ .../gst/audioconvert/gstaudioconvert.c | 22 +++++++++++++++++++ .../gst/audioconvert/gstaudioconvert.h | 1 + 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json b/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json index 80ac33a670..e02131d73b 100644 --- a/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json +++ b/subprojects/gst-plugins-base/docs/plugins/gst_plugins_cache.json @@ -813,6 +813,20 @@ "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, diff --git a/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.c b/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.c index 65396aa935..e607a5000f 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.c +++ b/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.c @@ -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"); diff --git a/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.h b/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.h index 083bda4fa2..ef5ac9a003 100644 --- a/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.h +++ b/subprojects/gst-plugins-base/gst-libs/gst/audio/audio-converter.h @@ -106,6 +106,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 diff --git a/subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.c b/subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.c index 3b6f40934a..48f15bf5e9 100644 --- a/subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.c +++ b/subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.c @@ -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); diff --git a/subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.h b/subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.h index 336bef27a7..0413d916e4 100644 --- a/subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.h +++ b/subprojects/gst-plugins-base/gst/audioconvert/gstaudioconvert.h @@ -41,6 +41,7 @@ struct _GstAudioConvert /* properties */ GstAudioDitherMethod dither; + guint dither_threshold; GstAudioNoiseShapingMethod ns; GValue mix_matrix; gboolean mix_matrix_is_set;