1 /* GStreamer
2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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 #ifdef HAVE_CONFIG_H
21 # include "config.h"
22 #endif
23
24 #include <string.h>
25
26 #include "audio.h"
27
28 #include <gst/gststructure.h>
29
30 #ifndef GST_DISABLE_GST_DEBUG
31 #define GST_CAT_DEFAULT ensure_debug_category()
32 static GstDebugCategory *
ensure_debug_category(void)33 ensure_debug_category (void)
34 {
35 static gsize cat_gonce = 0;
36
37 if (g_once_init_enter (&cat_gonce)) {
38 gsize cat_done;
39
40 cat_done = (gsize) _gst_debug_category_new ("audio-info", 0,
41 "audio-info object");
42
43 g_once_init_leave (&cat_gonce, cat_done);
44 }
45
46 return (GstDebugCategory *) cat_gonce;
47 }
48 #else
49 #define ensure_debug_category() /* NOOP */
50 #endif /* GST_DISABLE_GST_DEBUG */
51
52
53 /**
54 * gst_audio_info_copy:
55 * @info: a #GstAudioInfo
56 *
57 * Copy a GstAudioInfo structure.
58 *
59 * Returns: a new #GstAudioInfo. free with gst_audio_info_free.
60 */
61 GstAudioInfo *
gst_audio_info_copy(const GstAudioInfo * info)62 gst_audio_info_copy (const GstAudioInfo * info)
63 {
64 return g_slice_dup (GstAudioInfo, info);
65 }
66
67 /**
68 * gst_audio_info_free:
69 * @info: a #GstAudioInfo
70 *
71 * Free a GstAudioInfo structure previously allocated with gst_audio_info_new()
72 * or gst_audio_info_copy().
73 */
74 void
gst_audio_info_free(GstAudioInfo * info)75 gst_audio_info_free (GstAudioInfo * info)
76 {
77 g_slice_free (GstAudioInfo, info);
78 }
79
80 G_DEFINE_BOXED_TYPE (GstAudioInfo, gst_audio_info,
81 (GBoxedCopyFunc) gst_audio_info_copy, (GBoxedFreeFunc) gst_audio_info_free);
82
83 /**
84 * gst_audio_info_new:
85 *
86 * Allocate a new #GstAudioInfo that is also initialized with
87 * gst_audio_info_init().
88 *
89 * Returns: a new #GstAudioInfo. free with gst_audio_info_free().
90 */
91 GstAudioInfo *
gst_audio_info_new(void)92 gst_audio_info_new (void)
93 {
94 GstAudioInfo *info;
95
96 info = g_slice_new (GstAudioInfo);
97 gst_audio_info_init (info);
98
99 return info;
100 }
101
102 /**
103 * gst_audio_info_init:
104 * @info: (out caller-allocates): a #GstAudioInfo
105 *
106 * Initialize @info with default values.
107 */
108 void
gst_audio_info_init(GstAudioInfo * info)109 gst_audio_info_init (GstAudioInfo * info)
110 {
111 g_return_if_fail (info != NULL);
112
113 memset (info, 0, sizeof (GstAudioInfo));
114
115 info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_UNKNOWN);
116 }
117
118 /**
119 * gst_audio_info_set_format:
120 * @info: a #GstAudioInfo
121 * @format: the format
122 * @rate: the samplerate
123 * @channels: the number of channels
124 * @position: (array fixed-size=64) (nullable): the channel positions
125 *
126 * Set the default info for the audio info of @format and @rate and @channels.
127 *
128 * Note: This initializes @info first, no values are preserved.
129 */
130 void
gst_audio_info_set_format(GstAudioInfo * info,GstAudioFormat format,gint rate,gint channels,const GstAudioChannelPosition * position)131 gst_audio_info_set_format (GstAudioInfo * info, GstAudioFormat format,
132 gint rate, gint channels, const GstAudioChannelPosition * position)
133 {
134 const GstAudioFormatInfo *finfo;
135 gint i;
136
137 g_return_if_fail (info != NULL);
138 g_return_if_fail (format != GST_AUDIO_FORMAT_UNKNOWN);
139 g_return_if_fail (channels <= 64 || position == NULL);
140
141 gst_audio_info_init (info);
142
143 finfo = gst_audio_format_get_info (format);
144
145 info->flags = 0;
146 info->layout = GST_AUDIO_LAYOUT_INTERLEAVED;
147 info->finfo = finfo;
148 info->rate = rate;
149 info->channels = channels;
150 info->bpf = (finfo->width * channels) / 8;
151
152 memset (&info->position, 0xff, sizeof (info->position));
153
154 if (!position && channels == 1) {
155 info->position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
156 return;
157 } else if (!position && channels == 2) {
158 info->position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
159 info->position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
160 return;
161 } else {
162 if (!position
163 || !gst_audio_check_valid_channel_positions (position, channels,
164 TRUE)) {
165 if (position)
166 g_warning ("Invalid channel positions");
167 } else {
168 memcpy (&info->position, position,
169 info->channels * sizeof (info->position[0]));
170 if (info->position[0] == GST_AUDIO_CHANNEL_POSITION_NONE)
171 info->flags |= GST_AUDIO_FLAG_UNPOSITIONED;
172 return;
173 }
174 }
175
176 /* Otherwise a NONE layout */
177 info->flags |= GST_AUDIO_FLAG_UNPOSITIONED;
178 for (i = 0; i < MIN (64, channels); i++)
179 info->position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
180 }
181
182 /**
183 * gst_audio_info_from_caps:
184 * @info: (out caller-allocates): a #GstAudioInfo
185 * @caps: a #GstCaps
186 *
187 * Parse @caps and update @info.
188 *
189 * Returns: TRUE if @caps could be parsed
190 */
191 gboolean
gst_audio_info_from_caps(GstAudioInfo * info,const GstCaps * caps)192 gst_audio_info_from_caps (GstAudioInfo * info, const GstCaps * caps)
193 {
194 GstStructure *str;
195 const gchar *s;
196 GstAudioFormat format = GST_AUDIO_FORMAT_UNKNOWN;
197 gint rate = 0;
198 gint channels = 0;
199 guint64 channel_mask = 0;
200 gint i;
201 GstAudioChannelPosition position[64];
202 GstAudioFlags flags;
203 GstAudioLayout layout = GST_AUDIO_LAYOUT_INTERLEAVED;
204
205 g_return_val_if_fail (info != NULL, FALSE);
206 g_return_val_if_fail (caps != NULL, FALSE);
207 g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
208
209 GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps);
210
211 flags = 0;
212
213 str = gst_caps_get_structure (caps, 0);
214
215 if (gst_structure_has_name (str, "audio/x-raw")) {
216 if (!(s = gst_structure_get_string (str, "format")))
217 goto no_format;
218
219 format = gst_audio_format_from_string (s);
220 if (format == GST_AUDIO_FORMAT_UNKNOWN)
221 goto unknown_format;
222 } else if (g_str_has_prefix (gst_structure_get_name (str), "audio/")) {
223 format = GST_AUDIO_FORMAT_ENCODED;
224 } else {
225 goto wrong_name;
226 }
227
228 if (format != GST_AUDIO_FORMAT_ENCODED) {
229 if (!(s = gst_structure_get_string (str, "layout")))
230 goto no_layout;
231 if (g_str_equal (s, "interleaved"))
232 layout = GST_AUDIO_LAYOUT_INTERLEAVED;
233 else if (g_str_equal (s, "non-interleaved"))
234 layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED;
235 else
236 goto unknown_layout;
237 }
238
239 if (!gst_structure_get_int (str, "rate", &rate) &&
240 format != GST_AUDIO_FORMAT_ENCODED)
241 goto no_rate;
242 if (!gst_structure_get_int (str, "channels", &channels) &&
243 format != GST_AUDIO_FORMAT_ENCODED)
244 goto no_channels;
245
246 if (!gst_structure_get (str, "channel-mask", GST_TYPE_BITMASK, &channel_mask,
247 NULL) || (channel_mask == 0 && channels == 1)) {
248 if (channels == 1) {
249 position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
250 } else if (channels == 2) {
251 position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
252 position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
253 } else if (format != GST_AUDIO_FORMAT_ENCODED) {
254 goto no_channel_mask;
255 }
256 } else if (channel_mask == 0) {
257 flags |= GST_AUDIO_FLAG_UNPOSITIONED;
258 for (i = 0; i < MIN (64, channels); i++)
259 position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
260 } else {
261 if (!gst_audio_channel_positions_from_mask (channels, channel_mask,
262 position))
263 goto invalid_channel_mask;
264 }
265
266 gst_audio_info_set_format (info, format, rate, channels,
267 (channels > 64) ? NULL : position);
268
269 info->flags = flags;
270 info->layout = layout;
271
272 return TRUE;
273
274 /* ERROR */
275 wrong_name:
276 {
277 GST_ERROR ("wrong name, expected audio/x-raw");
278 return FALSE;
279 }
280 no_format:
281 {
282 GST_ERROR ("no format given");
283 return FALSE;
284 }
285 unknown_format:
286 {
287 GST_ERROR ("unknown format given");
288 return FALSE;
289 }
290 no_layout:
291 {
292 GST_ERROR ("no layout given");
293 return FALSE;
294 }
295 unknown_layout:
296 {
297 GST_ERROR ("unknown layout given");
298 return FALSE;
299 }
300 no_rate:
301 {
302 GST_ERROR ("no rate property given");
303 return FALSE;
304 }
305 no_channels:
306 {
307 GST_ERROR ("no channels property given");
308 return FALSE;
309 }
310 no_channel_mask:
311 {
312 GST_ERROR ("no channel-mask property given");
313 return FALSE;
314 }
315 invalid_channel_mask:
316 {
317 GST_ERROR ("Invalid channel mask 0x%016" G_GINT64_MODIFIER
318 "x for %d channels", channel_mask, channels);
319 return FALSE;
320 }
321 }
322
323 /**
324 * gst_audio_info_new_from_caps:
325 * @caps: a #GstCaps
326 *
327 * Parse @caps to generate a #GstAudioInfo.
328 *
329 * Returns: A #GstAudioInfo, or %NULL if @caps couldn't be parsed
330 * Since: 1.20
331 */
332 GstAudioInfo *
gst_audio_info_new_from_caps(const GstCaps * caps)333 gst_audio_info_new_from_caps (const GstCaps * caps)
334 {
335 GstAudioInfo *ret = gst_audio_info_new ();
336
337 if (gst_audio_info_from_caps (ret, caps)) {
338 return ret;
339 } else {
340 gst_audio_info_free (ret);
341 return NULL;
342 }
343 }
344
345 /**
346 * gst_audio_info_to_caps:
347 * @info: a #GstAudioInfo
348 *
349 * Convert the values of @info into a #GstCaps.
350 *
351 * Returns: (transfer full): the new #GstCaps containing the
352 * info of @info.
353 */
354 GstCaps *
gst_audio_info_to_caps(const GstAudioInfo * info)355 gst_audio_info_to_caps (const GstAudioInfo * info)
356 {
357 GstCaps *caps;
358 const gchar *format;
359 const gchar *layout;
360 GstAudioFlags flags;
361
362 g_return_val_if_fail (info != NULL, NULL);
363 g_return_val_if_fail (info->finfo != NULL, NULL);
364 g_return_val_if_fail (info->finfo->format != GST_AUDIO_FORMAT_UNKNOWN, NULL);
365
366 format = gst_audio_format_to_string (info->finfo->format);
367 g_return_val_if_fail (format != NULL, NULL);
368
369 if (info->layout == GST_AUDIO_LAYOUT_INTERLEAVED)
370 layout = "interleaved";
371 else if (info->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED)
372 layout = "non-interleaved";
373 else
374 g_return_val_if_reached (NULL);
375
376 flags = info->flags;
377 if ((flags & GST_AUDIO_FLAG_UNPOSITIONED) && info->channels > 1
378 && info->position[0] != GST_AUDIO_CHANNEL_POSITION_NONE) {
379 flags &= ~GST_AUDIO_FLAG_UNPOSITIONED;
380 g_warning ("Unpositioned audio channel position flag set but "
381 "channel positions present");
382 } else if (!(flags & GST_AUDIO_FLAG_UNPOSITIONED) && info->channels > 1
383 && info->position[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
384 flags |= GST_AUDIO_FLAG_UNPOSITIONED;
385 g_warning ("Unpositioned audio channel position flag not set "
386 "but no channel positions present");
387 }
388
389 caps = gst_caps_new_simple ("audio/x-raw",
390 "format", G_TYPE_STRING, format,
391 "layout", G_TYPE_STRING, layout,
392 "rate", G_TYPE_INT, info->rate,
393 "channels", G_TYPE_INT, info->channels, NULL);
394
395 if (info->channels > 1
396 || info->position[0] != GST_AUDIO_CHANNEL_POSITION_MONO) {
397 guint64 channel_mask = 0;
398
399 if ((flags & GST_AUDIO_FLAG_UNPOSITIONED)) {
400 channel_mask = 0;
401 } else {
402 if (!gst_audio_channel_positions_to_mask (info->position, info->channels,
403 TRUE, &channel_mask))
404 goto invalid_channel_positions;
405 }
406
407 if (info->channels == 1
408 && info->position[0] == GST_AUDIO_CHANNEL_POSITION_MONO) {
409 /* Default mono special case */
410 } else {
411 gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
412 NULL);
413 }
414 }
415
416 return caps;
417
418 invalid_channel_positions:
419 {
420 GST_ERROR ("Invalid channel positions");
421 gst_caps_unref (caps);
422 return NULL;
423 }
424 }
425
426 /**
427 * gst_audio_info_convert:
428 * @info: a #GstAudioInfo
429 * @src_fmt: #GstFormat of the @src_val
430 * @src_val: value to convert
431 * @dest_fmt: #GstFormat of the @dest_val
432 * @dest_val: (out): pointer to destination value
433 *
434 * Converts among various #GstFormat types. This function handles
435 * GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT. For
436 * raw audio, GST_FORMAT_DEFAULT corresponds to audio frames. This
437 * function can be used to handle pad queries of the type GST_QUERY_CONVERT.
438 *
439 * Returns: TRUE if the conversion was successful.
440 */
441 gboolean
gst_audio_info_convert(const GstAudioInfo * info,GstFormat src_fmt,gint64 src_val,GstFormat dest_fmt,gint64 * dest_val)442 gst_audio_info_convert (const GstAudioInfo * info,
443 GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
444 {
445 gboolean res = TRUE;
446 gint bpf, rate;
447
448 GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)",
449 src_val, gst_format_get_name (src_fmt), src_fmt,
450 gst_format_get_name (dest_fmt), dest_fmt);
451
452 if (src_fmt == dest_fmt || src_val == -1) {
453 *dest_val = src_val;
454 goto done;
455 }
456
457 /* get important info */
458 bpf = GST_AUDIO_INFO_BPF (info);
459 rate = GST_AUDIO_INFO_RATE (info);
460
461 if (bpf == 0 || rate == 0) {
462 GST_DEBUG ("no rate or bpf configured");
463 res = FALSE;
464 goto done;
465 }
466
467 switch (src_fmt) {
468 case GST_FORMAT_BYTES:
469 switch (dest_fmt) {
470 case GST_FORMAT_TIME:
471 *dest_val = GST_FRAMES_TO_CLOCK_TIME (src_val / bpf, rate);
472 break;
473 case GST_FORMAT_DEFAULT:
474 *dest_val = src_val / bpf;
475 break;
476 default:
477 res = FALSE;
478 break;
479 }
480 break;
481 case GST_FORMAT_DEFAULT:
482 switch (dest_fmt) {
483 case GST_FORMAT_TIME:
484 *dest_val = GST_FRAMES_TO_CLOCK_TIME (src_val, rate);
485 break;
486 case GST_FORMAT_BYTES:
487 *dest_val = src_val * bpf;
488 break;
489 default:
490 res = FALSE;
491 break;
492 }
493 break;
494 case GST_FORMAT_TIME:
495 switch (dest_fmt) {
496 case GST_FORMAT_DEFAULT:
497 *dest_val = GST_CLOCK_TIME_TO_FRAMES (src_val, rate);
498 break;
499 case GST_FORMAT_BYTES:
500 *dest_val = GST_CLOCK_TIME_TO_FRAMES (src_val, rate);
501 *dest_val *= bpf;
502 break;
503 default:
504 res = FALSE;
505 break;
506 }
507 break;
508 default:
509 res = FALSE;
510 break;
511 }
512 done:
513
514 GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, res, res ? *dest_val : -1);
515
516 return res;
517 }
518
519 /**
520 * gst_audio_info_is_equal:
521 * @info: a #GstAudioInfo
522 * @other: a #GstAudioInfo
523 *
524 * Compares two #GstAudioInfo and returns whether they are equal or not
525 *
526 * Returns: %TRUE if @info and @other are equal, else %FALSE.
527 *
528 * Since: 1.2
529 *
530 */
531 gboolean
gst_audio_info_is_equal(const GstAudioInfo * info,const GstAudioInfo * other)532 gst_audio_info_is_equal (const GstAudioInfo * info, const GstAudioInfo * other)
533 {
534 if (info == other)
535 return TRUE;
536 if (info->finfo == NULL || other->finfo == NULL)
537 return FALSE;
538 if (GST_AUDIO_INFO_FORMAT (info) != GST_AUDIO_INFO_FORMAT (other))
539 return FALSE;
540 if (GST_AUDIO_INFO_FLAGS (info) != GST_AUDIO_INFO_FLAGS (other))
541 return FALSE;
542 if (GST_AUDIO_INFO_LAYOUT (info) != GST_AUDIO_INFO_LAYOUT (other))
543 return FALSE;
544 if (GST_AUDIO_INFO_RATE (info) != GST_AUDIO_INFO_RATE (other))
545 return FALSE;
546 if (GST_AUDIO_INFO_CHANNELS (info) != GST_AUDIO_INFO_CHANNELS (other))
547 return FALSE;
548 if (GST_AUDIO_INFO_CHANNELS (info) > 64)
549 return TRUE;
550 if (memcmp (info->position, other->position,
551 GST_AUDIO_INFO_CHANNELS (info) * sizeof (GstAudioChannelPosition)) !=
552 0)
553 return FALSE;
554
555 return TRUE;
556 }
557