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: 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: 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;
197 gint rate, channels;
198 guint64 channel_mask;
199 gint i;
200 GstAudioChannelPosition position[64];
201 GstAudioFlags flags;
202 GstAudioLayout layout;
203
204 g_return_val_if_fail (info != NULL, FALSE);
205 g_return_val_if_fail (caps != NULL, FALSE);
206 g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
207
208 GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps);
209
210 flags = 0;
211
212 str = gst_caps_get_structure (caps, 0);
213
214 if (!gst_structure_has_name (str, "audio/x-raw"))
215 goto wrong_name;
216
217 if (!(s = gst_structure_get_string (str, "format")))
218 goto no_format;
219
220 format = gst_audio_format_from_string (s);
221 if (format == GST_AUDIO_FORMAT_UNKNOWN)
222 goto unknown_format;
223
224 if (!(s = gst_structure_get_string (str, "layout")))
225 goto no_layout;
226 if (g_str_equal (s, "interleaved"))
227 layout = GST_AUDIO_LAYOUT_INTERLEAVED;
228 else if (g_str_equal (s, "non-interleaved"))
229 layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED;
230 else
231 goto unknown_layout;
232
233 if (!gst_structure_get_int (str, "rate", &rate))
234 goto no_rate;
235 if (!gst_structure_get_int (str, "channels", &channels))
236 goto no_channels;
237
238 if (!gst_structure_get (str, "channel-mask", GST_TYPE_BITMASK, &channel_mask,
239 NULL) || (channel_mask == 0 && channels == 1)) {
240 if (channels == 1) {
241 position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
242 } else if (channels == 2) {
243 position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
244 position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
245 } else {
246 goto no_channel_mask;
247 }
248 } else if (channel_mask == 0) {
249 flags |= GST_AUDIO_FLAG_UNPOSITIONED;
250 for (i = 0; i < MIN (64, channels); i++)
251 position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
252 } else {
253 if (!gst_audio_channel_positions_from_mask (channels, channel_mask,
254 position))
255 goto invalid_channel_mask;
256 }
257
258 gst_audio_info_set_format (info, format, rate, channels,
259 (channels > 64) ? NULL : position);
260
261 info->flags = flags;
262 info->layout = layout;
263
264 return TRUE;
265
266 /* ERROR */
267 wrong_name:
268 {
269 GST_ERROR ("wrong name, expected audio/x-raw");
270 return FALSE;
271 }
272 no_format:
273 {
274 GST_ERROR ("no format given");
275 return FALSE;
276 }
277 unknown_format:
278 {
279 GST_ERROR ("unknown format given");
280 return FALSE;
281 }
282 no_layout:
283 {
284 GST_ERROR ("no layout given");
285 return FALSE;
286 }
287 unknown_layout:
288 {
289 GST_ERROR ("unknown layout given");
290 return FALSE;
291 }
292 no_rate:
293 {
294 GST_ERROR ("no rate property given");
295 return FALSE;
296 }
297 no_channels:
298 {
299 GST_ERROR ("no channels property given");
300 return FALSE;
301 }
302 no_channel_mask:
303 {
304 GST_ERROR ("no channel-mask property given");
305 return FALSE;
306 }
307 invalid_channel_mask:
308 {
309 GST_ERROR ("Invalid channel mask 0x%016" G_GINT64_MODIFIER
310 "x for %d channels", channel_mask, channels);
311 return FALSE;
312 }
313 }
314
315 /**
316 * gst_audio_info_to_caps:
317 * @info: a #GstAudioInfo
318 *
319 * Convert the values of @info into a #GstCaps.
320 *
321 * Returns: (transfer full): the new #GstCaps containing the
322 * info of @info.
323 */
324 GstCaps *
gst_audio_info_to_caps(const GstAudioInfo * info)325 gst_audio_info_to_caps (const GstAudioInfo * info)
326 {
327 GstCaps *caps;
328 const gchar *format;
329 const gchar *layout;
330 GstAudioFlags flags;
331
332 g_return_val_if_fail (info != NULL, NULL);
333 g_return_val_if_fail (info->finfo != NULL, NULL);
334 g_return_val_if_fail (info->finfo->format != GST_AUDIO_FORMAT_UNKNOWN, NULL);
335
336 format = gst_audio_format_to_string (info->finfo->format);
337 g_return_val_if_fail (format != NULL, NULL);
338
339 if (info->layout == GST_AUDIO_LAYOUT_INTERLEAVED)
340 layout = "interleaved";
341 else if (info->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED)
342 layout = "non-interleaved";
343 else
344 g_return_val_if_reached (NULL);
345
346 flags = info->flags;
347 if ((flags & GST_AUDIO_FLAG_UNPOSITIONED) && info->channels > 1
348 && info->position[0] != GST_AUDIO_CHANNEL_POSITION_NONE) {
349 flags &= ~GST_AUDIO_FLAG_UNPOSITIONED;
350 g_warning ("Unpositioned audio channel position flag set but "
351 "channel positions present");
352 } else if (!(flags & GST_AUDIO_FLAG_UNPOSITIONED) && info->channels > 1
353 && info->position[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
354 flags |= GST_AUDIO_FLAG_UNPOSITIONED;
355 g_warning ("Unpositioned audio channel position flag not set "
356 "but no channel positions present");
357 }
358
359 caps = gst_caps_new_simple ("audio/x-raw",
360 "format", G_TYPE_STRING, format,
361 "layout", G_TYPE_STRING, layout,
362 "rate", G_TYPE_INT, info->rate,
363 "channels", G_TYPE_INT, info->channels, NULL);
364
365 if (info->channels > 1
366 || info->position[0] != GST_AUDIO_CHANNEL_POSITION_MONO) {
367 guint64 channel_mask = 0;
368
369 if ((flags & GST_AUDIO_FLAG_UNPOSITIONED)) {
370 channel_mask = 0;
371 } else {
372 if (!gst_audio_channel_positions_to_mask (info->position, info->channels,
373 TRUE, &channel_mask))
374 goto invalid_channel_positions;
375 }
376
377 if (info->channels == 1
378 && info->position[0] == GST_AUDIO_CHANNEL_POSITION_MONO) {
379 /* Default mono special case */
380 } else {
381 gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
382 NULL);
383 }
384 }
385
386 return caps;
387
388 invalid_channel_positions:
389 {
390 GST_ERROR ("Invalid channel positions");
391 gst_caps_unref (caps);
392 return NULL;
393 }
394 }
395
396 /**
397 * gst_audio_info_convert:
398 * @info: a #GstAudioInfo
399 * @src_fmt: #GstFormat of the @src_val
400 * @src_val: value to convert
401 * @dest_fmt: #GstFormat of the @dest_val
402 * @dest_val: (out): pointer to destination value
403 *
404 * Converts among various #GstFormat types. This function handles
405 * GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT. For
406 * raw audio, GST_FORMAT_DEFAULT corresponds to audio frames. This
407 * function can be used to handle pad queries of the type GST_QUERY_CONVERT.
408 *
409 * Returns: TRUE if the conversion was successful.
410 */
411 gboolean
gst_audio_info_convert(const GstAudioInfo * info,GstFormat src_fmt,gint64 src_val,GstFormat dest_fmt,gint64 * dest_val)412 gst_audio_info_convert (const GstAudioInfo * info,
413 GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
414 {
415 gboolean res = TRUE;
416 gint bpf, rate;
417
418 GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)",
419 src_val, gst_format_get_name (src_fmt), src_fmt,
420 gst_format_get_name (dest_fmt), dest_fmt);
421
422 if (src_fmt == dest_fmt || src_val == -1) {
423 *dest_val = src_val;
424 goto done;
425 }
426
427 /* get important info */
428 bpf = GST_AUDIO_INFO_BPF (info);
429 rate = GST_AUDIO_INFO_RATE (info);
430
431 if (bpf == 0 || rate == 0) {
432 GST_DEBUG ("no rate or bpf configured");
433 res = FALSE;
434 goto done;
435 }
436
437 switch (src_fmt) {
438 case GST_FORMAT_BYTES:
439 switch (dest_fmt) {
440 case GST_FORMAT_TIME:
441 *dest_val = GST_FRAMES_TO_CLOCK_TIME (src_val / bpf, rate);
442 break;
443 case GST_FORMAT_DEFAULT:
444 *dest_val = src_val / bpf;
445 break;
446 default:
447 res = FALSE;
448 break;
449 }
450 break;
451 case GST_FORMAT_DEFAULT:
452 switch (dest_fmt) {
453 case GST_FORMAT_TIME:
454 *dest_val = GST_FRAMES_TO_CLOCK_TIME (src_val, rate);
455 break;
456 case GST_FORMAT_BYTES:
457 *dest_val = src_val * bpf;
458 break;
459 default:
460 res = FALSE;
461 break;
462 }
463 break;
464 case GST_FORMAT_TIME:
465 switch (dest_fmt) {
466 case GST_FORMAT_DEFAULT:
467 *dest_val = GST_CLOCK_TIME_TO_FRAMES (src_val, rate);
468 break;
469 case GST_FORMAT_BYTES:
470 *dest_val = GST_CLOCK_TIME_TO_FRAMES (src_val, rate);
471 *dest_val *= bpf;
472 break;
473 default:
474 res = FALSE;
475 break;
476 }
477 break;
478 default:
479 res = FALSE;
480 break;
481 }
482 done:
483
484 GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, res, res ? *dest_val : -1);
485
486 return res;
487 }
488
489 /**
490 * gst_audio_info_is_equal:
491 * @info: a #GstAudioInfo
492 * @other: a #GstAudioInfo
493 *
494 * Compares two #GstAudioInfo and returns whether they are equal or not
495 *
496 * Returns: %TRUE if @info and @other are equal, else %FALSE.
497 *
498 * Since: 1.2
499 *
500 */
501 gboolean
gst_audio_info_is_equal(const GstAudioInfo * info,const GstAudioInfo * other)502 gst_audio_info_is_equal (const GstAudioInfo * info, const GstAudioInfo * other)
503 {
504 if (info == other)
505 return TRUE;
506 if (info->finfo == NULL || other->finfo == NULL)
507 return FALSE;
508 if (GST_AUDIO_INFO_FORMAT (info) != GST_AUDIO_INFO_FORMAT (other))
509 return FALSE;
510 if (GST_AUDIO_INFO_FLAGS (info) != GST_AUDIO_INFO_FLAGS (other))
511 return FALSE;
512 if (GST_AUDIO_INFO_LAYOUT (info) != GST_AUDIO_INFO_LAYOUT (other))
513 return FALSE;
514 if (GST_AUDIO_INFO_RATE (info) != GST_AUDIO_INFO_RATE (other))
515 return FALSE;
516 if (GST_AUDIO_INFO_CHANNELS (info) != GST_AUDIO_INFO_CHANNELS (other))
517 return FALSE;
518 if (GST_AUDIO_INFO_CHANNELS (info) > 64)
519 return TRUE;
520 if (memcmp (info->position, other->position,
521 GST_AUDIO_INFO_CHANNELS (info) * sizeof (GstAudioChannelPosition)) !=
522 0)
523 return FALSE;
524
525 return TRUE;
526 }
527