audioconvert: add possibility to reorder input channels

When audioconvert has unpositionned audio channels as input
it can now use reordering configurations to automatically
position those channels.

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/5923>
This commit is contained in:
Loïc Le Page 2024-02-08 20:37:53 +01:00
parent 40f7d7f1f7
commit 8fb96253be
5 changed files with 1510 additions and 22 deletions

View file

@ -865,6 +865,30 @@
"type": "guint", "type": "guint",
"writable": true "writable": true
}, },
"input-channels-reorder": {
"blurb": "The positions configuration to use to reorder the input channels consecutively according to their index.",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "gst (0)",
"mutable": "null",
"readable": true,
"type": "GstAudioConvertInputChannelsReorder",
"writable": true
},
"input-channels-reorder-mode": {
"blurb": "The input channels reordering mode used to apply the selected positions configuration.",
"conditionally-available": false,
"construct": false,
"construct-only": false,
"controllable": false,
"default": "none (0)",
"mutable": "null",
"readable": true,
"type": "GstAudioConvertInputChannelsReorderMode",
"writable": true
},
"mix-matrix": { "mix-matrix": {
"blurb": "Transformation matrix for input/output channels.", "blurb": "Transformation matrix for input/output channels.",
"conditionally-available": false, "conditionally-available": false,
@ -894,7 +918,68 @@
}, },
"filename": "gstaudioconvert", "filename": "gstaudioconvert",
"license": "LGPL", "license": "LGPL",
"other-types": {}, "other-types": {
"GstAudioConvertInputChannelsReorder": {
"kind": "enum",
"values": [
{
"desc": "Reorder the input channels using the default GStreamer order",
"name": "gst",
"value": "0"
},
{
"desc": "Reorder the input channels using the SMPTE order",
"name": "smpte",
"value": "1"
},
{
"desc": "Reorder the input channels using the CINE order",
"name": "cine",
"value": "2"
},
{
"desc": "Reorder the input channels using the AC3 order",
"name": "ac3",
"value": "3"
},
{
"desc": "Reorder the input channels using the AAC order",
"name": "aac",
"value": "4"
},
{
"desc": "Reorder and mix all input channels to a single mono channel",
"name": "mono",
"value": "5"
},
{
"desc": "Reorder and mix all input channels to a single left and a single right stereo channels alternately",
"name": "alternate",
"value": "6"
}
]
},
"GstAudioConvertInputChannelsReorderMode": {
"kind": "enum",
"values": [
{
"desc": "Never reorder the input channels",
"name": "none",
"value": "0"
},
{
"desc": "Reorder the input channels only if they are unpositioned",
"name": "unpositioned",
"value": "1"
},
{
"desc": "Always reorder the input channels according to the selected configuration",
"name": "force",
"value": "2"
}
]
}
},
"package": "GStreamer Base Plug-ins", "package": "GStreamer Base Plug-ins",
"source": "gst-plugins-base", "source": "gst-plugins-base",
"tracers": {}, "tracers": {},

View file

@ -631,6 +631,75 @@ gst_audio_channel_mixer_fill_special (gfloat ** matrix, gint in_channels,
* Automagically generate conversion matrix. * Automagically generate conversion matrix.
*/ */
typedef enum
{
GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_NONE = 0,
GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_MONO,
GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_STEREO
} GstAudioChannelMixerVirtualInput;
/* Detects specific input channels configurations introduced in the
* audioconvert element (since version 1.26) with the
* `GstAudioConvertInputChannelsReorder` configurations.
*
* If all input channels are positioned to GST_AUDIO_CHANNEL_POSITION_MONO,
* the automatic mixing matrix should be configured like if there was only one
* virtual input mono channel. This virtual mono channel is the mix of all the
* real mono channels.
*
* If all input channels with an even index are positioned to
* GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT and all input channels with an odd
* index are positioned to GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, then the
* automatic mixing matrix should be configured like if there were only one
* virtual input left channel and one virtual input right channel. This virtual
* left or right channel is the mix of all the real left or right channels.
*/
static gboolean
gst_audio_channel_mixer_detect_virtual_input_channels (gint channels,
GstAudioChannelPosition * position,
GstAudioChannelMixerVirtualInput * virtual_input)
{
g_return_val_if_fail (position != NULL, FALSE);
g_return_val_if_fail (virtual_input != NULL, FALSE);
*virtual_input = GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_NONE;
if (channels < 2)
return FALSE;
static const GstAudioChannelPosition alternate_positions[2] =
{ GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT
};
gboolean is_mono = TRUE;
gboolean is_alternate = TRUE;
for (gint i = 0; i < channels; ++i) {
if (position[i] != GST_AUDIO_CHANNEL_POSITION_MONO)
is_mono = FALSE;
if (position[i] != alternate_positions[i % 2])
is_alternate = FALSE;
if (!is_mono && !is_alternate)
return FALSE;
}
if (is_mono) {
g_assert (!is_alternate);
*virtual_input = GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_MONO;
return TRUE;
}
if (is_alternate && (channels > 2)) {
g_assert (!is_mono);
*virtual_input = GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_STEREO;
return TRUE;
}
return FALSE;
}
static void static void
gst_audio_channel_mixer_fill_matrix (gfloat ** matrix, gst_audio_channel_mixer_fill_matrix (gfloat ** matrix,
GstAudioChannelMixerFlags flags, gint in_channels, GstAudioChannelMixerFlags flags, gint in_channels,
@ -641,15 +710,71 @@ gst_audio_channel_mixer_fill_matrix (gfloat ** matrix,
out_channels, out_position)) out_channels, out_position))
return; return;
gst_audio_channel_mixer_fill_identical (matrix, in_channels, in_position, /* If all input channels are positioned to mono, the mix matrix should be
* configured like if there was only one virtual input mono channel. This
* virtual mono channel is the mix of all the real input mono channels.
*
* If all input channels are positioned to left and right alternately, the mix
* matrix should be configured like if there were only two virtual input
* channels: one left and one right. This virtual left or right channel is the
* mix of all the real input left or right channels.
*/
gint in_size = in_channels;
GstAudioChannelMixerVirtualInput virtual_input =
GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_NONE;
if (gst_audio_channel_mixer_detect_virtual_input_channels (in_size,
in_position, &virtual_input)) {
switch (virtual_input) {
case GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_MONO:
in_size = 1;
break;
case GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_STEREO:
in_size = 2;
break;
default:
break;
}
}
gst_audio_channel_mixer_fill_identical (matrix, in_size, in_position,
out_channels, out_position, flags); out_channels, out_position, flags);
if (!(flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN)) { if (!(flags & GST_AUDIO_CHANNEL_MIXER_FLAGS_UNPOSITIONED_IN)) {
gst_audio_channel_mixer_fill_compatible (matrix, in_channels, in_position, gst_audio_channel_mixer_fill_compatible (matrix, in_size, in_position,
out_channels, out_position); out_channels, out_position);
gst_audio_channel_mixer_fill_others (matrix, in_channels, in_position, gst_audio_channel_mixer_fill_others (matrix, in_size, in_position,
out_channels, out_position); out_channels, out_position);
gst_audio_channel_mixer_fill_normalize (matrix, in_channels, out_channels); gst_audio_channel_mixer_fill_normalize (matrix, in_size, out_channels);
}
switch (virtual_input) {
case GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_MONO:{
for (gint out = 0; out < out_channels; ++out)
matrix[0][out] /= in_channels;
for (gint in = 1; in < in_channels; ++in)
memcpy (matrix[in], matrix[0], out_channels * sizeof (gfloat));
break;
}
case GST_AUDIO_CHANNEL_MIXER_VIRTUAL_INPUT_STEREO:{
gint right_channels = in_channels >> 1;
gint left_channels = right_channels + (in_channels % 2);
for (gint out = 0; out < out_channels; ++out) {
matrix[0][out] /= left_channels;
matrix[1][out] /= right_channels;
}
for (gint in = 2; in < in_channels; ++in)
memcpy (matrix[in], matrix[in % 2], out_channels * sizeof (gfloat));
break;
}
default:
break;
} }
} }

