14 * You should have received a copy of the GNU Library General Public |
14 * You should have received a copy of the GNU Library General Public |
15 * License along with this library; if not, write to the |
15 * License along with this library; if not, write to the |
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, |
17 * Boston, MA 02111-1307, USA. |
17 * Boston, MA 02111-1307, USA. |
18 */ |
18 */ |
19 /** |
19 |
20 * SECTION:gstmultichannel |
20 #ifdef HAVE_CONFIG_H |
21 * @short_description: Support for multichannel audio elements |
21 #include <config.h> |
22 * |
22 #endif |
23 * This module contains some helper functions and a enum to work with |
23 |
24 * multichannel audio. |
24 #include "multichannel.h" |
|
25 |
|
26 #define GST_AUDIO_CHANNEL_POSITIONS_FIELD_NAME "channel-positions" |
|
27 |
|
28 /* |
|
29 * This function checks if basic assumptions apply: |
|
30 * - does each position occur at most once? |
|
31 * - do conflicting positions occur? |
|
32 * + front_mono vs. front_left/right |
|
33 * + front_center vs. front_left/right_of_center |
|
34 * + rear_center vs. rear_left/right |
|
35 * It also adds some hacks that 0.8.x needs for compatibility: |
|
36 * - if channels == 1, are we really mono? |
|
37 * - if channels == 2, are we really stereo? |
25 */ |
38 */ |
26 |
39 |
27 #ifdef HAVE_CONFIG_H |
40 static gboolean |
28 #include "config.h" |
|
29 #endif |
|
30 |
|
31 #include "multichannel.h" |
|
32 |
|
33 #define GST_AUDIO_CHANNEL_POSITIONS_FIELD_NAME "channel-positions" |
|
34 |
|
35 /** |
|
36 * gst_audio_check_channel_positions: |
|
37 * @pos: An array of #GstAudioChannelPosition. |
|
38 * @channels: The number of elements in @pos. |
|
39 * |
|
40 * This functions checks if the given channel positions are valid. Channel |
|
41 * positions are valid if: |
|
42 * <itemizedlist> |
|
43 * <listitem><para>No channel positions appears twice or all positions are %GST_AUDIO_CHANNEL_POSITION_NONE. |
|
44 * </para></listitem> |
|
45 * <listitem><para>Either all or none of the channel positions are %GST_AUDIO_CHANNEL_POSITION_NONE. |
|
46 * </para></listitem> |
|
47 * <listitem><para>%GST_AUDIO_CHANNEL_POSITION_FRONT_MONO and %GST_AUDIO_CHANNEL_POSITION_LEFT or %GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT don't appear together in the given positions. |
|
48 * </para></listitem> |
|
49 * </itemizedlist> |
|
50 * |
|
51 * Since: 0.10.20 |
|
52 * |
|
53 * Returns: %TRUE if the given channel positions are valid |
|
54 * and %FALSE otherwise. |
|
55 */ |
|
56 #ifdef __SYMBIAN32__ |
|
57 EXPORT_C |
|
58 #endif |
|
59 |
|
60 gboolean |
|
61 gst_audio_check_channel_positions (const GstAudioChannelPosition * pos, |
41 gst_audio_check_channel_positions (const GstAudioChannelPosition * pos, |
62 guint channels) |
42 gint channels) |
63 { |
43 { |
64 gint i, n; |
44 gint i, n; |
65 |
|
66 const struct |
45 const struct |
67 { |
46 { |
68 const GstAudioChannelPosition pos1[2]; |
47 const GstAudioChannelPosition pos1[2]; |
69 const GstAudioChannelPosition pos2[1]; |
48 const GstAudioChannelPosition pos2[1]; |
70 } conf[] = { |
49 } conf[] = { |
71 /* front: mono <-> stereo */ |
50 /* front: mono <-> stereo */ |
72 { { |
51 { { |
73 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, |
52 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, |
74 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { |
53 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { |
75 GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}}, { { |
54 GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}}, |
|
55 /* front center: 2 <-> 1 */ |
|
56 { { |
|
57 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, |
|
58 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, { |
|
59 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}}, |
|
60 /* rear: 2 <-> 1 */ |
|
61 { { |
|
62 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, |
|
63 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, { |
|
64 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}}, { { |
76 GST_AUDIO_CHANNEL_POSITION_INVALID}} |
65 GST_AUDIO_CHANNEL_POSITION_INVALID}} |
77 }; |
66 }; |
78 |
67 |
79 g_return_val_if_fail (pos != NULL, FALSE); |
68 g_assert (pos != NULL && channels > 0); |
80 g_return_val_if_fail (channels > 0, FALSE); |
|
81 |
69 |
82 /* check for invalid channel positions */ |
70 /* check for invalid channel positions */ |
83 for (n = 0; n < channels; n++) { |
71 for (n = 0; n < channels; n++) { |
84 if (pos[n] <= GST_AUDIO_CHANNEL_POSITION_INVALID || |
72 if (pos[n] <= GST_AUDIO_CHANNEL_POSITION_INVALID || |
85 pos[n] >= GST_AUDIO_CHANNEL_POSITION_NUM) { |
73 pos[n] >= GST_AUDIO_CHANNEL_POSITION_NUM) { |
86 GST_WARNING ("Channel position %d for channel %d is invalid", pos[n], n); |
74 g_warning ("Channel position %d for channel %d is invalid", pos[n], n); |
87 return FALSE; |
75 return FALSE; |
88 } |
76 } |
89 } |
77 } |
90 |
78 |
91 /* either all channel positions are NONE or all are defined, |
79 /* either all channel positions are NONE or all are defined, |
92 * but having only some channel positions NONE and others not |
80 * but having only some channel positions NONE and others not |
93 * is not allowed */ |
81 * is not allowed */ |
94 if (pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) { |
82 if (pos[0] == GST_AUDIO_CHANNEL_POSITION_NONE) { |
95 for (n = 1; n < channels; ++n) { |
83 for (n = 1; n < channels; ++n) { |
96 if (pos[n] != GST_AUDIO_CHANNEL_POSITION_NONE) { |
84 if (pos[n] != GST_AUDIO_CHANNEL_POSITION_NONE) { |
97 GST_WARNING ("Either all channel positions must be defined, or all " |
85 g_warning ("Either all channel positions must be defined, or all " |
98 "be set to NONE, having only some defined is not allowed"); |
86 "be set to NONE, having only some defined is not allowed"); |
99 return FALSE; |
87 return FALSE; |
100 } |
88 } |
101 } |
89 } |
102 /* all positions are NONE, we are done here */ |
90 /* all positions are NONE, we are done here */ |
389 g_return_if_fail (pos != NULL); |
381 g_return_if_fail (pos != NULL); |
390 res = gst_structure_get_int (str, "channels", &channels); |
382 res = gst_structure_get_int (str, "channels", &channels); |
391 g_return_if_fail (res); |
383 g_return_if_fail (res); |
392 g_return_if_fail (channels > 0); |
384 g_return_if_fail (channels > 0); |
393 |
385 |
|
386 /* 0.8.x: channels=1 or channels=2 is mono/stereo, no positions needed |
|
387 * there (we discard them anyway) */ |
|
388 if (channels == 1 || channels == 2) |
|
389 return; |
|
390 |
394 /* create the array of lists */ |
391 /* create the array of lists */ |
395 g_value_init (&pos_val_arr, GST_TYPE_ARRAY); |
392 g_value_init (&pos_val_arr, GST_TYPE_ARRAY); |
396 g_value_init (&pos_val_entry, GST_TYPE_AUDIO_CHANNEL_POSITION); |
393 g_value_init (&pos_val_entry, GST_TYPE_AUDIO_CHANNEL_POSITION); |
397 for (n = 0; n < channels; n++) { |
394 for (n = 0; n < channels; n++) { |
398 g_value_init (&pos_val_list, GST_TYPE_LIST); |
395 g_value_init (&pos_val_list, GST_TYPE_LIST); |
418 static GstCaps * |
415 static GstCaps * |
419 add_list_to_struct (GstStructure * str, |
416 add_list_to_struct (GstStructure * str, |
420 const GstAudioChannelPosition * pos, gint num_positions) |
417 const GstAudioChannelPosition * pos, gint num_positions) |
421 { |
418 { |
422 GstCaps *caps = gst_caps_new_empty (); |
419 GstCaps *caps = gst_caps_new_empty (); |
423 |
|
424 const GValue *chan_val; |
420 const GValue *chan_val; |
425 |
421 |
426 chan_val = gst_structure_get_value (str, "channels"); |
422 chan_val = gst_structure_get_value (str, "channels"); |
427 if (G_VALUE_TYPE (chan_val) == G_TYPE_INT) { |
423 if (G_VALUE_TYPE (chan_val) == G_TYPE_INT) { |
428 gst_audio_set_structure_channel_positions_list (str, pos, num_positions); |
424 gst_audio_set_structure_channel_positions_list (str, pos, num_positions); |
429 } else if (G_VALUE_TYPE (chan_val) == GST_TYPE_LIST) { |
425 } else if (G_VALUE_TYPE (chan_val) == GST_TYPE_LIST) { |
430 gint size; |
426 gint size; |
431 |
|
432 const GValue *sub_val; |
427 const GValue *sub_val; |
433 |
428 |
434 size = gst_value_list_get_size (chan_val); |
429 size = gst_value_list_get_size (chan_val); |
435 sub_val = gst_value_list_get_value (chan_val, 0); |
430 sub_val = gst_value_list_get_value (chan_val, 0); |
436 gst_structure_set_value (str, "channels", sub_val); |
431 gst_structure_set_value (str, "channels", sub_val); |
529 |
524 |
530 GstAudioChannelPosition * |
525 GstAudioChannelPosition * |
531 gst_audio_fixate_channel_positions (GstStructure * str) |
526 gst_audio_fixate_channel_positions (GstStructure * str) |
532 { |
527 { |
533 GstAudioChannelPosition *pos; |
528 GstAudioChannelPosition *pos; |
534 |
|
535 gint channels, n, num_unfixed = 0, i, c; |
529 gint channels, n, num_unfixed = 0, i, c; |
536 |
|
537 const GValue *pos_val_arr, *pos_val_entry, *pos_val; |
530 const GValue *pos_val_arr, *pos_val_entry, *pos_val; |
538 |
|
539 gboolean res, is_stereo = TRUE; |
531 gboolean res, is_stereo = TRUE; |
540 |
|
541 GType t; |
532 GType t; |
542 |
533 |
543 /* |
534 /* |
544 * We're going to do this cluelessly. We'll make an array of values that |
535 * We're going to do this cluelessly. We'll make an array of values that |
545 * conflict with each other and, for each iteration in this array, pick |
536 * conflict with each other and, for each iteration in this array, pick |
550 { |
541 { |
551 const GstAudioChannelPosition pos1[2]; |
542 const GstAudioChannelPosition pos1[2]; |
552 const GstAudioChannelPosition pos2[1]; |
543 const GstAudioChannelPosition pos2[1]; |
553 } conf[] = { |
544 } conf[] = { |
554 /* front: mono <-> stereo */ |
545 /* front: mono <-> stereo */ |
555 { |
546 { { |
556 { |
547 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, |
557 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT, |
|
558 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { |
548 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT}, { |
559 GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}}, { { |
549 GST_AUDIO_CHANNEL_POSITION_FRONT_MONO}}, |
|
550 /* front center: 2 <-> 1 */ |
|
551 { { |
560 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, |
552 GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT_OF_CENTER, |
561 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, { |
553 GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT_OF_CENTER}, { |
562 GST_AUDIO_CHANNEL_POSITION_INVALID}}, { { |
554 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}}, |
563 GST_AUDIO_CHANNEL_POSITION_INVALID, GST_AUDIO_CHANNEL_POSITION_INVALID}, { |
555 /* rear: 2 <-> 1 */ |
564 GST_AUDIO_CHANNEL_POSITION_FRONT_CENTER}}, { { |
556 { { |
565 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, |
557 GST_AUDIO_CHANNEL_POSITION_REAR_LEFT, |
566 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, { |
558 GST_AUDIO_CHANNEL_POSITION_REAR_RIGHT}, { |
567 GST_AUDIO_CHANNEL_POSITION_INVALID}}, { { |
|
568 GST_AUDIO_CHANNEL_POSITION_INVALID, GST_AUDIO_CHANNEL_POSITION_INVALID}, { |
|
569 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}}, { { |
559 GST_AUDIO_CHANNEL_POSITION_REAR_CENTER}}, { { |
570 GST_AUDIO_CHANNEL_POSITION_INVALID, GST_AUDIO_CHANNEL_POSITION_INVALID}, { |
560 GST_AUDIO_CHANNEL_POSITION_INVALID, GST_AUDIO_CHANNEL_POSITION_INVALID}, { |
571 GST_AUDIO_CHANNEL_POSITION_LFE}}, { { |
561 GST_AUDIO_CHANNEL_POSITION_LFE}}, { { |
572 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, |
562 GST_AUDIO_CHANNEL_POSITION_SIDE_LEFT, |
573 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, { |
563 GST_AUDIO_CHANNEL_POSITION_SIDE_RIGHT}, { |