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:
Antonio Ospite 2014-09-23 10:48:09 +02:00 committed by Sebastian Dröge
parent 7729f4ce81
commit 7ae7f657fa
2 changed files with 29 additions and 3 deletions

View file

@ -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);

View file

@ -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;