mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-25 01:30:38 +00:00
interleave: interleave samples following the Default Channel Ordering
In order to have a full mapping between channel positions in the audio stream and loudspeaker positions, the channel-mask alone is not enough: the channels must be interleaved following some Default Channel Ordering as mentioned in the WAVEFORMATEXTENSIBLE[1] specification. As a Default Channel Ordering use the one implied by GstAudioChannelPosition which follows the ordering defined in SMPTE 2036-2-2008[2]. NOTE that the relative order in the Top Layer is not exactly the same as the one from the WAVEFORMATEXTENSIBLE[1] specification; let's hope users using so may channels are already aware of such discrepancies. [1] http://msdn.microsoft.com/en-us/library/windows/hardware/dn653308%28v=vs.85%29.aspx [2] http://www.itu.int/dms_pub/itu-r/opb/rep/R-REP-BS.2159-2-2011-PDF-E.pdf Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=737127
This commit is contained in:
parent
7729f4ce81
commit
7ae7f657fa
2 changed files with 29 additions and 3 deletions
|
@ -255,9 +255,24 @@ gst_interleave_finalize (GObject * object)
|
|||
G_OBJECT_CLASS (parent_class)->finalize (object);
|
||||
}
|
||||
|
||||
static gint
|
||||
compare_positions (gconstpointer a, gconstpointer b, gpointer user_data)
|
||||
{
|
||||
const gint i = *(const gint *) a;
|
||||
const gint j = *(const gint *) b;
|
||||
const gint *pos = (const gint *) user_data;
|
||||
|
||||
if (pos[i] < pos[j])
|
||||
return -1;
|
||||
else if (pos[i] > pos[j])
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_interleave_channel_positions_to_mask (GValueArray * positions,
|
||||
guint64 * mask)
|
||||
gint default_ordering_map[64], guint64 * mask)
|
||||
{
|
||||
gint i;
|
||||
guint channels;
|
||||
|
@ -274,6 +289,13 @@ gst_interleave_channel_positions_to_mask (GValueArray * positions,
|
|||
pos[i] = g_value_get_enum (val);
|
||||
}
|
||||
|
||||
/* sort the default ordering map according to the position order */
|
||||
for (i = 0; i < channels; i++) {
|
||||
default_ordering_map[i] = i;
|
||||
}
|
||||
g_qsort_with_data (default_ordering_map, channels,
|
||||
sizeof (*default_ordering_map), compare_positions, pos);
|
||||
|
||||
ret = gst_audio_channel_positions_to_mask (pos, channels, FALSE, mask);
|
||||
g_free (pos);
|
||||
|
||||
|
@ -288,7 +310,7 @@ gst_interleave_set_channel_positions (GstInterleave * self, GstStructure * s)
|
|||
if (self->channel_positions != NULL &&
|
||||
self->channels == self->channel_positions->n_values) {
|
||||
if (!gst_interleave_channel_positions_to_mask (self->channel_positions,
|
||||
&channel_mask)) {
|
||||
self->default_channels_ordering_map, &channel_mask)) {
|
||||
GST_WARNING_OBJECT (self, "Invalid channel positions, using NONE");
|
||||
channel_mask = 0;
|
||||
}
|
||||
|
@ -1264,6 +1286,7 @@ gst_interleave_collected (GstCollectPads * pads, GstInterleave * self)
|
|||
GstBuffer *inbuf;
|
||||
guint8 *outdata;
|
||||
GstMapInfo input_info;
|
||||
gint channel;
|
||||
|
||||
cdata = (GstCollectData *) collected->data;
|
||||
|
||||
|
@ -1282,8 +1305,9 @@ gst_interleave_collected (GstCollectPads * pads, GstInterleave * self)
|
|||
goto next;
|
||||
|
||||
empty = FALSE;
|
||||
channel = GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel;
|
||||
outdata =
|
||||
write_info.data + width * GST_INTERLEAVE_PAD_CAST (cdata->pad)->channel;
|
||||
write_info.data + width * self->default_channels_ordering_map[channel];
|
||||
|
||||
self->func (outdata, input_info.data, self->channels, nsamples);
|
||||
gst_buffer_unmap (inbuf, &input_info);
|
||||
|
|
|
@ -60,6 +60,8 @@ struct _GstInterleave
|
|||
GValueArray *input_channel_positions;
|
||||
gboolean channel_positions_from_input;
|
||||
|
||||
gint default_channels_ordering_map[64];
|
||||
|
||||
GstCaps *sinkcaps;
|
||||
gint configured_sinkpads_counter;
|
||||
|
||||
|
|
Loading…
Reference in a new issue