• 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: 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