2 * Copyright (C) <2016> Carlos Rafael Giani <dv at pseudoterminal dot org>
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.
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.
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.
21 * SECTION:element-rawaudioparse
22 * @title: rawaudioparse
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.
32 * Currently, this parser supports raw data in a-law, mu-law, or linear PCM format.
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".
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.
51 * ## Example pipelines
53 * gst-launch-1.0 souphttpsrc http://my-dlna-server/track.l16 \
54 * rawaudioparse ! audioconvert ! audioresample ! autoaudiosink
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.
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
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.
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
80 #include "gstrawaudioparse.h"
81 #include "unalignedaudio.h"
83 GST_DEBUG_CATEGORY_STATIC (raw_audio_parse_debug);
84 #define GST_CAT_DEFAULT raw_audio_parse_debug
94 PROP_CHANNEL_POSITIONS
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
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 ]; "
109 static GstStaticPadTemplate static_sink_template =
110 GST_STATIC_PAD_TEMPLATE ("sink",
113 GST_STATIC_CAPS (GST_UNALIGNED_RAW_AUDIO_CAPS "; " GST_RAW_AUDIO_PARSE_CAPS)
116 static GstStaticPadTemplate static_src_template =
117 GST_STATIC_PAD_TEMPLATE ("src",
120 GST_STATIC_CAPS (GST_RAW_AUDIO_PARSE_CAPS)
123 #define gst_raw_audio_parse_parent_class parent_class
124 G_DEFINE_TYPE (GstRawAudioParse, gst_raw_audio_parse, GST_TYPE_RAW_BASE_PARSE);
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);
131 static gboolean gst_raw_audio_parse_stop (GstBaseParse * parse);
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);
156 static gboolean gst_raw_audio_parse_is_using_sink_caps (GstRawAudioParse *
158 static GstRawAudioParseConfig
159 * gst_raw_audio_parse_get_config_ptr (GstRawAudioParse * raw_audio_parse,
160 GstRawBaseParseConfig config);
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);
166 gst_raw_audio_parse_update_channel_reordering_flag (GstRawAudioParseConfig *
168 static void gst_raw_audio_parse_update_config_bpf (GstRawAudioParseConfig *
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);
176 gst_raw_audio_parse_class_init (GstRawAudioParseClass * klass)
178 GObjectClass *object_class;
179 GstElementClass *element_class;
180 GstBaseParseClass *baseparse_class;
181 GstRawBaseParseClass *rawbaseparse_class;
183 GST_DEBUG_CATEGORY_INIT (raw_audio_parse_debug, "rawaudioparse", 0,
184 "rawaudioparse element");
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);
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));
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);
201 baseparse_class->stop = GST_DEBUG_FUNCPTR (gst_raw_audio_parse_stop);
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);
223 g_object_class_install_property (object_class,
225 g_param_spec_enum ("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)
232 g_object_class_install_property (object_class,
234 g_param_spec_enum ("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)
241 g_object_class_install_property (object_class,
243 g_param_spec_int ("sample-rate",
245 "Rate of audio samples in raw stream",
247 DEFAULT_SAMPLE_RATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
249 g_object_class_install_property (object_class,
251 g_param_spec_int ("num-channels",
252 "Number of channels",
253 "Number of channels in raw stream",
255 DEFAULT_NUM_CHANNELS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)
257 g_object_class_install_property (object_class,
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)
264 g_object_class_install_property (object_class,
265 PROP_CHANNEL_POSITIONS,
266 g_param_spec_value_array ("channel-positions",
268 "Channel positions used on the output",
269 g_param_spec_enum ("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)
278 gst_element_class_set_static_metadata (element_class,
280 "Codec/Parser/Audio",
281 "Converts unformatted data streams into timestamped raw audio frames",
282 "Carlos Rafael Giani <dv@pseudoterminal.org>");
284 gst_type_mark_as_plugin_api (GST_TYPE_RAW_AUDIO_PARSE_FORMAT, 0);
288 gst_raw_audio_parse_init (GstRawAudioParse * raw_audio_parse)
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);
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));
304 gst_raw_audio_parse_set_property (GObject * object, guint prop_id,
305 GValue const *value, GParamSpec * pspec)
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);
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
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
326 GstRawAudioParseFormat new_format = g_value_get_enum (value);
328 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
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));
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);
342 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
346 case PROP_PCM_FORMAT:
348 GstAudioFormat new_pcm_format = g_value_get_enum (value);
350 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
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));
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);
364 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
368 case PROP_SAMPLE_RATE:
370 guint new_sample_rate = g_value_get_int (value);
372 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
374 if (new_sample_rate != raw_audio_parse->properties_config.sample_rate) {
375 raw_audio_parse->properties_config.sample_rate = new_sample_rate;
377 if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse))
378 gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
381 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
385 case PROP_NUM_CHANNELS:
387 guint new_num_channels = g_value_get_int (value);
389 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
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);
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));
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);
406 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
410 case PROP_INTERLEAVED:
412 gboolean new_interleaved = g_value_get_boolean (value);
414 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
416 if (new_interleaved != raw_audio_parse->properties_config.interleaved) {
417 raw_audio_parse->properties_config.interleaved = new_interleaved;
419 if (!gst_raw_audio_parse_is_using_sink_caps (raw_audio_parse))
420 gst_raw_base_parse_invalidate_src_caps (raw_base_parse);
423 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
427 case PROP_CHANNEL_POSITIONS:
429 GValueArray *valarray = g_value_get_boxed (value);
430 GstRawAudioParseConfig *config = &(raw_audio_parse->properties_config);
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));
439 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
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,
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).
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,
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);
474 gst_raw_audio_parse_update_channel_reordering_flag (config);
477 gst_raw_audio_parse_update_config_bpf (&
478 (raw_audio_parse->properties_config));
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);
486 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
491 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
497 gst_raw_audio_parse_get_property (GObject * object, guint prop_id,
498 GValue * value, GParamSpec * pspec)
500 GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (object);
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);
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);
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);
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);
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);
534 case PROP_CHANNEL_POSITIONS:
536 GstRawAudioParseConfig *config;
537 GValueArray *valarray;
539 GST_RAW_BASE_PARSE_CONFIG_MUTEX_LOCK (object);
542 config = &(raw_audio_parse->properties_config);
544 /* Copy channel positions into the valuearray */
545 if (config->num_channels > 0) {
547 GValue val = G_VALUE_INIT;
548 g_assert (config->channel_positions);
550 g_value_init (&val, GST_TYPE_AUDIO_CHANNEL_POSITION);
551 valarray = g_value_array_new (config->num_channels);
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);
558 g_value_unset (&val);
561 GST_RAW_BASE_PARSE_CONFIG_MUTEX_UNLOCK (object);
563 /* Pass on ownership to the value array,
564 * since we don't need it anymore */
565 g_value_take_boxed (value, valarray);
571 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
577 gst_raw_audio_parse_stop (GstBaseParse * parse)
579 GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (parse);
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;
588 return GST_BASE_PARSE_CLASS (parent_class)->stop (parse);
592 gst_raw_audio_parse_set_current_config (GstRawBaseParse * raw_base_parse,
593 GstRawBaseParseConfig config)
595 GstRawAudioParse *raw_audio_parse = GST_RAW_AUDIO_PARSE (raw_base_parse);
598 case GST_RAW_BASE_PARSE_CONFIG_PROPERTIES:
599 raw_audio_parse->current_config = &(raw_audio_parse->properties_config);
602 case GST_RAW_BASE_PARSE_CONFIG_SINKCAPS:
603 raw_audio_parse->current_config = &(raw_audio_parse->sink_caps_config);
607 g_assert_not_reached ();
613 static GstRawBaseParseConfig
614 gst_raw_audio_parse_get_current_config (GstRawBaseParse * raw_base_parse)
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;
622 gst_raw_audio_parse_set_config_from_caps (GstRawBaseParse * raw_base_parse,
623 GstRawBaseParseConfig config, GstCaps * caps)
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));
631 gst_raw_audio_parse_get_caps_from_config (GstRawBaseParse * raw_base_parse,
632 GstRawBaseParseConfig config, GstCaps ** caps)
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));
640 gst_raw_audio_parse_get_config_frame_size (GstRawBaseParse * raw_base_parse,
641 GstRawBaseParseConfig config)
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;
648 gst_raw_audio_parse_is_config_ready (GstRawBaseParse * raw_base_parse,
649 GstRawBaseParseConfig config)
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;
656 round_up_pow2 (guint n)
668 gst_raw_audio_parse_get_alignment (GstRawBaseParse * raw_base_parse,
669 GstRawBaseParseConfig config)
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);
676 if (config_ptr->format != GST_RAW_AUDIO_PARSE_FORMAT_PCM)
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);
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)
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);
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
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,
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);
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);
719 *processed_data = outbuf;
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 */
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,
730 *processed_data = NULL;
737 gst_raw_audio_parse_is_unit_format_supported (G_GNUC_UNUSED GstRawBaseParse *
738 raw_base_parse, GstFormat format)
741 case GST_FORMAT_BYTES:
742 case GST_FORMAT_DEFAULT:
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)
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);
759 case GST_FORMAT_BYTES:
760 *units_per_sec_n = config_ptr->sample_rate * config_ptr->bpf;
761 *units_per_sec_d = 1;
764 case GST_FORMAT_DEFAULT:
765 *units_per_sec_n = config_ptr->sample_rate;
766 *units_per_sec_d = 1;
770 g_assert_not_reached ();
775 gst_raw_audio_parse_is_using_sink_caps (GstRawAudioParse * raw_audio_parse)
777 return raw_audio_parse->current_config ==
778 &(raw_audio_parse->sink_caps_config);
781 static GstRawAudioParseConfig *
782 gst_raw_audio_parse_get_config_ptr (GstRawAudioParse * raw_audio_parse,
783 GstRawBaseParseConfig config)
785 g_assert (raw_audio_parse->current_config != NULL);
788 case GST_RAW_BASE_PARSE_CONFIG_PROPERTIES:
789 return &(raw_audio_parse->properties_config);
791 case GST_RAW_BASE_PARSE_CONFIG_SINKCAPS:
792 return &(raw_audio_parse->sink_caps_config);
795 g_assert (raw_audio_parse->current_config != NULL);
796 return raw_audio_parse->current_config;
801 gst_raw_audio_parse_init_config (GstRawAudioParseConfig * config)
803 config->ready = FALSE;
804 config->format = DEFAULT_FORMAT;
805 config->pcm_format = DEFAULT_PCM_FORMAT;
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;
812 gst_raw_audio_parse_set_config_channels (config, config->num_channels, 0,
817 gst_raw_audio_parse_set_config_channels (GstRawAudioParseConfig * config,
818 guint num_channels, guint64 channel_mask, gboolean set_positions)
820 g_assert (num_channels > 0);
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;
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. */
831 if (channel_mask == 0)
832 channel_mask = gst_audio_channel_get_fallback_mask (config->num_channels);
834 return gst_audio_channel_positions_from_mask (config->num_channels,
835 channel_mask, config->channel_positions);
842 gst_raw_audio_parse_update_channel_reordering_flag (GstRawAudioParseConfig *
845 g_assert (config->num_channels > 0);
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.
854 if (gst_audio_check_valid_channel_positions (config->channel_positions,
855 config->num_channels, TRUE)) {
857 config->needs_channel_reordering = FALSE;
861 config->needs_channel_reordering = TRUE;
862 memcpy (config->reordered_channel_positions, config->channel_positions,
863 sizeof (GstAudioChannelPosition) * config->num_channels);
865 gst_audio_channel_positions_to_valid_order
866 (config->reordered_channel_positions, config->num_channels);
871 gst_raw_audio_parse_update_config_bpf (GstRawAudioParseConfig * config)
873 switch (config->format) {
874 case GST_RAW_AUDIO_PARSE_FORMAT_PCM:
876 GstAudioFormatInfo const *fmt_info =
877 gst_audio_format_get_info (config->pcm_format);
878 g_assert (fmt_info != NULL);
881 GST_AUDIO_FORMAT_INFO_WIDTH (fmt_info) * config->num_channels / 8;
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;
893 g_assert_not_reached ();
898 gst_raw_audio_parse_caps_to_config (GstRawAudioParse * raw_audio_parse,
899 GstCaps * caps, GstRawAudioParseConfig * config)
901 gboolean ret = FALSE;
902 GstStructure *structure;
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. */
910 structure = gst_caps_get_structure (caps, 0);
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);
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");
927 if (gst_structure_has_name (structure, "audio/x-raw")) {
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);
936 num_channels = GST_AUDIO_INFO_CHANNELS (&info);
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);
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")) {
951 guint64 channel_mask;
955 gst_structure_has_name (structure,
956 "audio/x-alaw") ? GST_RAW_AUDIO_PARSE_FORMAT_ALAW :
957 GST_RAW_AUDIO_PARSE_FORMAT_MULAW;
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);
964 config->sample_rate = i;
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);
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);
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);
989 /* A-law and mu-law both use 1 byte per sample */
990 config->bpf = 1 * num_channels;
992 GST_ERROR_OBJECT (raw_audio_parse,
993 "caps %" GST_PTR_FORMAT " have an unsupported media type",
1001 gst_caps_unref (caps);
1003 config->ready = TRUE;
1008 gst_raw_audio_parse_config_to_caps (GstRawAudioParse * raw_audio_parse,
1009 GstCaps ** caps, GstRawAudioParseConfig * config)
1011 gboolean ret = TRUE;
1012 GstAudioChannelPosition *channel_positions;
1014 g_assert (caps != NULL);
1016 if (config->bpf == 0) {
1017 GST_ERROR_OBJECT (raw_audio_parse,
1018 "cannot convert config to caps - config not filled with valid values");
1024 config->needs_channel_reordering ? &(config->
1025 reordered_channel_positions[0]) : &(config->channel_positions[0]);
1027 switch (config->format) {
1028 case GST_RAW_AUDIO_PARSE_FORMAT_PCM:
1031 gst_audio_info_init (&info);
1032 gst_audio_info_set_format (&info,
1034 config->sample_rate, config->num_channels, channel_positions);
1036 *caps = gst_audio_info_to_caps (&info);
1041 case GST_RAW_AUDIO_PARSE_FORMAT_ALAW:
1042 case GST_RAW_AUDIO_PARSE_FORMAT_MULAW:
1044 guint64 channel_mask;
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");
1053 *caps = gst_caps_new_simple (
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);
1064 g_assert_not_reached ();
1075 gst_raw_audio_parse_format_get_type (void)
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"},
1085 if (!audio_parse_format_gtype)
1086 audio_parse_format_gtype =
1087 g_enum_register_static ("GstRawAudioParseFormat", types);
1089 return audio_parse_format_gtype;