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