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: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/1730>
This commit is contained in:
Sebastian Dröge 2022-02-16 18:49:52 +02:00 committed by GStreamer Marge Bot
parent e10bd02e1d
commit 3941eb7dbd
5 changed files with 54 additions and 3 deletions

View file

@ -813,6 +813,20 @@
"type": "GstAudioDitherMethod", "type": "GstAudioDitherMethod",
"writable": true "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": { "mix-matrix": {
"blurb": "Transformation matrix for input/output channels", "blurb": "Transformation matrix for input/output channels",
"conditionally-available": false, "conditionally-available": false,

View file

@ -263,7 +263,6 @@ audio_chain_get_samples (AudioChain * chain, gsize * avail)
return res; return res;
} }
/*
static guint static guint
get_opt_uint (GstAudioConverter * convert, const gchar * opt, guint def) 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; res = def;
return res; return res;
} }
*/
static gint static gint
get_opt_enum (GstAudioConverter * convert, const gchar * opt, GType type, 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_RESAMPLER_METHOD GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL
#define DEFAULT_OPT_DITHER_METHOD GST_AUDIO_DITHER_NONE #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_NOISE_SHAPING_METHOD GST_AUDIO_NOISE_SHAPING_NONE
#define DEFAULT_OPT_QUANTIZATION 1 #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, \ #define GET_OPT_DITHER_METHOD(c) get_opt_enum(c, \
GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD, \ GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD, \
DEFAULT_OPT_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, \ #define GET_OPT_NOISE_SHAPING_METHOD(c) get_opt_enum(c, \
GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, \ GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, \
DEFAULT_OPT_NOISE_SHAPING_METHOD) DEFAULT_OPT_NOISE_SHAPING_METHOD)
@ -951,9 +952,11 @@ chain_quantize (GstAudioConverter * convert, AudioChain * prev)
gint in_depth, out_depth; gint in_depth, out_depth;
gboolean in_int, out_int; gboolean in_int, out_int;
GstAudioDitherMethod dither; GstAudioDitherMethod dither;
guint dither_threshold;
GstAudioNoiseShapingMethod ns; GstAudioNoiseShapingMethod ns;
dither = GET_OPT_DITHER_METHOD (convert); dither = GET_OPT_DITHER_METHOD (convert);
dither_threshold = GET_OPT_DITHER_THRESHOLD (convert);
ns = GET_OPT_NOISE_SHAPING_METHOD (convert); ns = GET_OPT_NOISE_SHAPING_METHOD (convert);
cur_finfo = gst_audio_format_get_info (convert->current_format); 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. * 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 * Also don't dither or apply noise shaping if target depth is larger than
* source depth. */ * 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; dither = GST_AUDIO_DITHER_NONE;
ns = GST_AUDIO_NOISE_SHAPING_NONE; ns = GST_AUDIO_NOISE_SHAPING_NONE;
GST_INFO ("using no dither and noise shaping"); GST_INFO ("using no dither and noise shaping");

View file

@ -106,6 +106,17 @@ typedef struct _GstAudioConverter GstAudioConverter;
*/ */
#define GST_AUDIO_CONVERTER_OPT_MIX_MATRIX "GstAudioConverter.mix-matrix" #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: * GstAudioConverterFlags:
* @GST_AUDIO_CONVERTER_FLAG_NONE: no flag * @GST_AUDIO_CONVERTER_FLAG_NONE: no flag

View file

@ -157,6 +157,7 @@ enum
PROP_DITHERING, PROP_DITHERING,
PROP_NOISE_SHAPING, PROP_NOISE_SHAPING,
PROP_MIX_MATRIX, PROP_MIX_MATRIX,
PROP_DITHERING_THRESHOLD
}; };
#define DEBUG_INIT \ #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),
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_element_class_add_static_pad_template (element_class,
&gst_audio_convert_src_template); &gst_audio_convert_src_template);
gst_element_class_add_static_pad_template (element_class, gst_element_class_add_static_pad_template (element_class,
@ -260,6 +273,7 @@ static void
gst_audio_convert_init (GstAudioConvert * this) gst_audio_convert_init (GstAudioConvert * this)
{ {
this->dither = GST_AUDIO_DITHER_TPDF; this->dither = GST_AUDIO_DITHER_TPDF;
this->dither_threshold = 20;
this->ns = GST_AUDIO_NOISE_SHAPING_NONE; this->ns = GST_AUDIO_NOISE_SHAPING_NONE;
g_value_init (&this->mix_matrix, GST_TYPE_ARRAY); 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", config = gst_structure_new ("GstAudioConverterConfig",
GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD, GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD,
this->dither, this->dither,
GST_AUDIO_CONVERTER_OPT_DITHER_THRESHOLD, G_TYPE_UINT,
this->dither_threshold,
GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD,
GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, this->ns, NULL); 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: case PROP_NOISE_SHAPING:
this->ns = g_value_get_enum (value); this->ns = g_value_get_enum (value);
break; break;
case PROP_DITHERING_THRESHOLD:
this->dither_threshold = g_value_get_uint (value);
break;
case PROP_MIX_MATRIX: case PROP_MIX_MATRIX:
if (!gst_value_array_get_size (value)) { if (!gst_value_array_get_size (value)) {
this->mix_matrix_is_set = FALSE; this->mix_matrix_is_set = FALSE;
@ -1014,6 +1033,9 @@ gst_audio_convert_get_property (GObject * object, guint prop_id,
case PROP_NOISE_SHAPING: case PROP_NOISE_SHAPING:
g_value_set_enum (value, this->ns); g_value_set_enum (value, this->ns);
break; break;
case PROP_DITHERING_THRESHOLD:
g_value_set_uint (value, this->dither_threshold);
break;
case PROP_MIX_MATRIX: case PROP_MIX_MATRIX:
if (this->mix_matrix_is_set) if (this->mix_matrix_is_set)
g_value_copy (&this->mix_matrix, value); g_value_copy (&this->mix_matrix, value);

View file

@ -41,6 +41,7 @@ struct _GstAudioConvert
/* properties */ /* properties */
GstAudioDitherMethod dither; GstAudioDitherMethod dither;
guint dither_threshold;
GstAudioNoiseShapingMethod ns; GstAudioNoiseShapingMethod ns;
GValue mix_matrix; GValue mix_matrix;
gboolean mix_matrix_is_set; gboolean mix_matrix_is_set;