tizen 2.0 init
[framework/multimedia/gst-plugins-base0.10.git] / gst-libs / gst / audio / audio.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., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, 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 "audio.h"
31 #include "audio-enumtypes.h"
32
33 #include <gst/gststructure.h>
34
35 #include <string.h>
36
37 /**
38  * gst_audio_frame_byte_size:
39  * @pad: the #GstPad to get the caps from
40  *
41  * Calculate byte size of an audio frame.
42  *
43  * Returns: the byte size, or 0 if there was an error
44  */
45 int
46 gst_audio_frame_byte_size (GstPad * pad)
47 {
48   /* FIXME: this should be moved closer to the gstreamer core
49    * and be implemented for every mime type IMO
50    */
51
52   int width = 0;
53   int channels = 0;
54   const GstCaps *caps = NULL;
55   GstStructure *structure;
56
57   /* get caps of pad */
58   caps = GST_PAD_CAPS (pad);
59
60   if (caps == NULL) {
61     /* ERROR: could not get caps of pad */
62     g_warning ("gstaudio: could not get caps of pad %s:%s\n",
63         GST_DEBUG_PAD_NAME (pad));
64     return 0;
65   }
66
67   structure = gst_caps_get_structure (caps, 0);
68
69   gst_structure_get_int (structure, "width", &width);
70   gst_structure_get_int (structure, "channels", &channels);
71   return (width / 8) * channels;
72 }
73
74 /**
75  * gst_audio_frame_length:
76  * @pad: the #GstPad to get the caps from
77  * @buf: the #GstBuffer
78  *
79  * Calculate length of buffer in frames.
80  *
81  * Returns: 0 if there's an error, or the number of frames if everything's ok
82  */
83 long
84 gst_audio_frame_length (GstPad * pad, GstBuffer * buf)
85 {
86   /* FIXME: this should be moved closer to the gstreamer core
87    * and be implemented for every mime type IMO
88    */
89   int frame_byte_size = 0;
90
91   frame_byte_size = gst_audio_frame_byte_size (pad);
92   if (frame_byte_size == 0)
93     /* error */
94     return 0;
95   /* FIXME: this function assumes the buffer size to be a whole multiple
96    *        of the frame byte size
97    */
98   return GST_BUFFER_SIZE (buf) / frame_byte_size;
99 }
100
101 /**
102  * gst_audio_duration_from_pad_buffer:
103  * @pad: the #GstPad to get the caps from
104  * @buf: the #GstBuffer
105  *
106  * Calculate length in nanoseconds of audio buffer @buf based on capabilities of
107  * @pad.
108  *
109  * Returns: the length.
110  */
111 GstClockTime
112 gst_audio_duration_from_pad_buffer (GstPad * pad, GstBuffer * buf)
113 {
114   long bytes = 0;
115   int width = 0;
116   int channels = 0;
117   int rate = 0;
118
119   GstClockTime length;
120
121   const GstCaps *caps = NULL;
122   GstStructure *structure;
123
124   g_assert (GST_IS_BUFFER (buf));
125   /* get caps of pad */
126   caps = GST_PAD_CAPS (pad);
127   if (caps == NULL) {
128     /* ERROR: could not get caps of pad */
129     g_warning ("gstaudio: could not get caps of pad %s:%s\n",
130         GST_DEBUG_PAD_NAME (pad));
131     length = GST_CLOCK_TIME_NONE;
132   } else {
133     structure = gst_caps_get_structure (caps, 0);
134     bytes = GST_BUFFER_SIZE (buf);
135     gst_structure_get_int (structure, "width", &width);
136     gst_structure_get_int (structure, "channels", &channels);
137     gst_structure_get_int (structure, "rate", &rate);
138
139     g_assert (bytes != 0);
140     g_assert (width != 0);
141     g_assert (channels != 0);
142     g_assert (rate != 0);
143     length = (bytes * 8 * GST_SECOND) / (rate * channels * width);
144   }
145   return length;
146 }
147
148 /**
149  * gst_audio_is_buffer_framed:
150  * @pad: the #GstPad to get the caps from
151  * @buf: the #GstBuffer
152  *
153  * Check if the buffer size is a whole multiple of the frame size.
154  *
155  * Returns: %TRUE if buffer size is multiple.
156  */
157 gboolean
158 gst_audio_is_buffer_framed (GstPad * pad, GstBuffer * buf)
159 {
160   if (GST_BUFFER_SIZE (buf) % gst_audio_frame_byte_size (pad) == 0)
161     return TRUE;
162   else
163     return FALSE;
164 }
165
166 /* _getcaps helper functions
167  * sets structure fields to default for audio type
168  * flag determines which structure fields to set to default
169  * keep these functions in sync with the templates in audio.h
170  */
171
172 /* private helper function
173  * sets a list on the structure
174  * pass in structure, fieldname for the list, type of the list values,
175  * number of list values, and each of the values, terminating with NULL
176  */
177 static void
178 _gst_audio_structure_set_list (GstStructure * structure,
179     const gchar * fieldname, GType type, int number, ...)
180 {
181   va_list varargs;
182   GValue value = { 0 };
183   GArray *array;
184   int j;
185
186   g_return_if_fail (structure != NULL);
187
188   g_value_init (&value, GST_TYPE_LIST);
189   array = g_value_peek_pointer (&value);
190
191   va_start (varargs, number);
192
193   for (j = 0; j < number; ++j) {
194     int i;
195     gboolean b;
196
197     GValue list_value = { 0 };
198
199     switch (type) {
200       case G_TYPE_INT:
201         i = va_arg (varargs, int);
202
203         g_value_init (&list_value, G_TYPE_INT);
204         g_value_set_int (&list_value, i);
205         break;
206       case G_TYPE_BOOLEAN:
207         b = va_arg (varargs, gboolean);
208         g_value_init (&list_value, G_TYPE_BOOLEAN);
209         g_value_set_boolean (&list_value, b);
210         break;
211       default:
212         g_warning
213             ("_gst_audio_structure_set_list: LIST of given type not implemented.");
214     }
215     g_array_append_val (array, list_value);
216
217   }
218   gst_structure_set_value (structure, fieldname, &value);
219   va_end (varargs);
220 }
221
222 /**
223  * gst_audio_structure_set_int:
224  * @structure: a #GstStructure
225  * @flag: a set of #GstAudioFieldFlag
226  *
227  * Do not use anymore.
228  *
229  * Deprecated: use gst_structure_set()
230  */
231 #ifndef GST_REMOVE_DEPRECATED
232 #ifdef GST_DISABLE_DEPRECATED
233 typedef enum
234 {
235   GST_AUDIO_FIELD_RATE = (1 << 0),
236   GST_AUDIO_FIELD_CHANNELS = (1 << 1),
237   GST_AUDIO_FIELD_ENDIANNESS = (1 << 2),
238   GST_AUDIO_FIELD_WIDTH = (1 << 3),
239   GST_AUDIO_FIELD_DEPTH = (1 << 4),
240   GST_AUDIO_FIELD_SIGNED = (1 << 5),
241 } GstAudioFieldFlag;
242 void
243 gst_audio_structure_set_int (GstStructure * structure, GstAudioFieldFlag flag);
244 #endif /* GST_DISABLE_DEPRECATED */
245
246 void
247 gst_audio_structure_set_int (GstStructure * structure, GstAudioFieldFlag flag)
248 {
249   /* was added here:
250    * http://webcvs.freedesktop.org/gstreamer/gst-plugins-base/gst-libs/gst/audio/audio.c?r1=1.16&r2=1.17
251    * but it is not used
252    */
253   if (flag & GST_AUDIO_FIELD_RATE)
254     gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
255         NULL);
256   if (flag & GST_AUDIO_FIELD_CHANNELS)
257     gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
258         NULL);
259   if (flag & GST_AUDIO_FIELD_ENDIANNESS)
260     _gst_audio_structure_set_list (structure, "endianness", G_TYPE_INT, 2,
261         G_LITTLE_ENDIAN, G_BIG_ENDIAN, NULL);
262   if (flag & GST_AUDIO_FIELD_WIDTH)
263     _gst_audio_structure_set_list (structure, "width", G_TYPE_INT, 3, 8, 16, 32,
264         NULL);
265   if (flag & GST_AUDIO_FIELD_DEPTH)
266     gst_structure_set (structure, "depth", GST_TYPE_INT_RANGE, 1, 32, NULL);
267   if (flag & GST_AUDIO_FIELD_SIGNED)
268     _gst_audio_structure_set_list (structure, "signed", G_TYPE_BOOLEAN, 2, TRUE,
269         FALSE, NULL);
270 }
271 #endif /* GST_REMOVE_DEPRECATED */
272
273 #define SINT (GST_AUDIO_FORMAT_FLAG_INTEGER | GST_AUDIO_FORMAT_FLAG_SIGNED)
274 #define UINT (GST_AUDIO_FORMAT_FLAG_INTEGER)
275
276 #define MAKE_FORMAT(str,flags,end,width,depth,silent) \
277   { GST_AUDIO_FORMAT_ ##str, G_STRINGIFY(str), flags, end, width, depth, silent }
278
279 #define SILENT_0         { 0, 0, 0, 0, 0, 0, 0, 0 }
280 #define SILENT_U8        { 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80 }
281 #define SILENT_U16LE     { 0x00, 0x80,  0x00, 0x80,  0x00, 0x80,  0x00, 0x80 }
282 #define SILENT_U16BE     { 0x80, 0x00,  0x80, 0x00,  0x80, 0x00,  0x80, 0x00 }
283 #define SILENT_U24_32LE  { 0x00, 0x00, 0x80, 0x00,  0x00, 0x00, 0x80, 0x00 }
284 #define SILENT_U24_32BE  { 0x00, 0x80, 0x00, 0x00,  0x00, 0x80, 0x00, 0x00 }
285 #define SILENT_U32LE     { 0x00, 0x00, 0x00, 0x80,  0x00, 0x00, 0x00, 0x80 }
286 #define SILENT_U32BE     { 0x80, 0x00, 0x00, 0x00,  0x80, 0x00, 0x00, 0x00 }
287 #define SILENT_U24LE     { 0x00, 0x00, 0x80,  0x00, 0x00, 0x80 }
288 #define SILENT_U24BE     { 0x80, 0x00, 0x00,  0x80, 0x00, 0x00 }
289 #define SILENT_U20LE     { 0x00, 0x00, 0x08,  0x00, 0x00, 0x08 }
290 #define SILENT_U20BE     { 0x08, 0x00, 0x00,  0x08, 0x00, 0x00 }
291 #define SILENT_U18LE     { 0x00, 0x00, 0x02,  0x00, 0x00, 0x02 }
292 #define SILENT_U18BE     { 0x02, 0x00, 0x00,  0x02, 0x00, 0x00 }
293
294 static GstAudioFormatInfo formats[] = {
295   {GST_AUDIO_FORMAT_UNKNOWN, "UNKNOWN", 0, 0, 0, 0},
296   /* 8 bit */
297   MAKE_FORMAT (S8, SINT, 0, 8, 8, SILENT_0),
298   MAKE_FORMAT (U8, UINT, 0, 8, 8, SILENT_U8),
299   /* 16 bit */
300   MAKE_FORMAT (S16LE, SINT, G_LITTLE_ENDIAN, 16, 16, SILENT_0),
301   MAKE_FORMAT (S16BE, SINT, G_BIG_ENDIAN, 16, 16, SILENT_0),
302   MAKE_FORMAT (U16LE, UINT, G_LITTLE_ENDIAN, 16, 16, SILENT_U16LE),
303   MAKE_FORMAT (U16BE, UINT, G_BIG_ENDIAN, 16, 16, SILENT_U16BE),
304   /* 24 bit in low 3 bytes of 32 bits */
305   MAKE_FORMAT (S24_32LE, SINT, G_LITTLE_ENDIAN, 32, 24, SILENT_0),
306   MAKE_FORMAT (S24_32BE, SINT, G_BIG_ENDIAN, 32, 24, SILENT_0),
307   MAKE_FORMAT (U24_32LE, UINT, G_LITTLE_ENDIAN, 32, 24, SILENT_U24_32LE),
308   MAKE_FORMAT (U24_32BE, UINT, G_BIG_ENDIAN, 32, 24, SILENT_U24_32BE),
309   /* 32 bit */
310   MAKE_FORMAT (S32LE, SINT, G_LITTLE_ENDIAN, 32, 32, SILENT_0),
311   MAKE_FORMAT (S32BE, SINT, G_BIG_ENDIAN, 32, 32, SILENT_0),
312   MAKE_FORMAT (U32LE, UINT, G_LITTLE_ENDIAN, 32, 32, SILENT_U32LE),
313   MAKE_FORMAT (U32BE, UINT, G_BIG_ENDIAN, 32, 32, SILENT_U32BE),
314   /* 24 bit in 3 bytes */
315   MAKE_FORMAT (S24LE, SINT, G_LITTLE_ENDIAN, 24, 24, SILENT_0),
316   MAKE_FORMAT (S24BE, SINT, G_BIG_ENDIAN, 24, 24, SILENT_0),
317   MAKE_FORMAT (U24LE, UINT, G_LITTLE_ENDIAN, 24, 24, SILENT_U24LE),
318   MAKE_FORMAT (U24BE, UINT, G_BIG_ENDIAN, 24, 24, SILENT_U24BE),
319   /* 20 bit in 3 bytes */
320   MAKE_FORMAT (S20LE, SINT, G_LITTLE_ENDIAN, 24, 20, SILENT_0),
321   MAKE_FORMAT (S20BE, SINT, G_BIG_ENDIAN, 24, 20, SILENT_0),
322   MAKE_FORMAT (U20LE, UINT, G_LITTLE_ENDIAN, 24, 20, SILENT_U20LE),
323   MAKE_FORMAT (U20BE, UINT, G_BIG_ENDIAN, 24, 20, SILENT_U20BE),
324   /* 18 bit in 3 bytes */
325   MAKE_FORMAT (S18LE, SINT, G_LITTLE_ENDIAN, 24, 18, SILENT_0),
326   MAKE_FORMAT (S18BE, SINT, G_BIG_ENDIAN, 24, 18, SILENT_0),
327   MAKE_FORMAT (U18LE, UINT, G_LITTLE_ENDIAN, 24, 18, SILENT_U18LE),
328   MAKE_FORMAT (U18BE, UINT, G_BIG_ENDIAN, 24, 18, SILENT_U18BE),
329   /* float */
330   MAKE_FORMAT (F32LE, GST_AUDIO_FORMAT_FLAG_FLOAT, G_LITTLE_ENDIAN, 32, 32,
331       SILENT_0),
332   MAKE_FORMAT (F32BE, GST_AUDIO_FORMAT_FLAG_FLOAT, G_BIG_ENDIAN, 32, 32,
333       SILENT_0),
334   MAKE_FORMAT (F64LE, GST_AUDIO_FORMAT_FLAG_FLOAT, G_LITTLE_ENDIAN, 64, 64,
335       SILENT_0),
336   MAKE_FORMAT (F64BE, GST_AUDIO_FORMAT_FLAG_FLOAT, G_BIG_ENDIAN, 64, 64,
337       SILENT_0)
338 };
339
340 static GstAudioFormat
341 gst_audio_format_from_caps_structure (const GstStructure * s)
342 {
343   gint endianness, width, depth;
344   guint i;
345
346   if (gst_structure_has_name (s, "audio/x-raw-int")) {
347     gboolean sign;
348
349     if (!gst_structure_get_boolean (s, "signed", &sign))
350       goto missing_field_signed;
351
352     if (!gst_structure_get_int (s, "endianness", &endianness))
353       goto missing_field_endianness;
354
355     if (!gst_structure_get_int (s, "width", &width))
356       goto missing_field_width;
357
358     if (!gst_structure_get_int (s, "depth", &depth))
359       goto missing_field_depth;
360
361     for (i = 0; i < G_N_ELEMENTS (formats); i++) {
362       if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (&formats[i]) &&
363           sign == GST_AUDIO_FORMAT_INFO_IS_SIGNED (&formats[i]) &&
364           GST_AUDIO_FORMAT_INFO_ENDIANNESS (&formats[i]) == endianness &&
365           GST_AUDIO_FORMAT_INFO_WIDTH (&formats[i]) == width &&
366           GST_AUDIO_FORMAT_INFO_DEPTH (&formats[i]) == depth) {
367         return GST_AUDIO_FORMAT_INFO_FORMAT (&formats[i]);
368       }
369     }
370   } else if (gst_structure_has_name (s, "audio/x-raw-float")) {
371     /* fallbacks are for backwards compatibility (is this needed at all?) */
372     if (!gst_structure_get_int (s, "endianness", &endianness)) {
373       GST_WARNING ("float audio caps without endianness %" GST_PTR_FORMAT, s);
374       endianness = G_BYTE_ORDER;
375     }
376
377     if (!gst_structure_get_int (s, "width", &width)) {
378       GST_WARNING ("float audio caps without width %" GST_PTR_FORMAT, s);
379       width = 32;
380     }
381
382     for (i = 0; i < G_N_ELEMENTS (formats); i++) {
383       if (GST_AUDIO_FORMAT_INFO_IS_FLOAT (&formats[i]) &&
384           GST_AUDIO_FORMAT_INFO_ENDIANNESS (&formats[i]) == endianness &&
385           GST_AUDIO_FORMAT_INFO_WIDTH (&formats[i]) == width) {
386         return GST_AUDIO_FORMAT_INFO_FORMAT (&formats[i]);
387       }
388     }
389   }
390
391   /* no match */
392   return GST_AUDIO_FORMAT_UNKNOWN;
393
394 missing_field_signed:
395   {
396     GST_ERROR ("missing 'signed' field in audio caps %" GST_PTR_FORMAT, s);
397     return GST_AUDIO_FORMAT_UNKNOWN;
398   }
399 missing_field_endianness:
400   {
401     GST_ERROR ("missing 'endianness' field in audio caps %" GST_PTR_FORMAT, s);
402     return GST_AUDIO_FORMAT_UNKNOWN;
403   }
404 missing_field_depth:
405   {
406     GST_ERROR ("missing 'depth' field in audio caps %" GST_PTR_FORMAT, s);
407     return GST_AUDIO_FORMAT_UNKNOWN;
408   }
409 missing_field_width:
410   {
411     GST_ERROR ("missing 'width' field in audio caps %" GST_PTR_FORMAT, s);
412     return GST_AUDIO_FORMAT_UNKNOWN;
413   }
414 }
415
416 /* FIXME: remove these if we don't actually go for deep alloc positions */
417 void
418 gst_audio_info_init (GstAudioInfo * info)
419 {
420   memset (info, 0, sizeof (GstAudioInfo));
421 }
422
423 void
424 gst_audio_info_clear (GstAudioInfo * info)
425 {
426   memset (info, 0, sizeof (GstAudioInfo));
427 }
428
429 GstAudioInfo *
430 gst_audio_info_copy (GstAudioInfo * info)
431 {
432   return (GstAudioInfo *) g_slice_copy (sizeof (GstAudioInfo), info);
433 }
434
435 void
436 gst_audio_info_free (GstAudioInfo * info)
437 {
438   g_slice_free (GstAudioInfo, info);
439 }
440
441 static void
442 gst_audio_info_set_format (GstAudioInfo * info, GstAudioFormat format,
443     gint rate, gint channels)
444 {
445   const GstAudioFormatInfo *finfo;
446
447   g_return_if_fail (info != NULL);
448   g_return_if_fail (format != GST_AUDIO_FORMAT_UNKNOWN);
449
450   finfo = &formats[format];
451
452   info->flags = 0;
453   info->finfo = finfo;
454   info->rate = rate;
455   info->channels = channels;
456   info->bpf = (finfo->width * channels) / 8;
457 }
458
459 /* from multichannel.c */
460 void priv_gst_audio_info_fill_default_channel_positions (GstAudioInfo * info);
461
462 /**
463  * gst_audio_info_from_caps:
464  * @info: a #GstAudioInfo
465  * @caps: a #GstCaps
466  *
467  * Parse @caps and update @info.
468  *
469  * Returns: TRUE if @caps could be parsed
470  *
471  * Since: 0.10.36
472  */
473 gboolean
474 gst_audio_info_from_caps (GstAudioInfo * info, const GstCaps * caps)
475 {
476   GstStructure *str;
477   GstAudioFormat format;
478   gint rate, channels;
479   const GValue *pos_val_arr, *pos_val_entry;
480   gint i;
481
482   g_return_val_if_fail (info != NULL, FALSE);
483   g_return_val_if_fail (caps != NULL, FALSE);
484   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
485
486   GST_DEBUG ("parsing caps %" GST_PTR_FORMAT, caps);
487
488   str = gst_caps_get_structure (caps, 0);
489
490   format = gst_audio_format_from_caps_structure (str);
491   if (format == GST_AUDIO_FORMAT_UNKNOWN)
492     goto unknown_format;
493
494   if (!gst_structure_get_int (str, "rate", &rate))
495     goto no_rate;
496   if (!gst_structure_get_int (str, "channels", &channels))
497     goto no_channels;
498
499   gst_audio_info_set_format (info, format, rate, channels);
500
501   pos_val_arr = gst_structure_get_value (str, "channel-positions");
502   if (pos_val_arr) {
503     if (channels <= G_N_ELEMENTS (info->position)) {
504       for (i = 0; i < channels; i++) {
505         pos_val_entry = gst_value_array_get_value (pos_val_arr, i);
506         info->position[i] = g_value_get_enum (pos_val_entry);
507       }
508     } else {
509       /* for that many channels, the positions are always NONE */
510       for (i = 0; i < G_N_ELEMENTS (info->position); i++)
511         info->position[i] = GST_AUDIO_CHANNEL_POSITION_NONE;
512       info->flags |= GST_AUDIO_FLAG_DEFAULT_POSITIONS;
513     }
514   } else {
515     info->flags |= GST_AUDIO_FLAG_DEFAULT_POSITIONS;
516     priv_gst_audio_info_fill_default_channel_positions (info);
517   }
518
519   return TRUE;
520
521   /* ERROR */
522 unknown_format:
523   {
524     GST_ERROR ("unknown format given");
525     return FALSE;
526   }
527 no_rate:
528   {
529     GST_ERROR ("no rate property given");
530     return FALSE;
531   }
532 no_channels:
533   {
534     GST_ERROR ("no channels property given");
535     return FALSE;
536   }
537 }
538
539 /**
540  * gst_audio_info_to_caps:
541  * @info: a #GstAudioInfo
542  *
543  * Convert the values of @info into a #GstCaps.
544  *
545  * Returns: (transfer full): the new #GstCaps containing the
546  *          info of @info.
547  *
548  * Since: 0.10.36
549  */
550 GstCaps *
551 gst_audio_info_to_caps (GstAudioInfo * info)
552 {
553   GstCaps *caps;
554
555   g_return_val_if_fail (info != NULL, NULL);
556   g_return_val_if_fail (info->finfo != NULL, NULL);
557   g_return_val_if_fail (info->finfo->format != GST_AUDIO_FORMAT_UNKNOWN, NULL);
558
559   if (GST_AUDIO_FORMAT_INFO_IS_INTEGER (info->finfo)) {
560     caps = gst_caps_new_simple ("audio/x-raw-int",
561         "width", G_TYPE_INT, GST_AUDIO_INFO_WIDTH (info),
562         "depth", G_TYPE_INT, GST_AUDIO_INFO_DEPTH (info),
563         "endianness", G_TYPE_INT,
564         GST_AUDIO_FORMAT_INFO_ENDIANNESS (info->finfo), "signed",
565         G_TYPE_BOOLEAN, GST_AUDIO_FORMAT_INFO_IS_SIGNED (info->finfo), "rate",
566         G_TYPE_INT, GST_AUDIO_INFO_RATE (info), "channels", G_TYPE_INT,
567         GST_AUDIO_INFO_CHANNELS (info), NULL);
568   } else if (GST_AUDIO_FORMAT_INFO_IS_FLOAT (info->finfo)) {
569     caps = gst_caps_new_simple ("audio/x-raw-float",
570         "width", G_TYPE_INT, GST_AUDIO_INFO_WIDTH (info),
571         "endianness", G_TYPE_INT,
572         GST_AUDIO_FORMAT_INFO_ENDIANNESS (info->finfo), "rate", G_TYPE_INT,
573         GST_AUDIO_INFO_RATE (info), "channels", G_TYPE_INT,
574         GST_AUDIO_INFO_CHANNELS (info), NULL);
575   } else {
576     GST_ERROR ("unknown audio format, neither integer nor float");
577     return NULL;
578   }
579
580   if (info->channels > 2) {
581     GValue pos_val_arr = { 0 }
582     , pos_val_entry = {
583     0};
584     GstStructure *str;
585     gint i;
586
587     /* build gvaluearray from positions */
588     g_value_init (&pos_val_arr, GST_TYPE_ARRAY);
589     g_value_init (&pos_val_entry, GST_TYPE_AUDIO_CHANNEL_POSITION);
590     for (i = 0; i < info->channels; i++) {
591       /* if we have many many channels, all positions are NONE */
592       if (info->channels <= 64)
593         g_value_set_enum (&pos_val_entry, info->position[i]);
594       else
595         g_value_set_enum (&pos_val_entry, GST_AUDIO_CHANNEL_POSITION_NONE);
596
597       gst_value_array_append_value (&pos_val_arr, &pos_val_entry);
598     }
599     g_value_unset (&pos_val_entry);
600
601     /* add to structure */
602     str = gst_caps_get_structure (caps, 0);
603     gst_structure_set_value (str, "channel-positions", &pos_val_arr);
604     g_value_unset (&pos_val_arr);
605   }
606
607   return caps;
608 }
609
610 /**
611  * gst_audio_format_convert:
612  * @info: a #GstAudioInfo
613  * @src_format: #GstFormat of the @src_value
614  * @src_value: value to convert
615  * @dest_format: #GstFormat of the @dest_value
616  * @dest_value: pointer to destination value
617  *
618  * Converts among various #GstFormat types.  This function handles
619  * GST_FORMAT_BYTES, GST_FORMAT_TIME, and GST_FORMAT_DEFAULT.  For
620  * raw audio, GST_FORMAT_DEFAULT corresponds to audio frames.  This
621  * function can be used to handle pad queries of the type GST_QUERY_CONVERT.
622  *
623  * Returns: TRUE if the conversion was successful.
624  *
625  * Since: 0.10.36
626  */
627 gboolean
628 gst_audio_info_convert (GstAudioInfo * info,
629     GstFormat src_fmt, gint64 src_val, GstFormat dest_fmt, gint64 * dest_val)
630 {
631   gboolean res = TRUE;
632   gint bpf, rate;
633
634   GST_DEBUG ("converting value %" G_GINT64_FORMAT " from %s (%d) to %s (%d)",
635       src_val, gst_format_get_name (src_fmt), src_fmt,
636       gst_format_get_name (dest_fmt), dest_fmt);
637
638   if (src_fmt == dest_fmt || src_val == -1) {
639     *dest_val = src_val;
640     goto done;
641   }
642
643   /* get important info */
644   bpf = GST_AUDIO_INFO_BPF (info);
645   rate = GST_AUDIO_INFO_RATE (info);
646
647   if (bpf == 0 || rate == 0) {
648     GST_DEBUG ("no rate or bpf configured");
649     res = FALSE;
650     goto done;
651   }
652
653   switch (src_fmt) {
654     case GST_FORMAT_BYTES:
655       switch (dest_fmt) {
656         case GST_FORMAT_TIME:
657           *dest_val = GST_FRAMES_TO_CLOCK_TIME (src_val / bpf, rate);
658           break;
659         case GST_FORMAT_DEFAULT:
660           *dest_val = src_val / bpf;
661           break;
662         default:
663           res = FALSE;
664           break;
665       }
666       break;
667     case GST_FORMAT_DEFAULT:
668       switch (dest_fmt) {
669         case GST_FORMAT_TIME:
670           *dest_val = GST_FRAMES_TO_CLOCK_TIME (src_val, rate);
671           break;
672         case GST_FORMAT_BYTES:
673           *dest_val = src_val * bpf;
674           break;
675         default:
676           res = FALSE;
677           break;
678       }
679       break;
680     case GST_FORMAT_TIME:
681       switch (dest_fmt) {
682         case GST_FORMAT_DEFAULT:
683           *dest_val = GST_CLOCK_TIME_TO_FRAMES (src_val, rate);
684           break;
685         case GST_FORMAT_BYTES:
686           *dest_val = GST_CLOCK_TIME_TO_FRAMES (src_val, rate);
687           *dest_val *= bpf;
688           break;
689         default:
690           res = FALSE;
691           break;
692       }
693       break;
694     default:
695       res = FALSE;
696       break;
697   }
698 done:
699   GST_DEBUG ("ret=%d result %" G_GINT64_FORMAT, res, *dest_val);
700
701   return res;
702 }
703
704 /**
705  * gst_audio_buffer_clip:
706  * @buffer: The buffer to clip.
707  * @segment: Segment in %GST_FORMAT_TIME or %GST_FORMAT_DEFAULT to which the buffer should be clipped.
708  * @rate: sample rate.
709  * @frame_size: size of one audio frame in bytes.
710  *
711  * Clip the buffer to the given %GstSegment.
712  *
713  * After calling this function the caller does not own a reference to 
714  * @buffer anymore.
715  *
716  * Returns: %NULL if the buffer is completely outside the configured segment,
717  * otherwise the clipped buffer is returned.
718  *
719  * If the buffer has no timestamp, it is assumed to be inside the segment and
720  * is not clipped 
721  *
722  * Since: 0.10.14
723  */
724 GstBuffer *
725 gst_audio_buffer_clip (GstBuffer * buffer, GstSegment * segment, gint rate,
726     gint frame_size)
727 {
728   GstBuffer *ret;
729   GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
730   guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE;
731   guint8 *data;
732   guint size;
733
734   gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end =
735       TRUE;
736
737   g_return_val_if_fail (segment->format == GST_FORMAT_TIME ||
738       segment->format == GST_FORMAT_DEFAULT, buffer);
739   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
740
741   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
742     /* No timestamp - assume the buffer is completely in the segment */
743     return buffer;
744
745   /* Get copies of the buffer metadata to change later. 
746    * Calculate the missing values for the calculations,
747    * they won't be changed later though. */
748
749   data = GST_BUFFER_DATA (buffer);
750   size = GST_BUFFER_SIZE (buffer);
751
752   timestamp = GST_BUFFER_TIMESTAMP (buffer);
753   if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
754     duration = GST_BUFFER_DURATION (buffer);
755   } else {
756     change_duration = FALSE;
757     duration = gst_util_uint64_scale (size / frame_size, GST_SECOND, rate);
758   }
759
760   if (GST_BUFFER_OFFSET_IS_VALID (buffer)) {
761     offset = GST_BUFFER_OFFSET (buffer);
762   } else {
763     change_offset = FALSE;
764     offset = 0;
765   }
766
767   if (GST_BUFFER_OFFSET_END_IS_VALID (buffer)) {
768     offset_end = GST_BUFFER_OFFSET_END (buffer);
769   } else {
770     change_offset_end = FALSE;
771     offset_end = offset + size / frame_size;
772   }
773
774   if (segment->format == GST_FORMAT_TIME) {
775     /* Handle clipping for GST_FORMAT_TIME */
776
777     gint64 start, stop, cstart, cstop, diff;
778
779     start = timestamp;
780     stop = timestamp + duration;
781
782     if (gst_segment_clip (segment, GST_FORMAT_TIME,
783             start, stop, &cstart, &cstop)) {
784
785       diff = cstart - start;
786       if (diff > 0) {
787         timestamp = cstart;
788
789         if (change_duration)
790           duration -= diff;
791
792         diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
793         if (change_offset)
794           offset += diff;
795         data += diff * frame_size;
796         size -= diff * frame_size;
797       }
798
799       diff = stop - cstop;
800       if (diff > 0) {
801         /* duration is always valid if stop is valid */
802         duration -= diff;
803
804         diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
805         if (change_offset_end)
806           offset_end -= diff;
807         size -= diff * frame_size;
808       }
809     } else {
810       gst_buffer_unref (buffer);
811       return NULL;
812     }
813   } else {
814     /* Handle clipping for GST_FORMAT_DEFAULT */
815     gint64 start, stop, cstart, cstop, diff;
816
817     g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer);
818
819     start = offset;
820     stop = offset_end;
821
822     if (gst_segment_clip (segment, GST_FORMAT_DEFAULT,
823             start, stop, &cstart, &cstop)) {
824
825       diff = cstart - start;
826       if (diff > 0) {
827         offset = cstart;
828
829         timestamp = gst_util_uint64_scale (cstart, GST_SECOND, rate);
830
831         if (change_duration)
832           duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
833
834         data += diff * frame_size;
835         size -= diff * frame_size;
836       }
837
838       diff = stop - cstop;
839       if (diff > 0) {
840         offset_end = cstop;
841
842         if (change_duration)
843           duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
844
845         size -= diff * frame_size;
846       }
847     } else {
848       gst_buffer_unref (buffer);
849       return NULL;
850     }
851   }
852
853   /* Get a metadata writable buffer and apply all changes */
854   ret = gst_buffer_make_metadata_writable (buffer);
855
856   GST_BUFFER_TIMESTAMP (ret) = timestamp;
857   GST_BUFFER_SIZE (ret) = size;
858   GST_BUFFER_DATA (ret) = data;
859
860   if (change_duration)
861     GST_BUFFER_DURATION (ret) = duration;
862   if (change_offset)
863     GST_BUFFER_OFFSET (ret) = offset;
864   if (change_offset_end)
865     GST_BUFFER_OFFSET_END (ret) = offset_end;
866
867   return ret;
868 }