From 7ae7f657fae542f06ba4c22d65a2084f5a4a3a5d Mon Sep 17 00:00:00 2001 From: Antonio Ospite Date: Tue, 23 Sep 2014 10:48:09 +0200 Subject: [PATCH] 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 --- gst/interleave/interleave.c | 30 +++++++++++++++++++++++++++--- gst/interleave/interleave.h | 2 ++ 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/gst/interleave/interleave.c b/gst/interleave/interleave.c index 41bf887f9f..cb2cd0fbb2 100644 --- a/gst/interleave/interleave.c +++ b/gst/interleave/interleave.c @@ -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); diff --git a/gst/interleave/interleave.h b/gst/interleave/interleave.h index 87a8eedb1d..78f519d99a 100644 --- a/gst/interleave/interleave.h +++ b/gst/interleave/interleave.h @@ -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;