mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
audioconvert: make the quantizer a reusable object
Turn the quantizer into a reusable object.
This commit is contained in:
parent
8fc2569328
commit
cd6c29e071
6 changed files with 244 additions and 231 deletions
|
@ -56,25 +56,10 @@
|
|||
* - (channel mix F64)
|
||||
* - pack from F64
|
||||
*/
|
||||
#define DOUBLE_INTERMEDIATE_FORMAT(ctx) \
|
||||
(!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo) || \
|
||||
!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo) || \
|
||||
(ctx->ns != NOISE_SHAPING_NONE))
|
||||
|
||||
static inline gboolean
|
||||
check_default (AudioConvertCtx * ctx, const GstAudioFormatInfo * fmt)
|
||||
{
|
||||
if (!DOUBLE_INTERMEDIATE_FORMAT (ctx)) {
|
||||
return GST_AUDIO_FORMAT_INFO_FORMAT (fmt) == GST_AUDIO_FORMAT_S32;
|
||||
} else {
|
||||
return GST_AUDIO_FORMAT_INFO_FORMAT (fmt) == GST_AUDIO_FORMAT_F64;
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
|
||||
GstAudioInfo * out, GstAudioConvertDithering dither,
|
||||
GstAudioConvertNoiseShaping ns)
|
||||
GstAudioInfo * out, GstAudioDitherMethod dither,
|
||||
GstAudioNoiseShapingMethod ns)
|
||||
{
|
||||
gint in_depth, out_depth;
|
||||
GstChannelMixFlags flags;
|
||||
|
@ -104,19 +89,19 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
|
|||
* source depth. */
|
||||
if (out_depth <= 20 && (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (in->finfo)
|
||||
|| in_depth >= out_depth)) {
|
||||
ctx->dither = dither;
|
||||
ctx->ns = ns;
|
||||
dither = dither;
|
||||
ns = ns;
|
||||
GST_INFO ("using dither %d and noise shaping %d", dither, ns);
|
||||
} else {
|
||||
ctx->dither = DITHER_NONE;
|
||||
ctx->ns = NOISE_SHAPING_NONE;
|
||||
dither = GST_AUDIO_DITHER_NONE;
|
||||
ns = GST_AUDIO_NOISE_SHAPING_NONE;
|
||||
GST_INFO ("using no dither and noise shaping");
|
||||
}
|
||||
|
||||
/* Use simple error feedback when output sample rate is smaller than
|
||||
* 32000 as the other methods might move the noise to audible ranges */
|
||||
if (ctx->ns > NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000)
|
||||
ctx->ns = NOISE_SHAPING_ERROR_FEEDBACK;
|
||||
if (ns > GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK && out->rate < 32000)
|
||||
ns = GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK;
|
||||
|
||||
flags =
|
||||
GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
|
||||
|
@ -128,11 +113,17 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
|
|||
ctx->mix = gst_channel_mix_new (flags, in->channels, in->position,
|
||||
out->channels, out->position);
|
||||
|
||||
if (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo) ||
|
||||
!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo) ||
|
||||
(ns != GST_AUDIO_NOISE_SHAPING_NONE))
|
||||
ctx->mix_format = GST_AUDIO_FORMAT_F64;
|
||||
else
|
||||
ctx->mix_format = GST_AUDIO_FORMAT_S32;
|
||||
|
||||
/* if one formats is float/double or we use noise shaping use double as
|
||||
* intermediate format and switch mixing */
|
||||
if (DOUBLE_INTERMEDIATE_FORMAT (ctx)) {
|
||||
if (ctx->mix_format == GST_AUDIO_FORMAT_F64) {
|
||||
GST_INFO ("use float mixing");
|
||||
ctx->mix_format = GST_AUDIO_FORMAT_F64;
|
||||
if (ctx->in.finfo->unpack_format != GST_AUDIO_FORMAT_F64) {
|
||||
ctx->convert = audio_convert_orc_s32_to_double;
|
||||
GST_INFO ("convert input to F64");
|
||||
|
@ -151,7 +142,6 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
|
|||
}
|
||||
} else {
|
||||
GST_INFO ("use int mixing");
|
||||
ctx->mix_format = GST_AUDIO_FORMAT_S32;
|
||||
/* check if input needs to be unpacked to intermediate format */
|
||||
ctx->in_default =
|
||||
GST_AUDIO_FORMAT_INFO_FORMAT (in->finfo) == GST_AUDIO_FORMAT_S32;
|
||||
|
@ -164,7 +154,8 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
|
|||
|
||||
/* check if channel mixer is passthrough */
|
||||
ctx->mix_passthrough = gst_channel_mix_is_passthrough (ctx->mix);
|
||||
ctx->quant_default = check_default (ctx, out->finfo);
|
||||
ctx->quant_default =
|
||||
GST_AUDIO_FORMAT_INFO_FORMAT (out->finfo) == ctx->mix_format;
|
||||
|
||||
GST_INFO ("in default %d, mix passthrough %d, out default %d",
|
||||
ctx->in_default, ctx->mix_passthrough, ctx->out_default);
|
||||
|
@ -174,7 +165,8 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
|
|||
|
||||
GST_INFO ("scale out %d", ctx->out_scale);
|
||||
|
||||
gst_audio_quantize_setup (ctx);
|
||||
ctx->quant = gst_audio_quantize_new (dither, ns, 0, ctx->mix_format,
|
||||
out->channels, ctx->out_scale);
|
||||
|
||||
return TRUE;
|
||||
|
||||
|
@ -191,7 +183,8 @@ audio_convert_clean_context (AudioConvertCtx * ctx)
|
|||
{
|
||||
g_return_val_if_fail (ctx != NULL, FALSE);
|
||||
|
||||
gst_audio_quantize_free (ctx);
|
||||
if (ctx->quant)
|
||||
gst_audio_quantize_free (ctx->quant);
|
||||
if (ctx->mix)
|
||||
gst_channel_mix_free (ctx->mix);
|
||||
ctx->mix = NULL;
|
||||
|
@ -244,7 +237,7 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
|
|||
out_width = GST_AUDIO_FORMAT_INFO_WIDTH (ctx->out.finfo);
|
||||
|
||||
/* find biggest temp buffer size */
|
||||
size = (DOUBLE_INTERMEDIATE_FORMAT (ctx)) ? sizeof (gdouble)
|
||||
size = (ctx->mix_format == GST_AUDIO_FORMAT_F64) ? sizeof (gdouble)
|
||||
: sizeof (gint32);
|
||||
|
||||
if (!ctx->in_default)
|
||||
|
@ -314,7 +307,9 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
|
|||
else
|
||||
outbuf = tmpbuf;
|
||||
|
||||
ctx->quantize (ctx, src, outbuf, samples);
|
||||
gst_audio_quantize_samples (ctx->quant, src, samples);
|
||||
|
||||
outbuf = src;
|
||||
}
|
||||
|
||||
if (!ctx->out_default) {
|
||||
|
|
|
@ -26,71 +26,13 @@
|
|||
#include <gst/audio/audio.h>
|
||||
|
||||
#include "gstchannelmix.h"
|
||||
#include "gstaudioquantize.h"
|
||||
|
||||
GST_DEBUG_CATEGORY_EXTERN (audio_convert_debug);
|
||||
#define GST_CAT_DEFAULT (audio_convert_debug)
|
||||
|
||||
/**
|
||||
* GstAudioConvertDithering:
|
||||
* @DITHER_NONE: No dithering
|
||||
* @DITHER_RPDF: Rectangular dithering
|
||||
* @DITHER_TPDF: Triangular dithering (default)
|
||||
* @DITHER_TPDF_HF: High frequency triangular dithering
|
||||
*
|
||||
* Set of available dithering methods when converting audio.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
DITHER_NONE = 0,
|
||||
DITHER_RPDF,
|
||||
DITHER_TPDF,
|
||||
DITHER_TPDF_HF
|
||||
} GstAudioConvertDithering;
|
||||
|
||||
/**
|
||||
* GstAudioConvertNoiseShaping:
|
||||
* @NOISE_SHAPING_NONE: No noise shaping (default)
|
||||
* @NOISE_SHAPING_ERROR_FEEDBACK: Error feedback
|
||||
* @NOISE_SHAPING_SIMPLE: Simple 2-pole noise shaping
|
||||
* @NOISE_SHAPING_MEDIUM: Medium 5-pole noise shaping
|
||||
* @NOISE_SHAPING_HIGH: High 8-pole noise shaping
|
||||
*
|
||||
* Set of available noise shaping methods
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
NOISE_SHAPING_NONE = 0,
|
||||
NOISE_SHAPING_ERROR_FEEDBACK,
|
||||
NOISE_SHAPING_SIMPLE,
|
||||
NOISE_SHAPING_MEDIUM,
|
||||
NOISE_SHAPING_HIGH
|
||||
} GstAudioConvertNoiseShaping;
|
||||
|
||||
typedef struct _AudioConvertCtx AudioConvertCtx;
|
||||
#if 0
|
||||
typedef struct _AudioConvertFmt AudioConvertFmt;
|
||||
|
||||
struct _AudioConvertFmt
|
||||
{
|
||||
/* general caps */
|
||||
gboolean is_int;
|
||||
gint endianness;
|
||||
gint width;
|
||||
gint rate;
|
||||
gint channels;
|
||||
GstAudioChannelPosition *pos;
|
||||
gboolean unpositioned_layout;
|
||||
|
||||
/* int audio caps */
|
||||
gboolean sign;
|
||||
gint depth;
|
||||
|
||||
gint unit_size;
|
||||
};
|
||||
#endif
|
||||
|
||||
typedef void (*AudioConvertQuantize) (AudioConvertCtx * ctx, gpointer src,
|
||||
gpointer dst, gint count);
|
||||
typedef void (*AudioConvertToF64) (gdouble *dst, const gint32 *src, gint count);
|
||||
|
||||
struct _AudioConvertCtx
|
||||
|
@ -98,7 +40,9 @@ struct _AudioConvertCtx
|
|||
GstAudioInfo in;
|
||||
GstAudioInfo out;
|
||||
|
||||
GstAudioFormat mix_format;
|
||||
GstChannelMix *mix;
|
||||
GstAudioQuantize *quant;
|
||||
|
||||
gboolean in_default;
|
||||
gboolean mix_passthrough;
|
||||
|
@ -109,22 +53,13 @@ struct _AudioConvertCtx
|
|||
gint tmpbufsize;
|
||||
|
||||
gint out_scale;
|
||||
GstAudioFormat mix_format;
|
||||
|
||||
AudioConvertToF64 convert;
|
||||
AudioConvertQuantize quantize;
|
||||
|
||||
GstAudioConvertDithering dither;
|
||||
GstAudioConvertNoiseShaping ns;
|
||||
/* last random number generated per channel for hifreq TPDF dither */
|
||||
gpointer last_random;
|
||||
/* contains the past quantization errors, error[out_channels][count] */
|
||||
gdouble *error_buf;
|
||||
};
|
||||
|
||||
gboolean audio_convert_prepare_context (AudioConvertCtx * ctx,
|
||||
GstAudioInfo * in, GstAudioInfo * out,
|
||||
GstAudioConvertDithering dither, GstAudioConvertNoiseShaping ns);
|
||||
GstAudioDitherMethod dither, GstAudioNoiseShapingMethod ns);
|
||||
gboolean audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples,
|
||||
gint * srcsize, gint * dstsize);
|
||||
|
||||
|
|
|
@ -140,11 +140,12 @@ gst_audio_convert_dithering_get_type (void)
|
|||
|
||||
if (gtype == 0) {
|
||||
static const GEnumValue values[] = {
|
||||
{DITHER_NONE, "No dithering",
|
||||
{GST_AUDIO_DITHER_NONE, "No dithering",
|
||||
"none"},
|
||||
{DITHER_RPDF, "Rectangular dithering", "rpdf"},
|
||||
{DITHER_TPDF, "Triangular dithering (default)", "tpdf"},
|
||||
{DITHER_TPDF_HF, "High frequency triangular dithering", "tpdf-hf"},
|
||||
{GST_AUDIO_DITHER_RPDF, "Rectangular dithering", "rpdf"},
|
||||
{GST_AUDIO_DITHER_TPDF, "Triangular dithering (default)", "tpdf"},
|
||||
{GST_AUDIO_DITHER_TPDF_HF, "High frequency triangular dithering",
|
||||
"tpdf-hf"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -161,12 +162,13 @@ gst_audio_convert_ns_get_type (void)
|
|||
|
||||
if (gtype == 0) {
|
||||
static const GEnumValue values[] = {
|
||||
{NOISE_SHAPING_NONE, "No noise shaping (default)",
|
||||
{GST_AUDIO_NOISE_SHAPING_NONE, "No noise shaping (default)",
|
||||
"none"},
|
||||
{NOISE_SHAPING_ERROR_FEEDBACK, "Error feedback", "error-feedback"},
|
||||
{NOISE_SHAPING_SIMPLE, "Simple 2-pole noise shaping", "simple"},
|
||||
{NOISE_SHAPING_MEDIUM, "Medium 5-pole noise shaping", "medium"},
|
||||
{NOISE_SHAPING_HIGH, "High 8-pole noise shaping", "high"},
|
||||
{GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK, "Error feedback",
|
||||
"error-feedback"},
|
||||
{GST_AUDIO_NOISE_SHAPING_SIMPLE, "Simple 2-pole noise shaping", "simple"},
|
||||
{GST_AUDIO_NOISE_SHAPING_MEDIUM, "Medium 5-pole noise shaping", "medium"},
|
||||
{GST_AUDIO_NOISE_SHAPING_HIGH, "High 8-pole noise shaping", "high"},
|
||||
{0, NULL, NULL}
|
||||
};
|
||||
|
||||
|
@ -191,13 +193,13 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass)
|
|||
g_object_class_install_property (gobject_class, PROP_DITHERING,
|
||||
g_param_spec_enum ("dithering", "Dithering",
|
||||
"Selects between different dithering methods.",
|
||||
GST_TYPE_AUDIO_CONVERT_DITHERING, DITHER_TPDF,
|
||||
GST_TYPE_AUDIO_CONVERT_DITHERING, GST_AUDIO_DITHER_TPDF,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_NOISE_SHAPING,
|
||||
g_param_spec_enum ("noise-shaping", "Noise shaping",
|
||||
"Selects between different noise shaping methods.",
|
||||
GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING, NOISE_SHAPING_NONE,
|
||||
GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING, GST_AUDIO_NOISE_SHAPING_NONE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
|
@ -227,8 +229,8 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass)
|
|||
static void
|
||||
gst_audio_convert_init (GstAudioConvert * this)
|
||||
{
|
||||
this->dither = DITHER_TPDF;
|
||||
this->ns = NOISE_SHAPING_NONE;
|
||||
this->dither = GST_AUDIO_DITHER_TPDF;
|
||||
this->ns = GST_AUDIO_NOISE_SHAPING_NONE;
|
||||
memset (&this->ctx, 0, sizeof (AudioConvertCtx));
|
||||
|
||||
gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (this), TRUE);
|
||||
|
|
|
@ -48,8 +48,8 @@ struct _GstAudioConvert
|
|||
|
||||
AudioConvertCtx ctx;
|
||||
|
||||
GstAudioConvertDithering dither;
|
||||
GstAudioConvertNoiseShaping ns;
|
||||
GstAudioDitherMethod dither;
|
||||
GstAudioNoiseShapingMethod ns;
|
||||
};
|
||||
|
||||
struct _GstAudioConvertClass
|
||||
|
|
|
@ -34,12 +34,31 @@
|
|||
#include <gst/gst.h>
|
||||
#include <string.h>
|
||||
#include <math.h>
|
||||
#include "audioconvert.h"
|
||||
#include "gstaudioconvertorc.h"
|
||||
#include "gstaudioquantize.h"
|
||||
|
||||
#include "gstfastrandom.h"
|
||||
|
||||
typedef void (*QuantizeFunc) (GstAudioQuantize * quant, gpointer src,
|
||||
gpointer dst, gint count);
|
||||
|
||||
struct _GstAudioQuantize
|
||||
{
|
||||
GstAudioDitherMethod dither;
|
||||
GstAudioNoiseShapingMethod ns;
|
||||
GstAudioQuantizeFlags flags;
|
||||
GstAudioFormat format;
|
||||
guint channels;
|
||||
guint quantizer;
|
||||
|
||||
/* last random number generated per channel for hifreq TPDF dither */
|
||||
gpointer last_random;
|
||||
/* contains the past quantization errors, error[out_channels][count] */
|
||||
gdouble *error_buf;
|
||||
|
||||
QuantizeFunc quantize;
|
||||
};
|
||||
|
||||
#define MAKE_QUANTIZE_FUNC_NAME(name) \
|
||||
gst_audio_quantize_quantize_##name
|
||||
|
||||
|
@ -48,11 +67,11 @@ gst_audio_quantize_quantize_##name
|
|||
#define MAKE_QUANTIZE_FUNC_I(name, DITHER_INIT_FUNC, ADD_DITHER_FUNC, \
|
||||
ROUND_FUNC) \
|
||||
static void \
|
||||
MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \
|
||||
MAKE_QUANTIZE_FUNC_NAME (name) (GstAudioQuantize *quant, gint32 *src, \
|
||||
gint32 *dst, gint count) \
|
||||
{ \
|
||||
gint scale = ctx->out_scale; \
|
||||
gint channels = ctx->out.channels; \
|
||||
gint scale = quant->quantizer; \
|
||||
gint channels = quant->channels; \
|
||||
gint chan_pos; \
|
||||
\
|
||||
if (scale > 0) { \
|
||||
|
@ -83,11 +102,11 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gint32 *src, \
|
|||
ADD_NS_FUNC, ADD_DITHER_FUNC, \
|
||||
UPDATE_ERROR_FUNC) \
|
||||
static void \
|
||||
MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
|
||||
MAKE_QUANTIZE_FUNC_NAME (name) (GstAudioQuantize *quant, gdouble *src, \
|
||||
gint32 *dst, gint count) \
|
||||
{ \
|
||||
gint scale = ctx->out_scale; \
|
||||
gint channels = ctx->out.channels; \
|
||||
gint scale = quant->quantizer; \
|
||||
gint channels = quant->channels; \
|
||||
gint chan_pos; \
|
||||
gdouble tmp, d, factor = (1U<<(32-scale-1)); \
|
||||
\
|
||||
|
@ -180,7 +199,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
|
|||
#define INIT_DITHER_TPDF_HF_I() \
|
||||
gint32 rand; \
|
||||
gint32 dither = (1<<(scale-1)); \
|
||||
gint32 *last_random = (gint32 *) ctx->last_random, tmp_rand;
|
||||
gint32 *last_random = (gint32 *) quant->last_random, tmp_rand;
|
||||
|
||||
#define ADD_DITHER_TPDF_HF_I() \
|
||||
tmp_rand = RANDOM_INT_DITHER(dither); \
|
||||
|
@ -199,7 +218,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
|
|||
#define INIT_DITHER_TPDF_HF_F() \
|
||||
gdouble rand; \
|
||||
gdouble dither = 1.0/(1U<<(32 - scale)); \
|
||||
gdouble *last_random = (gdouble *) ctx->last_random, tmp_rand;
|
||||
gdouble *last_random = (gdouble *) quant->last_random, tmp_rand;
|
||||
|
||||
#define ADD_DITHER_TPDF_HF_F() \
|
||||
tmp_rand = gst_fast_random_double_range (- dither, dither); \
|
||||
|
@ -216,7 +235,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
|
|||
|
||||
#define INIT_NS_ERROR_FEEDBACK() \
|
||||
gdouble orig; \
|
||||
gdouble *errors = ctx->error_buf;
|
||||
gdouble *errors = quant->error_buf;
|
||||
|
||||
#define ADD_NS_ERROR_FEEDBACK() \
|
||||
orig = tmp; \
|
||||
|
@ -230,7 +249,7 @@ MAKE_QUANTIZE_FUNC_NAME (name) (AudioConvertCtx *ctx, gdouble *src, \
|
|||
|
||||
#define INIT_NS_SIMPLE() \
|
||||
gdouble orig; \
|
||||
gdouble *errors = ctx->error_buf, cur_error;
|
||||
gdouble *errors = quant->error_buf, cur_error;
|
||||
|
||||
#define ADD_NS_SIMPLE() \
|
||||
cur_error = errors[chan_pos*2] - 0.5 * errors[chan_pos*2 + 1]; \
|
||||
|
@ -256,7 +275,7 @@ static const gdouble ns_medium_coeffs[] = {
|
|||
|
||||
#define INIT_NS_MEDIUM() \
|
||||
gdouble orig; \
|
||||
gdouble *errors = ctx->error_buf, cur_error; \
|
||||
gdouble *errors = quant->error_buf, cur_error; \
|
||||
int j;
|
||||
|
||||
#define ADD_NS_MEDIUM() \
|
||||
|
@ -280,7 +299,7 @@ static const gdouble ns_high_coeffs[] = {
|
|||
|
||||
#define INIT_NS_HIGH() \
|
||||
gdouble orig; \
|
||||
gdouble *errors = ctx->error_buf, cur_error; \
|
||||
gdouble *errors = quant->error_buf, cur_error; \
|
||||
int j;
|
||||
|
||||
#define ADD_NS_HIGH() \
|
||||
|
@ -352,142 +371,149 @@ MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_medium, INIT_DITHER_TPDF_HF_F,
|
|||
MAKE_QUANTIZE_FUNC_F (float_tpdf_hf_high, INIT_DITHER_TPDF_HF_F, INIT_NS_HIGH,
|
||||
ADD_NS_HIGH, ADD_DITHER_TPDF_HF_F, UPDATE_ERROR_HIGH);
|
||||
|
||||
static const AudioConvertQuantize quantize_funcs[] = {
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_none_none),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_rpdf_none),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_none),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_hf_none),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_none),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_error_feedback),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_simple),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_medium),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_none_high),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_none),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_error_feedback),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_simple),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_medium),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_high),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_none),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_error_feedback),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_simple),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_medium),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_high),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_none),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_error_feedback),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_simple),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_medium),
|
||||
(AudioConvertQuantize) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_high)
|
||||
static const QuantizeFunc quantize_funcs[] = {
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_none_none),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_rpdf_none),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_none),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (int_tpdf_hf_none),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_none),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_error_feedback),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_simple),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_medium),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_none_high),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_none),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_error_feedback),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_simple),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_medium),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_rpdf_high),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_none),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_error_feedback),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_simple),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_medium),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_high),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_none),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_error_feedback),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_simple),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_medium),
|
||||
(QuantizeFunc) MAKE_QUANTIZE_FUNC_NAME (float_tpdf_hf_high)
|
||||
};
|
||||
|
||||
static void
|
||||
gst_audio_quantize_setup_noise_shaping (AudioConvertCtx * ctx)
|
||||
gst_audio_quantize_setup_noise_shaping (GstAudioQuantize * quant)
|
||||
{
|
||||
switch (ctx->ns) {
|
||||
case NOISE_SHAPING_HIGH:{
|
||||
ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 8);
|
||||
switch (quant->ns) {
|
||||
case GST_AUDIO_NOISE_SHAPING_HIGH:{
|
||||
quant->error_buf = g_new0 (gdouble, quant->channels * 8);
|
||||
break;
|
||||
}
|
||||
case NOISE_SHAPING_MEDIUM:{
|
||||
ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 5);
|
||||
case GST_AUDIO_NOISE_SHAPING_MEDIUM:{
|
||||
quant->error_buf = g_new0 (gdouble, quant->channels * 5);
|
||||
break;
|
||||
}
|
||||
case NOISE_SHAPING_SIMPLE:{
|
||||
ctx->error_buf = g_new0 (gdouble, ctx->out.channels * 2);
|
||||
case GST_AUDIO_NOISE_SHAPING_SIMPLE:{
|
||||
quant->error_buf = g_new0 (gdouble, quant->channels * 2);
|
||||
break;
|
||||
}
|
||||
case NOISE_SHAPING_ERROR_FEEDBACK:
|
||||
ctx->error_buf = g_new0 (gdouble, ctx->out.channels);
|
||||
case GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK:
|
||||
quant->error_buf = g_new0 (gdouble, quant->channels);
|
||||
break;
|
||||
case NOISE_SHAPING_NONE:
|
||||
case GST_AUDIO_NOISE_SHAPING_NONE:
|
||||
default:
|
||||
ctx->error_buf = NULL;
|
||||
quant->error_buf = NULL;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_quantize_free_noise_shaping (AudioConvertCtx * ctx)
|
||||
gst_audio_quantize_setup_dither (GstAudioQuantize * quant)
|
||||
{
|
||||
switch (ctx->ns) {
|
||||
case NOISE_SHAPING_HIGH:
|
||||
case NOISE_SHAPING_MEDIUM:
|
||||
case NOISE_SHAPING_SIMPLE:
|
||||
case NOISE_SHAPING_ERROR_FEEDBACK:
|
||||
case NOISE_SHAPING_NONE:
|
||||
switch (quant->dither) {
|
||||
case GST_AUDIO_DITHER_TPDF_HF:
|
||||
quant->last_random = g_new0 (gdouble, quant->channels);
|
||||
break;
|
||||
case GST_AUDIO_DITHER_RPDF:
|
||||
case GST_AUDIO_DITHER_TPDF:
|
||||
quant->last_random = NULL;
|
||||
break;
|
||||
case GST_AUDIO_DITHER_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (ctx->error_buf);
|
||||
ctx->error_buf = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_quantize_setup_dither (AudioConvertCtx * ctx)
|
||||
{
|
||||
switch (ctx->dither) {
|
||||
case DITHER_TPDF_HF:
|
||||
if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo))
|
||||
ctx->last_random = g_new0 (gint32, ctx->out.channels);
|
||||
else
|
||||
ctx->last_random = g_new0 (gdouble, ctx->out.channels);
|
||||
break;
|
||||
case DITHER_RPDF:
|
||||
case DITHER_TPDF:
|
||||
ctx->last_random = NULL;
|
||||
break;
|
||||
case DITHER_NONE:
|
||||
default:
|
||||
ctx->last_random = NULL;
|
||||
quant->last_random = NULL;
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_quantize_free_dither (AudioConvertCtx * ctx)
|
||||
{
|
||||
g_free (ctx->last_random);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_audio_quantize_setup_quantize_func (AudioConvertCtx * ctx)
|
||||
gst_audio_quantize_setup_quantize_func (GstAudioQuantize * quant)
|
||||
{
|
||||
gint index = 0;
|
||||
|
||||
if (!GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->out.finfo)) {
|
||||
ctx->quantize = NULL;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ctx->ns == NOISE_SHAPING_NONE
|
||||
&& GST_AUDIO_FORMAT_INFO_IS_INTEGER (ctx->in.finfo)) {
|
||||
index += ctx->dither;
|
||||
if (quant->ns == GST_AUDIO_NOISE_SHAPING_NONE
|
||||
&& quant->format == GST_AUDIO_FORMAT_S32) {
|
||||
index += quant->dither;
|
||||
} else {
|
||||
index += 4 + (5 * ctx->dither);
|
||||
index += ctx->ns;
|
||||
}
|
||||
g_assert (quant->format == GST_AUDIO_FORMAT_F64);
|
||||
|
||||
ctx->quantize = quantize_funcs[index];
|
||||
index += 4 + (5 * quant->dither);
|
||||
index += quant->ns;
|
||||
}
|
||||
quant->quantize = quantize_funcs[index];
|
||||
}
|
||||
|
||||
gboolean
|
||||
gst_audio_quantize_setup (AudioConvertCtx * ctx)
|
||||
/**
|
||||
* gst_audio_quantize_new:
|
||||
* @dither: a #GstAudioDitherMethod
|
||||
* @ns: a #GstAudioNoiseShapingMethod
|
||||
* @flags: #GstAudioQuantizeFlags
|
||||
* @format: the #GstAudioFormat of the samples
|
||||
* @channels: the amount of channels in the samples
|
||||
* @quantizer: the quantizer to use
|
||||
*
|
||||
* Create a new quantizer object with the given parameters.
|
||||
*
|
||||
* Returns: a new #GstAudioQuantize. Free with gst_audio_quantize_free().
|
||||
*/
|
||||
GstAudioQuantize *
|
||||
gst_audio_quantize_new (GstAudioDitherMethod dither,
|
||||
GstAudioNoiseShapingMethod ns, GstAudioQuantizeFlags flags,
|
||||
GstAudioFormat format, guint channels, guint quantizer)
|
||||
{
|
||||
gst_audio_quantize_setup_dither (ctx);
|
||||
gst_audio_quantize_setup_noise_shaping (ctx);
|
||||
gst_audio_quantize_setup_quantize_func (ctx);
|
||||
GstAudioQuantize *quant;
|
||||
|
||||
return TRUE;
|
||||
quant = g_slice_new0 (GstAudioQuantize);
|
||||
quant->dither = dither;
|
||||
quant->ns = ns;
|
||||
quant->flags = flags;
|
||||
quant->format = format;
|
||||
quant->channels = channels;
|
||||
quant->quantizer = quantizer;
|
||||
|
||||
gst_audio_quantize_setup_dither (quant);
|
||||
gst_audio_quantize_setup_noise_shaping (quant);
|
||||
gst_audio_quantize_setup_quantize_func (quant);
|
||||
|
||||
return quant;
|
||||
}
|
||||
|
||||
/**
|
||||
* gst_audio_quantize_free:
|
||||
* @quant: a #GstAudioQuantize
|
||||
*
|
||||
* Free a #GstAudioQuantize.
|
||||
*/
|
||||
void
|
||||
gst_audio_quantize_free (GstAudioQuantize * quant)
|
||||
{
|
||||
g_free (quant->error_buf);
|
||||
g_free (quant->last_random);
|
||||
|
||||
g_slice_free (GstAudioQuantize, quant);
|
||||
}
|
||||
|
||||
void
|
||||
gst_audio_quantize_free (AudioConvertCtx * ctx)
|
||||
gst_audio_quantize_samples (GstAudioQuantize * quant,
|
||||
gpointer data, guint samples)
|
||||
{
|
||||
gst_audio_quantize_free_dither (ctx);
|
||||
gst_audio_quantize_free_noise_shaping (ctx);
|
||||
quant->quantize (quant, data, data, samples);
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) 2007 Sebastian Dröge <slomo@circular-chaos.org>
|
||||
* (C) 2015 Wim Taymans <wim.taymans@gmail.com>
|
||||
*
|
||||
* gstaudioquantize.h: quantizes audio to the target format and optionally
|
||||
* applies dithering and noise shaping.
|
||||
|
@ -21,14 +22,68 @@
|
|||
*/
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include "audioconvert.h"
|
||||
|
||||
#include <gst/audio/audio.h>
|
||||
|
||||
|
||||
#ifndef __GST_AUDIO_QUANTIZE_H__
|
||||
#define __GST_AUDIO_QUANTIZE_H__
|
||||
|
||||
gboolean gst_audio_quantize_setup (AudioConvertCtx * ctx);
|
||||
void gst_audio_quantize_reset (AudioConvertCtx * ctx);
|
||||
void gst_audio_quantize_free (AudioConvertCtx * ctx);
|
||||
/**
|
||||
* GstAudioDitherMethod:
|
||||
* @GST_AUDIO_DITHER_NONE: No dithering
|
||||
* @GST_AUDIO_DITHER_RPDF: Rectangular dithering
|
||||
* @GST_AUDIO_DITHER_TPDF: Triangular dithering (default)
|
||||
* @GST_AUDIO_DITHER_TPDF_HF: High frequency triangular dithering
|
||||
*
|
||||
* Set of available dithering methods.
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_AUDIO_DITHER_NONE = 0,
|
||||
GST_AUDIO_DITHER_RPDF,
|
||||
GST_AUDIO_DITHER_TPDF,
|
||||
GST_AUDIO_DITHER_TPDF_HF
|
||||
} GstAudioDitherMethod;
|
||||
|
||||
/**
|
||||
* GstAudioNoiseShapingMethod:
|
||||
* @GST_AUDIO_NOISE_SHAPING_NONE: No noise shaping (default)
|
||||
* @GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK: Error feedback
|
||||
* @GST_AUDIO_NOISE_SHAPING_SIMPLE: Simple 2-pole noise shaping
|
||||
* @GST_AUDIO_NOISE_SHAPING_MEDIUM: Medium 5-pole noise shaping
|
||||
* @GST_AUDIO_NOISE_SHAPING_HIGH: High 8-pole noise shaping
|
||||
*
|
||||
* Set of available noise shaping methods
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
GST_AUDIO_NOISE_SHAPING_NONE = 0,
|
||||
GST_AUDIO_NOISE_SHAPING_ERROR_FEEDBACK,
|
||||
GST_AUDIO_NOISE_SHAPING_SIMPLE,
|
||||
GST_AUDIO_NOISE_SHAPING_MEDIUM,
|
||||
GST_AUDIO_NOISE_SHAPING_HIGH
|
||||
} GstAudioNoiseShapingMethod;
|
||||
|
||||
|
||||
typedef enum
|
||||
{
|
||||
GST_AUDIO_QUANTIZE_FLAG_NONE = 0
|
||||
} GstAudioQuantizeFlags;
|
||||
|
||||
|
||||
typedef struct _GstAudioQuantize GstAudioQuantize;
|
||||
|
||||
GstAudioQuantize * gst_audio_quantize_new (GstAudioDitherMethod dither,
|
||||
GstAudioNoiseShapingMethod ns,
|
||||
GstAudioQuantizeFlags flags,
|
||||
GstAudioFormat format,
|
||||
guint channels,
|
||||
guint quantizer);
|
||||
|
||||
void gst_audio_quantize_free (GstAudioQuantize * quant);
|
||||
|
||||
void gst_audio_quantize_samples (GstAudioQuantize * quant,
|
||||
gpointer data, guint samples);
|
||||
|
||||
#endif /* __GST_AUDIO_QUANTIZE_H__ */
|
||||
|
|
Loading…
Reference in a new issue