diff --git a/ChangeLog b/ChangeLog index 841c95ac3f..657c41b76a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,24 @@ +2008-05-06 Sebastian Dröge + + Based on a patch by: Tim-Philipp Müller + + * gst/audioconvert/audioconvert.c: (audio_convert_prepare_context): + * gst/audioconvert/audioconvert.h: + * gst/audioconvert/gstaudioconvert.c: + (gst_audio_convert_parse_caps), + (structure_has_fixed_channel_positions), + (gst_audio_convert_transform_caps): + * gst/audioconvert/gstchannelmix.c: (gst_channel_mix_fill_matrix): + Add support for more than 8 channels and NONE channel layouts. For + more than 8 channels no channel conversion is supported yet, only + format conversions are supported. Fixes bug #398033. + + * tests/check/elements/audioconvert.c: (verify_convert), + (GST_START_TEST), (audioconvert_suite): + Add some unit tests by Tim for checking the NONE channel layouts + and more than 8 channels and add some more unit tests for channel + conversions. + 2008-05-06 Wim Taymans * gst/playback/gstdecodebin2.c: (connect_pad): diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c index f3948bb974..b4f8c741b9 100644 --- a/gst/audioconvert/audioconvert.c +++ b/gst/audioconvert/audioconvert.c @@ -420,6 +420,9 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in, /* first clean the existing context */ audio_convert_clean_context (ctx); + g_return_val_if_fail (in->unpositioned_layout == out->unpositioned_layout, + FALSE); + ctx->in = *in; ctx->out = *out; diff --git a/gst/audioconvert/audioconvert.h b/gst/audioconvert/audioconvert.h index 7e79f5a421..9c61cc6d54 100644 --- a/gst/audioconvert/audioconvert.h +++ b/gst/audioconvert/audioconvert.h @@ -54,6 +54,7 @@ struct _AudioConvertFmt gint rate; gint channels; GstAudioChannelPosition *pos; + gboolean unpositioned_layout; /* int audio caps */ gboolean sign; diff --git a/gst/audioconvert/gstaudioconvert.c b/gst/audioconvert/gstaudioconvert.c index 3c437d0c24..8a663769dd 100644 --- a/gst/audioconvert/gstaudioconvert.c +++ b/gst/audioconvert/gstaudioconvert.c @@ -107,7 +107,8 @@ static void gst_audio_convert_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); static void gst_audio_convert_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); - +static gboolean structure_has_fixed_channel_positions (GstStructure * s, + gboolean * unpositioned_layout); /* AudioConvert signals and args */ enum @@ -135,37 +136,37 @@ GST_BOILERPLATE_FULL (GstAudioConvert, gst_audio_convert, GstBaseTransform, GST_STATIC_CAPS ( \ "audio/x-raw-float, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 64;" \ "audio/x-raw-float, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 32;" \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 32, " \ "depth = (int) [ 1, 32 ], " \ "signed = (boolean) { true, false }; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 24, " \ "depth = (int) [ 1, 24 ], " "signed = (boolean) { true, false }; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 16, " \ "depth = (int) [ 1, 16 ], " \ "signed = (boolean) { true, false }; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 8, " \ "depth = (int) [ 1, 8 ], " \ @@ -333,6 +334,10 @@ gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt) goto no_values; if (!(fmt->pos = gst_audio_get_channel_positions (structure))) goto no_values; + + fmt->unpositioned_layout = FALSE; + structure_has_fixed_channel_positions (structure, &fmt->unpositioned_layout); + if (!gst_structure_get_int (structure, "width", &fmt->width)) goto no_values; if (!gst_structure_get_int (structure, "rate", &fmt->rate)) @@ -532,6 +537,42 @@ append_with_other_format (GstCaps * caps, GstStructure * s, gboolean isfloat) } } +static gboolean +structure_has_fixed_channel_positions (GstStructure * s, + gboolean * unpositioned_layout) +{ + GstAudioChannelPosition *pos; + const GValue *val; + gint channels = 0; + + if (!gst_structure_get_int (s, "channels", &channels)) + return FALSE; /* probably a range */ + + if (channels > 8) { + GST_LOG ("%d channels, undefined channel positions are implicit", channels); + *unpositioned_layout = TRUE; + return TRUE; + } + + val = gst_structure_get_value (s, "channel-positions"); + if (val == NULL || !gst_value_is_fixed (val)) { + GST_LOG ("no or unfixed channel-positions in %" GST_PTR_FORMAT, s); + return FALSE; + } + + pos = gst_audio_get_channel_positions (s); + if ((pos && pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) || channels > 8) { + GST_LOG ("fixed undefined channel-positions in %" GST_PTR_FORMAT, s); + *unpositioned_layout = TRUE; + } else { + GST_LOG ("fixed defined channel-positions in %" GST_PTR_FORMAT, s); + *unpositioned_layout = FALSE; + } + g_free (pos); + + return TRUE; +} + /* Audioconvert can perform all conversions on audio except for resampling. * However, there are some conversions we _prefer_ not to do. For example, it's * better to convert format (float<->int, endianness, etc) than the number of @@ -549,8 +590,8 @@ gst_audio_convert_transform_caps (GstBaseTransform * base, { GstCaps *ret; GstStructure *s, *structure; - gboolean isfloat; - gint width, depth, channels; + gboolean isfloat, allow_mixing; + gint width, depth, channels = 0; const gchar *fields_used[] = { "width", "depth", "rate", "channels", "endianness", "signed" }; @@ -606,11 +647,26 @@ gst_audio_convert_transform_caps (GstBaseTransform * base, } } + allow_mixing = TRUE; if (gst_structure_get_int (structure, "channels", &channels)) { - if (channels == 8) - gst_structure_set (s, "channels", G_TYPE_INT, 8, NULL); + gboolean unpositioned; + + /* we don't support mixing for channels without channel positions */ + if (structure_has_fixed_channel_positions (structure, &unpositioned)) + allow_mixing = (unpositioned == FALSE); + } + + if (!allow_mixing || channels == 8) { + gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL); + if (gst_structure_has_field (structure, "channel-positions")) + gst_structure_set_value (s, "channel-positions", + gst_structure_get_value (structure, "channel-positions")); + } else { + if (channels == 0) + gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 8, NULL); else gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, channels, 8, NULL); + gst_structure_remove_field (s, "channel-positions"); } gst_caps_append_structure (ret, s); @@ -639,7 +695,16 @@ gst_audio_convert_transform_caps (GstBaseTransform * base, * it's very bad to drop channels entirely. */ s = gst_structure_copy (s); - gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 8, NULL); + if (allow_mixing) { + gst_structure_set (s, "channels", GST_TYPE_INT_RANGE, 1, 8, NULL); + gst_structure_remove_field (s, "channel-positions"); + } else { + /* allow_mixing can only be FALSE if we got a fixed number of channels */ + gst_structure_set (s, "channels", G_TYPE_INT, channels, NULL); + if (gst_structure_has_field (structure, "channel-positions")) + gst_structure_set_value (s, "channel-positions", + gst_structure_get_value (structure, "channel-positions")); + } gst_caps_append_structure (ret, s); /* Same, plus a float<->int conversion */ diff --git a/gst/audioconvert/gstchannelmix.c b/gst/audioconvert/gstchannelmix.c index 94023d99fc..98648db869 100644 --- a/gst/audioconvert/gstchannelmix.c +++ b/gst/audioconvert/gstchannelmix.c @@ -464,9 +464,12 @@ static void gst_channel_mix_fill_matrix (AudioConvertCtx * this) { gst_channel_mix_fill_identical (this); - gst_channel_mix_fill_compatible (this); - gst_channel_mix_fill_others (this); - gst_channel_mix_fill_normalize (this); + + if (!this->in.unpositioned_layout) { + gst_channel_mix_fill_compatible (this); + gst_channel_mix_fill_others (this); + gst_channel_mix_fill_normalize (this); + } } /* only call after this->out and this->in are filled in */ diff --git a/tests/check/elements/audioconvert.c b/tests/check/elements/audioconvert.c index c61d7e9bf5..92e62db878 100644 --- a/tests/check/elements/audioconvert.c +++ b/tests/check/elements/audioconvert.c @@ -3,6 +3,7 @@ * unit test for audioconvert * * Copyright (C) <2005> Thomas Vander Stichele + * Copyright (C) <2007> Tim-Philipp Müller * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -34,33 +35,33 @@ static GstPad *mysrcpad, *mysinkpad; #define CONVERT_CAPS_TEMPLATE_STRING \ "audio/x-raw-float, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) { 32, 64 };" \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 32, " \ "depth = (int) [ 1, 32 ], " \ "signed = (boolean) { true, false }; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 24, " \ "depth = (int) [ 1, 24 ], " \ "signed = (boolean) { true, false }; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 16, " \ "depth = (int) [ 1, 16 ], " \ "signed = (boolean) { true, false }; " \ "audio/x-raw-int, " \ "rate = (int) [ 1, MAX ], " \ - "channels = (int) [ 1, 8 ], " \ + "channels = (int) [ 1, MAX ], " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \ "width = (int) 8, " \ "depth = (int) [ 1, 8 ], " \ @@ -229,6 +230,65 @@ static GstAudioChannelPosition mixed_up_positions[][6] = { } }; +/* we get this when recording from a soundcard with lots of input channels */ +static GstAudioChannelPosition undefined_positions[][9] = { + { + GST_AUDIO_CHANNEL_POSITION_NONE}, + { + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE}, + { + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE}, + { + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE}, + { + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE}, + { + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE}, + { + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE}, + { + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE}, + { + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE, + GST_AUDIO_CHANNEL_POSITION_NONE} + +}; + static void set_channel_positions (GstCaps * caps, int channels, GstAudioChannelPosition * channelpositions) @@ -289,7 +349,8 @@ get_int_mc_caps (guint channels, gchar * endianness, guint width, /* eats the refs to the caps */ static void 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) { GstBuffer *inbuffer, *outbuffer; GstElement *audioconvert; @@ -315,8 +376,12 @@ verify_convert (const gchar * which, void *in, int inlength, /* pushing gives away my reference ... */ GST_DEBUG ("push it"); - fail_unless (gst_pad_push (mysrcpad, inbuffer) == GST_FLOW_OK); + fail_unless_equals_int (gst_pad_push (mysrcpad, inbuffer), expected_flow); GST_DEBUG ("pushed it"); + + if (expected_flow != GST_FLOW_OK) + goto done; + /* ... and puts a new buffer on the global list */ fail_unless (g_list_length (buffers) == 1); fail_if ((outbuffer = (GstBuffer *) buffers->data) == NULL); @@ -355,6 +420,8 @@ verify_convert (const gchar * which, void *in, int inlength, buffers = g_list_remove (buffers, outbuffer); gst_buffer_unref (outbuffer); + +done: fail_unless (gst_element_set_state (audioconvert, GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null"); /* cleanup */ @@ -368,7 +435,11 @@ verify_convert (const gchar * which, void *in, int inlength, #define RUN_CONVERSION(which, inarray, in_get_caps, outarray, out_get_caps) \ verify_convert (which, inarray, sizeof (inarray), \ - in_get_caps, outarray, sizeof (outarray), out_get_caps) + in_get_caps, outarray, sizeof (outarray), out_get_caps, GST_FLOW_OK) + +#define RUN_CONVERSION_TO_FAIL(which, inarray, in_caps, outarray, out_caps) \ + verify_convert (which, inarray, sizeof (inarray), \ + in_caps, outarray, sizeof (outarray), out_caps, GST_FLOW_NOT_NEGOTIATED) GST_START_TEST (test_int16) @@ -733,23 +804,54 @@ GST_END_TEST; GST_START_TEST (test_multichannel_conversion) { { - /* Ensure that audioconvert prefers to convert to integer, rather than mix - * to mono - */ gfloat in[] = { 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 }; gfloat out[] = { 0.0, 0.0 }; - /* only one direction conversion, the other direction does - * not produce exactly the same as the input due to floating - * point rounding errors etc. */ RUN_CONVERSION ("3 channels to 1", in, get_float_mc_caps (3, "BYTE_ORDER", 32, FALSE), out, get_float_caps (1, "BYTE_ORDER", 32)); + RUN_CONVERSION ("1 channels to 3", out, get_float_caps (1, + "BYTE_ORDER", 32), in, get_float_mc_caps (3, "BYTE_ORDER", + 32, TRUE)); } + + { + gint16 in[] = { 0, 0, 0, 0, 0, 0 }; + gint16 out[] = { 0, 0 }; + + RUN_CONVERSION ("3 channels to 1", in, get_int_mc_caps (3, + "BYTE_ORDER", 16, 16, TRUE, FALSE), out, get_int_caps (1, + "BYTE_ORDER", 16, 16, TRUE)); + RUN_CONVERSION ("1 channels to 3", out, get_int_caps (1, "BYTE_ORDER", 16, + 16, TRUE), in, get_int_mc_caps (3, "BYTE_ORDER", 16, 16, TRUE, + TRUE)); + } + } GST_END_TEST; +/* for testing channel remapping with 8 channels */ +static GstAudioChannelPosition n8chan_pos_remap_in[8] = { + 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_SIDE_LEFT, + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT +}; +static GstAudioChannelPosition n8chan_pos_remap_out[8] = { + GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER, + GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, + GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT, + GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT, + GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, + GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT, + GST_AUDIO_CHANNEL_POSITION_LFE +}; GST_START_TEST (test_channel_remapping) { @@ -775,8 +877,52 @@ GST_START_TEST (test_channel_remapping) out, out_caps); } - /* TODO: float => int conversion with remapping and vice versa, - * int => int conversion with remapping */ + /* int with 8 channels (= largest number allowed with channel positions) */ + { + guint16 in[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + guint16 out[] = { 4, 0, 1, 6, 7, 2, 3, 5 }; + GstCaps *in_caps = get_int_mc_caps (8, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (8, "BYTE_ORDER", 16, 16, FALSE, TRUE); + + set_channel_positions (in_caps, 8, n8chan_pos_remap_in); + set_channel_positions (out_caps, 8, n8chan_pos_remap_out); + + RUN_CONVERSION ("8 channels layout remapping int", in, in_caps, + out, out_caps); + } + + /* int16 to int32 with 8 channels (= largest number allowed with channel positions) */ + { + guint16 in[] = { 0, 1, 2, 3, 4, 5, 6, 7 }; + guint32 out[] = + { 4 << 16, 0, 1 << 16, 6 << 16, 7 << 16, 2 << 16, 3 << 16, 5 << 16 }; + GstCaps *in_caps = get_int_mc_caps (8, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (8, "BYTE_ORDER", 32, 32, FALSE, TRUE); + + set_channel_positions (in_caps, 8, n8chan_pos_remap_in); + set_channel_positions (out_caps, 8, n8chan_pos_remap_out); + + RUN_CONVERSION ("8 channels layout remapping int16 --> int32", in, in_caps, + out, out_caps); + + in_caps = get_int_mc_caps (8, "BYTE_ORDER", 16, 16, FALSE, FALSE); + out_caps = get_int_mc_caps (8, "BYTE_ORDER", 32, 32, FALSE, TRUE); + set_channel_positions (in_caps, 8, n8chan_pos_remap_in); + set_channel_positions (out_caps, 8, n8chan_pos_remap_out); + RUN_CONVERSION ("8 channels layout remapping int16 <-- int32", out, + out_caps, in, in_caps); + } + + /* float to gint16 with 3 channels */ + { + gfloat in[] = { 100.0 / G_MAXINT16, 0.0, -100.0 / G_MAXINT16 }; + gint16 out[] = { -100, 0, 100 }; + GstCaps *in_caps = get_float_mc_caps (3, "BYTE_ORDER", 32, TRUE); + GstCaps *out_caps = get_int_mc_caps (3, "BYTE_ORDER", 16, 16, TRUE, FALSE); + + RUN_CONVERSION ("3 channels layout remapping float32 --> int16", in, + in_caps, out, out_caps); + } } GST_END_TEST; @@ -847,6 +993,265 @@ GST_START_TEST (test_caps_negotiation) GST_END_TEST; +GST_START_TEST (test_convert_undefined_multichannel) +{ + /* (A) CONVERSION FROM 'WORSE' TO 'BETTER' FORMAT */ + + /* 1 channel, NONE positions, int8 => int16 */ + { + guint16 out[] = { 0x2000 }; + guint8 in[] = { 0x20 }; + GstCaps *out_caps = get_int_mc_caps (1, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *in_caps = get_int_mc_caps (1, "BYTE_ORDER", 8, 8, FALSE, FALSE); + + set_channel_positions (out_caps, 1, undefined_positions[1 - 1]); + set_channel_positions (in_caps, 1, undefined_positions[1 - 1]); + + RUN_CONVERSION ("1 channel, undefined layout, identity conversion, " + "int8 => int16", in, in_caps, out, out_caps); + } + + /* 2 channels, NONE positions, int8 => int16 */ + { + guint16 out[] = { 0x8000, 0x2000 }; + guint8 in[] = { 0x80, 0x20 }; + GstCaps *out_caps = get_int_mc_caps (2, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *in_caps = get_int_mc_caps (2, "BYTE_ORDER", 8, 8, FALSE, FALSE); + + set_channel_positions (out_caps, 2, undefined_positions[2 - 1]); + set_channel_positions (in_caps, 2, undefined_positions[2 - 1]); + + RUN_CONVERSION ("2 channels, undefined layout, identity conversion, " + "int8 => int16", in, in_caps, out, out_caps); + } + + /* 6 channels, NONE positions, int8 => int16 */ + { + guint16 out[] = { 0x0000, 0x2000, 0x8000, 0x2000, 0x0000, 0xff00 }; + guint8 in[] = { 0x00, 0x20, 0x80, 0x20, 0x00, 0xff }; + GstCaps *out_caps = get_int_mc_caps (6, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *in_caps = get_int_mc_caps (6, "BYTE_ORDER", 8, 8, FALSE, FALSE); + + set_channel_positions (out_caps, 6, undefined_positions[6 - 1]); + set_channel_positions (in_caps, 6, undefined_positions[6 - 1]); + + RUN_CONVERSION ("6 channels, undefined layout, identity conversion, " + "int8 => int16", in, in_caps, out, out_caps); + } + + /* 9 channels, NONE positions, int8 => int16 */ + { + guint16 out[] = { 0x0000, 0xff00, 0x0000, 0x2000, 0x8000, 0x2000, + 0x0000, 0xff00, 0x0000 + }; + guint8 in[] = { 0x00, 0xff, 0x00, 0x20, 0x80, 0x20, 0x00, 0xff, 0x00 }; + GstCaps *out_caps = get_int_mc_caps (9, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *in_caps = get_int_mc_caps (9, "BYTE_ORDER", 8, 8, FALSE, FALSE); + + set_channel_positions (out_caps, 9, undefined_positions[9 - 1]); + set_channel_positions (in_caps, 9, undefined_positions[9 - 1]); + + RUN_CONVERSION ("9 channels, undefined layout, identity conversion, " + "int8 => int16", in, in_caps, out, out_caps); + } + + /* (B) CONVERSION FROM 'BETTER' TO 'WORSE' FORMAT */ + + /* 1 channel, NONE positions, int16 => int8 */ + { + guint16 in[] = { 0x2000 }; + guint8 out[] = { 0x20 }; + GstCaps *in_caps = get_int_mc_caps (1, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (1, "BYTE_ORDER", 8, 8, FALSE, FALSE); + + set_channel_positions (out_caps, 1, undefined_positions[1 - 1]); + set_channel_positions (in_caps, 1, undefined_positions[1 - 1]); + + RUN_CONVERSION ("1 channel, undefined layout, identity conversion, " + "int16 => int8", in, in_caps, out, out_caps); + } + + /* 2 channels, NONE positions, int16 => int8 */ + { + guint16 in[] = { 0x8000, 0x2000 }; + guint8 out[] = { 0x80, 0x20 }; + GstCaps *in_caps = get_int_mc_caps (2, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (2, "BYTE_ORDER", 8, 8, FALSE, FALSE); + + set_channel_positions (out_caps, 2, undefined_positions[2 - 1]); + set_channel_positions (in_caps, 2, undefined_positions[2 - 1]); + + RUN_CONVERSION ("2 channels, undefined layout, identity conversion, " + "int16 => int8", in, in_caps, out, out_caps); + } + + /* 6 channels, NONE positions, int16 => int8 */ + { + guint16 in[] = { 0x0000, 0x2000, 0x8000, 0x2000, 0x0000, 0xff00 }; + guint8 out[] = { 0x00, 0x20, 0x80, 0x20, 0x00, 0xff }; + GstCaps *in_caps = get_int_mc_caps (6, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (6, "BYTE_ORDER", 8, 8, FALSE, FALSE); + + set_channel_positions (out_caps, 6, undefined_positions[6 - 1]); + set_channel_positions (in_caps, 6, undefined_positions[6 - 1]); + + RUN_CONVERSION ("6 channels, undefined layout, identity conversion, " + "int16 => int8", in, in_caps, out, out_caps); + } + + /* 9 channels, NONE positions, int16 => int8 */ + { + guint16 in[] = { 0x0000, 0xff00, 0x0000, 0x2000, 0x8000, 0x2000, + 0x0000, 0xff00, 0x0000 + }; + guint8 out[] = { 0x00, 0xff, 0x00, 0x20, 0x80, 0x20, 0x00, 0xff, 0x00 }; + GstCaps *in_caps = get_int_mc_caps (9, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (9, "BYTE_ORDER", 8, 8, FALSE, FALSE); + + set_channel_positions (out_caps, 9, undefined_positions[9 - 1]); + set_channel_positions (in_caps, 9, undefined_positions[9 - 1]); + + RUN_CONVERSION ("9 channels, undefined layout, identity conversion, " + "int16 => int8", in, in_caps, out, out_caps); + } + + /* (C) NO CONVERSION, SAME FORMAT */ + + /* 1 channel, NONE positions, int16 => int16 */ + { + guint16 in[] = { 0x2000 }; + guint16 out[] = { 0x2000 }; + GstCaps *in_caps = get_int_mc_caps (1, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (1, "BYTE_ORDER", 16, 16, FALSE, FALSE); + + set_channel_positions (out_caps, 1, undefined_positions[1 - 1]); + set_channel_positions (in_caps, 1, undefined_positions[1 - 1]); + + RUN_CONVERSION ("1 channel, undefined layout, identity conversion, " + "int16 => int16", in, in_caps, out, out_caps); + } + + /* 2 channels, NONE positions, int16 => int16 */ + { + guint16 in[] = { 0x8000, 0x2000 }; + guint16 out[] = { 0x8000, 0x2000 }; + GstCaps *in_caps = get_int_mc_caps (2, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (2, "BYTE_ORDER", 16, 16, FALSE, FALSE); + + set_channel_positions (out_caps, 2, undefined_positions[2 - 1]); + set_channel_positions (in_caps, 2, undefined_positions[2 - 1]); + + RUN_CONVERSION ("2 channels, undefined layout, identity conversion, " + "int16 => int16", in, in_caps, out, out_caps); + } + + /* 6 channels, NONE positions, int16 => int16 */ + { + guint16 in[] = { 0x0000, 0x2000, 0x8000, 0x2000, 0x0000, 0xff00 }; + guint16 out[] = { 0x0000, 0x2000, 0x8000, 0x2000, 0x0000, 0xff00 }; + GstCaps *in_caps = get_int_mc_caps (6, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (6, "BYTE_ORDER", 16, 16, FALSE, FALSE); + + set_channel_positions (out_caps, 6, undefined_positions[6 - 1]); + set_channel_positions (in_caps, 6, undefined_positions[6 - 1]); + + RUN_CONVERSION ("6 channels, undefined layout, identity conversion, " + "int16 => int16", in, in_caps, out, out_caps); + } + + /* 9 channels, NONE positions, int16 => int16 */ + { + guint16 in[] = { 0x0000, 0xff00, 0x0000, 0x2000, 0x8000, 0x2000, + 0x0000, 0xff00, 0x0000 + }; + guint16 out[] = { 0x0000, 0xff00, 0x0000, 0x2000, 0x8000, 0x2000, + 0x0000, 0xff00, 0x0000 + }; + GstCaps *in_caps = get_int_mc_caps (9, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_int_mc_caps (9, "BYTE_ORDER", 16, 16, FALSE, FALSE); + + set_channel_positions (out_caps, 9, undefined_positions[9 - 1]); + set_channel_positions (in_caps, 9, undefined_positions[9 - 1]); + + RUN_CONVERSION ("9 channels, undefined layout, identity conversion, " + "int16 => int16", in, in_caps, out, out_caps); + } + + /* (C) int16 => float */ + + /* 9 channels, NONE positions, int16 => float */ + { + guint16 in[] = { 0x0000, 0x8000, 0x0000, 0x8000, 0x8000, 0x8000, + 0x0000, 0x8000, 0x0000 + }; + gfloat out[] = { -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0, 0.0, -1.0 }; + GstCaps *in_caps = get_int_mc_caps (9, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_float_mc_caps (9, "BYTE_ORDER", 32, FALSE); + + set_channel_positions (out_caps, 9, undefined_positions[9 - 1]); + set_channel_positions (in_caps, 9, undefined_positions[9 - 1]); + + RUN_CONVERSION ("9 channels, undefined layout, identity conversion, " + "int16 => float", in, in_caps, out, out_caps); + } + + /* 9 channels, NONE positions, int16 => float (same as above, but no + * position on output caps to see if audioconvert transforms correctly) */ + { + guint16 in[] = { 0x0000, 0x8000, 0x0000, 0x8000, 0x8000, 0x8000, + 0x0000, 0x8000, 0x0000 + }; + gfloat out[] = { -1.0, 0.0, -1.0, 0.0, 0.0, 0.0, -1.0, 0.0, -1.0 }; + GstCaps *in_caps = get_int_mc_caps (9, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_float_mc_caps (9, "BYTE_ORDER", 32, FALSE); + + //set_channel_positions (out_caps, 9, undefined_positions[9 - 1]); + set_channel_positions (in_caps, 9, undefined_positions[9 - 1]); + + RUN_CONVERSION ("9 channels, undefined layout, identity conversion, " + "int16 => float", in, in_caps, out, out_caps); + } + + /* 8 channels, NONE positions => 2 channels: should fail, no mixing allowed */ + { + guint16 in[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + gfloat out[] = { -1.0, -1.0 }; + GstCaps *in_caps = get_int_mc_caps (8, "BYTE_ORDER", 16, 16, FALSE, FALSE); + GstCaps *out_caps = get_float_mc_caps (2, "BYTE_ORDER", 32, FALSE); + + set_channel_positions (in_caps, 8, undefined_positions[8 - 1]); + + RUN_CONVERSION_TO_FAIL ("8 channels with layout => 2 channels", + in, in_caps, out, out_caps); + } + + /* 8 channels, with positions => 2 channels (makes sure channel-position + * fields are removed properly in some cases in ::transform_caps, so we + * don't up with caps with 2 channels and 8 channel positions) */ + { + GstAudioChannelPosition layout8ch[] = { + 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_SIDE_LEFT, + GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT + }; + gint16 in[] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + gint16 out[] = { 0, 0 }; + GstCaps *in_caps = get_int_mc_caps (8, "BYTE_ORDER", 16, 16, TRUE, FALSE); + GstCaps *out_caps = get_int_mc_caps (2, "BYTE_ORDER", 16, 16, TRUE, FALSE); + + set_channel_positions (in_caps, 8, layout8ch); + + RUN_CONVERSION ("8 channels with layout => 2 channels", + in, in_caps, out, out_caps); + } +} + +GST_END_TEST; static Suite * audioconvert_suite (void) @@ -862,23 +1267,9 @@ audioconvert_suite (void) tcase_add_test (tc_chain, test_multichannel_conversion); tcase_add_test (tc_chain, test_channel_remapping); tcase_add_test (tc_chain, test_caps_negotiation); + tcase_add_test (tc_chain, test_convert_undefined_multichannel); return s; } -int -main (int argc, char **argv) -{ - int nf; - - Suite *s = audioconvert_suite (); - SRunner *sr = srunner_create (s); - - gst_check_init (&argc, &argv); - - srunner_run_all (sr, CK_NORMAL); - nf = srunner_ntests_failed (sr); - srunner_free (sr); - - return nf; -} +GST_CHECK_MAIN (audioconvert);