audioconvert: move audio quantize code to libs

Move the audio quantize code from audioconvert to the audio library.
work on making an audio converter helper function similar to the video
converter.
Fold fastrandom directly into the quantizer, add some ORC code to
optimize this later.
This commit is contained in:
Wim Taymans 2015-11-06 12:10:48 +01:00
parent a7789854d5
commit c36ac3ce45
11 changed files with 353 additions and 258 deletions

View file

@ -7,6 +7,7 @@ glib_enum_headers= \
audio-format.h \
audio-channels.h \
audio-info.h \
audio-quantize.h \
gstaudioringbuffer.h
glib_enum_define = GST_AUDIO
@ -27,6 +28,7 @@ libgstaudio_@GST_API_VERSION@_la_SOURCES = \
audio-format.c \
audio-channels.c \
audio-info.c \
audio-quantize.c \
gstaudioringbuffer.c \
gstaudioclock.c \
gstaudiocdsrc.c \
@ -50,6 +52,7 @@ libgstaudio_@GST_API_VERSION@include_HEADERS = \
audio-format.h \
audio-channels.h \
audio-info.h \
audio-quantize.h \
gstaudioringbuffer.h \
gstaudioclock.h \
gstaudiofilter.h \

View file

@ -29,10 +29,9 @@
#include <gst/gst.h>
#include <string.h>
#include <math.h>
#include "gstaudioconvertorc.h"
#include "gstaudioquantize.h"
#include "gstfastrandom.h"
#include "gstaudiopack.h"
#include "audio-quantize.h"
typedef void (*QuantizeFunc) (GstAudioQuantize * quant, const gpointer src,
gpointer dst, gint count);
@ -85,10 +84,26 @@ static void
gst_audio_quantize_quantize_int_none_none (GstAudioQuantize * quant,
const gpointer src, gpointer dst, gint samples)
{
audio_convert_orc_int_bias (dst, src, quant->bias, ~quant->mask,
audio_orc_int_bias (dst, src, quant->bias, ~quant->mask,
samples * quant->channels);
}
/* This is the base function, implementing a linear congruential generator
* and returning a pseudo random number between 0 and 2^32 - 1.
*/
static inline guint32
gst_fast_random_uint32 (void)
{
static guint32 state = 0xdeadbeef;
return (state = state * 1103515245 + 12345);
}
static inline gint32
gst_fast_random_int32 (void)
{
return (gint32) gst_fast_random_uint32 ();
}
/* Assuming dither == 2^n,
* returns one of 2^(n+1) possible random values:
* -dither <= retval < dither */
@ -155,7 +170,7 @@ gst_audio_quantize_quantize_int_dither_none (GstAudioQuantize * quant,
{
setup_dither_buf (quant, samples);
audio_convert_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask,
audio_orc_int_dither (dst, src, quant->dither_buf, ~quant->mask,
samples * quant->channels);
}

View file

@ -27,6 +27,7 @@
#include <gst/audio/audio-format.h>
#include <gst/audio/audio-channels.h>
#include <gst/audio/audio-info.h>
#include <gst/audio/audio-quantize.h>
G_BEGIN_DECLS

View file

@ -380,3 +380,31 @@ copyl d1, p1
copyq d1, p1
.function audio_orc_int_bias
.dest 4 d1 gint32
.source 4 s1 gint32
.param 4 bias gint32
.param 4 mask gint32
.temp 4 t1
addssl t1, s1, bias
andl d1, t1, mask
.function audio_orc_int_dither
.dest 4 d1 gint32
.source 4 s1 gint32
.source 4 dither gint32
.param 4 mask gint32
.temp 4 t1
addssl t1, s1, dither
andl d1, t1, mask
.function audio_orc_update_rand
.dest 4 r guint32
.temp 4 t
mulll t, r, 1103515245
addl r, t, 12345

View file

@ -7,7 +7,6 @@ libgstaudioconvert_la_SOURCES = \
gstaudioconvert.c \
audioconvert.c \
gstchannelmix.c \
gstaudioquantize.c \
plugin.c
nodist_libgstaudioconvert_la_SOURCES = $(ORC_NODIST_SOURCES)
@ -22,6 +21,4 @@ noinst_HEADERS = \
gstaudioconvert.h \
audioconvert.h \
gstchannelmix.h \
gstaudioquantize.h \
gstfastrandom.h \
plugin.h

View file

@ -27,10 +27,11 @@
#include <string.h>
#include "gstchannelmix.h"
#include "gstaudioquantize.h"
#include "audioconvert.h"
#include "gstaudioconvertorc.h"
typedef void (*AudioConvertFunc) (gpointer dst, const gpointer src, gint count);
/**
* int/int int/float float/int float/float
*
@ -41,29 +42,160 @@
* quantize S32 S32
* pack S32 F64 S32 F64
*/
gboolean
audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
GstAudioInfo * out, GstAudioDitherMethod dither,
GstAudioNoiseShapingMethod ns)
struct _GstAudioConverter
{
GstAudioInfo in;
GstAudioInfo out;
GstStructure *config;
gboolean in_default;
AudioConvertFunc convert_in;
GstAudioFormat mix_format;
gboolean mix_passthrough;
GstChannelMix *mix;
AudioConvertFunc convert_out;
GstAudioQuantize *quant;
gboolean out_default;
gboolean passthrough;
gpointer tmpbuf;
gpointer tmpbuf2;
gint tmpbufsize;
};
/*
static guint
get_opt_uint (GstAudioConverter * convert, const gchar * opt, guint def)
{
guint res;
if (!gst_structure_get_uint (convert->config, opt, &res))
res = def;
return res;
}
*/
static gint
get_opt_enum (GstAudioConverter * convert, const gchar * opt, GType type,
gint def)
{
gint res;
if (!gst_structure_get_enum (convert->config, opt, type, &res))
res = def;
return res;
}
#define DEFAULT_OPT_DITHER_METHOD GST_AUDIO_DITHER_NONE
#define DEFAULT_OPT_NOISE_SHAPING_METHOD GST_AUDIO_NOISE_SHAPING_NONE
#define DEFAULT_OPT_QUANTIZATION 1
#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_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)
#define GET_OPT_QUANTIZATION(c) get_opt_uint(c, \
GST_AUDIO_CONVERTER_OPT_QUANTIZATION, DEFAULT_OPT_QUANTIZATION)
static gboolean
copy_config (GQuark field_id, const GValue * value, gpointer user_data)
{
GstAudioConverter *convert = user_data;
gst_structure_id_set_value (convert->config, field_id, value);
return TRUE;
}
/**
* gst_audio_converter_set_config:
* @convert: a #GstAudioConverter
* @config: (transfer full): a #GstStructure
*
* Set @config as extra configuraion for @convert.
*
* If the parameters in @config can not be set exactly, this function returns
* %FALSE and will try to update as much state as possible. The new state can
* then be retrieved and refined with gst_audio_converter_get_config().
*
* Look at the #GST_AUDIO_CONVERTER_OPT_* fields to check valid configuration
* option and values.
*
* Returns: %TRUE when @config could be set.
*/
gboolean
gst_audio_converter_set_config (GstAudioConverter * convert,
GstStructure * config)
{
g_return_val_if_fail (convert != NULL, FALSE);
g_return_val_if_fail (config != NULL, FALSE);
gst_structure_foreach (config, copy_config, convert);
gst_structure_free (config);
return TRUE;
}
/**
* gst_audio_converter_get_config:
* @convert: a #GstAudioConverter
*
* Get the current configuration of @convert.
*
* Returns: a #GstStructure that remains valid for as long as @convert is valid
* or until gst_audio_converter_set_config() is called.
*/
const GstStructure *
gst_audio_converter_get_config (GstAudioConverter * convert)
{
g_return_val_if_fail (convert != NULL, NULL);
return convert->config;
}
/**
*
*/
GstAudioConverter *
gst_audio_converter_new (GstAudioInfo * in, GstAudioInfo * out,
GstStructure * config)
{
GstAudioConverter *convert;
gint in_depth, out_depth;
GstChannelMixFlags flags;
gboolean in_int, out_int;
GstAudioFormat format;
GstAudioDitherMethod dither;
GstAudioNoiseShapingMethod ns;
g_return_val_if_fail (ctx != NULL, FALSE);
g_return_val_if_fail (in != NULL, FALSE);
g_return_val_if_fail (out != NULL, FALSE);
/* first clean the existing context */
audio_convert_clean_context (ctx);
if ((GST_AUDIO_INFO_CHANNELS (in) != GST_AUDIO_INFO_CHANNELS (out)) &&
(GST_AUDIO_INFO_IS_UNPOSITIONED (in)
|| GST_AUDIO_INFO_IS_UNPOSITIONED (out)))
goto unpositioned;
ctx->in = *in;
ctx->out = *out;
convert = g_slice_new0 (GstAudioConverter);
convert->in = *in;
convert->out = *out;
/* default config */
convert->config = gst_structure_new_empty ("GstAudioConverter");
if (config)
gst_audio_converter_set_config (convert, config);
dither = GET_OPT_DITHER_METHOD (convert);
ns = GET_OPT_NOISE_SHAPING_METHOD (convert);
GST_INFO ("unitsizes: %d -> %d", in->bpf, out->bpf);
@ -85,7 +217,7 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
/* step 1, unpack */
format = in->finfo->unpack_format;
ctx->in_default = in->finfo->unpack_format == in->finfo->format;
convert->in_default = in->finfo->unpack_format == in->finfo->format;
GST_INFO ("unpack format %s to %s",
gst_audio_format_to_string (in->finfo->format),
gst_audio_format_to_string (format));
@ -93,23 +225,23 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
/* step 2, optional convert from S32 to F64 for channel mix */
if (in_int && !out_int) {
GST_INFO ("convert S32 to F64");
ctx->convert_in = (AudioConvertFunc) audio_convert_orc_s32_to_double;
convert->convert_in = (AudioConvertFunc) audio_convert_orc_s32_to_double;
format = GST_AUDIO_FORMAT_F64;
}
/* step 3, channel mix */
ctx->mix_format = format;
ctx->mix = gst_channel_mix_new (flags, in->channels, in->position,
convert->mix_format = format;
convert->mix = gst_channel_mix_new (flags, in->channels, in->position,
out->channels, out->position);
ctx->mix_passthrough = gst_channel_mix_is_passthrough (ctx->mix);
convert->mix_passthrough = gst_channel_mix_is_passthrough (convert->mix);
GST_INFO ("mix format %s, passthrough %d, in_channels %d, out_channels %d",
gst_audio_format_to_string (format), ctx->mix_passthrough,
gst_audio_format_to_string (format), convert->mix_passthrough,
in->channels, out->channels);
/* step 4, optional convert for quantize */
if (!in_int && out_int) {
GST_INFO ("convert F64 to S32");
ctx->convert_out = (AudioConvertFunc) audio_convert_orc_double_to_s32;
convert->convert_out = (AudioConvertFunc) audio_convert_orc_double_to_s32;
format = GST_AUDIO_FORMAT_S32;
}
/* step 5, optional quantize */
@ -132,78 +264,72 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, GstAudioInfo * in,
* the rounding correct */
if (out_int && out_depth < 32) {
GST_INFO ("quantize to %d bits, dither %d, ns %d", out_depth, dither, ns);
ctx->quant = gst_audio_quantize_new (dither, ns, 0, format,
convert->quant = gst_audio_quantize_new (dither, ns, 0, format,
out->channels, 1U << (32 - out_depth));
}
/* step 6, pack */
g_assert (out->finfo->unpack_format == format);
ctx->out_default = format == out->finfo->format;
convert->out_default = format == out->finfo->format;
GST_INFO ("pack format %s to %s", gst_audio_format_to_string (format),
gst_audio_format_to_string (out->finfo->format));
/* optimize */
if (out->finfo->format == in->finfo->format && ctx->mix_passthrough) {
if (out->finfo->format == in->finfo->format && convert->mix_passthrough) {
GST_INFO ("same formats and passthrough mixing -> passthrough");
ctx->passthrough = TRUE;
convert->passthrough = TRUE;
}
return TRUE;
return convert;
/* ERRORS */
unpositioned:
{
GST_WARNING ("unpositioned channels");
return FALSE;
return NULL;
}
}
gboolean
audio_convert_clean_context (AudioConvertCtx * ctx)
void
gst_audio_converter_free (GstAudioConverter * convert)
{
g_return_val_if_fail (ctx != NULL, FALSE);
g_return_if_fail (convert != NULL);
if (ctx->quant)
gst_audio_quantize_free (ctx->quant);
ctx->quant = NULL;
if (ctx->mix)
gst_channel_mix_free (ctx->mix);
ctx->mix = NULL;
gst_audio_info_init (&ctx->in);
gst_audio_info_init (&ctx->out);
ctx->convert_in = NULL;
ctx->convert_out = NULL;
if (convert->quant)
gst_audio_quantize_free (convert->quant);
if (convert->mix)
gst_channel_mix_free (convert->mix);
gst_audio_info_init (&convert->in);
gst_audio_info_init (&convert->out);
g_free (ctx->tmpbuf);
g_free (ctx->tmpbuf2);
ctx->tmpbuf = NULL;
ctx->tmpbuf2 = NULL;
ctx->tmpbufsize = 0;
g_free (convert->tmpbuf);
g_free (convert->tmpbuf2);
gst_structure_free (convert->config);
return TRUE;
g_slice_free (GstAudioConverter, convert);
}
gboolean
audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gint * srcsize,
gint * dstsize)
gst_audio_converter_get_sizes (GstAudioConverter * convert, gint samples,
gint * srcsize, gint * dstsize)
{
g_return_val_if_fail (ctx != NULL, FALSE);
g_return_val_if_fail (convert != NULL, FALSE);
if (srcsize)
*srcsize = samples * ctx->in.bpf;
*srcsize = samples * convert->in.bpf;
if (dstsize)
*dstsize = samples * ctx->out.bpf;
*dstsize = samples * convert->out.bpf;
return TRUE;
}
gboolean
audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
gpointer dst, gint samples, gboolean src_writable)
gst_audio_converter_samples (GstAudioConverter * convert,
GstAudioConverterFlags flags, gpointer src, gpointer dst, gint samples)
{
guint size;
gpointer outbuf, tmpbuf, tmpbuf2;
g_return_val_if_fail (ctx != NULL, FALSE);
g_return_val_if_fail (convert != NULL, FALSE);
g_return_val_if_fail (src != NULL, FALSE);
g_return_val_if_fail (dst != NULL, FALSE);
g_return_val_if_fail (samples >= 0, FALSE);
@ -211,86 +337,88 @@ audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
if (samples == 0)
return TRUE;
if (ctx->passthrough) {
memcpy (dst, src, samples * ctx->in.bpf);
if (convert->passthrough) {
memcpy (dst, src, samples * convert->in.bpf);
return TRUE;
}
size = sizeof (gdouble) * samples * MAX (ctx->in.channels, ctx->out.channels);
size =
sizeof (gdouble) * samples * MAX (convert->in.channels,
convert->out.channels);
if (size > ctx->tmpbufsize) {
ctx->tmpbuf = g_realloc (ctx->tmpbuf, size);
ctx->tmpbuf2 = g_realloc (ctx->tmpbuf2, size);
ctx->tmpbufsize = size;
if (size > convert->tmpbufsize) {
convert->tmpbuf = g_realloc (convert->tmpbuf, size);
convert->tmpbuf2 = g_realloc (convert->tmpbuf2, size);
convert->tmpbufsize = size;
}
tmpbuf = ctx->tmpbuf;
tmpbuf2 = ctx->tmpbuf2;
tmpbuf = convert->tmpbuf;
tmpbuf2 = convert->tmpbuf2;
/* 1. unpack */
if (!ctx->in_default) {
if (!ctx->convert_in && ctx->mix_passthrough && !ctx->convert_out
&& !ctx->quant && ctx->out_default)
if (!convert->in_default) {
if (!convert->convert_in && convert->mix_passthrough
&& !convert->convert_out && !convert->quant && convert->out_default)
outbuf = dst;
else
outbuf = tmpbuf;
ctx->in.finfo->unpack_func (ctx->in.finfo,
convert->in.finfo->unpack_func (convert->in.finfo,
GST_AUDIO_PACK_FLAG_TRUNCATE_RANGE, outbuf, src,
samples * ctx->in.channels);
samples * convert->in.channels);
src = outbuf;
}
/* 2. optionally convert for mixing */
if (ctx->convert_in) {
if (ctx->mix_passthrough && !ctx->convert_out && !ctx->quant
&& ctx->out_default)
if (convert->convert_in) {
if (convert->mix_passthrough && !convert->convert_out && !convert->quant
&& convert->out_default)
outbuf = dst;
else if (src == tmpbuf)
outbuf = tmpbuf2;
else
outbuf = tmpbuf;
ctx->convert_in (outbuf, src, samples * ctx->in.channels);
convert->convert_in (outbuf, src, samples * convert->in.channels);
src = outbuf;
}
/* step 3, channel mix if not passthrough */
if (!ctx->mix_passthrough) {
if (!ctx->convert_out && !ctx->quant && ctx->out_default)
if (!convert->mix_passthrough) {
if (!convert->convert_out && !convert->quant && convert->out_default)
outbuf = dst;
else
outbuf = tmpbuf;
gst_channel_mix_mix (ctx->mix, ctx->mix_format, ctx->in.layout, src, outbuf,
samples);
gst_channel_mix_mix (convert->mix, convert->mix_format, convert->in.layout,
src, outbuf, samples);
src = outbuf;
}
/* step 4, optional convert F64 -> S32 for quantize */
if (ctx->convert_out) {
if (!ctx->quant && ctx->out_default)
if (convert->convert_out) {
if (!convert->quant && convert->out_default)
outbuf = dst;
else
outbuf = tmpbuf;
ctx->convert_out (outbuf, src, samples * ctx->out.channels);
convert->convert_out (outbuf, src, samples * convert->out.channels);
src = outbuf;
}
/* step 5, optional quantize */
if (ctx->quant) {
if (ctx->out_default)
if (convert->quant) {
if (convert->out_default)
outbuf = dst;
else
outbuf = tmpbuf;
gst_audio_quantize_samples (ctx->quant, outbuf, src, samples);
gst_audio_quantize_samples (convert->quant, outbuf, src, samples);
src = outbuf;
}
/* step 6, pack */
if (!ctx->out_default) {
ctx->out.finfo->pack_func (ctx->out.finfo, 0, src, dst,
samples * ctx->out.channels);
if (!convert->out_default) {
convert->out.finfo->pack_func (convert->out.finfo, 0, src, dst,
samples * convert->out.channels);
}
return TRUE;

View file

@ -1,7 +1,8 @@
/* GStreamer
* Copyright (C) 2004 Ronald Bultje <rbultje@ronald.bitfreak.net>
* (C) 2015 Wim Taymans <wim.taymans@gmail.com>
*
* audioconvert.h: audio format conversion library
* audioconverter.h: audio format conversion library
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@ -19,57 +20,73 @@
* Boston, MA 02110-1301, USA.
*/
#ifndef __AUDIO_CONVERT_H__
#define __AUDIO_CONVERT_H__
#ifndef __GST_AUDIO_CONVERTER_H__
#define __GST_AUDIO_CONVERTER_H__
#include <gst/gst.h>
#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)
typedef struct _GstAudioConverter GstAudioConverter;
typedef struct _AudioConvertCtx AudioConvertCtx;
/**
* GST_AUDIO_CONVERTER_OPT_DITHER_METHOD:
*
* #GST_TYPE_AUDIO_DITHER_METHOD, The dither method to use when
* changing bit depth.
* Default is #GST_AUDIO_DITHER_NONE.
*/
#define GST_AUDIO_CONVERTER_OPT_DITHER_METHOD "GstAudioConverter.dither-method"
typedef void (*AudioConvertFunc) (gpointer dst, const gpointer src, gint count);
/**
* GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD:
*
* #GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, The noise shaping method to use
* to mask noise from quantization errors.
* Default is #GST_AUDIO_NOISE_SHAPING_NONE.
*/
#define GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD "GstAudioConverter.noise-shaping-method"
struct _AudioConvertCtx
{
GstAudioInfo in;
GstAudioInfo out;
/**
* GST_AUDIO_CONVERTER_OPT_QUANTIZATION:
*
* #G_TYPE_UINT, The quantization amount. Components will be
* quantized to multiples of this value.
* Default is 1
*/
#define GST_AUDIO_CONVERTER_OPT_QUANTIZATION "GstAudioConverter.quantization"
gboolean in_default;
AudioConvertFunc convert_in;
/**
* @GST_AUDIO_CONVERTER_FLAG_NONE: no flag
* @GST_AUDIO_CONVERTER_FLAG_SOURCE_WRITABLE: the source is writable and can be
* used as temporary storage during conversion.
*
* Extra flags passed to gst_audio_converter_samples().
*/
typedef enum {
GST_AUDIO_CONVERTER_FLAG_NONE = 0,
GST_AUDIO_CONVERTER_FLAG_SOURCE_WRITABLE = (1 << 0)
} GstAudioConverterFlags;
GstAudioFormat mix_format;
gboolean mix_passthrough;
GstChannelMix *mix;
GstAudioConverter * gst_audio_converter_new (GstAudioInfo *in_info,
GstAudioInfo *out_info,
GstStructure *config);
AudioConvertFunc convert_out;
void gst_audio_converter_free (GstAudioConverter * convert);
GstAudioQuantize *quant;
gboolean gst_audio_converter_set_config (GstAudioConverter * convert, GstStructure *config);
const GstStructure * gst_audio_converter_get_config (GstAudioConverter * convert);
gboolean out_default;
gboolean passthrough;
gboolean gst_audio_converter_get_sizes (GstAudioConverter * convert,
gint samples,
gint * srcsize, gint * dstsize);
gpointer tmpbuf;
gpointer tmpbuf2;
gint tmpbufsize;
};
gboolean gst_audio_converter_samples (GstAudioConverter * convert,
GstAudioConverterFlags flags,
gpointer src, gpointer dst,
gint samples);
gboolean audio_convert_prepare_context (AudioConvertCtx * ctx,
GstAudioInfo * in, GstAudioInfo * out,
GstAudioDitherMethod dither, GstAudioNoiseShapingMethod ns);
gboolean audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples,
gint * srcsize, gint * dstsize);
gboolean audio_convert_clean_context (AudioConvertCtx * ctx);
gboolean audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
gpointer dst, gint samples, gboolean src_writable);
#endif /* __AUDIO_CONVERT_H__ */
#endif /* __GST_AUDIO_CONVERTER_H__ */

View file

@ -64,7 +64,6 @@
#include "gstaudioconvert.h"
#include "gstchannelmix.h"
#include "gstaudioquantize.h"
#include "plugin.h"
GST_DEBUG_CATEGORY (audio_convert_debug);
@ -134,51 +133,6 @@ GST_STATIC_PAD_TEMPLATE ("sink",
GST_PAD_ALWAYS,
STATIC_CAPS);
#define GST_TYPE_AUDIO_CONVERT_DITHERING (gst_audio_convert_dithering_get_type ())
static GType
gst_audio_convert_dithering_get_type (void)
{
static GType gtype = 0;
if (gtype == 0) {
static const GEnumValue values[] = {
{GST_AUDIO_DITHER_NONE, "No dithering",
"none"},
{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}
};
gtype = g_enum_register_static ("GstAudioConvertDithering", values);
}
return gtype;
}
#define GST_TYPE_AUDIO_CONVERT_NOISE_SHAPING (gst_audio_convert_ns_get_type ())
static GType
gst_audio_convert_ns_get_type (void)
{
static GType gtype = 0;
if (gtype == 0) {
static const GEnumValue values[] = {
{GST_AUDIO_NOISE_SHAPING_NONE, "No noise shaping (default)",
"none"},
{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}
};
gtype = g_enum_register_static ("GstAudioConvertNoiseShaping", values);
}
return gtype;
}
/*** TYPE FUNCTIONS ***********************************************************/
static void
@ -195,13 +149,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, GST_AUDIO_DITHER_TPDF,
GST_TYPE_AUDIO_DITHER_METHOD, 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, GST_AUDIO_NOISE_SHAPING_NONE,
GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, GST_AUDIO_NOISE_SHAPING_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_element_class_add_pad_template (element_class,
@ -235,7 +189,6 @@ gst_audio_convert_init (GstAudioConvert * this)
{
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);
}
@ -245,7 +198,7 @@ gst_audio_convert_dispose (GObject * obj)
{
GstAudioConvert *this = GST_AUDIO_CONVERT (obj);
audio_convert_clean_context (&this->ctx);
gst_audio_converter_free (this->convert);
G_OBJECT_CLASS (parent_class)->dispose (obj);
}
@ -694,15 +647,29 @@ gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
GST_PTR_FORMAT, incaps, outcaps);
if (this->convert) {
gst_audio_converter_free (this->convert);
this->convert = NULL;
}
if (!gst_audio_info_from_caps (&in_info, incaps))
goto invalid_in;
if (!gst_audio_info_from_caps (&out_info, outcaps))
goto invalid_out;
if (!audio_convert_prepare_context (&this->ctx, &in_info, &out_info,
this->dither, this->ns))
this->convert = gst_audio_converter_new (&in_info, &out_info,
gst_structure_new ("GstAudioConverterConfig",
GST_AUDIO_CONVERTER_OPT_DITHER_METHOD, GST_TYPE_AUDIO_DITHER_METHOD,
this->dither,
GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD,
GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, this->ns, NULL));
if (this->convert == NULL)
goto no_converter;
this->in_info = in_info;
this->out_info = out_info;
return TRUE;
/* ERRORS */
@ -718,7 +685,7 @@ invalid_out:
}
no_converter:
{
GST_ERROR_OBJECT (base, "could not find converter");
GST_ERROR_OBJECT (base, "could not make converter");
return FALSE;
}
}
@ -732,15 +699,17 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
GstMapInfo srcmap, dstmap;
gint insize, outsize;
gboolean inbuf_writable;
GstAudioConverterFlags flags;
gint samples;
/* get amount of samples to convert. */
samples = gst_buffer_get_size (inbuf) / this->ctx.in.bpf;
samples = gst_buffer_get_size (inbuf) / this->in_info.bpf;
/* get in/output sizes, to see if the buffers we got are of correct
* sizes */
if (!audio_convert_get_sizes (&this->ctx, samples, &insize, &outsize))
if (!gst_audio_converter_get_sizes (this->convert, samples, &insize,
&outsize))
goto error;
if (insize == 0 || outsize == 0)
@ -762,13 +731,17 @@ gst_audio_convert_transform (GstBaseTransform * base, GstBuffer * inbuf,
goto wrong_size;
/* and convert the samples */
flags = 0;
if (inbuf_writable)
flags |= GST_AUDIO_CONVERTER_FLAG_SOURCE_WRITABLE;
if (!GST_BUFFER_FLAG_IS_SET (inbuf, GST_BUFFER_FLAG_GAP)) {
if (!audio_convert_convert (&this->ctx, srcmap.data, dstmap.data,
samples, inbuf_writable))
if (!gst_audio_converter_samples (this->convert, flags, srcmap.data,
dstmap.data, samples))
goto convert_error;
} else {
/* Create silence buffer */
gst_audio_format_fill_silence (this->ctx.out.finfo, dstmap.data, outsize);
gst_audio_format_fill_silence (this->out_info.finfo, dstmap.data, outsize);
}
ret = GST_FLOW_OK;
@ -829,8 +802,8 @@ gst_audio_convert_submit_input_buffer (GstBaseTransform * base,
if (base->segment.format == GST_FORMAT_TIME) {
input =
gst_audio_buffer_clip (input, &base->segment, this->ctx.in.rate,
this->ctx.in.bpf);
gst_audio_buffer_clip (input, &base->segment, this->in_info.rate,
this->in_info.bpf);
if (!input)
return GST_FLOW_OK;

View file

@ -46,10 +46,13 @@ struct _GstAudioConvert
{
GstBaseTransform element;
AudioConvertCtx ctx;
/* properties */
GstAudioDitherMethod dither;
GstAudioNoiseShapingMethod ns;
GstAudioInfo in_info;
GstAudioInfo out_info;
GstAudioConverter *convert;
};
struct _GstAudioConvertClass

View file

@ -1,70 +0,0 @@
/* GStreamer
* Copyright (C) 2008 Sebastian Dröge <sebastian.droege@collabora.co.uk>
*
* gstfastrandom.h: Fast, bad PNRG
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include <glib.h>
#ifndef __GST_FAST_RANDOM__
#define __GST_FAST_RANDOM__
/* transform [0..2^32] -> [0..1] */
#define GST_RAND_DOUBLE_TRANSFORM 2.3283064365386962890625e-10
/* This is the base function, implementing a linear congruential generator
* and returning a pseudo random number between 0 and 2^32 - 1.
*/
static inline guint32
gst_fast_random_uint32 (void)
{
static guint32 state = 0xdeadbeef;
return (state = state * 1103515245 + 12345);
}
static inline gint32
gst_fast_random_int32 (void)
{
return (gint32) gst_fast_random_uint32 ();
}
static inline gdouble
gst_fast_random_double (void)
{
gdouble ret;
ret = gst_fast_random_uint32 () * GST_RAND_DOUBLE_TRANSFORM;
ret = (ret + gst_fast_random_uint32 ()) * GST_RAND_DOUBLE_TRANSFORM;
if (ret >= 1.0)
return gst_fast_random_double ();
return ret;
}
static inline gdouble
gst_fast_random_double_range (gdouble start, gdouble end)
{
return gst_fast_random_double () * (end - start) + start;
}
#undef GST_RAND_DOUBLE_TRANSFORM
#endif /* __GST_FAST_RANDOM__ */