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