Git 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 /**
36  * gst_audio_frame_byte_size:
37  * @pad: the #GstPad to get the caps from
38  *
39  * Calculate byte size of an audio frame.
40  *
41  * Returns: the byte size, or 0 if there was an error
42  */
43 int
44 gst_audio_frame_byte_size (GstPad * pad)
45 {
46   /* FIXME: this should be moved closer to the gstreamer core
47    * and be implemented for every mime type IMO
48    */
49
50   int width = 0;
51   int channels = 0;
52   const GstCaps *caps = NULL;
53   GstStructure *structure;
54
55   /* get caps of pad */
56   caps = GST_PAD_CAPS (pad);
57
58   if (caps == NULL) {
59     /* ERROR: could not get caps of pad */
60     g_warning ("gstaudio: could not get caps of pad %s:%s\n",
61         GST_DEBUG_PAD_NAME (pad));
62     return 0;
63   }
64
65   structure = gst_caps_get_structure (caps, 0);
66
67   gst_structure_get_int (structure, "width", &width);
68   gst_structure_get_int (structure, "channels", &channels);
69   return (width / 8) * channels;
70 }
71
72 /**
73  * gst_audio_frame_length:
74  * @pad: the #GstPad to get the caps from
75  * @buf: the #GstBuffer
76  *
77  * Calculate length of buffer in frames.
78  *
79  * Returns: 0 if there's an error, or the number of frames if everything's ok
80  */
81 long
82 gst_audio_frame_length (GstPad * pad, GstBuffer * buf)
83 {
84   /* FIXME: this should be moved closer to the gstreamer core
85    * and be implemented for every mime type IMO
86    */
87   int frame_byte_size = 0;
88
89   frame_byte_size = gst_audio_frame_byte_size (pad);
90   if (frame_byte_size == 0)
91     /* error */
92     return 0;
93   /* FIXME: this function assumes the buffer size to be a whole multiple
94    *        of the frame byte size
95    */
96   return GST_BUFFER_SIZE (buf) / frame_byte_size;
97 }
98
99 /**
100  * gst_audio_duration_from_pad_buffer:
101  * @pad: the #GstPad to get the caps from
102  * @buf: the #GstBuffer
103  *
104  * Calculate length in nanoseconds of audio buffer @buf based on capabilities of
105  * @pad.
106  *
107  * Returns: the length.
108  */
109 GstClockTime
110 gst_audio_duration_from_pad_buffer (GstPad * pad, GstBuffer * buf)
111 {
112   long bytes = 0;
113   int width = 0;
114   int channels = 0;
115   int rate = 0;
116
117   GstClockTime length;
118
119   const GstCaps *caps = NULL;
120   GstStructure *structure;
121
122   g_assert (GST_IS_BUFFER (buf));
123   /* get caps of pad */
124   caps = GST_PAD_CAPS (pad);
125   if (caps == NULL) {
126     /* ERROR: could not get caps of pad */
127     g_warning ("gstaudio: could not get caps of pad %s:%s\n",
128         GST_DEBUG_PAD_NAME (pad));
129     length = GST_CLOCK_TIME_NONE;
130   } else {
131     structure = gst_caps_get_structure (caps, 0);
132     bytes = GST_BUFFER_SIZE (buf);
133     gst_structure_get_int (structure, "width", &width);
134     gst_structure_get_int (structure, "channels", &channels);
135     gst_structure_get_int (structure, "rate", &rate);
136
137     g_assert (bytes != 0);
138     g_assert (width != 0);
139     g_assert (channels != 0);
140     g_assert (rate != 0);
141     length = (bytes * 8 * GST_SECOND) / (rate * channels * width);
142   }
143   return length;
144 }
145
146 /**
147  * gst_audio_is_buffer_framed:
148  * @pad: the #GstPad to get the caps from
149  * @buf: the #GstBuffer
150  *
151  * Check if the buffer size is a whole multiple of the frame size.
152  *
153  * Returns: %TRUE if buffer size is multiple.
154  */
155 gboolean
156 gst_audio_is_buffer_framed (GstPad * pad, GstBuffer * buf)
157 {
158   if (GST_BUFFER_SIZE (buf) % gst_audio_frame_byte_size (pad) == 0)
159     return TRUE;
160   else
161     return FALSE;
162 }
163
164 /* _getcaps helper functions
165  * sets structure fields to default for audio type
166  * flag determines which structure fields to set to default
167  * keep these functions in sync with the templates in audio.h
168  */
169
170 /* private helper function
171  * sets a list on the structure
172  * pass in structure, fieldname for the list, type of the list values,
173  * number of list values, and each of the values, terminating with NULL
174  */
175 static void
176 _gst_audio_structure_set_list (GstStructure * structure,
177     const gchar * fieldname, GType type, int number, ...)
178 {
179   va_list varargs;
180   GValue value = { 0 };
181   GArray *array;
182   int j;
183
184   g_return_if_fail (structure != NULL);
185
186   g_value_init (&value, GST_TYPE_LIST);
187   array = g_value_peek_pointer (&value);
188
189   va_start (varargs, number);
190
191   for (j = 0; j < number; ++j) {
192     int i;
193     gboolean b;
194
195     GValue list_value = { 0 };
196
197     switch (type) {
198       case G_TYPE_INT:
199         i = va_arg (varargs, int);
200
201         g_value_init (&list_value, G_TYPE_INT);
202         g_value_set_int (&list_value, i);
203         break;
204       case G_TYPE_BOOLEAN:
205         b = va_arg (varargs, gboolean);
206         g_value_init (&list_value, G_TYPE_BOOLEAN);
207         g_value_set_boolean (&list_value, b);
208         break;
209       default:
210         g_warning
211             ("_gst_audio_structure_set_list: LIST of given type not implemented.");
212     }
213     g_array_append_val (array, list_value);
214
215   }
216   gst_structure_set_value (structure, fieldname, &value);
217   va_end (varargs);
218 }
219
220 /**
221  * gst_audio_structure_set_int:
222  * @structure: a #GstStructure
223  * @flag: a set of #GstAudioFieldFlag
224  *
225  * Do not use anymore.
226  *
227  * Deprecated: use gst_structure_set()
228  */
229 #ifndef GST_REMOVE_DEPRECATED
230 #ifdef GST_DISABLE_DEPRECATED
231 typedef enum
232 {
233   GST_AUDIO_FIELD_RATE = (1 << 0),
234   GST_AUDIO_FIELD_CHANNELS = (1 << 1),
235   GST_AUDIO_FIELD_ENDIANNESS = (1 << 2),
236   GST_AUDIO_FIELD_WIDTH = (1 << 3),
237   GST_AUDIO_FIELD_DEPTH = (1 << 4),
238   GST_AUDIO_FIELD_SIGNED = (1 << 5),
239 } GstAudioFieldFlag;
240 void
241 gst_audio_structure_set_int (GstStructure * structure, GstAudioFieldFlag flag);
242 #endif /* GST_DISABLE_DEPRECATED */
243
244 void
245 gst_audio_structure_set_int (GstStructure * structure, GstAudioFieldFlag flag)
246 {
247   /* was added here:
248    * http://webcvs.freedesktop.org/gstreamer/gst-plugins-base/gst-libs/gst/audio/audio.c?r1=1.16&r2=1.17
249    * but it is not used
250    */
251   if (flag & GST_AUDIO_FIELD_RATE)
252     gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
253         NULL);
254   if (flag & GST_AUDIO_FIELD_CHANNELS)
255     gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
256         NULL);
257   if (flag & GST_AUDIO_FIELD_ENDIANNESS)
258     _gst_audio_structure_set_list (structure, "endianness", G_TYPE_INT, 2,
259         G_LITTLE_ENDIAN, G_BIG_ENDIAN, NULL);
260   if (flag & GST_AUDIO_FIELD_WIDTH)
261     _gst_audio_structure_set_list (structure, "width", G_TYPE_INT, 3, 8, 16, 32,
262         NULL);
263   if (flag & GST_AUDIO_FIELD_DEPTH)
264     gst_structure_set (structure, "depth", GST_TYPE_INT_RANGE, 1, 32, NULL);
265   if (flag & GST_AUDIO_FIELD_SIGNED)
266     _gst_audio_structure_set_list (structure, "signed", G_TYPE_BOOLEAN, 2, TRUE,
267         FALSE, NULL);
268 }
269 #endif /* GST_REMOVE_DEPRECATED */
270
271 /**
272  * gst_audio_buffer_clip:
273  * @buffer: The buffer to clip.
274  * @segment: Segment in %GST_FORMAT_TIME or %GST_FORMAT_DEFAULT to which the buffer should be clipped.
275  * @rate: sample rate.
276  * @frame_size: size of one audio frame in bytes.
277  *
278  * Clip the the buffer to the given %GstSegment.
279  *
280  * After calling this function the caller does not own a reference to 
281  * @buffer anymore.
282  *
283  * Returns: %NULL if the buffer is completely outside the configured segment,
284  * otherwise the clipped buffer is returned.
285  *
286  * If the buffer has no timestamp, it is assumed to be inside the segment and
287  * is not clipped 
288  *
289  * Since: 0.10.14
290  */
291 GstBuffer *
292 gst_audio_buffer_clip (GstBuffer * buffer, GstSegment * segment, gint rate,
293     gint frame_size)
294 {
295   GstBuffer *ret;
296   GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
297   guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE;
298   guint8 *data;
299   guint size;
300
301   gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end =
302       TRUE;
303
304   g_return_val_if_fail (segment->format == GST_FORMAT_TIME ||
305       segment->format == GST_FORMAT_DEFAULT, buffer);
306   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
307
308   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
309     /* No timestamp - assume the buffer is completely in the segment */
310     return buffer;
311
312   /* Get copies of the buffer metadata to change later. 
313    * Calculate the missing values for the calculations,
314    * they won't be changed later though. */
315
316   data = GST_BUFFER_DATA (buffer);
317   size = GST_BUFFER_SIZE (buffer);
318
319   timestamp = GST_BUFFER_TIMESTAMP (buffer);
320   if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
321     duration = GST_BUFFER_DURATION (buffer);
322   } else {
323     change_duration = FALSE;
324     duration = gst_util_uint64_scale (size / frame_size, GST_SECOND, rate);
325   }
326
327   if (GST_BUFFER_OFFSET_IS_VALID (buffer)) {
328     offset = GST_BUFFER_OFFSET (buffer);
329   } else {
330     change_offset = FALSE;
331     offset = 0;
332   }
333
334   if (GST_BUFFER_OFFSET_END_IS_VALID (buffer)) {
335     offset_end = GST_BUFFER_OFFSET_END (buffer);
336   } else {
337     change_offset_end = FALSE;
338     offset_end = offset + size / frame_size;
339   }
340
341   if (segment->format == GST_FORMAT_TIME) {
342     /* Handle clipping for GST_FORMAT_TIME */
343
344     gint64 start, stop, cstart, cstop, diff;
345
346     start = timestamp;
347     stop = timestamp + duration;
348
349     if (gst_segment_clip (segment, GST_FORMAT_TIME,
350             start, stop, &cstart, &cstop)) {
351
352       diff = cstart - start;
353       if (diff > 0) {
354         timestamp = cstart;
355
356         if (change_duration)
357           duration -= diff;
358
359         diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
360         if (change_offset)
361           offset += diff;
362         data += diff * frame_size;
363         size -= diff * frame_size;
364       }
365
366       diff = stop - cstop;
367       if (diff > 0) {
368         /* duration is always valid if stop is valid */
369         duration -= diff;
370
371         diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
372         if (change_offset_end)
373           offset_end -= diff;
374         size -= diff * frame_size;
375       }
376     } else {
377       gst_buffer_unref (buffer);
378       return NULL;
379     }
380   } else {
381     /* Handle clipping for GST_FORMAT_DEFAULT */
382     gint64 start, stop, cstart, cstop, diff;
383
384     g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer);
385
386     start = offset;
387     stop = offset_end;
388
389     if (gst_segment_clip (segment, GST_FORMAT_DEFAULT,
390             start, stop, &cstart, &cstop)) {
391
392       diff = cstart - start;
393       if (diff > 0) {
394         offset = cstart;
395
396         timestamp = gst_util_uint64_scale (cstart, GST_SECOND, rate);
397
398         if (change_duration)
399           duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
400
401         data += diff * frame_size;
402         size -= diff * frame_size;
403       }
404
405       diff = stop - cstop;
406       if (diff > 0) {
407         offset_end = cstop;
408
409         if (change_duration)
410           duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
411
412         size -= diff * frame_size;
413       }
414     } else {
415       gst_buffer_unref (buffer);
416       return NULL;
417     }
418   }
419
420   /* Get a metadata writable buffer and apply all changes */
421   ret = gst_buffer_make_metadata_writable (buffer);
422
423   GST_BUFFER_TIMESTAMP (ret) = timestamp;
424   GST_BUFFER_SIZE (ret) = size;
425   GST_BUFFER_DATA (ret) = data;
426
427   if (change_duration)
428     GST_BUFFER_DURATION (ret) = duration;
429   if (change_offset)
430     GST_BUFFER_OFFSET (ret) = offset;
431   if (change_offset_end)
432     GST_BUFFER_OFFSET_END (ret) = offset_end;
433
434   return ret;
435 }