mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-03-30 12:49:40 +00:00
[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:
parent
877d6faeea
commit
4196e67ff1
2 changed files with 142 additions and 12 deletions
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in a new issue