diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c index dea382ed02..dcb139d501 100644 --- a/gst/audioconvert/gstaudioconvert.c +++ b/gst/audioconvert/gstaudioconvert.c @@ -275,6 +275,7 @@ gst_audio_convert_caps_remove_format_info (GstCaps * caps) GstStructure *st; gint i, n; GstCaps *res; + guint64 channel_mask; res = gst_caps_new_empty (); @@ -288,8 +289,16 @@ gst_audio_convert_caps_remove_format_info (GstCaps * caps) continue; st = gst_structure_copy (st); - gst_structure_remove_fields (st, "format", "channel-positions", "channels", - NULL); + gst_structure_remove_field (st, "format"); + + /* Only remove the channels and channel-mask for non-NONE layouts */ + if (gst_structure_get (st, "channel-mask", GST_TYPE_BITMASK, &channel_mask, + NULL)) { + if (channel_mask != 0) + gst_structure_remove_fields (st, "channel-mask", "channels", NULL); + } else { + gst_structure_remove_fields (st, "channel-mask", "channels", NULL); + } gst_caps_append_structure (res, st); } @@ -327,7 +336,7 @@ gst_audio_convert_transform_caps (GstBaseTransform * btrans, static const GstAudioChannelPosition default_positions[8][8] = { /* 1 channel */ { - GST_AUDIO_CHANNEL_POSITION_FRONT_MONO, + GST_AUDIO_CHANNEL_POSITION_MONO, }, /* 2 channels */ { @@ -338,9 +347,9 @@ static const GstAudioChannelPosition default_positions[8][8] = { { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, - GST_AUDIO_CHANNEL_POSITION_LFE, /* or FRONT_CENTER for 3.0? */ + GST_AUDIO_CHANNEL_POSITION_LFE1, }, - /* 4 channels (4.0 or 3.1?) */ + /* 4 channels (4.0) */ { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, @@ -355,68 +364,82 @@ static const GstAudioChannelPosition default_positions[8][8] = { GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, }, - /* 6 channels */ + /* 6 channels (5.1) */ { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_LFE1, }, - /* 7 channels */ + /* 7 channels (6.1) */ { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_REAR_CENTER, }, - /* 8 channels */ + /* 8 channels (7.1) */ { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, - GST_AUDIO_CHANNEL_POSITION_LFE, + GST_AUDIO_CHANNEL_POSITION_LFE1, GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, } }; -static const GValue * -find_suitable_channel_layout (const GValue * val, guint chans) +static gint +n_bits_set (guint64 x) { - /* if output layout is fixed already and looks sane, we're done */ - if (GST_VALUE_HOLDS_ARRAY (val) && gst_value_array_get_size (val) == chans) - return val; + gint i; + gint c = 0; + guint64 y = 1; - /* if it's a list, go through it recursively and return the first - * sane-enough looking value we find */ - if (GST_VALUE_HOLDS_LIST (val)) { - gint i; - - for (i = 0; i < gst_value_list_get_size (val); ++i) { - const GValue *v, *ret; - - v = gst_value_list_get_value (val, i); - if ((ret = find_suitable_channel_layout (v, chans))) - return ret; - } + for (i = 0; i < 64; i++) { + if (x & y) + c++; + y <<= 1; } - return NULL; + return c; +} + +static guint64 +find_suitable_mask (guint64 mask, gint n_chans) +{ + guint64 intersection; + gint i; + + i = 0; + + g_assert (n_bits_set (mask) >= n_chans); + + intersection = mask; + do { + intersection = intersection & ((~G_GUINT64_CONSTANT (0)) >> i); + i++; + } while (n_bits_set (intersection) > n_chans && i < 64); + + if (i < 64) + return intersection; + return 0; } static void gst_audio_convert_fixate_channels (GstBaseTransform * base, GstStructure * ins, GstStructure * outs) { - const GValue *in_layout, *out_layout; gint in_chans, out_chans; + guint64 in_mask = 0, out_mask = 0; + gboolean has_in_mask = FALSE, has_out_mask = FALSE; if (!gst_structure_get_int (ins, "channels", &in_chans)) return; /* this shouldn't really happen, should it? */ @@ -424,7 +447,7 @@ gst_audio_convert_fixate_channels (GstBaseTransform * base, GstStructure * ins, if (!gst_structure_has_field (outs, "channels")) { /* we could try to get the implied number of channels from the layout, * but that seems overdoing it for a somewhat exotic corner case */ - gst_structure_remove_field (outs, "channel-positions"); + gst_structure_remove_field (outs, "channel-mask"); return; } @@ -433,70 +456,101 @@ gst_audio_convert_fixate_channels (GstBaseTransform * base, GstStructure * ins, if (!gst_structure_get_int (outs, "channels", &out_chans)) { /* shouldn't really happen ... */ - gst_structure_remove_field (outs, "channel-positions"); + gst_structure_remove_field (outs, "channel-mask"); return; } - /* check if the output has a channel layout (or a list of layouts) */ - out_layout = gst_structure_get_value (outs, "channel-positions"); - - /* get the channel layout of the input if any */ - in_layout = gst_structure_get_value (ins, "channel-positions"); - - if (out_layout == NULL) { - if (out_chans <= 2 && (in_chans != out_chans || in_layout == NULL)) - return; /* nothing to do, default layout will be assumed */ - GST_WARNING_OBJECT (base, "downstream caps contain no channel layout"); + /* get the channel layout of the output if any */ + has_out_mask = gst_structure_has_field (outs, "channel-mask"); + if (has_out_mask) { + gst_structure_get (outs, "channel-mask", GST_TYPE_BITMASK, &out_mask, NULL); + } else { + /* channels == 1 => MONO */ + if (out_chans == 2) { + out_mask = + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT | + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; + has_out_mask = TRUE; + } } - if (in_chans == out_chans && in_layout != NULL) { - GValue res = { 0, }; + /* get the channel layout of the input if any */ + has_in_mask = gst_structure_has_field (ins, "channel-mask"); + if (has_in_mask) { + gst_structure_get (ins, "channel-mask", GST_TYPE_BITMASK, &in_mask, NULL); + } else { + /* channels == 1 => MONO */ + if (in_chans == 2) { + in_mask = + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT | + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT; + has_in_mask = TRUE; + } else if (in_chans > 2) + g_warning ("%s: Upstream caps contain no channel mask", + GST_ELEMENT_NAME (base)); + } + if (!has_out_mask && out_chans == 1 && (in_chans != out_chans + || !has_in_mask)) + return; /* nothing to do, default layout will be assumed */ + + if (in_chans == out_chans && (has_in_mask || in_chans == 1)) { /* same number of channels and no output layout: just use input layout */ - if (out_layout == NULL) { - gst_structure_set_value (outs, "channel-positions", in_layout); + if (!has_out_mask) { + /* in_chans == 1 handled above already */ + gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, in_mask, NULL); return; } + /* If both masks are the same we're done, this includes the NONE layout case */ + if (in_mask == out_mask) + return; + /* if output layout is fixed already and looks sane, we're done */ - if (GST_VALUE_HOLDS_ARRAY (out_layout) && - gst_value_array_get_size (out_layout) == out_chans) { + if (n_bits_set (out_mask) == out_chans) return; - } - /* if the output layout is not fixed, check if the output layout contains - * the input layout */ - if (gst_value_intersect (&res, in_layout, out_layout)) { - gst_structure_set_value (outs, "channel-positions", in_layout); - g_value_unset (&res); - return; - } + if (n_bits_set (out_mask) < in_chans) { + /* Not much we can do here, this shouldn't just happen */ + g_warning ("%s: Invalid downstream channel-mask with too few bits set", + GST_ELEMENT_NAME (base)); + } else { + guint64 intersection; - /* output layout is not fixed and does not contain the input layout, so - * just pick the first layout in the list (it should be a list ...) */ - if ((out_layout = find_suitable_channel_layout (out_layout, out_chans))) { - gst_structure_set_value (outs, "channel-positions", out_layout); - return; + /* if the output layout is not fixed, check if the output layout contains + * the input layout */ + intersection = in_mask & out_mask; + if (n_bits_set (intersection) >= in_chans) { + gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, in_mask, + NULL); + return; + } + + /* output layout is not fixed and does not contain the input layout, so + * just pick the first possibility */ + intersection = find_suitable_mask (out_mask, out_chans); + if (intersection) { + gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, intersection, + NULL); + return; + } } /* ... else fall back to default layout (NB: out_layout is NULL here) */ GST_WARNING_OBJECT (base, "unexpected output channel layout"); - } + } else { + guint64 intersection; - /* number of input channels != number of output channels: - * if this value contains a list of channel layouts (or even worse: a list - * with another list), just pick the first value and repeat until we find a - * channel position array or something else that's not a list; we assume - * the input if half-way sane and don't try to fall back on other list items - * if the first one is something unexpected or non-channel-pos-array-y */ - if (out_layout != NULL && GST_VALUE_HOLDS_LIST (out_layout)) - out_layout = find_suitable_channel_layout (out_layout, out_chans); - - if (out_layout != NULL) { - if (GST_VALUE_HOLDS_ARRAY (out_layout) && - gst_value_array_get_size (out_layout) == out_chans) { - /* looks sane enough, let's use it */ - gst_structure_set_value (outs, "channel-positions", out_layout); + /* number of input channels != number of output channels: + * if this value contains a list of channel layouts (or even worse: a list + * with another list), just pick the first value and repeat until we find a + * channel position array or something else that's not a list; we assume + * the input if half-way sane and don't try to fall back on other list items + * if the first one is something unexpected or non-channel-pos-array-y */ + if (n_bits_set (out_mask) >= out_chans) { + intersection = find_suitable_mask (out_mask, out_chans); + gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, intersection, + NULL); return; } @@ -510,8 +564,18 @@ gst_audio_convert_fixate_channels (GstBaseTransform * base, GstStructure * ins, * layout based on LFE-presence in input layout, but let's save that for * another day) */ if (out_chans > 0 && out_chans <= G_N_ELEMENTS (default_positions[0])) { + gint i; + GST_DEBUG_OBJECT (base, "using default channel layout as fallback"); - gst_audio_set_channel_positions (outs, default_positions[out_chans - 1]); + + out_mask = 0; + for (i = 0; i < out_chans; i++) + out_mask |= default_positions[out_chans - 1][i]; + + gst_structure_set (outs, "channel-mask", GST_TYPE_BITMASK, out_mask, NULL); + } else { + GST_ERROR_OBJECT (base, "Have no default layout for %d channels", + out_chans); } } diff --git a/gst/audioconvert/gstchannelmix.c b/gst/audioconvert/gstchannelmix.c index 2694780aea..21a70cafd1 100644 --- a/gst/audioconvert/gstchannelmix.c +++ b/gst/audioconvert/gstchannelmix.c @@ -26,7 +26,6 @@ #include #include -#include #include "gstchannelmix.h" @@ -96,7 +95,7 @@ gst_channel_mix_fill_compatible (AudioConvertCtx * this) { { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { - GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}}, + GST_AUDIO_CHANNEL_POSITION_MONO}}, /* front center: 2 <-> 1 */ { { GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, @@ -191,7 +190,7 @@ gst_channel_mix_detect_pos (GstAudioInfo * info, for (n = 0; n < info->channels; n++) { switch (info->position[n]) { - case GST_AUDIO_CHANNEL_POSITION_FRONT_MONO: + case GST_AUDIO_CHANNEL_POSITION_MONO: f[1] = n; *has_f = TRUE; break; @@ -235,7 +234,7 @@ gst_channel_mix_detect_pos (GstAudioInfo * info, s[2] = n; *has_s = TRUE; break; - case GST_AUDIO_CHANNEL_POSITION_LFE: + case GST_AUDIO_CHANNEL_POSITION_LFE1: *has_b = TRUE; b[1] = n; break; @@ -552,7 +551,7 @@ gst_channel_mix_fill_special (AudioConvertCtx * this) in->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) || (in->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT && in->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) && - out->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { + out->position[0] == GST_AUDIO_CHANNEL_POSITION_MONO) { this->matrix[0][0] = 0.5; this->matrix[1][0] = 0.5; return TRUE; @@ -561,7 +560,7 @@ gst_channel_mix_fill_special (AudioConvertCtx * this) out->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT) || (out->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT && out->position[1] == GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT)) && - in->position[0] == GST_AUDIO_CHANNEL_POSITION_FRONT_MONO) { + in->position[0] == GST_AUDIO_CHANNEL_POSITION_MONO) { this->matrix[0][0] = 1.0; this->matrix[0][1] = 1.0; return TRUE; @@ -584,8 +583,7 @@ gst_channel_mix_fill_matrix (AudioConvertCtx * this) gst_channel_mix_fill_identical (this); - if (!GST_AUDIO_INFO_HAS_DEFAULT_POSITIONS (&this->in) && - !GST_AUDIO_INFO_IS_UNPOSITIONED (&this->in)) { + if (!GST_AUDIO_INFO_IS_UNPOSITIONED (&this->in)) { gst_channel_mix_fill_compatible (this); gst_channel_mix_fill_others (this); gst_channel_mix_fill_normalize (this); @@ -650,17 +648,20 @@ gboolean gst_channel_mix_passthrough (AudioConvertCtx * this) { gint i; + guint64 in_mask, out_mask; /* only NxN matrices can be identities */ if (this->in.channels != this->out.channels) return FALSE; - /* this assumes a normalized matrix */ - for (i = 0; i < this->in.channels; i++) - if (this->matrix[i][i] != 1.) - return FALSE; + /* passthrough if both channel masks are the same */ + in_mask = out_mask = 0; + for (i = 0; i < this->in.channels; i++) { + in_mask |= this->in.position[i]; + out_mask |= this->out.position[i]; + } - return TRUE; + return in_mask == out_mask; } /* IMPORTANT: out_data == in_data is possible, make sure to not overwrite data diff --git a/gst/audioconvert/plugin.c b/gst/audioconvert/plugin.c index 105f0e9a92..5218b7c33d 100644 --- a/gst/audioconvert/plugin.c +++ b/gst/audioconvert/plugin.c @@ -25,16 +25,11 @@ #include "plugin.h" -#include #include "gstaudioconvertorc.h" static gboolean plugin_init (GstPlugin * plugin) { - /* ensure GstAudioChannelPosition type is registered */ - if (!gst_audio_channel_position_get_type ()) - return FALSE; - if (!gst_element_register (plugin, "audioconvert", GST_RANK_PRIMARY, gst_audio_convert_get_type ())) return FALSE;