gst/audioconvert/: Cleanups, librarify a bit, optimize, better negotiation and more.
[platform/upstream/gst-plugins-base.git] / gst / audioconvert / audioconvert.c
1 /* GStreamer
2  * Copyright (C) 2005 Wim Taymans <wim at fluendo dot com>
3  *
4  * audioconvert.c: Convert audio to different audio formats automatically
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25
26 #include <string.h>
27
28 #include "gstchannelmix.h"
29 #include "audioconvert.h"
30
31 /* int to float conversion: int2float(i) = 1 / (2^31-1) * i */
32 #define INT2FLOAT(i) (4.6566128752457969e-10 * ((gfloat)i))
33
34 #define UNPACK_CODE(type, corr, E_FUNC)                                 \
35   type* p = (type *) src;                                               \
36   gint64 tmp;                                                           \
37   for (;count; count--) {                                               \
38     tmp = ((gint64) E_FUNC (*p) - corr) * scale;                        \
39     *dst++ = CLAMP (tmp, -((gint64) 1 << 32), (gint64) 0x7FFFFFFF);     \
40     p++;                                                                \
41   }
42
43 #define MAKE_UNPACK_FUNC_NAME(name)                                     \
44 audio_convert_unpack_##name
45
46 /* unsigned case */
47 #define MAKE_UNPACK_FUNC_U(name, type, E_FUNC)                          \
48 static void                                                             \
49 MAKE_UNPACK_FUNC_NAME (name) (gpointer src, gint32 *dst,                \
50         gint64 scale, gint count)                                       \
51 {                                                                       \
52   UNPACK_CODE(type, (1 << (sizeof (type) * 8 - 1)), E_FUNC);            \
53 }
54
55 /* signed case */
56 #define MAKE_UNPACK_FUNC_S(name, type, E_FUNC)                          \
57 static void                                                             \
58 MAKE_UNPACK_FUNC_NAME (name) (gpointer src, gint32 *dst,                \
59         gint64 scale, gint count)                                       \
60 {                                                                       \
61   UNPACK_CODE(type, 0, E_FUNC);                                         \
62 }
63
64 MAKE_UNPACK_FUNC_U (u8, guint8, /* nothing */ )
65     MAKE_UNPACK_FUNC_S (s8, gint8, /* nothing */ )
66     MAKE_UNPACK_FUNC_U (u16_le, guint16, GUINT16_FROM_LE)
67     MAKE_UNPACK_FUNC_S (s16_le, gint16, GINT16_FROM_LE)
68     MAKE_UNPACK_FUNC_U (u16_be, guint16, GUINT16_FROM_BE)
69     MAKE_UNPACK_FUNC_S (s16_be, gint16, GINT16_FROM_BE)
70     MAKE_UNPACK_FUNC_U (u32_le, guint32, GUINT32_FROM_LE)
71     MAKE_UNPACK_FUNC_S (s32_le, gint32, GINT32_FROM_LE)
72     MAKE_UNPACK_FUNC_U (u32_be, guint32, GUINT32_FROM_BE)
73     MAKE_UNPACK_FUNC_S (s32_be, gint32, GINT32_FROM_BE)
74
75 /* FIXME 24 bits */
76 #if 0
77      gint64 cur = 0;
78
79         /* FIXME */
80
81         /* Read 24-bits LE/BE into signed 64 host-endian */
82 if (this->sinkcaps.endianness == G_LITTLE_ENDIAN)
83 {
84 cur = src[0] | (src[1] << 8) | (src[2] << 16);
85 } else {
86   cur = src[2] | (src[1] << 8) | (src[0] << 16);
87 }
88
89         /* Sign extend */
90 if ((this->sinkcaps.sign)
91     && (cur & (1 << (this->sinkcaps.depth - 1))))
92   cur |= ((gint64) (-1)) ^ ((1 << this->sinkcaps.depth) - 1);
93
94 src -= 3;
95 #endif
96
97 static void
98 MAKE_UNPACK_FUNC_NAME (float) (gpointer src, gint32 * dst,
99     gint64 scale, gint count)
100 {
101   gfloat *p = (gfloat *) src;
102   gfloat temp;
103
104   for (; count; count--) {
105     temp = *p++ * 2147483647.0f + .5;
106     *dst++ = (gint32) CLAMP (temp, -2147483648ll, 2147483647ll);
107   }
108 }
109
110 #define PACK_CODE(type, corr, E_FUNC)                                   \
111   type* p = (type *) dst;                                               \
112   gint32 scale = (32 - depth);                                          \
113   for (;count; count--) {                                               \
114     *p = E_FUNC ((type)((*src) >> scale) + corr);                       \
115     p++; src++;                                                         \
116   }
117
118 #define MAKE_PACK_FUNC_NAME(name)                                       \
119 audio_convert_pack_##name
120
121 #define MAKE_PACK_FUNC_U(name, type, E_FUNC)                            \
122 static void                                                             \
123 MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst,                  \
124         gint depth, gint count)                                         \
125 {                                                                       \
126   PACK_CODE (type, (1 << (depth - 1)), E_FUNC);                         \
127 }
128
129 #define MAKE_PACK_FUNC_S(name, type, E_FUNC)                            \
130 static void                                                             \
131 MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst,                  \
132         gint depth, gint count)                                         \
133 {                                                                       \
134   PACK_CODE (type, 0, E_FUNC);                                          \
135 }
136
137 MAKE_PACK_FUNC_U (u8, guint8, /* nothing */ );
138 MAKE_PACK_FUNC_S (s8, gint8, /* nothing */ );
139 MAKE_PACK_FUNC_U (u16_le, guint16, GUINT16_TO_LE);
140 MAKE_PACK_FUNC_S (s16_le, gint16, GINT16_TO_LE);
141 MAKE_PACK_FUNC_U (u16_be, guint16, GUINT16_TO_BE);
142 MAKE_PACK_FUNC_S (s16_be, gint16, GINT16_TO_BE);
143 MAKE_PACK_FUNC_U (u32_le, guint32, GUINT32_TO_LE);
144 MAKE_PACK_FUNC_S (s32_le, gint32, GINT32_TO_LE);
145 MAKE_PACK_FUNC_U (u32_be, guint32, GUINT32_TO_BE);
146 MAKE_PACK_FUNC_S (s32_be, gint32, GINT32_TO_BE);
147
148 static void
149 MAKE_PACK_FUNC_NAME (float) (gint32 * src, gpointer dst, gint depth, gint count)
150 {
151   gfloat *p = (gfloat *) dst;
152
153   for (; count; count--) {
154     *p++ = INT2FLOAT (*src++);
155   }
156 }
157
158 static AudioConvertUnpack unpack_funcs[] = {
159   MAKE_UNPACK_FUNC_NAME (u8),
160   MAKE_UNPACK_FUNC_NAME (s8),
161   MAKE_UNPACK_FUNC_NAME (u8),
162   MAKE_UNPACK_FUNC_NAME (s8),
163   MAKE_UNPACK_FUNC_NAME (u16_le),
164   MAKE_UNPACK_FUNC_NAME (s16_le),
165   MAKE_UNPACK_FUNC_NAME (u16_be),
166   MAKE_UNPACK_FUNC_NAME (s16_be),
167   NULL,
168   NULL,
169   NULL,
170   NULL,
171   MAKE_UNPACK_FUNC_NAME (u32_le),
172   MAKE_UNPACK_FUNC_NAME (s32_le),
173   MAKE_UNPACK_FUNC_NAME (u32_be),
174   MAKE_UNPACK_FUNC_NAME (s32_be),
175   MAKE_UNPACK_FUNC_NAME (float),
176 };
177
178 static AudioConvertPack pack_funcs[] = {
179   MAKE_PACK_FUNC_NAME (u8),
180   MAKE_PACK_FUNC_NAME (s8),
181   MAKE_PACK_FUNC_NAME (u8),
182   MAKE_PACK_FUNC_NAME (s8),
183   MAKE_PACK_FUNC_NAME (u16_le),
184   MAKE_PACK_FUNC_NAME (s16_le),
185   MAKE_PACK_FUNC_NAME (u16_be),
186   MAKE_PACK_FUNC_NAME (s16_be),
187   NULL,
188   NULL,
189   NULL,
190   NULL,
191   MAKE_PACK_FUNC_NAME (u32_le),
192   MAKE_PACK_FUNC_NAME (s32_le),
193   MAKE_PACK_FUNC_NAME (u32_be),
194   MAKE_PACK_FUNC_NAME (s32_be),
195   MAKE_PACK_FUNC_NAME (float),
196 };
197
198 static gint
199 audio_convert_get_func_index (AudioConvertFmt * fmt)
200 {
201   gint index = 0;
202
203   if (fmt->is_int) {
204     index += (fmt->width / 8 - 1) * 4;
205     index += fmt->endianness == G_LITTLE_ENDIAN ? 0 : 2;
206     index += fmt->sign ? 1 : 0;
207   } else {
208     index = 16;
209   }
210   return index;
211 }
212
213 static gboolean
214 check_default (AudioConvertFmt * fmt)
215 {
216   return (fmt->width == 32 && fmt->depth == 32 &&
217       fmt->endianness == G_BYTE_ORDER && fmt->sign == TRUE);
218 }
219
220 gboolean
221 audio_convert_clean_fmt (AudioConvertFmt * fmt)
222 {
223   g_return_val_if_fail (fmt != NULL, FALSE);
224
225   g_free (fmt->pos);
226   fmt->pos = NULL;
227
228   return TRUE;
229 }
230
231
232 gboolean
233 audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in,
234     AudioConvertFmt * out)
235 {
236   gint idx;
237
238   g_return_val_if_fail (ctx != NULL, FALSE);
239   g_return_val_if_fail (in != NULL, FALSE);
240   g_return_val_if_fail (out != NULL, FALSE);
241
242   /* first clean the existing context */
243   audio_convert_clean_context (ctx);
244
245   ctx->in = *in;
246   ctx->out = *out;
247
248   gst_channel_mix_setup_matrix (ctx);
249
250   idx = audio_convert_get_func_index (in);
251   if (!(ctx->unpack = unpack_funcs[idx]))
252     goto not_supported;
253
254   idx = audio_convert_get_func_index (out);
255   if (!(ctx->pack = pack_funcs[idx]))
256     goto not_supported;
257
258   /* check if input is in default format */
259   ctx->in_default = check_default (in);
260   /* check if channel mixer is passthrough */
261   ctx->mix_passthrough = gst_channel_mix_passthrough (ctx);
262   /* check if output is in default format */
263   ctx->out_default = check_default (out);
264
265   ctx->scale = ((gint64) 1 << (32 - in->depth));
266   ctx->depth = out->depth;
267
268   return TRUE;
269
270 not_supported:
271   {
272     return FALSE;
273   }
274 }
275
276 gboolean
277 audio_convert_clean_context (AudioConvertCtx * ctx)
278 {
279   g_return_val_if_fail (ctx != NULL, FALSE);
280
281   audio_convert_clean_fmt (&ctx->in);
282   audio_convert_clean_fmt (&ctx->out);
283   gst_channel_mix_unset_matrix (ctx);
284
285   g_free (ctx->tmpbuf);
286   ctx->tmpbuf = NULL;
287
288   return TRUE;
289 }
290
291 gboolean
292 audio_convert_get_sizes (AudioConvertCtx * ctx, gint samples, gint * srcsize,
293     gint * dstsize)
294 {
295   g_return_val_if_fail (ctx != NULL, FALSE);
296
297   if (srcsize)
298     *srcsize = samples * ctx->in.unit_size;
299   if (dstsize)
300     *dstsize = samples * ctx->out.unit_size;
301
302   return TRUE;
303 }
304
305 static gpointer
306 get_temp_buffer (AudioConvertCtx * ctx, gpointer src, gint srcsize,
307     gboolean writable, gint tmpsize)
308 {
309   gpointer result;
310
311   if (srcsize >= tmpsize && writable) {
312     result = src;
313   } else {
314     if (ctx->tmpbufsize < tmpsize) {
315       ctx->tmpbuf = g_realloc (ctx->tmpbuf, tmpsize);
316       ctx->tmpbufsize = tmpsize;
317     }
318     result = ctx->tmpbuf;
319   }
320   return result;
321 }
322
323 gboolean
324 audio_convert_convert (AudioConvertCtx * ctx, gpointer src,
325     gpointer dst, gint samples, gboolean src_writable)
326 {
327   gint insize;
328   gboolean final;
329   gpointer buf;
330   gint bufsize;
331   gboolean bufwritable;
332   gpointer tmpdst;
333   gint tmpsize;
334
335   g_return_val_if_fail (ctx != NULL, FALSE);
336   g_return_val_if_fail (src != NULL, FALSE);
337   g_return_val_if_fail (dst != NULL, FALSE);
338   g_return_val_if_fail (samples >= 0, FALSE);
339
340   if (samples == 0)
341     return TRUE;
342
343   insize = ctx->in.unit_size * samples;
344   tmpsize = insize * 32 / ctx->in.width;
345
346   /* this is our source data, we start with the input src data. */
347   buf = src;
348   bufsize = insize;
349   bufwritable = src_writable;
350
351   if (!ctx->in_default) {
352     /* check if final conversion */
353     final = (ctx->out_default && ctx->mix_passthrough);
354
355     if (final)
356       tmpdst = dst;
357     else
358       tmpdst = get_temp_buffer (ctx, buf, bufsize, bufwritable, tmpsize);
359
360     ctx->unpack (buf, tmpdst, ctx->scale, samples * ctx->in.channels);
361
362     if (!final) {
363       /* new source data, it is writable */
364       buf = tmpdst;
365       bufsize = tmpsize;
366       bufwritable = TRUE;
367     }
368   }
369
370   if (!ctx->mix_passthrough) {
371     /* see if we need an intermediate step */
372     final = ctx->out_default;
373
374     if (final)
375       tmpdst = dst;
376     else
377       tmpdst = get_temp_buffer (ctx, buf, bufsize, bufwritable, tmpsize);
378
379     /* convert */
380     gst_channel_mix_mix (ctx, buf, tmpdst, samples);
381
382     if (!final) {
383       buf = tmpdst;
384     }
385   }
386
387   if (!ctx->out_default) {
388     /* output always to dst buffer */
389     ctx->pack (buf, dst, ctx->depth, samples * ctx->out.channels);
390   }
391
392   return TRUE;
393 }