[API]: GST_AUDIO_CONVERTER_OPT_MIX_MATRIX

Taken from audiomixmatrix, credits to Vivia Nikolaidou

https://bugzilla.gnome.org/show_bug.cgi?id=785471
This commit is contained in:
Mathieu Duponchelle 2017-07-27 19:31:48 +02:00
parent 877d6faeea
commit 4196e67ff1
2 changed files with 142 additions and 12 deletions

View file

@ -120,6 +120,7 @@ struct _GstAudioConverter
/* channel mix */
gboolean mix_passthrough;
gfloat **mix_matrix;
GstAudioChannelMixer *mix;
/* resample */
@ -263,6 +264,12 @@ get_opt_enum (GstAudioConverter * convert, const gchar * opt, GType type,
return res;
}
static const GValue *
get_opt_value (GstAudioConverter * convert, const gchar * opt)
{
return gst_structure_get_value (convert->config, opt);
}
#define DEFAULT_OPT_RESAMPLER_METHOD GST_AUDIO_RESAMPLER_METHOD_BLACKMAN_NUTTALL
#define DEFAULT_OPT_DITHER_METHOD GST_AUDIO_DITHER_NONE
#define DEFAULT_OPT_NOISE_SHAPING_METHOD GST_AUDIO_NOISE_SHAPING_NONE
@ -279,6 +286,8 @@ get_opt_enum (GstAudioConverter * convert, const gchar * opt, GType type,
DEFAULT_OPT_NOISE_SHAPING_METHOD)
#define GET_OPT_QUANTIZATION(c) get_opt_uint(c, \
GST_AUDIO_CONVERTER_OPT_QUANTIZATION, DEFAULT_OPT_QUANTIZATION)
#define GET_OPT_MIX_MATRIX(c) get_opt_value(c, \
GST_AUDIO_CONVERTER_OPT_MIX_MATRIX)
static gboolean
copy_config (GQuark field_id, const GValue * value, gpointer user_data)
@ -624,26 +633,99 @@ chain_convert_in (GstAudioConverter * convert, AudioChain * prev)
return prev;
}
static gboolean
check_mix_matrix (guint in_channels, guint out_channels, const GValue * value)
{
guint i, j;
if (gst_value_array_get_size (value) != out_channels) {
GST_ERROR ("Invalid mix matrix size, should be %d", out_channels);
goto fail;
}
for (j = 0; j < out_channels; j++) {
const GValue *row = gst_value_array_get_value (value, j);
if (gst_value_array_get_size (row) != in_channels) {
GST_ERROR ("Invalid mix matrix row size, should be %d", in_channels);
goto fail;
}
for (i = 0; i < in_channels; i++) {
const GValue *itm;
itm = gst_value_array_get_value (row, i);
if (!G_VALUE_HOLDS_FLOAT (itm)) {
GST_ERROR ("Invalid mix matrix element type, should be float");
goto fail;
}
}
}
return TRUE;
fail:
return FALSE;
}
static gfloat **
mix_matrix_from_g_value (guint in_channels, guint out_channels,
const GValue * value)
{
guint i, j;
gfloat **matrix = g_new (gfloat *, in_channels);
for (i = 0; i < in_channels; i++)
matrix[i] = g_new (gfloat, out_channels);
for (j = 0; j < out_channels; j++) {
const GValue *row = gst_value_array_get_value (value, j);
for (i = 0; i < in_channels; i++) {
const GValue *itm;
gfloat coefficient;
itm = gst_value_array_get_value (row, i);
coefficient = g_value_get_float (itm);
matrix[i][j] = coefficient;
}
}
return matrix;
}
static AudioChain *
chain_mix (GstAudioConverter * convert, AudioChain * prev)
{
GstAudioChannelMixerFlags flags;
GstAudioInfo *in = &convert->in;
GstAudioInfo *out = &convert->out;
GstAudioFormat format = convert->current_format;
flags =
GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN : 0;
flags |=
GST_AUDIO_INFO_IS_UNPOSITIONED (out) ?
GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_OUT : 0;
const GValue *opt_matrix = GET_OPT_MIX_MATRIX (convert);
convert->current_channels = out->channels;
convert->mix =
gst_audio_channel_mixer_new (flags, format, in->channels, in->position,
out->channels, out->position);
if (opt_matrix) {
gfloat **matrix =
mix_matrix_from_g_value (in->channels, out->channels, opt_matrix);
convert->mix =
gst_audio_channel_mixer_new_with_matrix (0, format, in->channels,
out->channels, matrix);
} else {
GstAudioChannelMixerFlags flags;
flags =
GST_AUDIO_INFO_IS_UNPOSITIONED (in) ?
GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN : 0;
flags |=
GST_AUDIO_INFO_IS_UNPOSITIONED (out) ?
GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_OUT : 0;
convert->mix =
gst_audio_channel_mixer_new (flags, format, in->channels, in->position,
out->channels, out->position);
}
convert->mix_passthrough =
gst_audio_channel_mixer_is_passthrough (convert->mix);
GST_INFO ("mix format %s, passthrough %d, in_channels %d, out_channels %d",
@ -1077,15 +1159,25 @@ gst_audio_converter_new (GstAudioConverterFlags flags, GstAudioInfo * in_info,
{
GstAudioConverter *convert;
AudioChain *prev;
const GValue *opt_matrix = NULL;
g_return_val_if_fail (in_info != NULL, FALSE);
g_return_val_if_fail (out_info != NULL, FALSE);
g_return_val_if_fail (in_info->layout == GST_AUDIO_LAYOUT_INTERLEAVED, FALSE);
g_return_val_if_fail (in_info->layout == out_info->layout, FALSE);
if (config)
opt_matrix =
gst_structure_get_value (config, GST_AUDIO_CONVERTER_OPT_MIX_MATRIX);
if (opt_matrix
&& !check_mix_matrix (in_info->channels, out_info->channels, opt_matrix))
goto invalid_mix_matrix;
if ((GST_AUDIO_INFO_CHANNELS (in_info) != GST_AUDIO_INFO_CHANNELS (out_info))
&& (GST_AUDIO_INFO_IS_UNPOSITIONED (in_info)
|| GST_AUDIO_INFO_IS_UNPOSITIONED (out_info)))
|| GST_AUDIO_INFO_IS_UNPOSITIONED (out_info))
&& !opt_matrix)
goto unpositioned;
convert = g_slice_new0 (GstAudioConverter);
@ -1175,6 +1267,12 @@ unpositioned:
GST_WARNING ("unpositioned channels");
return NULL;
}
invalid_mix_matrix:
{
GST_WARNING ("Invalid mix matrix");
return NULL;
}
}
/**

View file

@ -64,6 +64,38 @@ typedef struct _GstAudioConverter GstAudioConverter;
*/
#define GST_AUDIO_CONVERTER_OPT_QUANTIZATION "GstAudioConverter.quantization"
/**
* GST_AUDIO_CONVERTER_OPT_MIX_MATRIX:
*
* #GST_TYPE_VALUE_LIST, The channel mapping matrix.
*
* The matrix coefficients must be between -1 and 1: the number of rows is equal
* to the number of output channels and the number of columns is equal to the
* number of input channels.
*
* ## Example matrix generation code
* To generate the matrix using code:
*
* |[
* GValue v = G_VALUE_INIT;
* GValue v2 = G_VALUE_INIT;
* GValue v3 = G_VALUE_INIT;
*
* g_value_init (&v2, GST_TYPE_ARRAY);
* g_value_init (&v3, G_TYPE_DOUBLE);
* g_value_set_double (&v3, 1);
* gst_value_array_append_value (&v2, &v3);
* g_value_unset (&v3);
* [ Repeat for as many double as your input channels - unset and reinit v3 ]
* g_value_init (&v, GST_TYPE_ARRAY);
* gst_value_array_append_value (&v, &v2);
* g_value_unset (&v2);
* [ Repeat for as many v2's as your output channels - unset and reinit v2]
* g_object_set_property (G_OBJECT (audiomixmatrix), "matrix", &v);
* g_value_unset (&v);
* ]|
*/
#define GST_AUDIO_CONVERTER_OPT_MIX_MATRIX "GstAudioConverter.mix-matrix"
/**
* GstAudioConverterFlags: