Fix FSF address
[platform/upstream/gstreamer.git] / gst-libs / gst / audio / audio-info.c
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  * SECTION:gstaudio
21  * @short_description: Support library for audio elements
22  *
23  * This library contains some helper functions for audio elements.
24  */
25
26 #ifdef HAVE_CONFIG_H
27 #  include "config.h"
28 #endif
29
30 #include <string.h>
31
32 #include "audio.h"
33
34 #include <gst/gststructure.h>
35
36 /**
37  * gst_audio_info_copy:
38  * @info: a #GstAudioInfo
39  *
40  * Copy a GstAudioInfo structure.
41  *
42  * Returns: a new #GstAudioInfo. free with gst_audio_info_free.
43  */
44 GstAudioInfo *
45 gst_audio_info_copy (const GstAudioInfo * info)
46 {
47   return g_slice_dup (GstAudioInfo, info);
48 }
49
50 /**
51  * gst_audio_info_free:
52  * @info: a #GstAudioInfo
53  *
54  * Free a GstAudioInfo structure previously allocated with gst_audio_info_new()
55  * or gst_audio_info_copy().
56  */
57 void
58 gst_audio_info_free (GstAudioInfo * info)
59 {
60   g_slice_free (GstAudioInfo, info);
61 }
62
63 G_DEFINE_BOXED_TYPE (GstAudioInfo, gst_audio_info,
64     (GBoxedCopyFunc) gst_audio_info_copy, (GBoxedFreeFunc) gst_audio_info_free);
65
66 /**
67  * gst_audio_info_new:
68  *
69  * Allocate a new #GstAudioInfo that is also initialized with
70  * gst_audio_info_init().
71  *
72  * Returns: a new #GstAudioInfo. free with gst_audio_info_free().
73  */
74 GstAudioInfo *
75 gst_audio_info_new (void)
76 {
77   GstAudioInfo *info;
78
79   info = g_slice_new (GstAudioInfo);
80   gst_audio_info_init (info);
81
82   return info;
83 }
84
85 /**
86  * gst_audio_info_init:
87  * @info: a #GstAudioInfo
88  *
89  * Initialize @info with default values.
90  */
91 void
92 gst_audio_info_init (GstAudioInfo * info)
93 {
94   g_return_if_fail (info != NULL);
95
96   memset (info, 0, sizeof (GstAudioInfo));
97
98   info->finfo = gst_audio_format_get_info (GST_AUDIO_FORMAT_UNKNOWN);
99
100   memset (&info->position, 0xff, sizeof (info->position));
101 }
102
103 /**
104  * gst_audio_info_set_format:
105  * @info: a #GstAudioInfo
106  * @format: the format
107  * @rate: the samplerate
108  * @channels: the number of channels
109  * @position: the channel positions
110  *
111  * Set the default info for the audio info of @format and @rate and @channels.
112  */
113 void
114 gst_audio_info_set_format (GstAudioInfo * info, GstAudioFormat format,
115     gint rate, gint channels, const GstAudioChannelPosition * position)
116 {
117   const GstAudioFormatInfo *finfo;
118   gint i;
119
120   g_return_if_fail (info != NULL);
121   g_return_if_fail (format != GST_AUDIO_FORMAT_UNKNOWN);
122
123   finfo = gst_audio_format_get_info (format);
124
125   info->flags = 0;
126   info->layout = GST_AUDIO_LAYOUT_INTERLEAVED;
127   info->finfo = finfo;
128   info->rate = rate;
129   info->channels = channels;
130   info->bpf = (finfo->width * channels) / 8;
131
132   memset (&info->position, 0xff, sizeof (info->position));
133
134   if (!position && channels == 1) {
135     info->position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
136     return;
137   } else if (!position && channels == 2) {
138     info->position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
139     info->position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
140     return;
141   } else {
142     if (!position
143         || !gst_audio_check_valid_channel_positions (position, channels,
144             TRUE)) {
145       if (position)
146         g_warning ("Invalid channel positions");
147     } else {
148       memcpy (&info->position, position,
149           info->channels * sizeof (info->position[0]));
150       if (info->position[0] == GST_AUDIO_CHANNEL_POSITION_NONE)
151         info->flags |= GST_AUDIO_FLAG_UNPOSITIONED;
152       return;
153     }
154   }
155
156   /* Otherwise a NONE layout */
157   info->flags |= GST_AUDIO_FLAG_UNPOSITIONED;
158   for (i = 0; i < MIN (64, channels); i++)
159     info->position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
160 }
161
162 /**
163  * gst_audio_info_from_caps:
164  * @info: a #GstAudioInfo
165  * @caps: a #GstCaps
166  *
167  * Parse @caps and update @info.
168  *
169  * Returns: TRUE if @caps could be parsed
170  */
171 gboolean
172 gst_audio_info_from_caps (GstAudioInfo * info, const GstCaps * caps)
173 {
174   GstStructure *str;
175   const gchar *s;
176   GstAudioFormat format;
177   gint rate, channels;
178   guint64 channel_mask;
179   gint i;
180   GstAudioChannelPosition position[64];
181
182   g_return_val_if_fail (info != NULL, FALSE);
183   g_return_val_if_fail (caps != NULL, FALSE);
184   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
185
186   GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps);
187
188   info->flags = 0;
189
190   str = gst_caps_get_structure (caps, 0);
191
192   if (!gst_structure_has_name (str, "audio/x-raw"))
193     goto wrong_name;
194
195   if (!(s = gst_structure_get_string (str, "format")))
196     goto no_format;
197
198   format = gst_audio_format_from_string (s);
199   if (format == GST_AUDIO_FORMAT_UNKNOWN)
200     goto unknown_format;
201
202   if (!(s = gst_structure_get_string (str, "layout")))
203     goto no_layout;
204   if (g_str_equal (s, "interleaved"))
205     info->layout = GST_AUDIO_LAYOUT_INTERLEAVED;
206   else if (g_str_equal (s, "non-interleaved"))
207     info->layout = GST_AUDIO_LAYOUT_NON_INTERLEAVED;
208   else
209     goto unknown_layout;
210
211   if (!gst_structure_get_int (str, "rate", &rate))
212     goto no_rate;
213   if (!gst_structure_get_int (str, "channels", &channels))
214     goto no_channels;
215
216   if (!gst_structure_get (str, "channel-mask", GST_TYPE_BITMASK, &channel_mask,
217           NULL)) {
218     if (channels == 1) {
219       position[0] = GST_AUDIO_CHANNEL_POSITION_MONO;
220     } else if (channels == 2) {
221       position[0] = GST_AUDIO_CHANNEL_POSITION_FRONT_LEFT;
222       position[1] = GST_AUDIO_CHANNEL_POSITION_FRONT_RIGHT;
223     } else {
224       goto no_channel_mask;
225     }
226   } else if (channel_mask == 0) {
227     info->flags |= GST_AUDIO_FLAG_UNPOSITIONED;
228     for (i = 0; i < MIN (64, channels); i++)
229       position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
230   } else {
231     if (!gst_audio_channel_positions_from_mask (channels, channel_mask,
232             position))
233       goto invalid_channel_mask;
234   }
235
236   gst_audio_info_set_format (info, format, rate, channels, position);
237
238   return TRUE;
239
240   /* ERROR */
241 wrong_name:
242   {
243     GST_ERROR ("wrong name, expected audio/x-raw");
244     return FALSE;
245   }
246 no_format:
247   {
248     GST_ERROR ("no format given");
249     return FALSE;
250   }
251 unknown_format:
252   {
253     GST_ERROR ("unknown format given");
254     return FALSE;
255   }
256 no_layout:
257   {
258     GST_ERROR ("no layout given");
259     return FALSE;
260   }
261 unknown_layout:
262   {
263     GST_ERROR ("unknown layout given");
264     return FALSE;
265   }
266 no_rate:
267   {
268     GST_ERROR ("no rate property given");
269     return FALSE;
270   }
271 no_channels:
272   {
273     GST_ERROR ("no channels property given");
274     return FALSE;
275   }
276 no_channel_mask:
277   {
278     GST_ERROR ("no channel-mask property given");
279     return FALSE;
280   }
281 invalid_channel_mask:
282   {
283     GST_ERROR ("Invalid channel mask 0x%016" G_GINT64_MODIFIER
284         "x for %d channels", channel_mask, channels);
285     return FALSE;
286   }
287 }
288
289 /**
290  * gst_audio_info_to_caps:
291  * @info: a #GstAudioInfo
292  *
293  * Convert the values of @info into a #GstCaps.
294  *
295  * Returns: (transfer full): the new #GstCaps containing the
296  *          info of @info.
297  */
298 GstCaps *
299 gst_audio_info_to_caps (const GstAudioInfo * info)
300 {
301   GstCaps *caps;
302   const gchar *format;
303   const gchar *layout;
304   GstAudioFlags flags;
305
306   g_return_val_if_fail (info != NULL, NULL);
307   g_return_val_if_fail (info->finfo != NULL, NULL);
308   g_return_val_if_fail (info->finfo->format != GST_AUDIO_FORMAT_UNKNOWN, NULL);
309
310   format = gst_audio_format_to_string (info->finfo->format);
311   g_return_val_if_fail (format != NULL, NULL);
312
313   if (info->layout == GST_AUDIO_LAYOUT_INTERLEAVED)
314     layout = "interleaved";
315   else if (info->layout == GST_AUDIO_LAYOUT_NON_INTERLEAVED)
316     layout = "non-interleaved";
317   else
318     g_return_val_if_reached (NULL);
319
320   flags = info->flags;
321   if ((flags & GST_AUDIO_FLAG_UNPOSITIONED) && info->channels > 1
322       && info->position[0] != GST_AUDIO_CHANNEL_POSITION_NONE) {
323     flags &= ~GST_AUDIO_FLAG_UNPOSITIONED;
324     g_warning ("Unpositioned audio channel position flag set but "
325         "channel positions present");
326   } else if (!(flags & GST_AUDIO_FLAG_UNPOSITIONED) && info->channels > 1
327       && info->position[0] == GST_AUDIO_CHANNEL_POSITION_NONE) {
328     flags |= GST_AUDIO_FLAG_UNPOSITIONED;
329     g_warning ("Unpositioned audio channel position flag not set "
330         "but no channel positions present");
331   }
332
333   caps = gst_caps_new_simple ("audio/x-raw",
334       "format", G_TYPE_STRING, format,
335       "layout", G_TYPE_STRING, layout,
336       "rate", G_TYPE_INT, info->rate,
337       "channels", G_TYPE_INT, info->channels, NULL);
338
339   if (info->channels > 1
340       || info->position[0] != GST_AUDIO_CHANNEL_POSITION_MONO) {
341     guint64 channel_mask = 0;
342
343     if ((flags & GST_AUDIO_FLAG_UNPOSITIONED)) {
344       channel_mask = 0;
345     } else {
346       if (!gst_audio_channel_positions_to_mask (info->position, info->channels,
347               TRUE, &channel_mask))
348         goto invalid_channel_positions;
349     }
350
351     if (info->channels == 1
352         && info->position[0] == GST_AUDIO_CHANNEL_POSITION_MONO) {
353       /* Default mono special case */
354     } else {
355       gst_caps_set_simple (caps, "channel-mask", GST_TYPE_BITMASK, channel_mask,
356           NULL);
357     }
358   }
359
360   return caps;
361
362 invalid_channel_positions:
363   {
364     GST_ERROR ("Invalid channel positions");
365     gst_caps_unref (caps);
366     return NULL;
367   }
368 }
369
370 /**
371  * gst_audio_info_convert:
372  * @info: a #GstAudioInfo
373  * @src_fmt: #GstFormat of the @src_val
374  * @src_val: value to convert
375  * @dest_fmt: #GstFormat of the @dest_val
376  * @dest_val: pointer to destination value
377  *
378  * Converts among various #GstFormat types.  This function handles
379  * GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT.  For
380  * raw audio, GST_FORMAT_DEFAULT corresponds to audio frames.  This
381  * function can be used to handle pad queries of the type GST_QUERY_CONVERT.
382  *
383  * Returns: TRUE if the conversion was successful.
384  */
385 gboolean
386 gst_audio_info_convert (const GstAudioInfo * info,
387     GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
388 {
389   gboolean res = TRUE;
390   gint bpf, rate;
391
392   GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)",
393       src_val, gst_format_get_name (src_fmt), src_fmt,
394       gst_format_get_name (dest_fmt), dest_fmt);
395
396   if (src_fmt == dest_fmt || src_val == -1) {
397     *dest_val = src_val;
398     goto done;
399   }
400
401   /* get important info */
402   bpf = GST_AUDIO_INFO_BPF (info);
403   rate = GST_AUDIO_INFO_RATE (info);
404
405   if (bpf == 0 || rate == 0) {
406     GST_DEBUG ("no rate or bpf configured");
407     res = FALSE;
408     goto done;
409   }
410
411   switch (src_fmt) {
412     case GST_FORMAT_BYTES:
413       switch (dest_fmt) {
414         case GST_FORMAT_TIME:
415           *dest_val = GST_FRAMES_TO_CLOCK_TIME (src_val / bpf, rate);
416           break;
417         case GST_FORMAT_DEFAULT:
418           *dest_val = src_val / bpf;
419           break;
420         default:
421           res = FALSE;
422           break;
423       }
424       break;
425     case GST_FORMAT_DEFAULT:
426       switch (dest_fmt) {
427         case GST_FORMAT_TIME:
428           *dest_val = GST_FRAMES_TO_CLOCK_TIME (src_val, rate);
429           break;
430         case GST_FORMAT_BYTES:
431           *dest_val = src_val * bpf;
432           break;
433         default:
434           res = FALSE;
435           break;
436       }
437       break;
438     case GST_FORMAT_TIME:
439       switch (dest_fmt) {
440         case GST_FORMAT_DEFAULT:
441           *dest_val = GST_CLOCK_TIME_TO_FRAMES (src_val, rate);
442           break;
443         case GST_FORMAT_BYTES:
444           *dest_val = GST_CLOCK_TIME_TO_FRAMES (src_val, rate);
445           *dest_val *= bpf;
446           break;
447         default:
448           res = FALSE;
449           break;
450       }
451       break;
452     default:
453       res = FALSE;
454       break;
455   }
456 done:
457   GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, res, *dest_val);
458
459   return res;
460 }