mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
audioconvert: [API]: expose mix-matrix property.
This obsoletes audiomixmatrix https://bugzilla.gnome.org/show_bug.cgi?id=785471
This commit is contained in:
parent
4196e67ff1
commit
8d52a107a4
2 changed files with 112 additions and 10 deletions
|
@ -44,6 +44,34 @@
|
|||
* (or any other audio file for which decoders are installed) and re-encodes
|
||||
* it into an Ogg/Vorbis audio file.
|
||||
*
|
||||
* A mix matrix can be passed to audioconvert, that will govern the
|
||||
* remapping of input to output 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_FLOAT);
|
||||
* g_value_set_float (&v3, 1);
|
||||
* gst_value_array_append_value (&v2, &v3);
|
||||
* g_value_unset (&v3);
|
||||
* [ Repeat for as many float 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 (audioconvert), "mix-matrix", &v);
|
||||
* g_value_unset (&v);
|
||||
* ]|
|
||||
*
|
||||
* ## Example launch line
|
||||
* |[
|
||||
* gst-launch-1.0 audiotestsrc ! audio/x-raw, channels=4 ! audioconvert mix-matrix="<<(float)1.0, (float)0.0, (float)0.0, (float)0.0>, <(float)0.0, (float)1.0, (float)0.0, (float)0.0>>" ! audio/x-raw,channels=2 ! autoaudiosink
|
||||
* ]|
|
||||
*/
|
||||
|
||||
/*
|
||||
|
@ -110,6 +138,7 @@ enum
|
|||
PROP_0,
|
||||
PROP_DITHERING,
|
||||
PROP_NOISE_SHAPING,
|
||||
PROP_MIX_MATRIX,
|
||||
};
|
||||
|
||||
#define DEBUG_INIT \
|
||||
|
@ -162,6 +191,17 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass)
|
|||
GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, GST_AUDIO_NOISE_SHAPING_NONE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property (gobject_class, PROP_MIX_MATRIX,
|
||||
gst_param_spec_array ("mix-matrix",
|
||||
"Input/output channel matrix",
|
||||
"Transformation matrix for input/output channels",
|
||||
gst_param_spec_array ("matrix-rows", "rows", "rows",
|
||||
g_param_spec_float ("matrix-cols", "cols", "cols",
|
||||
-1, 1, 0,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
|
||||
|
||||
gst_element_class_add_static_pad_template (element_class,
|
||||
&gst_audio_convert_src_template);
|
||||
gst_element_class_add_static_pad_template (element_class,
|
||||
|
@ -196,6 +236,7 @@ gst_audio_convert_init (GstAudioConvert * this)
|
|||
{
|
||||
this->dither = GST_AUDIO_DITHER_TPDF;
|
||||
this->ns = GST_AUDIO_NOISE_SHAPING_NONE;
|
||||
g_value_init (&this->mix_matrix, GST_TYPE_ARRAY);
|
||||
|
||||
gst_base_transform_set_gap_aware (GST_BASE_TRANSFORM (this), TRUE);
|
||||
}
|
||||
|
@ -210,6 +251,8 @@ gst_audio_convert_dispose (GObject * obj)
|
|||
this->convert = NULL;
|
||||
}
|
||||
|
||||
g_value_unset (&this->mix_matrix);
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (obj);
|
||||
}
|
||||
|
||||
|
@ -249,13 +292,16 @@ remove_format_from_structure (GstCapsFeatures * features,
|
|||
|
||||
static gboolean
|
||||
remove_channels_from_structure (GstCapsFeatures * features, GstStructure * s,
|
||||
gpointer user_data G_GNUC_UNUSED)
|
||||
gpointer user_data)
|
||||
{
|
||||
guint64 mask;
|
||||
gint channels;
|
||||
GstAudioConvert *this = GST_AUDIO_CONVERT (user_data);
|
||||
|
||||
/* Only remove the channels and channel-mask for non-NONE layouts */
|
||||
if (!gst_structure_get (s, "channel-mask", GST_TYPE_BITMASK, &mask, NULL) ||
|
||||
/* Only remove the channels and channel-mask for non-NONE layouts,
|
||||
* or if a mix matrix was manually specified */
|
||||
if (gst_value_array_get_size (&this->mix_matrix) ||
|
||||
!gst_structure_get (s, "channel-mask", GST_TYPE_BITMASK, &mask, NULL) ||
|
||||
(mask != 0 || (gst_structure_get_int (s, "channels", &channels)
|
||||
&& channels == 1))) {
|
||||
gst_structure_remove_fields (s, "channel-mask", "channels", NULL);
|
||||
|
@ -264,6 +310,17 @@ remove_channels_from_structure (GstCapsFeatures * features, GstStructure * s,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_other_channels_to_structure (GstCapsFeatures * features, GstStructure * s,
|
||||
gpointer user_data)
|
||||
{
|
||||
gint other_channels = GPOINTER_TO_INT (user_data);
|
||||
|
||||
gst_structure_set (s, "channels", G_TYPE_INT, other_channels, NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* The caps can be transformed into any other caps with format info removed.
|
||||
* However, we should prefer passthrough, so if passthrough is possible,
|
||||
* put it first in the list. */
|
||||
|
@ -273,11 +330,29 @@ gst_audio_convert_transform_caps (GstBaseTransform * btrans,
|
|||
{
|
||||
GstCaps *tmp, *tmp2;
|
||||
GstCaps *result;
|
||||
GstAudioConvert *this = GST_AUDIO_CONVERT (btrans);
|
||||
|
||||
tmp = gst_caps_copy (caps);
|
||||
|
||||
gst_caps_map_in_place (tmp, remove_format_from_structure, NULL);
|
||||
gst_caps_map_in_place (tmp, remove_channels_from_structure, NULL);
|
||||
gst_caps_map_in_place (tmp, remove_channels_from_structure, btrans);
|
||||
|
||||
/* We can infer the required input / output channels based on the
|
||||
* matrix dimensions */
|
||||
if (gst_value_array_get_size (&this->mix_matrix)) {
|
||||
gint other_channels;
|
||||
|
||||
if (direction == GST_PAD_SRC) {
|
||||
const GValue *first_row =
|
||||
gst_value_array_get_value (&this->mix_matrix, 0);
|
||||
other_channels = gst_value_array_get_size (first_row);
|
||||
} else {
|
||||
other_channels = gst_value_array_get_size (&this->mix_matrix);
|
||||
}
|
||||
|
||||
gst_caps_map_in_place (tmp, add_other_channels_to_structure,
|
||||
GINT_TO_POINTER (other_channels));
|
||||
}
|
||||
|
||||
if (filter) {
|
||||
tmp2 = gst_caps_intersect_full (filter, tmp, GST_CAPS_INTERSECT_FIRST);
|
||||
|
@ -637,6 +712,7 @@ gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
|
|||
GstAudioInfo in_info;
|
||||
GstAudioInfo out_info;
|
||||
gboolean in_place;
|
||||
GstStructure *config;
|
||||
|
||||
GST_DEBUG_OBJECT (base, "incaps %" GST_PTR_FORMAT ", outcaps %"
|
||||
GST_PTR_FORMAT, incaps, outcaps);
|
||||
|
@ -651,12 +727,17 @@ gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
|
|||
if (!gst_audio_info_from_caps (&out_info, outcaps))
|
||||
goto invalid_out;
|
||||
|
||||
this->convert = gst_audio_converter_new (0, &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));
|
||||
config = 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 (gst_value_array_get_size (&this->mix_matrix))
|
||||
gst_structure_set_value (config, GST_AUDIO_CONVERTER_OPT_MIX_MATRIX,
|
||||
&this->mix_matrix);
|
||||
|
||||
this->convert = gst_audio_converter_new (0, &in_info, &out_info, config);
|
||||
|
||||
if (this->convert == NULL)
|
||||
goto no_converter;
|
||||
|
@ -850,6 +931,22 @@ gst_audio_convert_set_property (GObject * object, guint prop_id,
|
|||
case PROP_NOISE_SHAPING:
|
||||
this->ns = g_value_get_enum (value);
|
||||
break;
|
||||
case PROP_MIX_MATRIX:
|
||||
if (!gst_value_array_get_size (value)) {
|
||||
g_warning ("Empty mix matrix");
|
||||
} else {
|
||||
const GValue *first_row = gst_value_array_get_value (value, 0);
|
||||
|
||||
if (gst_value_array_get_size (first_row)) {
|
||||
if (gst_value_array_get_size (&this->mix_matrix))
|
||||
g_value_unset (&this->mix_matrix);
|
||||
|
||||
g_value_copy (value, &this->mix_matrix);
|
||||
} else {
|
||||
g_warning ("Empty mix matrix's first row");
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
@ -869,6 +966,10 @@ gst_audio_convert_get_property (GObject * object, guint prop_id,
|
|||
case PROP_NOISE_SHAPING:
|
||||
g_value_set_enum (value, this->ns);
|
||||
break;
|
||||
case PROP_MIX_MATRIX:
|
||||
if (gst_value_array_get_size (&this->mix_matrix))
|
||||
g_value_copy (&this->mix_matrix, value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
|
|
|
@ -47,6 +47,7 @@ struct _GstAudioConvert
|
|||
/* properties */
|
||||
GstAudioDitherMethod dither;
|
||||
GstAudioNoiseShapingMethod ns;
|
||||
GValue mix_matrix;
|
||||
|
||||
GstAudioInfo in_info;
|
||||
GstAudioInfo out_info;
|
||||
|
|
Loading…
Reference in a new issue