1 /* GStreamer
2  * Copyright (C) <2016> Carlos Rafael Giani <dv at pseudoterminal dot org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 
20 /**
21  * SECTION:element-rawaudioparse
22  * @title: rawaudioparse
23  *
24  * This element parses incoming data as raw audio samples and timestamps it.
25  * It also handles seek queries in said raw audio data, and ensures that output
26  * buffers contain an integer number of samples, even if the input buffers don't.
27  * For example, with sample format S16LE and 2 channels, an input buffer of 411
28  * bytes contains 102.75 samples. rawaudioparse will then output 102 samples
29  * (= 408 bytes) and keep the remaining 3 bytes. These will then be prepended to
30  * the next input data.
31  *
32  * The element implements the properties and sink caps configuration as specified
33  * in the #GstRawBaseParse documentation. The properties configuration can be
34  * modified by using the sample-rate, num-channels, channel-positions, format,
35  * and pcm-format properties.
36  *
37  * Currently, this parser supports raw data in a-law, mu-law, or linear PCM format.
38  *
39  * To facilitate operation with the unalignedaudioparse element, rawaudioparse
40  * supports the "audio/x-unaligned-raw" media type. This is treated identically to
41  * "audio/x-raw", except that it is used by source elements which do not guarantee
42  * that the buffers they push out are timestamped and contain an integer amount of
43  * samples (see the 411 bytes example above). By using a different media type, it
44  * is guaranteed that unalignedaudioparse is autoplugged, making sure that the
45  * autoplugged chain does not push unparsed content downstream. The source caps'
46  * media type with linear PCM data is always "audio/x-raw", even if the sink caps
47  * use "audio/x-unaligned-raw".
48  *
49  * The channel-positions property can be used to set explicit position information
50  * for each channel. If the array that is passed to this property does not match
51  * the number of channels indicated by num-channels, then said number of channels
52  * is updated to the array length. If channel-positions is NULL, then the default
53  * GStreamer positioning is used. This property is also useful for swapping left
54  * and right in a stereo signal for example.
55  *
56  * ## Example pipelines
57  * |[
58  * gst-launch-1.0 souphttpsrc http://my-dlna-server/track.l16 \
59  *     rawaudioparse ! audioconvert ! audioresample ! autoaudiosink
60  * ]|
61  *  Receive L16 data from a DLNA server, parse and timestamp it with
62  * rawaudioparse, and play it. use-sink-caps is set to true since souphttpsrc
63  * will set its source pad's caps to audio/x-unaligned-raw for the L16 stream.
64  * |[
65  * gst-launch-1.0 filesrc location=audio.raw ! rawaudioparse use-sink-caps=false \
66  *         format=pcm pcm-format=s16le sample-rate=48000 num-channels=2 \
67  *         audioconvert ! audioresample ! autoaudiosink
68  * ]|
69  *  Read raw data from a local file and parse it as PCM data with 48000 Hz sample
70  * rate, signed 16 bit integer samples, and 2 channels. use-sink-caps is set to
71  * false to ensure the property information is used and the parser does not expect
72  * audio/x-raw or audio/x-unaligned-raw caps.
73  *
74  */
75 
76 #ifdef HAVE_CONFIG_H
77 #  include "config.h"
78 #endif
79 
80 /* FIXME: GValueArray is deprecated, but there is currently no viabla alternative
81  * See https://bugzilla.gnome.org/show_bug.cgi?id=667228 */
82 #define GLIB_DISABLE_DEPRECATION_WARNINGS
83 
84 #include <string.h>
85 #include "gstrawaudioparse.h"
86 #include "unalignedaudio.h"
87 
88 GST_DEBUG_CATEGORY_STATIC (raw_audio_parse_debug);
89 #define GST_CAT_DEFAULT raw_audio_parse_debug
90 
91 enum
92 {
93   PROP_0,
94   PROP_FORMAT,
95   PROP_PCM_FORMAT,
96   PROP_SAMPLE_RATE,
97   PROP_NUM_CHANNELS,
98   PROP_INTERLEAVED,
99   PROP_CHANNEL_POSITIONS
100 };
101 
102 #define DEFAULT_FORMAT         GST_RAW_AUDIO_PARSE_FORMAT_PCM
103 #define DEFAULT_PCM_FORMAT     GST_AUDIO_FORMAT_S16
104 #define DEFAULT_SAMPLE_RATE    44100
105 #define DEFAULT_NUM_CHANNELS   2
106 #define DEFAULT_INTERLEAVED    TRUE
107 
108 #define GST_RAW_AUDIO_PARSE_CAPS \
109   GST_AUDIO_CAPS_MAKE(GST_AUDIO_FORMATS_ALL) \
110   ", layout = (string) { interleaved, non-interleaved }; " \
111   "audio/x-alaw, rate = (int) [ 1, MAX ], channels = (int) [ 1, MAX ]; " \
112   "audio/x-mulaw, rate = (int) [ 1, MAX ], channels = (int) [ 1, MAX ]; "
113 
114 static GstStaticPadTemplate static_sink_template =
115     GST_STATIC_PAD_TEMPLATE ("sink",
116     GST_PAD_SINK,
117     GST_PAD_ALWAYS,
118     GST_STATIC_CAPS (GST_UNALIGNED_RAW_AUDIO_CAPS "; " GST_RAW_AUDIO_PARSE_CAPS)
119     );
120 
121 static GstStaticPadTemplate static_src_template =
122 GST_STATIC_PAD_TEMPLATE ("src",
123     GST_PAD_SRC,
124     GST_PAD_ALWAYS,
125     GST_STATIC_CAPS (GST_RAW_AUDIO_PARSE_CAPS)
126     );
127 
128 #define gst_raw_audio_parse_parent_class parent_class
129 G_DEFINE_TYPE (GstRawAudioParse, gst_raw_audio_parse, GST_TYPE_RAW_BASE_PARSE);
130 
131 static void gst_raw_audio_parse_set_property (GObject * object, guint prop_id,
132     GValue const *value, GParamSpec * pspec);
133 static void gst_raw_audio_parse_get_property (GObject * object, guint prop_id,
134     GValue * value, GParamSpec * pspec);
135 
136 static gboolean gst_raw_audio_parse_stop (GstBaseParse * parse);
137 
138 static gboolean gst_raw_audio_parse_set_current_config (GstRawBaseParse *
139     raw_base_parse, GstRawBaseParseConfig config);
140 static GstRawBaseParseConfig
141 gst_raw_audio_parse_get_current_config (GstRawBaseParse * raw_base_parse);
142 static gboolean gst_raw_audio_parse_set_config_from_caps (GstRawBaseParse *
143     raw_base_parse, GstRawBaseParseConfig config, GstCaps * caps);
144 static gboolean gst_raw_audio_parse_get_caps_from_config (GstRawBaseParse *
145     raw_base_parse, GstRawBaseParseConfig config, GstCaps ** caps);
146 static gsize gst_raw_audio_parse_get_config_frame_size (GstRawBaseParse *
147     raw_base_parse, GstRawBaseParseConfig config);
148 static gboolean gst_raw_audio_parse_is_config_ready (GstRawBaseParse *
149     raw_base_parse, GstRawBaseParseConfig config);
150 static gboolean gst_raw_audio_parse_process (GstRawBaseParse * raw_base_parse,
151     GstRawBaseParseConfig config, GstBuffer * in_data, gsize total_num_in_bytes,
152     gsize num_valid_in_bytes, GstBuffer ** processed_data);
153 static gboolean gst_raw_audio_parse_is_unit_format_supported (GstRawBaseParse *
154     raw_base_parse, GstFormat format);
155 static void gst_raw_audio_parse_get_units_per_second (GstRawBaseParse *
156     raw_base_parse, GstFormat format, GstRawBaseParseConfig config,
157     gsize * units_per_sec_n, gsize * units_per_sec_d);
158 static gint gst_raw_audio_parse_get_alignment (GstRawBaseParse * raw_base_parse,
159     GstRawBaseParseConfig config);
160 
161 static gboolean gst_raw_audio_parse_is_using_sink_caps (GstRawAudioParse *
162     raw_audio_parse);
163 static GstRawAudioParseConfig
164     * gst_raw_audio_parse_get_config_ptr (GstRawAudioParse * raw_audio_parse,
165     GstRawBaseParseConfig config);
166 
167 static void gst_raw_audio_parse_init_config (GstRawAudioParseConfig * config);
168 static gboolean gst_raw_audio_parse_set_config_channels (GstRawAudioParseConfig
169     * config, guint num_channels, guint64 channel_mask, gboolean set_positions);
170 static gboolean
171 gst_raw_audio_parse_update_channel_reordering_flag (GstRawAudioParseConfig *
172     config);
173 static void gst_raw_audio_parse_update_config_bpf (GstRawAudioParseConfig *
174     config);
175 static gboolean gst_raw_audio_parse_caps_to_config (GstRawAudioParse *
176     raw_audio_parse, GstCaps * caps, GstRawAudioParseConfig * config);
177 static gboolean gst_raw_audio_parse_config_to_caps (GstRawAudioParse *
178     raw_audio_parse, GstCaps ** caps, GstRawAudioParseConfig * config);
179 
180 static void
gst_raw_audio_parse_class_init(GstRawAudioParseClass * klass)181 gst_raw_audio_parse_class_init (GstRawAudioParseClass * klass)
182 {
183   GObjectClass *object_class;
184   GstElementClass *element_class;
185   GstBaseParseClass *baseparse_class;
186   GstRawBaseParseClass *rawbaseparse_class;
187 
188   GST_DEBUG_CATEGORY_INIT (raw_audio_parse_debug, "rawaudioparse", 0,
189       "rawaudioparse element");
190 
191   object_class = G_OBJECT_CLASS (klass);
192   element_class = GST_ELEMENT_CLASS (klass);
193   baseparse_class = GST_BASE_PARSE_CLASS (klass);
194   rawbaseparse_class = GST_RAW_BASE_PARSE_CLASS (klass);
195 
196   gst_element_class_add_pad_template (element_class,
197       gst_static_pad_template_get (&static_sink_template));
198   gst_element_class_add_pad_template (element_class,
199       gst_static_pad_template_get (&static_src_template));
200 
201   object_class->set_property =
202       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_set_property);
203   object_class->get_property =
204       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_get_property);
205 
206   baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_raw_audio_parse_stop);
207 
208   rawbaseparse_class->set_current_config =
209       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_set_current_config);
210   rawbaseparse_class->get_current_config =
211       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_get_current_config);
212   rawbaseparse_class->set_config_from_caps =
213       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_set_config_from_caps);
214   rawbaseparse_class->get_caps_from_config =
215       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_get_caps_from_config);
216   rawbaseparse_class->get_config_frame_size =
217       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_get_config_frame_size);
218   rawbaseparse_class->is_config_ready =
219       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_is_config_ready);
220   rawbaseparse_class->process = GST_DEBUG_FUNCPTR (gst_raw_audio_parse_process);
221   rawbaseparse_class->is_unit_format_supported =
222       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_is_unit_format_supported);
223   rawbaseparse_class->get_units_per_second =
224       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_get_units_per_second);
225   rawbaseparse_class->get_alignment =
226       GST_DEBUG_FUNCPTR (gst_raw_audio_parse_get_alignment);
227 
228   g_object_class_install_property (object_class,
229       PROP_FORMAT,
230       g_param_spec_enum ("format",
231           "Format",
232           "Format of the raw audio stream",
233           gst_raw_audio_parse_format_get_type (),
234           GST_RAW_AUDIO_PARSE_FORMAT_PCM,
235           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
236       );
237   g_object_class_install_property (object_class,
238       PROP_PCM_FORMAT,
239       g_param_spec_enum ("pcm-format",
240           "PCM format",
241           "Format of audio samples in PCM stream (ignored if format property is not set to pcm)",
242           GST_TYPE_AUDIO_FORMAT,
243           GST_RAW_AUDIO_PARSE_FORMAT_PCM,
244           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
245       );
246   g_object_class_install_property (object_class,
247       PROP_SAMPLE_RATE,
248       g_param_spec_int ("sample-rate",
249           "Sample rate",
250           "Rate of audio samples in raw stream",
251           1, INT_MAX,
252           DEFAULT_SAMPLE_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
253       );
254   g_object_class_install_property (object_class,
255       PROP_NUM_CHANNELS,
256       g_param_spec_int ("num-channels",
257           "Number of channels",
258           "Number of channels in raw stream",
259           1, INT_MAX,
260           DEFAULT_NUM_CHANNELS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
261       );
262   g_object_class_install_property (object_class,
263       PROP_INTERLEAVED,
264       g_param_spec_boolean ("interleaved",
265           "Interleaved layout",
266           "True if audio has interleaved layout",
267           DEFAULT_INTERLEAVED, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
268       );
269   g_object_class_install_property (object_class,
270       PROP_CHANNEL_POSITIONS,
271       g_param_spec_value_array ("channel-positions",
272           "Channel positions",
273           "Channel positions used on the output",
274           g_param_spec_enum ("channel-position",
275               "Channel position",
276               "Channel position of the n-th input",
277               GST_TYPE_AUDIO_CHANNEL_POSITION,
278               GST_AUDIO_CHANNEL_POSITION_NONE,
279               G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS),
280           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
281       );
282 
283   gst_element_class_set_static_metadata (element_class,
284       "rawaudioparse",
285       "Codec/Parser/Audio",
286       "Converts unformatted data streams into timestamped raw audio frames",
287       "Carlos Rafael Giani <dv@pseudoterminal.org>");
288 }
289 
290 static void
gst_raw_audio_parse_init(GstRawAudioParse * raw_audio_parse)291 gst_raw_audio_parse_init (GstRawAudioParse * raw_audio_parse)
292 {
293   /* Setup configs and select which one shall be the current one from the start. */
294   gst_raw_audio_parse_init_config (&(raw_audio_parse->properties_config));
295   gst_raw_audio_parse_init_config (&(raw_audio_parse->sink_caps_config));
296   /* As required by GstRawBaseParse, ensure that the current configuration
297    * is initially set to be the properties config */
298   raw_audio_parse->current_config = &(raw_audio_parse->properties_config);
299 
300   /* Properties config must be valid from the start, so set its ready value
301    * to TRUE, and make sure its bpf value is valid. */
302   raw_audio_parse->properties_config.ready = TRUE;
303   gst_raw_audio_parse_update_config_bpf (&(raw_audio_parse->properties_config));
304 }
305 
306 static void
gst_raw_audio_parse_set_property(GObject * object,guint prop_id,GValue const * value,GParamSpec * pspec)307 gst_raw_audio_parse_set_property (GObject * object, guint prop_id,
308     GValue const *value, GParamSpec * pspec)
309 {
310   GstBaseParse *base_parse = GST_BASE_PARSE (object);
311   GstRawBaseParse *raw_base_parse = GST_RAW_BASE_PARSE (object);
312   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (object);
313 
314   /* All properties are handled similarly:
315    * - if the new value is the same as the current value, nothing is done
316    * - the parser lock is held while the new value is set
317    * - if the properties config is the current config, the source caps are
318    *   invalidated to ensure that the code in handle_frame pushes a new CAPS
319    *   event out
320    * - properties that affect the bpf value call the function to update
321    *   the bpf and also call gst_base_parse_set_min_frame_size() to ensure
322    *   that the minimum frame size can hold 1 frame (= one sample for each
323    *   channel)
324    */
325 
326   switch (prop_id) {
327     case PROP_FORMAT:
328     {
329       GstRawAudioParseFormat new_format = g_value_get_enum (value);
330 
331       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
332 
333       if (new_format != raw_audio_parse->properties_config.format) {
334         raw_audio_parse->properties_config.format = new_format;
335         gst_raw_audio_parse_update_config_bpf (&
336             (raw_audio_parse->properties_config));
337 
338         if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) {
339           gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
340           gst_base_parse_set_min_frame_size (base_parse,
341               raw_audio_parse->properties_config.bpf);
342         }
343       }
344 
345       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
346       break;
347     }
348 
349     case PROP_PCM_FORMAT:
350     {
351       GstAudioFormat new_pcm_format = g_value_get_enum (value);
352 
353       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
354 
355       if (new_pcm_format != raw_audio_parse->properties_config.pcm_format) {
356         raw_audio_parse->properties_config.pcm_format = new_pcm_format;
357         gst_raw_audio_parse_update_config_bpf (&
358             (raw_audio_parse->properties_config));
359 
360         if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) {
361           gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
362           gst_base_parse_set_min_frame_size (base_parse,
363               raw_audio_parse->properties_config.bpf);
364         }
365       }
366 
367       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
368       break;
369     }
370 
371     case PROP_SAMPLE_RATE:
372     {
373       guint new_sample_rate = g_value_get_int (value);
374 
375       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
376 
377       if (new_sample_rate != raw_audio_parse->properties_config.sample_rate) {
378         raw_audio_parse->properties_config.sample_rate = new_sample_rate;
379 
380         if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse))
381           gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
382       }
383 
384       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
385       break;
386     }
387 
388     case PROP_NUM_CHANNELS:
389     {
390       guint new_num_channels = g_value_get_int (value);
391 
392       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
393 
394       if (new_num_channels != raw_audio_parse->properties_config.num_channels) {
395         gst_raw_audio_parse_set_config_channels (&
396             (raw_audio_parse->properties_config), new_num_channels, 0, TRUE);
397 
398         raw_audio_parse->properties_config.num_channels = new_num_channels;
399         gst_raw_audio_parse_update_config_bpf (&
400             (raw_audio_parse->properties_config));
401 
402         if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) {
403           gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
404           gst_base_parse_set_min_frame_size (base_parse,
405               raw_audio_parse->properties_config.bpf);
406         }
407       }
408 
409       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
410       break;
411     }
412 
413     case PROP_INTERLEAVED:
414     {
415       gboolean new_interleaved = g_value_get_boolean (value);
416 
417       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
418 
419       if (new_interleaved != raw_audio_parse->properties_config.interleaved) {
420         raw_audio_parse->properties_config.interleaved = new_interleaved;
421 
422         if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse))
423           gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
424       }
425 
426       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
427       break;
428     }
429 
430     case PROP_CHANNEL_POSITIONS:
431     {
432       GValueArray *valarray = g_value_get_boxed (value);
433       GstRawAudioParseConfig *config = &(raw_audio_parse->properties_config);
434 
435       /* Sanity check - reject empty arrays */
436       if ((valarray != NULL) && (valarray->n_values == 0)) {
437         GST_ELEMENT_ERROR (raw_audio_parse, LIBRARY, SETTINGS,
438             ("channel position property holds an empty array"), (NULL));
439         break;
440       }
441 
442       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
443 
444       if ((valarray == NULL) && (config->num_channels > 0)) {
445         /* NULL value given, and number of channels is nonzero.
446          * Use the default GStreamer positioning. Call
447          * set_config_channels with the set_positions parameter
448          * set to TRUE to ensure the position values are filled. */
449         gst_raw_audio_parse_set_config_channels (&
450             (raw_audio_parse->properties_config), config->num_channels, 0,
451             TRUE);
452       } else if (valarray != NULL) {
453         /* Non-NULL value given. Make sure the channel_positions
454          * array in the properties config has enough room, and that
455          * the num_channels value equals the array length. Then copy
456          * the values from the valarray to channel_positions, and
457          * produce a copy of that array in case its channel positions
458          * are not in a valid GStreamer order (to be able to apply
459          * channel reordering later).
460          */
461 
462         guint i;
463 
464         if (valarray->n_values != config->num_channels) {
465           /* Call with set_positions == FALSE to ensure that
466            * the array is properly allocated but not filled
467            * (it is filled below) */
468           gst_raw_audio_parse_set_config_channels (config, valarray->n_values,
469               0, FALSE);
470         }
471 
472         for (i = 0; i < config->num_channels; ++i) {
473           GValue *val = g_value_array_get_nth (valarray, i);
474           config->channel_positions[i] = g_value_get_enum (val);
475         }
476 
477         gst_raw_audio_parse_update_channel_reordering_flag (config);
478       }
479 
480       gst_raw_audio_parse_update_config_bpf (&
481           (raw_audio_parse->properties_config));
482 
483       if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse)) {
484         gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
485         gst_base_parse_set_min_frame_size (base_parse,
486             raw_audio_parse->properties_config.bpf);
487       }
488 
489       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
490       break;
491     }
492 
493     default:
494       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
495       break;
496   }
497 }
498 
499 static void
gst_raw_audio_parse_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)500 gst_raw_audio_parse_get_property (GObject * object, guint prop_id,
501     GValue * value, GParamSpec * pspec)
502 {
503   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (object);
504 
505   switch (prop_id) {
506     case PROP_FORMAT:
507       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
508       g_value_set_enum (value, raw_audio_parse->properties_config.format);
509       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
510       break;
511 
512     case PROP_PCM_FORMAT:
513       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
514       g_value_set_enum (value, raw_audio_parse->properties_config.pcm_format);
515       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
516       break;
517 
518     case PROP_SAMPLE_RATE:
519       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
520       g_value_set_int (value, raw_audio_parse->properties_config.sample_rate);
521       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
522       break;
523 
524     case PROP_NUM_CHANNELS:
525       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
526       g_value_set_int (value, raw_audio_parse->properties_config.num_channels);
527       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
528       break;
529 
530     case PROP_INTERLEAVED:
531       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
532       g_value_set_boolean (value,
533           raw_audio_parse->properties_config.interleaved);
534       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
535       break;
536 
537     case PROP_CHANNEL_POSITIONS:
538     {
539       GstRawAudioParseConfig *config;
540       GValueArray *valarray;
541 
542       GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
543 
544       valarray = NULL;
545       config = &(raw_audio_parse->properties_config);
546 
547       /* Copy channel positions into the valuearray */
548       if (config->num_channels > 0) {
549         guint i;
550         GValue val = G_VALUE_INIT;
551         g_assert (config->channel_positions);
552 
553         g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
554         valarray = g_value_array_new (config->num_channels);
555 
556         for (i = 0; i < config->num_channels; ++i) {
557           g_value_set_enum (&val, config->channel_positions[i]);
558           g_value_array_insert (valarray, i, &val);
559         }
560 
561         g_value_unset (&val);
562       }
563 
564       GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
565 
566       /* Pass on ownership to the value array,
567        * since we don't need it anymore */
568       g_value_take_boxed (value, valarray);
569 
570       break;
571     }
572 
573     default:
574       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
575       break;
576   }
577 }
578 
579 static gboolean
gst_raw_audio_parse_stop(GstBaseParse * parse)580 gst_raw_audio_parse_stop (GstBaseParse * parse)
581 {
582   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (parse);
583 
584   /* Sink caps config is not ready until caps come in.
585    * We are stopping processing, the element is being reset,
586    * so the config has to be un-readied.
587    * (Since the properties config is not depending on caps,
588    * its ready status is always TRUE.) */
589   raw_audio_parse->sink_caps_config.ready = FALSE;
590 
591   return GST_BASE_PARSE_CLASS (parent_class)->stop (parse);
592 }
593 
594 static gboolean
gst_raw_audio_parse_set_current_config(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config)595 gst_raw_audio_parse_set_current_config (GstRawBaseParse * raw_base_parse,
596     GstRawBaseParseConfig config)
597 {
598   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
599 
600   switch (config) {
601     case GST_RAW_BASE_PARSE_CONFIG_PROPERTIES:
602       raw_audio_parse->current_config = &(raw_audio_parse->properties_config);
603       break;
604 
605     case GST_RAW_BASE_PARSE_CONFIG_SINKCAPS:
606       raw_audio_parse->current_config = &(raw_audio_parse->sink_caps_config);
607       break;
608 
609     default:
610       g_assert_not_reached ();
611   }
612 
613   return TRUE;
614 }
615 
616 static GstRawBaseParseConfig
gst_raw_audio_parse_get_current_config(GstRawBaseParse * raw_base_parse)617 gst_raw_audio_parse_get_current_config (GstRawBaseParse * raw_base_parse)
618 {
619   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
620   return gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse) ?
621       GST_RAW_BASE_PARSE_CONFIG_SINKCAPS : GST_RAW_BASE_PARSE_CONFIG_PROPERTIES;
622 }
623 
624 static gboolean
gst_raw_audio_parse_set_config_from_caps(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config,GstCaps * caps)625 gst_raw_audio_parse_set_config_from_caps (GstRawBaseParse * raw_base_parse,
626     GstRawBaseParseConfig config, GstCaps * caps)
627 {
628   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
629   return gst_raw_audio_parse_caps_to_config (raw_audio_parse, caps,
630       gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config));
631 }
632 
633 static gboolean
gst_raw_audio_parse_get_caps_from_config(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config,GstCaps ** caps)634 gst_raw_audio_parse_get_caps_from_config (GstRawBaseParse * raw_base_parse,
635     GstRawBaseParseConfig config, GstCaps ** caps)
636 {
637   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
638   return gst_raw_audio_parse_config_to_caps (raw_audio_parse, caps,
639       gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config));
640 }
641 
642 static gsize
gst_raw_audio_parse_get_config_frame_size(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config)643 gst_raw_audio_parse_get_config_frame_size (GstRawBaseParse * raw_base_parse,
644     GstRawBaseParseConfig config)
645 {
646   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
647   return gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config)->bpf;
648 }
649 
650 static gboolean
gst_raw_audio_parse_is_config_ready(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config)651 gst_raw_audio_parse_is_config_ready (GstRawBaseParse * raw_base_parse,
652     GstRawBaseParseConfig config)
653 {
654   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
655   return gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config)->ready;
656 }
657 
658 static guint
round_up_pow2(guint n)659 round_up_pow2 (guint n)
660 {
661   n = n - 1;
662   n = n | (n >> 1);
663   n = n | (n >> 2);
664   n = n | (n >> 4);
665   n = n | (n >> 8);
666   n = n | (n >> 16);
667   return n + 1;
668 }
669 
670 static gint
gst_raw_audio_parse_get_alignment(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config)671 gst_raw_audio_parse_get_alignment (GstRawBaseParse * raw_base_parse,
672     GstRawBaseParseConfig config)
673 {
674   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
675   GstRawAudioParseConfig *config_ptr =
676       gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config);
677   gint width;
678 
679   if (config_ptr->format != GST_RAW_AUDIO_PARSE_FORMAT_PCM)
680     return 1;
681 
682   width =
683       GST_AUDIO_FORMAT_INFO_WIDTH (gst_audio_format_get_info
684       (config_ptr->pcm_format)) / 8;
685   width = GST_ROUND_UP_8 (width);
686   width = round_up_pow2 (width);
687 
688   return width;
689 }
690 
691 static gboolean
gst_raw_audio_parse_process(GstRawBaseParse * raw_base_parse,GstRawBaseParseConfig config,GstBuffer * in_data,gsize total_num_in_bytes,gsize num_valid_in_bytes,GstBuffer ** processed_data)692 gst_raw_audio_parse_process (GstRawBaseParse * raw_base_parse,
693     GstRawBaseParseConfig config, GstBuffer * in_data, gsize total_num_in_bytes,
694     gsize num_valid_in_bytes, GstBuffer ** processed_data)
695 {
696   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
697   GstRawAudioParseConfig *config_ptr =
698       gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config);
699 
700   if ((config_ptr->format == GST_RAW_AUDIO_PARSE_FORMAT_PCM)
701       && config_ptr->needs_channel_reordering) {
702     /* Need to reorder samples, since they are in an invalid
703      * channel order. */
704 
705     GstBuffer *outbuf;
706 
707     GST_LOG_OBJECT (raw_audio_parse,
708         "using %" G_GSIZE_FORMAT " bytes out of the %" G_GSIZE_FORMAT
709         " bytes from the input buffer with reordering", num_valid_in_bytes,
710         total_num_in_bytes);
711 
712     outbuf =
713         gst_buffer_copy_region (in_data,
714         GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS |
715         GST_BUFFER_COPY_META | GST_BUFFER_COPY_MEMORY, 0, num_valid_in_bytes);
716 
717     gst_audio_buffer_reorder_channels (outbuf,
718         config_ptr->pcm_format,
719         config_ptr->num_channels,
720         config_ptr->channel_positions, config_ptr->reordered_channel_positions);
721 
722     *processed_data = outbuf;
723   } else {
724     /* Nothing needs to be done with the sample data.
725      * Instruct the baseparse class to just take out_size bytes
726      * from the input buffer */
727 
728     GST_LOG_OBJECT (raw_audio_parse,
729         "using %" G_GSIZE_FORMAT " bytes out of the %" G_GSIZE_FORMAT
730         " bytes from the input buffer without reordering", num_valid_in_bytes,
731         total_num_in_bytes);
732 
733     *processed_data = NULL;
734   }
735 
736   return TRUE;
737 }
738 
739 static gboolean
gst_raw_audio_parse_is_unit_format_supported(G_GNUC_UNUSED GstRawBaseParse * raw_base_parse,GstFormat format)740 gst_raw_audio_parse_is_unit_format_supported (G_GNUC_UNUSED GstRawBaseParse *
741     raw_base_parse, GstFormat format)
742 {
743   switch (format) {
744     case GST_FORMAT_BYTES:
745     case GST_FORMAT_DEFAULT:
746       return TRUE;
747     default:
748       return FALSE;
749   }
750 }
751 
752 static void
gst_raw_audio_parse_get_units_per_second(GstRawBaseParse * raw_base_parse,GstFormat format,GstRawBaseParseConfig config,gsize * units_per_sec_n,gsize * units_per_sec_d)753 gst_raw_audio_parse_get_units_per_second (GstRawBaseParse * raw_base_parse,
754     GstFormat format, GstRawBaseParseConfig config, gsize * units_per_sec_n,
755     gsize * units_per_sec_d)
756 {
757   GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
758   GstRawAudioParseConfig *config_ptr =
759       gst_raw_audio_parse_get_config_ptr (raw_audio_parse, config);
760 
761   switch (format) {
762     case GST_FORMAT_BYTES:
763       *units_per_sec_n = config_ptr->sample_rate * config_ptr->bpf;
764       *units_per_sec_d = 1;
765       break;
766 
767     case GST_FORMAT_DEFAULT:
768       *units_per_sec_n = config_ptr->sample_rate;
769       *units_per_sec_d = 1;
770       break;
771 
772     default:
773       g_assert_not_reached ();
774   }
775 }
776 
777 static gboolean
gst_raw_audio_parse_is_using_sink_caps(GstRawAudioParse * raw_audio_parse)778 gst_raw_audio_parse_is_using_sink_caps (GstRawAudioParse * raw_audio_parse)
779 {
780   return raw_audio_parse->current_config ==
781       &(raw_audio_parse->sink_caps_config);
782 }
783 
784 static GstRawAudioParseConfig *
gst_raw_audio_parse_get_config_ptr(GstRawAudioParse * raw_audio_parse,GstRawBaseParseConfig config)785 gst_raw_audio_parse_get_config_ptr (GstRawAudioParse * raw_audio_parse,
786     GstRawBaseParseConfig config)
787 {
788   g_assert (raw_audio_parse->current_config != NULL);
789 
790   switch (config) {
791     case GST_RAW_BASE_PARSE_CONFIG_PROPERTIES:
792       return &(raw_audio_parse->properties_config);
793 
794     case GST_RAW_BASE_PARSE_CONFIG_SINKCAPS:
795       return &(raw_audio_parse->sink_caps_config);
796 
797     default:
798       g_assert (raw_audio_parse->current_config != NULL);
799       return raw_audio_parse->current_config;
800   }
801 }
802 
803 static void
gst_raw_audio_parse_init_config(GstRawAudioParseConfig * config)804 gst_raw_audio_parse_init_config (GstRawAudioParseConfig * config)
805 {
806   config->ready = FALSE;
807   config->format = DEFAULT_FORMAT;
808   config->pcm_format = DEFAULT_PCM_FORMAT;
809   config->bpf = 0;
810   config->sample_rate = DEFAULT_SAMPLE_RATE;
811   config->num_channels = DEFAULT_NUM_CHANNELS;
812   config->interleaved = DEFAULT_INTERLEAVED;
813   config->needs_channel_reordering = FALSE;
814 
815   gst_raw_audio_parse_set_config_channels (config, config->num_channels, 0,
816       TRUE);
817 }
818 
819 static gboolean
gst_raw_audio_parse_set_config_channels(GstRawAudioParseConfig * config,guint num_channels,guint64 channel_mask,gboolean set_positions)820 gst_raw_audio_parse_set_config_channels (GstRawAudioParseConfig * config,
821     guint num_channels, guint64 channel_mask, gboolean set_positions)
822 {
823   g_assert (num_channels > 0);
824 
825   config->num_channels = num_channels;
826   /* Setting this to FALSE, since initially, after setting the channels,
827    * the default GStreamer channel ordering is used. */
828   config->needs_channel_reordering = FALSE;
829 
830   /* Set the channel positions based on the given channel mask if set_positions
831    * is set to TRUE. A channel mask of 0 signifies that a fallback mask should be
832    * used for the given number of channels. */
833   if (set_positions) {
834     if (channel_mask == 0)
835       channel_mask = gst_audio_channel_get_fallback_mask (config->num_channels);
836 
837     return gst_audio_channel_positions_from_mask (config->num_channels,
838         channel_mask, config->channel_positions);
839   } else {
840     return TRUE;
841   }
842 }
843 
844 static gboolean
gst_raw_audio_parse_update_channel_reordering_flag(GstRawAudioParseConfig * config)845 gst_raw_audio_parse_update_channel_reordering_flag (GstRawAudioParseConfig *
846     config)
847 {
848   g_assert (config->num_channels > 0);
849 
850   /* If the channel_positions array contains channel positions which are in an
851    * order that conforms to the valid GStreamer order, ensure that channel
852    * reordering is disabled.
853    * Otherwise, if the order of the positions in the channel_positions array
854    * does not conform to the GStreamer order, ensure it is enabled.
855    */
856 
857   if (gst_audio_check_valid_channel_positions (config->channel_positions,
858           config->num_channels, TRUE)) {
859 
860     config->needs_channel_reordering = FALSE;
861 
862     return TRUE;
863   } else {
864     config->needs_channel_reordering = TRUE;
865     memcpy (config->reordered_channel_positions, config->channel_positions,
866         sizeof (GstAudioChannelPosition) * config->num_channels);
867     return
868         gst_audio_channel_positions_to_valid_order
869         (config->reordered_channel_positions, config->num_channels);
870   }
871 }
872 
873 static void
gst_raw_audio_parse_update_config_bpf(GstRawAudioParseConfig * config)874 gst_raw_audio_parse_update_config_bpf (GstRawAudioParseConfig * config)
875 {
876   switch (config->format) {
877     case GST_RAW_AUDIO_PARSE_FORMAT_PCM:
878     {
879       GstAudioFormatInfo const *fmt_info =
880           gst_audio_format_get_info (config->pcm_format);
881       g_assert (fmt_info != NULL);
882 
883       config->bpf =
884           GST_AUDIO_FORMAT_INFO_WIDTH (fmt_info) * config->num_channels / 8;
885 
886       break;
887     }
888 
889     case GST_RAW_AUDIO_PARSE_FORMAT_ALAW:
890     case GST_RAW_AUDIO_PARSE_FORMAT_MULAW:
891       /* A-law and mu-law both use 1 byte per sample */
892       config->bpf = 1 * config->num_channels;
893       break;
894 
895     default:
896       g_assert_not_reached ();
897   }
898 }
899 
900 static gboolean
gst_raw_audio_parse_caps_to_config(GstRawAudioParse * raw_audio_parse,GstCaps * caps,GstRawAudioParseConfig * config)901 gst_raw_audio_parse_caps_to_config (GstRawAudioParse * raw_audio_parse,
902     GstCaps * caps, GstRawAudioParseConfig * config)
903 {
904   gboolean ret = FALSE;
905   GstStructure *structure;
906 
907   /* Caps might get copied, and the copy needs to be unref'd.
908    * Also, the caller retains ownership over the original caps.
909    * So, to make this mechanism also work with cases where the
910    * caps are *not* copied, ref the original caps here first. */
911   gst_caps_ref (caps);
912 
913   structure = gst_caps_get_structure (caps, 0);
914 
915   /* For unaligned raw data, the output caps stay the same,
916    * except that audio/x-unaligned-raw becomes audio/x-raw,
917    * since the parser aligns the sample data */
918   if (gst_structure_has_name (structure, "audio/x-unaligned-raw")) {
919     /* Copy the caps to be able to modify them */
920     GstCaps *new_caps = gst_caps_copy (caps);
921     gst_caps_unref (caps);
922     caps = new_caps;
923 
924     /* Change the media type to audio/x-raw , otherwise
925      * gst_audio_info_from_caps() won't work */
926     structure = gst_caps_get_structure (caps, 0);
927     gst_structure_set_name (structure, "audio/x-raw");
928   }
929 
930   if (gst_structure_has_name (structure, "audio/x-raw")) {
931     guint num_channels;
932     GstAudioInfo info;
933     if (!gst_audio_info_from_caps (&info, caps)) {
934       GST_ERROR_OBJECT (raw_audio_parse,
935           "failed to parse caps %" GST_PTR_FORMAT, (gpointer) caps);
936       goto done;
937     }
938 
939     num_channels = GST_AUDIO_INFO_CHANNELS (&info);
940 
941     config->format = GST_RAW_AUDIO_PARSE_FORMAT_PCM;
942     config->pcm_format = GST_AUDIO_INFO_FORMAT (&info);
943     config->bpf = GST_AUDIO_INFO_BPF (&info);
944     config->sample_rate = GST_AUDIO_INFO_RATE (&info);
945     config->interleaved =
946         (GST_AUDIO_INFO_LAYOUT (&info) == GST_AUDIO_LAYOUT_INTERLEAVED);
947 
948     gst_raw_audio_parse_set_config_channels (config, num_channels, 0, FALSE);
949     memcpy (config->channel_positions, &(GST_AUDIO_INFO_POSITION (&info, 0)),
950         sizeof (GstAudioChannelPosition) * num_channels);
951   } else if (gst_structure_has_name (structure, "audio/x-alaw")
952       || gst_structure_has_name (structure, "audio/x-mulaw")) {
953     gint i;
954     guint64 channel_mask;
955     guint num_channels;
956 
957     config->format =
958         gst_structure_has_name (structure,
959         "audio/x-alaw") ? GST_RAW_AUDIO_PARSE_FORMAT_ALAW :
960         GST_RAW_AUDIO_PARSE_FORMAT_MULAW;
961 
962     if (!gst_structure_get_int (structure, "rate", &i)) {
963       GST_ERROR_OBJECT (raw_audio_parse,
964           "missing rate value in caps %" GST_PTR_FORMAT, (gpointer) caps);
965       goto done;
966     }
967     config->sample_rate = i;
968 
969     if (!gst_structure_get_int (structure, "channels", &i)) {
970       GST_ERROR_OBJECT (raw_audio_parse,
971           "missing channels value in caps %" GST_PTR_FORMAT, (gpointer) caps);
972       goto done;
973     }
974     num_channels = i;
975 
976     if (!gst_structure_get (structure, "channel-mask", GST_TYPE_BITMASK,
977             &channel_mask, NULL)) {
978       channel_mask = gst_audio_channel_get_fallback_mask (num_channels);
979       GST_DEBUG_OBJECT (raw_audio_parse,
980           "input caps have no channel mask - using fallback mask %#"
981           G_GINT64_MODIFIER "x for %u channels", channel_mask, num_channels);
982     }
983 
984     if (!gst_raw_audio_parse_set_config_channels (config, num_channels,
985             channel_mask, TRUE)) {
986       GST_ERROR_OBJECT (raw_audio_parse,
987           "could not use channel mask %#" G_GINT64_MODIFIER
988           "x for channel positions", channel_mask);
989       goto done;
990     }
991 
992     /* A-law and mu-law both use 1 byte per sample */
993     config->bpf = 1 * num_channels;
994   } else {
995     GST_ERROR_OBJECT (raw_audio_parse,
996         "caps %" GST_PTR_FORMAT " have an unsupported media type",
997         (gpointer) caps);
998     goto done;
999   }
1000 
1001   ret = TRUE;
1002 
1003 done:
1004   gst_caps_unref (caps);
1005   if (ret)
1006     config->ready = TRUE;
1007   return ret;
1008 }
1009 
1010 static gboolean
gst_raw_audio_parse_config_to_caps(GstRawAudioParse * raw_audio_parse,GstCaps ** caps,GstRawAudioParseConfig * config)1011 gst_raw_audio_parse_config_to_caps (GstRawAudioParse * raw_audio_parse,
1012     GstCaps ** caps, GstRawAudioParseConfig * config)
1013 {
1014   gboolean ret = TRUE;
1015   GstAudioChannelPosition *channel_positions;
1016 
1017   g_assert (caps != NULL);
1018 
1019   if (config->bpf == 0) {
1020     GST_ERROR_OBJECT (raw_audio_parse,
1021         "cannot convert config to caps - config not filled with valid values");
1022     *caps = NULL;
1023     return FALSE;
1024   }
1025 
1026   channel_positions =
1027       config->needs_channel_reordering ? &(config->
1028       reordered_channel_positions[0]) : &(config->channel_positions[0]);
1029 
1030   switch (config->format) {
1031     case GST_RAW_AUDIO_PARSE_FORMAT_PCM:
1032     {
1033       GstAudioInfo info;
1034       gst_audio_info_init (&info);
1035       gst_audio_info_set_format (&info,
1036           config->pcm_format,
1037           config->sample_rate, config->num_channels, channel_positions);
1038 
1039       *caps = gst_audio_info_to_caps (&info);
1040 
1041       break;
1042     }
1043 
1044     case GST_RAW_AUDIO_PARSE_FORMAT_ALAW:
1045     case GST_RAW_AUDIO_PARSE_FORMAT_MULAW:
1046     {
1047       guint64 channel_mask;
1048 
1049       if (!gst_audio_channel_positions_to_mask (channel_positions,
1050               config->num_channels, TRUE, &channel_mask)) {
1051         GST_ERROR_OBJECT (raw_audio_parse, "invalid channel positions");
1052         ret = FALSE;
1053         break;
1054       }
1055 
1056       *caps = gst_caps_new_simple (
1057           (config->format ==
1058               GST_RAW_AUDIO_PARSE_FORMAT_ALAW) ? "audio/x-alaw" :
1059           "audio/x-mulaw", "rate", G_TYPE_INT, config->sample_rate, "channels",
1060           G_TYPE_INT, config->num_channels, "channel-mask", GST_TYPE_BITMASK,
1061           channel_mask, NULL);
1062 
1063       break;
1064     }
1065 
1066     default:
1067       g_assert_not_reached ();
1068       ret = FALSE;
1069   }
1070 
1071   if (!ret)
1072     *caps = NULL;
1073 
1074   return ret;
1075 }
1076 
1077 GType
gst_raw_audio_parse_format_get_type(void)1078 gst_raw_audio_parse_format_get_type (void)
1079 {
1080   static GType audio_parse_format_gtype = 0;
1081   static const GEnumValue types[] = {
1082     {GST_RAW_AUDIO_PARSE_FORMAT_PCM, "PCM", "pcm"},
1083     {GST_RAW_AUDIO_PARSE_FORMAT_ALAW, "A-Law", "alaw"},
1084     {GST_RAW_AUDIO_PARSE_FORMAT_MULAW, "\302\265-Law", "mulaw"},
1085     {0, NULL, NULL}
1086   };
1087 
1088   if (!audio_parse_format_gtype)
1089     audio_parse_format_gtype =
1090         g_enum_register_static ("GstRawAudioParseFormat", types);
1091 
1092   return audio_parse_format_gtype;
1093 }
1094