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