mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-26 03:31:05 +00:00
audioconvert: Fix fallback to identity mixing matrix when setting an empty mix-matrix
Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5530>
This commit is contained in:
parent
d20d94cc48
commit
9cc7e8c035
3 changed files with 84 additions and 16 deletions
|
@ -866,7 +866,7 @@
|
|||
"writable": true
|
||||
},
|
||||
"mix-matrix": {
|
||||
"blurb": "Transformation matrix for input/output channels",
|
||||
"blurb": "Transformation matrix for input/output channels.",
|
||||
"conditionally-available": false,
|
||||
"construct": false,
|
||||
"construct-only": false,
|
||||
|
|
|
@ -46,6 +46,9 @@
|
|||
*
|
||||
* A mix matrix can be passed to audioconvert, that will govern the
|
||||
* remapping of input to output channels.
|
||||
* This is required if the input channels are unpositioned and no standard layout can be determined.
|
||||
* If an empty mix matrix is specified, a (potentially truncated) identity matrix will be generated.
|
||||
*
|
||||
* ## Example matrix generation code
|
||||
* To generate the matrix using code:
|
||||
*
|
||||
|
@ -73,8 +76,6 @@
|
|||
* 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
|
||||
* ]|
|
||||
*
|
||||
* > If an empty mix matrix is specified, a (potentially truncated)
|
||||
* > identity matrix will be generated.
|
||||
*
|
||||
* ## Example empty matrix generation code
|
||||
* |[
|
||||
|
@ -214,10 +215,18 @@ 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));
|
||||
|
||||
/**
|
||||
* GstAudioConvert:mix-matrix:
|
||||
*
|
||||
* Transformation matrix for input/output channels.
|
||||
* Required if the input channels are unpositioned and no standard layout can be determined.
|
||||
* Setting an empty matrix like \"< >\" will generate an identity matrix."
|
||||
*
|
||||
*/
|
||||
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",
|
||||
"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,
|
||||
|
@ -345,8 +354,9 @@ remove_channels_from_structure (GstCapsFeatures * features, GstStructure * s,
|
|||
gint channels;
|
||||
GstAudioConvert *this = GST_AUDIO_CONVERT (user_data);
|
||||
|
||||
/* Only remove the channels and channel-mask for non-NONE layouts,
|
||||
* or if a mix matrix was manually specified */
|
||||
/* Only remove the channels and channel-mask if a (empty) mix matrix was manually specified,
|
||||
* if no channel-mask is specified, for non-NONE channel layouts or for a single channel layout
|
||||
*/
|
||||
if (this->mix_matrix_is_set ||
|
||||
!gst_structure_get (s, "channel-mask", GST_TYPE_BITMASK, &mask, NULL) ||
|
||||
(mask != 0 || (gst_structure_get_int (s, "channels", &channels)
|
||||
|
@ -1006,7 +1016,7 @@ gst_audio_convert_set_property (GObject * object, guint prop_id,
|
|||
break;
|
||||
case PROP_MIX_MATRIX:
|
||||
if (!gst_value_array_get_size (value)) {
|
||||
this->mix_matrix_is_set = FALSE;
|
||||
this->mix_matrix_is_set = TRUE;
|
||||
} else {
|
||||
const GValue *first_row = gst_value_array_get_value (value, 0);
|
||||
|
||||
|
@ -1017,7 +1027,8 @@ gst_audio_convert_set_property (GObject * object, guint prop_id,
|
|||
/* issue a reconfigure upstream */
|
||||
gst_base_transform_reconfigure_sink (GST_BASE_TRANSFORM (this));
|
||||
} else {
|
||||
g_warning ("Empty mix matrix's first row");
|
||||
g_warning ("Empty mix matrix's first row.");
|
||||
this->mix_matrix_is_set = FALSE;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
|
|
@ -46,7 +46,8 @@ static GstPad *mysrcpad, *mysinkpad;
|
|||
|
||||
/* takes over reference for outcaps */
|
||||
static GstElement *
|
||||
setup_audioconvert (GstCaps * outcaps)
|
||||
setup_audioconvert (GstCaps * outcaps, gboolean use_mix_matrix,
|
||||
GValue * mix_matrix)
|
||||
{
|
||||
GstPadTemplate *sinktemplate;
|
||||
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
|
||||
|
@ -63,6 +64,9 @@ setup_audioconvert (GstCaps * outcaps)
|
|||
audioconvert = gst_check_setup_element ("audioconvert");
|
||||
g_object_set (G_OBJECT (audioconvert), "dithering", 0, NULL);
|
||||
g_object_set (G_OBJECT (audioconvert), "noise-shaping", 0, NULL);
|
||||
if (use_mix_matrix) {
|
||||
g_object_set_property (G_OBJECT (audioconvert), "mix-matrix", mix_matrix);
|
||||
}
|
||||
mysrcpad = gst_check_setup_src_pad (audioconvert, &srctemplate);
|
||||
mysinkpad =
|
||||
gst_check_setup_sink_pad_from_template (audioconvert, sinktemplate);
|
||||
|
@ -408,7 +412,8 @@ get_int_mc_caps (guint channels, gint endianness, guint width,
|
|||
static void
|
||||
verify_convert (const gchar * which, void *in, int inlength,
|
||||
GstCaps * incaps, void *out, int outlength, GstCaps * outcaps,
|
||||
GstFlowReturn expected_flow, gboolean in_place_allowed)
|
||||
GstFlowReturn expected_flow, gboolean in_place_allowed,
|
||||
gboolean use_mix_matrix, GValue * mix_matrix)
|
||||
{
|
||||
GstBuffer *inbuffer, *outbuffer;
|
||||
GstElement *audioconvert;
|
||||
|
@ -419,7 +424,7 @@ verify_convert (const gchar * which, void *in, int inlength,
|
|||
GST_DEBUG ("outcaps: %" GST_PTR_FORMAT, outcaps);
|
||||
ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1);
|
||||
ASSERT_CAPS_REFCOUNT (outcaps, "outcaps", 1);
|
||||
audioconvert = setup_audioconvert (outcaps);
|
||||
audioconvert = setup_audioconvert (outcaps, use_mix_matrix, mix_matrix);
|
||||
ASSERT_CAPS_REFCOUNT (outcaps, "outcaps", 2);
|
||||
|
||||
fail_unless (gst_element_set_state (audioconvert,
|
||||
|
@ -505,17 +510,22 @@ done:
|
|||
#define RUN_CONVERSION(which, inarray, in_get_caps, outarray, out_get_caps) \
|
||||
verify_convert (which, inarray, sizeof (inarray), \
|
||||
in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \
|
||||
TRUE)
|
||||
TRUE, FALSE, &(GValue) G_VALUE_INIT);
|
||||
|
||||
#define RUN_CONVERSION_WITH_MATRIX(which, inarray, in_get_caps, outarray, out_get_caps, mix_matrix) \
|
||||
verify_convert (which, inarray, sizeof (inarray), \
|
||||
in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \
|
||||
TRUE, TRUE, mix_matrix);
|
||||
|
||||
#define RUN_CONVERSION_TO_FAIL(which, inarray, in_caps, outarray, out_caps) \
|
||||
verify_convert (which, inarray, sizeof (inarray), \
|
||||
in_caps, outarray, sizeof (outarray), out_caps, \
|
||||
GST_FLOW_NOT_NEGOTIATED, TRUE)
|
||||
GST_FLOW_NOT_NEGOTIATED, TRUE, FALSE, &(GValue) G_VALUE_INIT);
|
||||
|
||||
#define RUN_CONVERSION_NOT_INPLACE(which, inarray, in_get_caps, outarray, out_get_caps) \
|
||||
verify_convert (which, inarray, sizeof (inarray), \
|
||||
in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \
|
||||
FALSE)
|
||||
FALSE, FALSE, &(GValue) G_VALUE_INIT);
|
||||
|
||||
#define INTERLEAVED GST_AUDIO_LAYOUT_INTERLEAVED
|
||||
#define PLANAR GST_AUDIO_LAYOUT_NON_INTERLEAVED
|
||||
|
@ -1559,6 +1569,53 @@ GST_START_TEST (test_convert_undefined_multichannel)
|
|||
RUN_CONVERSION ("8 channels with layout => 2 channels",
|
||||
in, in_caps, out, out_caps);
|
||||
}
|
||||
|
||||
/* 9 channels, NONE positions => 2 channels, with empty mix-matrix */
|
||||
{
|
||||
guint16 in[] =
|
||||
{ 0, 0, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000 };
|
||||
gfloat out[] = { -1.0, -1.0 };
|
||||
GstCaps *in_caps = get_int_mc_caps (9, G_BYTE_ORDER, 16, 16, FALSE,
|
||||
INTERLEAVED, undefined_positions[9 - 1]);
|
||||
GstCaps *out_caps = get_float_mc_caps (2, G_BYTE_ORDER, 32, INTERLEAVED,
|
||||
NULL);
|
||||
GValue empty_mix_matrix = G_VALUE_INIT;
|
||||
g_value_init (&empty_mix_matrix, GST_TYPE_ARRAY);
|
||||
|
||||
RUN_CONVERSION_WITH_MATRIX ("9 channels, undefined layout => 2 channels",
|
||||
in, in_caps, out, out_caps, &empty_mix_matrix);
|
||||
g_value_unset (&empty_mix_matrix);
|
||||
}
|
||||
|
||||
/* 9 channels, NONE positions => 2 channels, with specified mix-matrix */
|
||||
{
|
||||
guint16 in[] =
|
||||
{ 0, 0, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000, 0x8000 };
|
||||
gfloat out[] = { -1.0, -1.0 };
|
||||
GstCaps *in_caps = get_int_mc_caps (9, G_BYTE_ORDER, 16, 16, FALSE,
|
||||
INTERLEAVED, undefined_positions[9 - 1]);
|
||||
GstCaps *out_caps = get_float_mc_caps (2, G_BYTE_ORDER, 32, INTERLEAVED,
|
||||
NULL);
|
||||
GValue mix_matrix = G_VALUE_INIT;
|
||||
GValue row = G_VALUE_INIT;
|
||||
GValue value = G_VALUE_INIT;
|
||||
g_value_init (&mix_matrix, GST_TYPE_ARRAY);
|
||||
for (int j = 0; j < 2; j++) {
|
||||
g_value_init (&row, GST_TYPE_ARRAY);
|
||||
for (int i = 0; i < 9; i++) {
|
||||
g_value_init (&value, G_TYPE_FLOAT);
|
||||
g_value_set_float (&value, i == j && i < 2 ? 1 : 0);
|
||||
gst_value_array_append_value (&row, &value);
|
||||
g_value_unset (&value);
|
||||
}
|
||||
gst_value_array_append_value (&mix_matrix, &row);
|
||||
g_value_unset (&row);
|
||||
}
|
||||
|
||||
RUN_CONVERSION_WITH_MATRIX ("9 channels, undefined layout => 2 channels",
|
||||
in, in_caps, out, out_caps, &mix_matrix);
|
||||
g_value_unset (&mix_matrix);
|
||||
}
|
||||
}
|
||||
|
||||
GST_END_TEST;
|
||||
|
@ -1637,7 +1694,7 @@ GST_START_TEST (test_gap_buffers)
|
|||
gsize data_len = sizeof (data);
|
||||
gint i;
|
||||
|
||||
audioconvert = setup_audioconvert (caps);
|
||||
audioconvert = setup_audioconvert (caps, FALSE, &(GValue) G_VALUE_INIT);
|
||||
|
||||
fail_unless (gst_element_set_state (audioconvert,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
|
@ -1797,7 +1854,7 @@ GST_START_TEST (test_layout_conv_fixate_caps)
|
|||
"layout = (string) non-interleaved, "
|
||||
"rate = (int) [ 1, MAX ], " "channels = (int) [1, 8]");
|
||||
|
||||
audioconvert = setup_audioconvert (outcaps);
|
||||
audioconvert = setup_audioconvert (outcaps, FALSE, &(GValue) G_VALUE_INIT);
|
||||
|
||||
fail_unless (gst_element_set_state (audioconvert,
|
||||
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
|
||||
|
|
Loading…
Reference in a new issue