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