• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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