View file

@ -90,6 +90,31 @@
* |[ * |[
* gst-launch-1.0 -v audiotestsrc ! audio/x-raw,channels=8 ! audioconvert mix-matrix="<>" ! audio/x-raw,channels=16,channel-mask=\(bitmask\)0x0000000000000000 ! fakesink * gst-launch-1.0 -v audiotestsrc ! audio/x-raw,channels=8 ! audioconvert mix-matrix="<>" ! audio/x-raw,channels=16,channel-mask=\(bitmask\)0x0000000000000000 ! fakesink
* ]| * ]|
*
* If input channels are unpositioned but follow a standard layout, they can be
* automatically positioned according to their index using one of the reorder
* configurations.
*
* ## Example with unpositioned input channels reordering
* |[
* gst-launch-1.0 -v audiotestsrc ! audio/x-raw,channels=6,channel-mask=\(bitmask\)0x0000000000000000 ! audioconvert input-channels-reorder-mode=unpositioned input-channels-reorder=smpte ! fakesink
* ]|
* In this case the input channels will be automatically positioned to the
* SMPTE order (left, right, center, lfe, rear-left and rear-right).
*
* The input channels reorder configurations can also be used to force the
* repositioning of the input channels when needed, for example when channels'
* positions are not correctly identified in an encoded file.
*
* ## Example with the forced reordering of input channels wrongly positioned
* |[
* gst-launch-1.0 -v audiotestsrc ! audio/x-raw,channels=3,channel-mask=\(bitmask\)0x0000000000000034 ! audioconvert input-channels-reorder-mode=force input-channels-reorder=aac ! fakesink
* ]|
* In this case the input channels are positioned upstream as center,
* rear-left and rear-right in this order. Using the "force" reorder mode and
* the "aac" order, the input channels are going to be repositioned to left,
* right and lfe, ignoring the actual value of the `channel-mask` in the input
* caps.
*/ */
/* /*
@ -158,7 +183,9 @@ enum
PROP_DITHERING, PROP_DITHERING,
PROP_NOISE_SHAPING, PROP_NOISE_SHAPING,
PROP_MIX_MATRIX, PROP_MIX_MATRIX,
PROP_DITHERING_THRESHOLD PROP_DITHERING_THRESHOLD,
PROP_INPUT_CHANNELS_REORDER,
PROP_INPUT_CHANNELS_REORDER_MODE
}; };
#define DEBUG_INIT \ #define DEBUG_INIT \
@ -192,6 +219,80 @@ GST_STATIC_PAD_TEMPLATE ("sink",
static GQuark meta_tag_audio_quark; static GQuark meta_tag_audio_quark;
/*** TYPE FUNCTIONS ***********************************************************/ /*** TYPE FUNCTIONS ***********************************************************/
#define GST_TYPE_AUDIO_CONVERT_INPUT_CHANNELS_REORDER (gst_audio_convert_input_channels_reorder_get_type ())
static GType
gst_audio_convert_input_channels_reorder_get_type (void)
{
static GType reorder_type = 0;
if (g_once_init_enter (&reorder_type)) {
static GEnumValue reorder_types[] = {
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST,
"Reorder the input channels using the default GStreamer order",
"gst"},
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_SMPTE,
"Reorder the input channels using the SMPTE order",
"smpte"},
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE,
"Reorder the input channels using the CINE order",
"cine"},
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AC3,
"Reorder the input channels using the AC3 order",
"ac3"},
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AAC,
"Reorder the input channels using the AAC order",
"aac"},
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MONO,
"Reorder and mix all input channels to a single mono channel",
"mono"},
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE,
"Reorder and mix all input channels to a single left and a single right stereo channels alternately",
"alternate"},
{0, NULL, NULL},
};
GType type = g_enum_register_static ("GstAudioConvertInputChannelsReorder",
reorder_types);
g_once_init_leave (&reorder_type, type);
}
return reorder_type;
}
#define GST_TYPE_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE (gst_audio_convert_input_channels_reorder_mode_get_type ())
static GType
gst_audio_convert_input_channels_reorder_mode_get_type (void)
{
static GType reorder_mode_type = 0;
if (g_once_init_enter (&reorder_mode_type)) {
static GEnumValue reorder_mode_types[] = {
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_NONE,
"Never reorder the input channels",
"none"},
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_UNPOSITIONED,
"Reorder the input channels only if they are unpositioned",
"unpositioned"},
{GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_FORCE,
"Always reorder the input channels according to the selected configuration",
"force"},
{0, NULL, NULL},
};
GType type =
g_enum_register_static ("GstAudioConvertInputChannelsReorderMode",
reorder_mode_types);
g_once_init_leave (&reorder_mode_type, type);
}
return reorder_mode_type;
}
static void static void
gst_audio_convert_class_init (GstAudioConvertClass * klass) gst_audio_convert_class_init (GstAudioConvertClass * klass)
{ {
@ -246,6 +347,53 @@ gst_audio_convert_class_init (GstAudioConvertClass * klass)
"Threshold for the output bit depth at/below which to apply dithering.", "Threshold for the output bit depth at/below which to apply dithering.",
0, 32, 20, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); 0, 32, 20, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
/**
* GstAudioConvert:input-channels-reorder:
*
* The positions configuration to use to reorder the input channels
* consecutively according to their index. If a `mix-matrix` is specified,
* this configuration is ignored.
*
* When the input channels reordering is activated (because the
* `input-channels-reorder-mode` property is
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_FORCE or the input channels
* are unpositioned and the reorder mode is
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_UNPOSITIONED), input
* channels will be reordered consecutively according to their index
* independently of the `channel-mask` value in the sink pad audio caps.
*
* Since: 1.26
*/
g_object_class_install_property (gobject_class,
PROP_INPUT_CHANNELS_REORDER,
g_param_spec_enum ("input-channels-reorder",
"Input Channels Reorder",
"The positions configuration to use to reorder the input channels consecutively according to their index.",
GST_TYPE_AUDIO_CONVERT_INPUT_CHANNELS_REORDER,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_type_mark_as_plugin_api (GST_TYPE_AUDIO_CONVERT_INPUT_CHANNELS_REORDER,
0);
/**
* GstAudioConvert:input-channels-reorder-mode:
*
* The input channels reordering mode used to apply the selected positions
* configuration.
*
* Since: 1.26
*/
g_object_class_install_property (gobject_class,
PROP_INPUT_CHANNELS_REORDER_MODE,
g_param_spec_enum ("input-channels-reorder-mode",
"Input Channels Reorder Mode",
"The input channels reordering mode used to apply the selected positions configuration.",
GST_TYPE_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_NONE,
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
gst_type_mark_as_plugin_api
(GST_TYPE_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE, 0);
gst_element_class_add_static_pad_template (element_class, gst_element_class_add_static_pad_template (element_class,
&gst_audio_convert_src_template); &gst_audio_convert_src_template);
gst_element_class_add_static_pad_template (element_class, gst_element_class_add_static_pad_template (element_class,
@ -304,6 +452,574 @@ gst_audio_convert_dispose (GObject * obj)
G_OBJECT_CLASS (parent_class)->dispose (obj); G_OBJECT_CLASS (parent_class)->dispose (obj);
} }
/*** INPUT CHANNELS REORDER FUNCTIONS *****************************************/
typedef struct
{
gboolean has_stereo;
gboolean lfe_as_last_channel;
} GstAudioConvertInputChannelsReorderConfig;
static const GstAudioConvertInputChannelsReorderConfig
input_channels_reorder_config[] = {
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST
{TRUE, FALSE},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_SMPTE
{TRUE, FALSE},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE
{TRUE, TRUE},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AC3
{TRUE, TRUE},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AAC
{TRUE, TRUE},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MONO
{FALSE, FALSE},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE
{TRUE, FALSE}
};
#define GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_NB G_N_ELEMENTS (input_channels_reorder_config)
static const GstAudioChannelPosition
channel_position_per_reorder_config
[GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_NB][64] = {
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE1,
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT,
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER,
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER,
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER,
GST_AUDIO_CHANNEL_POSITION_LFE2,
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT,
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT,
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_TOP_CENTER,
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT,
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT,
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT,
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT,
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER,
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER,
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT,
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT,
GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT,
GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT,
GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT,
GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_SMPTE (see: https://www.sis.se/api/document/preview/919377/)
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // Left front (L)
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // Right front (R)
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, // Center front (C)
GST_AUDIO_CHANNEL_POSITION_LFE1, // Low frequency enhancement (LFE)
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, // Left surround (Ls)
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, // Right surround (Rs)
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, // Left front center (Lc)
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, // Right front center (Rc)
GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT, // Rear surround left (Lsr)
GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT, // Rear surround right (Rsr)
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, // Rear center (Cs)
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, // Left side surround (Lss)
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, // Right side surround (Rss)
GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT, // Left wide front (Lw)
GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT, // Right wide front (Rw)
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, // Left front vertical height (Lv)
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, // Right front vertical height (Rv)
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, // Center front vertical height (Cv)
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, // Left surround vertical height rear (Lvr)
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, // Right surround vertical height rear (Rvr)
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, // Center vertical height rear (Cvr)
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT, // Left vertical height side surround (Lvss)
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT, // Right vertical height side surround (Rvss)
GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, // Top center surround (Ts)
GST_AUDIO_CHANNEL_POSITION_LFE2, // Low frequency enhancement 2 (LFE2)
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT, // Left front vertical bottom (Lb)
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT, // Right front vertical bottom (Rb)
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER, // Center front vertical bottom (Cb)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Left vertical height surround (Lvs)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Right vertical height surround (Rvs)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Reserved
GST_AUDIO_CHANNEL_POSITION_INVALID, // Reserved
GST_AUDIO_CHANNEL_POSITION_INVALID, // Reserved
GST_AUDIO_CHANNEL_POSITION_INVALID, // Reserved
GST_AUDIO_CHANNEL_POSITION_INVALID, // Low frequency enhancement 3 (LFE3)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Left edge of screen (Leos)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Right edge of screen (Reos)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Half-way between center of screen and left edge of screen (Hwbcal)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Half-way between center of screen and right edge of screen (Hwbcar)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Left back surround (Lbs)
GST_AUDIO_CHANNEL_POSITION_INVALID, // Right back surround (Rbs)
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, // C
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, // Ls
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, // Rs
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, // Lc
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, // Rc
GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT, // Lsr
GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT, // Rsr
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, // Cs
GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, // Ts
GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT, // Lw
GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT, // Rw
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, // Lv
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, // Rv
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, // Cv
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, // Lvr
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, // Rvr
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, // Cvr
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, // Lss
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, // Rss
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT, // Lvss
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT, // Rvss
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT, // Lb
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT, // Rb
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER, // Cb
GST_AUDIO_CHANNEL_POSITION_LFE2, // LFE2
GST_AUDIO_CHANNEL_POSITION_LFE1, // LFE1
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AC3
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, // C
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, // Ls
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, // Rs
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, // Lc
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, // Rc
GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT, // Lsr
GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT, // Rsr
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, // Cs
GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, // Ts
GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT, // Lw
GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT, // Rw
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, // Lv
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, // Rv
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, // Cv
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, // Lvr
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, // Rvr
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, // Cvr
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, // Lss
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, // Rss
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT, // Lvss
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT, // Rvss
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT, // Lb
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT, // Rb
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER, // Cb
GST_AUDIO_CHANNEL_POSITION_LFE2, // LFE2
GST_AUDIO_CHANNEL_POSITION_LFE1, // LFE1
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AAC
{
GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, // C
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, // Ls
GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, // Rs
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, // Lc
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER, // Rc
GST_AUDIO_CHANNEL_POSITION_SURROUND_LEFT, // Lsr
GST_AUDIO_CHANNEL_POSITION_SURROUND_RIGHT, // Rsr
GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, // Cs
GST_AUDIO_CHANNEL_POSITION_TOP_CENTER, // Ts
GST_AUDIO_CHANNEL_POSITION_WIDE_LEFT, // Lw
GST_AUDIO_CHANNEL_POSITION_WIDE_RIGHT, // Rw
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_LEFT, // Lv
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_RIGHT, // Rv
GST_AUDIO_CHANNEL_POSITION_TOP_FRONT_CENTER, // Cv
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_LEFT, // Lvr
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_RIGHT, // Rvr
GST_AUDIO_CHANNEL_POSITION_TOP_REAR_CENTER, // Cvr
GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, // Lss
GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, // Rss
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_LEFT, // Lvss
GST_AUDIO_CHANNEL_POSITION_TOP_SIDE_RIGHT, // Rvss
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_LEFT, // Lb
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_RIGHT, // Rb
GST_AUDIO_CHANNEL_POSITION_BOTTOM_FRONT_CENTER, // Cb
GST_AUDIO_CHANNEL_POSITION_LFE2, // LFE2
GST_AUDIO_CHANNEL_POSITION_LFE1, // LFE1
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
GST_AUDIO_CHANNEL_POSITION_INVALID,
},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MONO
{
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
GST_AUDIO_CHANNEL_POSITION_MONO,
},
// GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE
{
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, // L
GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, // R
}
};
static const gchar *gst_audio_convert_input_channels_reorder_to_string
(GstAudioConvertInputChannelsReorder reorder)
{
switch (reorder) {
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST:
return "GST";
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_SMPTE:
return "SMPTE";
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE:
return "CINE";
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AC3:
return "AC3";
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AAC:
return "AAC";
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MONO:
return "MONO";
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE:
return "ALTERNATE";
default:
return "UNKNOWN";
}
}
static gboolean
gst_audio_convert_position_channels_from_reorder_configuration (gint channels,
GstAudioConvertInputChannelsReorder reorder,
GstAudioChannelPosition * position)
{
g_return_val_if_fail (channels > 0, FALSE);
g_return_val_if_fail (reorder >= 0
&& reorder < GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_NB, FALSE);
g_return_val_if_fail (position != NULL, FALSE);
GST_DEBUG ("ordering %d audio channel(s) according to the %s configuration",
channels, gst_audio_convert_input_channels_reorder_to_string (reorder));
if (channels == 1) {
position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
return TRUE;
}
if (channels == 2 && input_channels_reorder_config[reorder].has_stereo) {
position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
return TRUE;
}
for (gint i = 0; i < channels; ++i) {
if (i < G_N_ELEMENTS (channel_position_per_reorder_config[reorder]))
position[i] = channel_position_per_reorder_config[reorder][i];
else
position[i] = GST_AUDIO_CHANNEL_POSITION_INVALID;
}
if (channels > 2
&& input_channels_reorder_config[reorder].lfe_as_last_channel) {
position[channels - 1] = GST_AUDIO_CHANNEL_POSITION_LFE1;
if (channels == 3 && input_channels_reorder_config[reorder].has_stereo) {
position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
}
}
return TRUE;
}
/*** GSTREAMER FUNCTIONS ******************************************************/ /*** GSTREAMER FUNCTIONS ******************************************************/
/* BaseTransform vmethods */ /* BaseTransform vmethods */
@ -352,12 +1068,14 @@ remove_channels_from_structure (GstCapsFeatures * features, GstStructure * s,
{ {
guint64 mask; guint64 mask;
gint channels; gint channels;
GstAudioConvert *this = GST_AUDIO_CONVERT (user_data); gboolean force_removing = *(gboolean *) user_data;
/* Only remove the channels and channel-mask if a (empty) mix matrix was manually specified, /* Only remove the channels and channel-mask if a mix matrix was manually
* if no channel-mask is specified, for non-NONE channel layouts or for a single channel layout * specified or an input channels reordering is applied, or if no
* channel-mask is specified, for non-NONE channel layouts or for a single
* channel layout.
*/ */
if (this->mix_matrix_is_set || if (force_removing ||
!gst_structure_get (s, "channel-mask", GST_TYPE_BITMASK, &mask, NULL) || !gst_structure_get (s, "channel-mask", GST_TYPE_BITMASK, &mask, NULL) ||
(mask != 0 || (gst_structure_get_int (s, "channels", &channels) (mask != 0 || (gst_structure_get_int (s, "channels", &channels)
&& channels == 1))) { && channels == 1))) {
@ -393,7 +1111,12 @@ gst_audio_convert_transform_caps (GstBaseTransform * btrans,
gst_caps_map_in_place (tmp, remove_format_from_structure, NULL); gst_caps_map_in_place (tmp, remove_format_from_structure, NULL);
gst_caps_map_in_place (tmp, remove_layout_from_structure, NULL); gst_caps_map_in_place (tmp, remove_layout_from_structure, NULL);
gst_caps_map_in_place (tmp, remove_channels_from_structure, btrans);
gboolean force_removing = this->mix_matrix_is_set
|| (direction == GST_PAD_SINK
&& this->input_channels_reorder_mode !=
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_NONE);
gst_caps_map_in_place (tmp, remove_channels_from_structure, &force_removing);
/* We can infer the required input / output channels based on the /* We can infer the required input / output channels based on the
* matrix dimensions */ * matrix dimensions */
@ -796,12 +1519,47 @@ gst_audio_convert_set_caps (GstBaseTransform * base, GstCaps * incaps,
GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD, GST_AUDIO_CONVERTER_OPT_NOISE_SHAPING_METHOD,
GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, this->ns, NULL); GST_TYPE_AUDIO_NOISE_SHAPING_METHOD, this->ns, NULL);
if (this->mix_matrix_is_set) if (this->mix_matrix_is_set) {
gst_structure_set_value (config, GST_AUDIO_CONVERTER_OPT_MIX_MATRIX, gst_structure_set_value (config, GST_AUDIO_CONVERTER_OPT_MIX_MATRIX,
&this->mix_matrix); &this->mix_matrix);
this->convert = gst_audio_converter_new (0, &in_info, &out_info, config); this->convert = gst_audio_converter_new (0, &in_info, &out_info, config);
} else if (this->input_channels_reorder_mode !=
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_NONE) {
GstAudioFlags in_flags;
GstAudioChannelPosition in_position[64];
gboolean restore_in = FALSE;
if (this->input_channels_reorder_mode ==
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_FORCE
|| GST_AUDIO_INFO_IS_UNPOSITIONED (&in_info)) {
in_flags = GST_AUDIO_INFO_FLAGS (&in_info);
memcpy (in_position, in_info.position,
GST_AUDIO_INFO_CHANNELS (&in_info) *
sizeof (GstAudioChannelPosition));
if (gst_audio_convert_position_channels_from_reorder_configuration
(GST_AUDIO_INFO_CHANNELS (&in_info), this->input_channels_reorder,
in_info.position)) {
GST_AUDIO_INFO_FLAGS (&in_info) &= ~GST_AUDIO_FLAG_UNPOSITIONED;
restore_in = TRUE;
}
}
this->convert = gst_audio_converter_new (0, &in_info, &out_info, config);
if (restore_in) {
GST_AUDIO_INFO_FLAGS (&in_info) = in_flags;
memcpy (in_info.position, in_position,
GST_AUDIO_INFO_CHANNELS (&in_info) *
sizeof (GstAudioChannelPosition));
}
} else {
this->convert = gst_audio_converter_new (0, &in_info, &out_info, config);
}
if (this->convert == NULL) if (this->convert == NULL)
goto no_converter; goto no_converter;
@ -1033,6 +1791,12 @@ gst_audio_convert_set_property (GObject * object, guint prop_id,
} }
} }
break; break;
case PROP_INPUT_CHANNELS_REORDER:
this->input_channels_reorder = g_value_get_enum (value);
break;
case PROP_INPUT_CHANNELS_REORDER_MODE:
this->input_channels_reorder_mode = g_value_get_enum (value);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;
@ -1059,6 +1823,12 @@ gst_audio_convert_get_property (GObject * object, guint prop_id,
if (this->mix_matrix_is_set) if (this->mix_matrix_is_set)
g_value_copy (&this->mix_matrix, value); g_value_copy (&this->mix_matrix, value);
break; break;
case PROP_INPUT_CHANNELS_REORDER:
g_value_set_enum (value, this->input_channels_reorder);
break;
case PROP_INPUT_CHANNELS_REORDER_MODE:
g_value_set_enum (value, this->input_channels_reorder_mode);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break; break;

View file

@ -26,6 +26,150 @@
#include <gst/base/gstbasetransform.h> #include <gst/base/gstbasetransform.h>
#include <gst/audio/audio.h> #include <gst/audio/audio.h>
/**
* GstAudioConvertInputChannelsReorder:
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST: reorder input channels
* according to the default ordering in GStreamer: FRONT_LEFT, FRONT_RIGHT,
* FRONT_CENTER, LFE1 and then the other channels. If there is only one
* input channel available, it will be positioned to MONO.
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_SMPTE: reorder input channels
* according to the SMPTE standard: FRONT_LEFT, FRONT_RIGHT, FRONT_CENTER,
* LFE1 and then the other channels (the ordering is slightly different from
* the default GStreamer order). This audio channels ordering is the only
* one that is officially standardized and used by default in many audio
* softwares (see: https://www.sis.se/api/document/preview/919377/). If
* there is only one input channel available, it will be positioned to MONO.
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE: reorder input channels as it
* is commonly used in the cinema industry: FRONT_LEFT, FRONT_RIGHT,
* FRONT_CENTER, the other channels and then LFE1. This configuration is not
* standardized but usually appears in the literature related to the cinema
* industry and as an alternate ordering in different audio softwares. On
* some web sites, this configuration and the
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AC3 ordering are switched. If
* there is only one input channel available, it will be positioned to
* MONO. If the number of available input channels is > 2, the last channel
* will always be positioned to LFE1.
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AC3: reorder input channels in the
* same order as the default order of the AC3 format: FRONT_LEFT,
* FRONT_CENTER, FRONT_RIGHT, the other channels (same order as in the
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE policy) and then LFE1.
* This configuration is also commonly used in the cinema industry and in
* professional audio softwares (like ProTools under the name "FILM"
* ordering). The only difference with the
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE configuration is the
* order of the first 3 channels. If there is only one input channel
* available, it will be positioned to MONO. If the number of available
* input channels is > 2, the last channel will always be positioned to
* LFE1. If the number of available input channels is 2 or 3, the first two
* channels will be positioned to FRONT_LEFT and FRONT_RIGHT.
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AAC: reorder input channels in the
* same order as the default order of the AAC format: FRONT_CENTER,
* FRONT_LEFT, FRONT_RIGHT, the other channels (same order as in the
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE configuration) and then
* LFE1. The only difference with the
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE configuration is the
* order of the first 3 channels. If there is only one input channel
* available, it will be positioned to MONO. If the number of available
* input channels is > 2, the last channel will always be positioned to
* LFE1. If the number of available input channels is 2 or 3, the first two
* channels will be positioned to FRONT_LEFT and FRONT_RIGHT.
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MONO: reorder all input channels
* to MONO. All input channels are mixed together at the same level to a
* virtual single mono channel. For `n` input channels, the virtual output
* sample value is computed as:
* `output_sample[MONO] = (1/n) x input_sample_for_channel(i)` with
* `0 <= i < n`. A concrete usage for this configuration is, for example,
* when importing audio from an array of multiple mono microphones and you
* want to use them as a unique mono channel.
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE: reorder all input
* channels to FRONT_LEFT and FRONT_RIGHT channels alternately (or MONO if
* there is only one input channel available). All left input channels are
* mixed together, at the same level, to a single FRONT_LEFT virtual
* channel and all right input channels are mixed together to a single
* FRONT_RIGHT virtual channel. For `2n` input channels the FRONT_LEFT and
* FRONT_RIGHT virtual output samples are computed as:
* `output_sample[FRONT_LEFT] = (1/n) x input_sample_for_channel(2i)` and
* `output_sample[FRONT_RIGHT] = (1/n) x input_sample_for_channel(2i+1)`
* with `0 <= i < n` (in case of an odd number of input channels the
* principle is the same but with an extra input left channel). A concrete
* usage for this configuration is, for example, when importing audio from
* an array of multiple stereo microphones and you want to use them as a
* simple pair of stereo channels.
*
* Input audio channels reordering configurations.
*
* It defines different ways of reordering input audio channels when they are
* not positioned by GStreamer. As a general matter, channels are always ordered
* in the @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST order and the
* `channel-mask` field in the audio caps allows specifying which channels are
* active.
*
* Depending on the selected mode (see:
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_UNPOSITIONED), input channels
* can be automatically positioned when the `channel-mask` is not specified or
* equals 0. In this case, all input channels will be positioned according to
* the selected reordering configuration and the index of each input channel.
* This can be useful when importing audio from an array of independent
* microphones for example.
*
* The reordering configuration can also be forced (see:
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_FORCE) to reposition all
* input channels according to each channel index. In this case the
* `channel-mask` will be totally ignored and input channels will be reordered
* just like if they were unpositioned. This can be useful when importing
* multi-channels audio with errors in the channels positioning.
*
* For any of the former configurations, when the reordering is applied
* (input channels are unpositioned or the "force" mode is active):
* - When there is only one input channel available, it is positioned to MONO
* always, independently of the selected configuration.
* - When there are 2 input channels available, they are positioned to
* FRONT_LEFT and FRONT_RIGHT (except for the
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MONO configuration where all
* input channels are positioned to MONO).
*
* Since: 1.26
*/
typedef enum {
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST = 0,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_SMPTE,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AC3,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AAC,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MONO,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE
} GstAudioConvertInputChannelsReorder;
/**
* GstAudioConvertInputChannelsReorderMode:
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_NONE: never reorder the input
* channels. If input channels are unpositioned and there are, at least, 3
* input channels, an error will be generated.
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_UNPOSITIONED: automatically
* reorder the input channels according to the selected
* #GstAudioConvertInputChannelsReorder configuration when, and only when,
* they are unpositioned (the `channel-mask` equals 0 or is not specified
* in the input caps).
* @GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_FORCE: always reorder the
* input channels according to the selected
* #GstAudioConvertInputChannelsReorder configuration. The `channel-mask`
* value in the input caps is completely ignored. Input channels are always
* reordered as if they were unpositioned independently of the input caps.
*
* The different usage modes of the input channels reordering configuration.
*
* Independently of the selected mode, the explicit definition of a mix matrix
* takes precedence over the reorder configuration. In this case, the provided
* mix matrix will override the reorder configuration.
*
* Since: 1.26
*/
typedef enum {
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_NONE = 0,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_UNPOSITIONED,
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_FORCE
} GstAudioConvertInputChannelsReorderMode;
#define GST_TYPE_AUDIO_CONVERT (gst_audio_convert_get_type()) #define GST_TYPE_AUDIO_CONVERT (gst_audio_convert_get_type())
G_DECLARE_FINAL_TYPE (GstAudioConvert, gst_audio_convert, G_DECLARE_FINAL_TYPE (GstAudioConvert, gst_audio_convert,
GST, AUDIO_CONVERT, GstBaseTransform); GST, AUDIO_CONVERT, GstBaseTransform);
@ -45,6 +189,8 @@ struct _GstAudioConvert
GstAudioNoiseShapingMethod ns; GstAudioNoiseShapingMethod ns;
GValue mix_matrix; GValue mix_matrix;
gboolean mix_matrix_is_set; gboolean mix_matrix_is_set;
GstAudioConvertInputChannelsReorder input_channels_reorder;
GstAudioConvertInputChannelsReorderMode input_channels_reorder_mode;
GstAudioInfo in_info; GstAudioInfo in_info;
GstAudioInfo out_info; GstAudioInfo out_info;

View file

@ -26,6 +26,7 @@
#include <gst/check/gstcheck.h> #include <gst/check/gstcheck.h>
#include <gst/audio/audio.h> #include <gst/audio/audio.h>
#include <gst/audioconvert/gstaudioconvert.h>
/* For ease of programming we use globals to keep refs for our floating /* For ease of programming we use globals to keep refs for our floating
* src and sink pads we create; otherwise we always have to do get_pad, * src and sink pads we create; otherwise we always have to do get_pad,
@ -82,6 +83,46 @@ setup_audioconvert (GstCaps * outcaps, gboolean use_mix_matrix,
return audioconvert; return audioconvert;
} }
static GstElement *
setup_audioconvert_with_input_channels_reorder (GstCaps * outcaps,
GstAudioConvertInputChannelsReorder reorder)
{
GstPadTemplate *sinktemplate;
static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src",
GST_PAD_SRC,
GST_PAD_ALWAYS,
GST_STATIC_CAPS (CONVERT_CAPS_TEMPLATE_STRING)
);
GstElement *audioconvert;
ASSERT_CAPS_REFCOUNT (outcaps, "outcaps", 1);
sinktemplate =
gst_pad_template_new ("sink", GST_PAD_SINK, GST_PAD_ALWAYS, outcaps);
GST_DEBUG ("setup_audioconvert with caps %" GST_PTR_FORMAT, 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);
g_object_set (G_OBJECT (audioconvert), "input-channels-reorder",
reorder, "input-channels-reorder-mode",
GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MODE_UNPOSITIONED, NULL);
mysrcpad = gst_check_setup_src_pad (audioconvert, &srctemplate);
mysinkpad =
gst_check_setup_sink_pad_from_template (audioconvert, sinktemplate);
/* this installs a getcaps func that will always return the caps we set
* later */
gst_pad_use_fixed_caps (mysinkpad);
gst_pad_set_active (mysrcpad, TRUE);
gst_pad_set_active (mysinkpad, TRUE);
gst_object_unref (sinktemplate);
ASSERT_CAPS_REFCOUNT (outcaps, "outcaps", 2);
return audioconvert;
}
static void static void
cleanup_audioconvert (GstElement * audioconvert) cleanup_audioconvert (GstElement * audioconvert)
{ {
@ -94,6 +135,41 @@ cleanup_audioconvert (GstElement * audioconvert)
gst_check_teardown_element (audioconvert); gst_check_teardown_element (audioconvert);
} }
static gchar *
format_input_channels_reorder_test_name (const gchar * test_name,
GstAudioConvertInputChannelsReorder reorder)
{
const gchar *reorder_name = "unknown";
switch (reorder) {
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST:
reorder_name = "gst";
break;
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_SMPTE:
reorder_name = "smpte";
break;
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_CINE:
reorder_name = "cine";
break;
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AC3:
reorder_name = "ac3";
break;
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_AAC:
reorder_name = "aac";
break;
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_MONO:
reorder_name = "mono";
break;
case GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE:
reorder_name = "alternate";
break;
default:
break;
}
return g_strdup_printf ("%s with input channels %s reorder", test_name,
reorder_name);
}
/* returns a newly allocated caps */ /* returns a newly allocated caps */
static GstCaps * static GstCaps *
get_int_caps (guint channels, gint endianness, guint width, get_int_caps (guint channels, gint endianness, guint width,
@ -159,6 +235,29 @@ get_float_caps (guint channels, gint endianness, guint width,
return caps; return caps;
} }
static GstCaps *
get_unpositioned_input_caps (guint channels)
{
GstCaps *caps;
GstAudioInfo info;
gst_audio_info_init (&info);
gst_audio_info_set_format (&info,
gst_audio_format_build_integer (TRUE, G_BYTE_ORDER, 16, 16),
GST_AUDIO_DEF_RATE, channels, NULL);
info.layout = GST_AUDIO_LAYOUT_INTERLEAVED;
info.flags = GST_AUDIO_FLAG_UNPOSITIONED;
for (guint i = 0; i < MIN (64, channels); ++i)
info.position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
caps = gst_audio_info_to_caps (&info);
fail_unless (caps != NULL);
GST_DEBUG ("returning caps %" GST_PTR_FORMAT, caps);
return caps;
}
/* Copied from vorbis; the particular values used don't matter */ /* Copied from vorbis; the particular values used don't matter */
static GstAudioChannelPosition channelpositions[][6] = { static GstAudioChannelPosition channelpositions[][6] = {
{ /* Mono */ { /* Mono */
@ -413,7 +512,8 @@ static void
verify_convert (const gchar * which, void *in, int inlength, verify_convert (const gchar * which, void *in, int inlength,
GstCaps * incaps, void *out, int outlength, GstCaps * outcaps, 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) gboolean use_mix_matrix, GValue * mix_matrix,
GstElement * custom_audioconvert)
{ {
GstBuffer *inbuffer, *outbuffer; GstBuffer *inbuffer, *outbuffer;
GstElement *audioconvert; GstElement *audioconvert;
@ -423,8 +523,13 @@ verify_convert (const gchar * which, void *in, int inlength,
GST_DEBUG ("incaps: %" GST_PTR_FORMAT, incaps); GST_DEBUG ("incaps: %" GST_PTR_FORMAT, incaps);
GST_DEBUG ("outcaps: %" GST_PTR_FORMAT, outcaps); GST_DEBUG ("outcaps: %" GST_PTR_FORMAT, outcaps);
ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1); ASSERT_CAPS_REFCOUNT (incaps, "incaps", 1);
if (custom_audioconvert) {
audioconvert = custom_audioconvert;
} else {
ASSERT_CAPS_REFCOUNT (outcaps, "outcaps", 1); ASSERT_CAPS_REFCOUNT (outcaps, "outcaps", 1);
audioconvert = setup_audioconvert (outcaps, use_mix_matrix, mix_matrix); audioconvert = setup_audioconvert (outcaps, use_mix_matrix, mix_matrix);
}
ASSERT_CAPS_REFCOUNT (outcaps, "outcaps", 2); ASSERT_CAPS_REFCOUNT (outcaps, "outcaps", 2);
fail_unless (gst_element_set_state (audioconvert, fail_unless (gst_element_set_state (audioconvert,
@ -510,22 +615,36 @@ done:
#define RUN_CONVERSION(which, inarray, in_get_caps, outarray, out_get_caps) \ #define RUN_CONVERSION(which, inarray, in_get_caps, outarray, out_get_caps) \
verify_convert (which, inarray, sizeof (inarray), \ verify_convert (which, inarray, sizeof (inarray), \
in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \ in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \
TRUE, FALSE, &(GValue) G_VALUE_INIT); TRUE, FALSE, &(GValue) G_VALUE_INIT, NULL);
#define RUN_CONVERSION_WITH_MATRIX(which, inarray, in_get_caps, outarray, out_get_caps, mix_matrix) \ #define RUN_CONVERSION_WITH_MATRIX(which, inarray, in_get_caps, outarray, out_get_caps, mix_matrix) \
verify_convert (which, inarray, sizeof (inarray), \ verify_convert (which, inarray, sizeof (inarray), \
in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \ in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \
TRUE, TRUE, mix_matrix); TRUE, TRUE, mix_matrix, NULL);
#define RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER(which, inarray, \
in_channels, reorder, outarray, out_channels) \
{ \
GstCaps *in_get_caps = get_unpositioned_input_caps (in_channels); \
GstCaps *out_get_caps = get_int_mc_caps (out_channels, G_BYTE_ORDER, 16, \
16, TRUE, GST_AUDIO_LAYOUT_INTERLEAVED, NULL); \
verify_convert ( \
which, inarray, sizeof (inarray), in_get_caps, outarray, \
sizeof (outarray), out_get_caps, GST_FLOW_OK, TRUE, FALSE, \
&(GValue) G_VALUE_INIT, \
setup_audioconvert_with_input_channels_reorder (out_get_caps, \
reorder)); \
}
#define RUN_CONVERSION_TO_FAIL(which, inarray, in_caps, outarray, out_caps) \ #define RUN_CONVERSION_TO_FAIL(which, inarray, in_caps, outarray, out_caps) \
verify_convert (which, inarray, sizeof (inarray), \ verify_convert (which, inarray, sizeof (inarray), \
in_caps, outarray, sizeof (outarray), out_caps, \ in_caps, outarray, sizeof (outarray), out_caps, \
GST_FLOW_NOT_NEGOTIATED, TRUE, FALSE, &(GValue) G_VALUE_INIT); GST_FLOW_NOT_NEGOTIATED, TRUE, FALSE, &(GValue) G_VALUE_INIT, NULL);
#define RUN_CONVERSION_NOT_INPLACE(which, inarray, in_get_caps, outarray, out_get_caps) \ #define RUN_CONVERSION_NOT_INPLACE(which, inarray, in_get_caps, outarray, out_get_caps) \
verify_convert (which, inarray, sizeof (inarray), \ verify_convert (which, inarray, sizeof (inarray), \
in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \ in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK, \
FALSE, FALSE, &(GValue) G_VALUE_INIT); FALSE, FALSE, &(GValue) G_VALUE_INIT, NULL);
#define INTERLEAVED GST_AUDIO_LAYOUT_INTERLEAVED #define INTERLEAVED GST_AUDIO_LAYOUT_INTERLEAVED
#define PLANAR GST_AUDIO_LAYOUT_NON_INTERLEAVED #define PLANAR GST_AUDIO_LAYOUT_NON_INTERLEAVED
@ -1094,6 +1213,245 @@ GST_START_TEST (test_multichannel_conversion)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_multichannel_crossmixing_with_input_channels_reorder)
{
{
gint16 in[] = { 12400, -120 };
gint16 out[] = { 12400, -120 };
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("1 channel to 1", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 1, reorder,
out, 1);
g_free (test_name);
}
}
{
gint16 in[] = { 12400, -120 };
gint16 out[] = { 12400, 12400, -120, -120 };
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("1 channel to 2", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 1, reorder,
out, 2);
g_free (test_name);
}
}
{
gint16 in[] = { 12400, -120 };
gint16 out[] = { 12400, 12400, 8767, -120, -120, -85 };
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("1 channel to 3", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 1, reorder,
out, 3);
g_free (test_name);
}
}
{
gint16 in[] = { 12400, -120, -10844, 5842 };
gint16 out[] = { 6140, -2501 };
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("2 channels to 1", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 2, reorder,
out, 1);
g_free (test_name);
}
}
{
gint16 in[] = { 12400, -120, -10844, 5842 };
gint16 out[][4] = {
{12400, -120, -10844, 5842},
{12400, -120, -10844, 5842},
{12400, -120, -10844, 5842},
{12400, -120, -10844, 5842},
{12400, -120, -10844, 5842},
{6140, 6140, -2501, -2501},
{12400, -120, -10844, 5842}
};
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("2 channels to 2", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 2, reorder,
out[reorder], 2);
g_free (test_name);
}
}
{
gint16 in[] = { 12400, -120, -10844, 5842 };
gint16 out[][6] = {
{8767, -85, 6140, -7667, 4130, -2501},
{8767, -85, 6140, -7667, 4130, -2501},
{8767, -85, 6140, -7667, 4130, -2501},
{8767, -85, 6140, -7667, 4130, -2501},
{8767, -85, 6140, -7667, 4130, -2501},
{6140, 6140, 4341, -2501, -2501, -1768},
{8767, -85, 6140, -7667, 4130, -2501}
};
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("2 channels to 3", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 2, reorder,
out[reorder], 3);
g_free (test_name);
}
}
{
gint16 in[] = { 12400, -120, 1120, -10844, 5842, -48 };
gint16 out[][2] = {
{4825, -1859},
{4825, -1859},
{4462, -1682},
{4462, -1682},
{4462, -1682},
{4462, -1682},
{3320, 198}
};
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("3 channels to 1", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 3, reorder,
out[reorder], 1);
g_free (test_name);
}
}
{
gint16 in[] = { 12400, -120, 1120, -10844, 5842, -48 };
gint16 out[][4] = {
{7717, 394, -6363, 3397},
{7717, 394, -6363, 3397},
{6760, 500, -5446, 2897},
{6760, 500, -5446, 2897},
{6760, 500, -5446, 2897},
{4462, 4462, -1682, -1682},
{6760, -120, -5446, 5842}
};
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("3 channels to 2", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 3, reorder,
out[reorder], 2);
g_free (test_name);
}
}
{
gint16 in[] = { 12400, -120, 1120, -10844, 5842, -48 };
gint16 out[][6] = {
{12400, -120, 1120, -10844, 5842, -48},
{12400, -120, 1120, -10844, 5842, -48},
{6364, 471, 4462, -5127, 2727, -1682},
{6364, 471, 4462, -5127, 2727, -1682},
{6364, 471, 4462, -5127, 2727, -1682},
{4462, 4462, 3154, -1682, -1682, -1189},
{4780, -85, 3320, -3850, 4130, 198}
};
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("3 channels to 3", reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 3, reorder,
out[reorder], 3);
g_free (test_name);
}
}
}
GST_END_TEST;
GST_START_TEST
(test_multichannel_downmixing_to_stereo_with_input_channels_reorder) {
{
gint16 in[] =
{ 12400, -120, 1248, 10140, 368, -32124, 8145, 7411, -212, -5489, 18523,
10003
};
gint16 out[][4] = {
{7353, -1592, 3657, 2105},
{7353, -1592, 3657, 2105},
{-4296, -9713, 4755, 8254},
{-4596, -9588, 6430, 7555},
{-5746, -6837, 6362, 7716},
{-1343, -1343, 6372, 6372},
{4667, -7361, 8810, 3971}
};
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("5.1 channels to stereo",
reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 6, reorder,
out[reorder], 2);
g_free (test_name);
}
}
{
gint16 in[] =
{ 12400, -120, 1248, 10140, 368, -32124, 1247, -458, 8145, 7411, -212,
-5489, 18523, 10003, 789, -5557
};
gint16 out[][4] = {
{6739, -1645, 3467, 813},
{6739, -1645, 3467, 813},
{-1482, 260, 1921, 3242},
{-1617, 508, 2673, 1857},
{-3891, 1743, 2539, 1930},
{-912, -912, 4202, 4202},
{3816, -5640, 6811, 1592}
};
for (gint reorder = GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_GST;
reorder <= GST_AUDIO_CONVERT_INPUT_CHANNELS_REORDER_ALTERNATE;
++reorder) {
gchar *test_name =
format_input_channels_reorder_test_name ("7.1 channels to stereo",
reorder);
RUN_CONVERSION_WITH_INPUT_CHANNELS_REORDER (test_name, in, 8, reorder,
out[reorder], 2);
g_free (test_name);
}
}
}
GST_END_TEST;
GST_START_TEST (test_passthrough) GST_START_TEST (test_passthrough)
{ {
/* int 8 bit */ /* int 8 bit */
@ -1894,6 +2252,10 @@ audioconvert_suite (void)
tcase_add_test (tc_chain, test_float_conversion); tcase_add_test (tc_chain, test_float_conversion);
tcase_add_test (tc_chain, test_int_float_conversion); tcase_add_test (tc_chain, test_int_float_conversion);
tcase_add_test (tc_chain, test_multichannel_conversion); tcase_add_test (tc_chain, test_multichannel_conversion);
tcase_add_test (tc_chain,
test_multichannel_crossmixing_with_input_channels_reorder);
tcase_add_test (tc_chain,
test_multichannel_downmixing_to_stereo_with_input_channels_reorder);
tcase_add_test (tc_chain, test_passthrough); tcase_add_test (tc_chain, test_passthrough);
tcase_add_test (tc_chain, test_caps_negotiation); tcase_add_test (tc_chain, test_caps_negotiation);
tcase_add_test (tc_chain, test_convert_undefined_multichannel); tcase_add_test (tc_chain, test_convert_undefined_multichannel);