gst_plugins_base/gst-libs/gst/audio/multichannel.c
changeset 16 8e837d1bf446
parent 2 5505e8908944
child 30 7e817e7e631c
equal deleted inserted replaced
15:4b0c6ed43234 16:8e837d1bf446
    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 */
   101         count++;
   113         count++;
   102     }
   114     }
   103 
   115 
   104     /* NONE may not occur mixed with other channel positions */
   116     /* NONE may not occur mixed with other channel positions */
   105     if (i == GST_AUDIO_CHANNEL_POSITION_NONE && count > 0) {
   117     if (i == GST_AUDIO_CHANNEL_POSITION_NONE && count > 0) {
   106       g_warning ("Either all channel positions must be defined, or all "
   118       GST_WARNING ("Either all channel positions must be defined, or all "
   107           "be set to NONE, having only some defined is not allowed");
   119           "be set to NONE, having only some defined is not allowed");
   108       return FALSE;
   120       return FALSE;
   109     }
   121     }
   110 
   122 
   111     if (count > 1) {
   123     if (count > 1) {
   112       g_warning ("Channel position %d occurred %d times, not allowed",
   124       GST_WARNING ("Channel position %d occurred %d times, not allowed",
   113           i, count);
   125           i, count);
   114       return FALSE;
   126       return FALSE;
   115     }
   127     }
   116   }
   128   }
   117 
   129 
   125       else if (pos[n] == conf[i].pos2[0])
   137       else if (pos[n] == conf[i].pos2[0])
   126         found2 = TRUE;
   138         found2 = TRUE;
   127     }
   139     }
   128 
   140 
   129     if (found1 && found2) {
   141     if (found1 && found2) {
   130       g_warning ("Found conflicting channel positions %d/%d and %d",
   142       GST_WARNING ("Found conflicting channel positions %d/%d and %d",
   131           conf[i].pos1[0], conf[i].pos1[1], conf[i].pos2[0]);
   143           conf[i].pos1[0], conf[i].pos1[1], conf[i].pos2[0]);
   132       return FALSE;
   144       return FALSE;
   133     }
   145     }
   134   }
       
   135 
       
   136   /* Throw warning if we encounter an unusual 2-channel configuration,
       
   137    * at least until someone finds a reason why we should not */
       
   138   if (channels == 2 && (pos[0] != GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT ||
       
   139           pos[1] != GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT)) {
       
   140     g_warning ("channels=2 implies stereo, but channel positions are "
       
   141         "< %d, %d>", pos[0], pos[1]);
       
   142     return FALSE;
       
   143   }
   146   }
   144 
   147 
   145   return TRUE;
   148   return TRUE;
   146 }
   149 }
   147 
   150 
   234 
   237 
   235 GstAudioChannelPosition *
   238 GstAudioChannelPosition *
   236 gst_audio_get_channel_positions (GstStructure * str)
   239 gst_audio_get_channel_positions (GstStructure * str)
   237 {
   240 {
   238   GstAudioChannelPosition *pos;
   241   GstAudioChannelPosition *pos;
       
   242 
   239   gint channels, n;
   243   gint channels, n;
       
   244 
   240   const GValue *pos_val_arr, *pos_val_entry;
   245   const GValue *pos_val_arr, *pos_val_entry;
       
   246 
   241   gboolean res;
   247   gboolean res;
       
   248 
   242   GType t;
   249   GType t;
   243 
   250 
   244   /* get number of channels, general type checkups */
   251   /* get number of channels, general type checkups */
   245   g_return_val_if_fail (str != NULL, NULL);
   252   g_return_val_if_fail (str != NULL, NULL);
   246   res = gst_structure_get_int (str, "channels", &channels);
   253   res = gst_structure_get_int (str, "channels", &channels);
   314     const GstAudioChannelPosition * pos)
   321     const GstAudioChannelPosition * pos)
   315 {
   322 {
   316   GValue pos_val_arr = { 0 }, pos_val_entry = {
   323   GValue pos_val_arr = { 0 }, pos_val_entry = {
   317   0};
   324   0};
   318   gint channels, n;
   325   gint channels, n;
       
   326 
   319   gboolean res;
   327   gboolean res;
   320 
   328 
   321   /* get number of channels, checkups */
   329   /* get number of channels, checkups */
   322   g_return_if_fail (str != NULL);
   330   g_return_if_fail (str != NULL);
   323   g_return_if_fail (pos != NULL);
   331   g_return_if_fail (pos != NULL);
   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}, {