gio: Remove unused function
[platform/upstream/gstreamer.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 #endif /* GST_DISABLE_DEPRECATED */
241
242 void
243 gst_audio_structure_set_int (GstStructure * structure, GstAudioFieldFlag flag)
244 {
245   /* was added here:
246    * http://webcvs.freedesktop.org/gstreamer/gst-plugins-base/gst-libs/gst/audio/audio.c?r1=1.16&r2=1.17
247    * but it is not used
248    */
249   if (flag & GST_AUDIO_FIELD_RATE)
250     gst_structure_set (structure, "rate", GST_TYPE_INT_RANGE, 1, G_MAXINT,
251         NULL);
252   if (flag & GST_AUDIO_FIELD_CHANNELS)
253     gst_structure_set (structure, "channels", GST_TYPE_INT_RANGE, 1, G_MAXINT,
254         NULL);
255   if (flag & GST_AUDIO_FIELD_ENDIANNESS)
256     _gst_audio_structure_set_list (structure, "endianness", G_TYPE_INT, 2,
257         G_LITTLE_ENDIAN, G_BIG_ENDIAN, NULL);
258   if (flag & GST_AUDIO_FIELD_WIDTH)
259     _gst_audio_structure_set_list (structure, "width", G_TYPE_INT, 3, 8, 16, 32,
260         NULL);
261   if (flag & GST_AUDIO_FIELD_DEPTH)
262     gst_structure_set (structure, "depth", GST_TYPE_INT_RANGE, 1, 32, NULL);
263   if (flag & GST_AUDIO_FIELD_SIGNED)
264     _gst_audio_structure_set_list (structure, "signed", G_TYPE_BOOLEAN, 2, TRUE,
265         FALSE, NULL);
266 }
267 #endif /* GST_REMOVE_DEPRECATED */
268
269 /**
270  * gst_audio_buffer_clip:
271  * @buffer: The buffer to clip.
272  * @segment: Segment in %GST_FORMAT_TIME or %GST_FORMAT_DEFAULT to which the buffer should be clipped.
273  * @rate: sample rate.
274  * @frame_size: size of one audio frame in bytes.
275  *
276  * Clip the the buffer to the given %GstSegment.
277  *
278  * After calling this function the caller does not own a reference to 
279  * @buffer anymore.
280  *
281  * Returns: %NULL if the buffer is completely outside the configured segment,
282  * otherwise the clipped buffer is returned.
283  *
284  * If the buffer has no timestamp, it is assumed to be inside the segment and
285  * is not clipped 
286  *
287  * Since: 0.10.14
288  */
289 GstBuffer *
290 gst_audio_buffer_clip (GstBuffer * buffer, GstSegment * segment, gint rate,
291     gint frame_size)
292 {
293   GstBuffer *ret;
294   GstClockTime timestamp = GST_CLOCK_TIME_NONE, duration = GST_CLOCK_TIME_NONE;
295   guint64 offset = GST_BUFFER_OFFSET_NONE, offset_end = GST_BUFFER_OFFSET_NONE;
296   guint8 *data;
297   guint size;
298
299   gboolean change_duration = TRUE, change_offset = TRUE, change_offset_end =
300       TRUE;
301
302   g_return_val_if_fail (segment->format == GST_FORMAT_TIME ||
303       segment->format == GST_FORMAT_DEFAULT, buffer);
304   g_return_val_if_fail (GST_IS_BUFFER (buffer), NULL);
305
306   if (!GST_BUFFER_TIMESTAMP_IS_VALID (buffer))
307     /* No timestamp - assume the buffer is completely in the segment */
308     return buffer;
309
310   /* Get copies of the buffer metadata to change later. 
311    * Calculate the missing values for the calculations,
312    * they won't be changed later though. */
313
314   data = GST_BUFFER_DATA (buffer);
315   size = GST_BUFFER_SIZE (buffer);
316
317   timestamp = GST_BUFFER_TIMESTAMP (buffer);
318   if (GST_BUFFER_DURATION_IS_VALID (buffer)) {
319     duration = GST_BUFFER_DURATION (buffer);
320   } else {
321     change_duration = FALSE;
322     duration = gst_util_uint64_scale (size / frame_size, GST_SECOND, rate);
323   }
324
325   if (GST_BUFFER_OFFSET_IS_VALID (buffer)) {
326     offset = GST_BUFFER_OFFSET (buffer);
327   } else {
328     change_offset = FALSE;
329     offset = 0;
330   }
331
332   if (GST_BUFFER_OFFSET_END_IS_VALID (buffer)) {
333     offset_end = GST_BUFFER_OFFSET_END (buffer);
334   } else {
335     change_offset_end = FALSE;
336     offset_end = offset + size / frame_size;
337   }
338
339   if (segment->format == GST_FORMAT_TIME) {
340     /* Handle clipping for GST_FORMAT_TIME */
341
342     gint64 start, stop, cstart, cstop, diff;
343
344     start = timestamp;
345     stop = timestamp + duration;
346
347     if (gst_segment_clip (segment, GST_FORMAT_TIME,
348             start, stop, &cstart, &cstop)) {
349
350       diff = cstart - start;
351       if (diff > 0) {
352         timestamp = cstart;
353
354         if (change_duration)
355           duration -= diff;
356
357         diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
358         if (change_offset)
359           offset += diff;
360         data += diff * frame_size;
361         size -= diff * frame_size;
362       }
363
364       diff = stop - cstop;
365       if (diff > 0) {
366         /* duration is always valid if stop is valid */
367         duration -= diff;
368
369         diff = gst_util_uint64_scale (diff, rate, GST_SECOND);
370         if (change_offset_end)
371           offset_end -= diff;
372         size -= diff * frame_size;
373       }
374     } else {
375       gst_buffer_unref (buffer);
376       return NULL;
377     }
378   } else {
379     /* Handle clipping for GST_FORMAT_DEFAULT */
380     gint64 start, stop, cstart, cstop, diff;
381
382     g_return_val_if_fail (GST_BUFFER_OFFSET_IS_VALID (buffer), buffer);
383
384     start = offset;
385     stop = offset_end;
386
387     if (gst_segment_clip (segment, GST_FORMAT_DEFAULT,
388             start, stop, &cstart, &cstop)) {
389
390       diff = cstart - start;
391       if (diff > 0) {
392         offset = cstart;
393
394         timestamp = gst_util_uint64_scale (cstart, GST_SECOND, rate);
395
396         if (change_duration)
397           duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
398
399         data += diff * frame_size;
400         size -= diff * frame_size;
401       }
402
403       diff = stop - cstop;
404       if (diff > 0) {
405         offset_end = cstop;
406
407         if (change_duration)
408           duration -= gst_util_uint64_scale (diff, GST_SECOND, rate);
409
410         size -= diff * frame_size;
411       }
412     } else {
413       gst_buffer_unref (buffer);
414       return NULL;
415     }
416   }
417
418   /* Get a metadata writable buffer and apply all changes */
419   ret = gst_buffer_make_metadata_writable (buffer);
420
421   GST_BUFFER_TIMESTAMP (ret) = timestamp;
422   GST_BUFFER_SIZE (ret) = size;
423   GST_BUFFER_DATA (ret) = data;
424
425   if (change_duration)
426     GST_BUFFER_DURATION (ret) = duration;
427   if (change_offset)
428     GST_BUFFER_OFFSET (ret) = offset;
429   if (change_offset_end)
430     GST_BUFFER_OFFSET_END (ret) = offset_end;
431
432   return ret;
433 }