summaryrefslogtreecommitdiff
path: root/gst/audioconvert/audioconvert.c
diff options
context:
space:
mode:
authorSebastian Dröge <slomo@circular-chaos.org>2007-03-27 12:44:14 +0000
committerSebastian Dröge <slomo@circular-chaos.org>2007-03-27 12:44:14 +0000
commit293a9c09b858faeda971300a8f00a439b73aeb37 (patch)
treeb5697504d5bdcc774e26f0d95a785bf2606dab40 /gst/audioconvert/audioconvert.c
parente1544977a6c6413e9ca39a9044139dba3b4e9b94 (diff)
downloadgstreamer-plugins-base-293a9c09b858faeda971300a8f00a439b73aeb37.tar.gz
gst/audioconvert/audioconvert.c: Add docs to the integer pack functions and implement proper rounding. Before we had ...
Original commit message from CVS: * gst/audioconvert/audioconvert.c: Add docs to the integer pack functions and implement proper rounding. Before we had rounding towards negative infinity, i.e. always the smaller number was taken. Now we use natural rounding, i.e. rounding to the nearest integer and to the one with the largest absolute value for X.5. The old rounding introduced some minor distortions. Fixes #420079 * tests/check/elements/audioconvert.c: (GST_START_TEST): Fix one unit test that assumed the old rounding and added unit tests for checking signed/unsigned int16 <-> signed/unsigned int16 with depth 8, one for signed int16 <-> unsigned int16 and one for the new rounding from signed int32 to signed/unsigned int16.
Diffstat (limited to 'gst/audioconvert/audioconvert.c')
-rw-r--r--gst/audioconvert/audioconvert.c49
1 files changed, 44 insertions, 5 deletions
diff --git a/gst/audioconvert/audioconvert.c b/gst/audioconvert/audioconvert.c
index cfdfda9bb..cadb82773 100644
--- a/gst/audioconvert/audioconvert.c
+++ b/gst/audioconvert/audioconvert.c
@@ -121,17 +121,56 @@ MAKE_UNPACK_FUNC (s32_be, 4, 0, READ32_FROM_BE);
#define MAKE_PACK_FUNC_NAME(name) \
audio_convert_pack_##name
+/*
+ * These functions convert the signed 32 bit integers to the
+ * target format. For this to work the following steps are done:
+ *
+ * 1) If the output format is smaller than 32 bit we add 0.5LSB of
+ * the target format (i.e. 1<<(scale-1)) to get proper rounding.
+ * Shifting will result in rounding towards negative infinity (for
+ * signed values) or zero (for unsigned values). As we might overflow
+ * an overflow check is performed.
+ * Additionally, if our target format is signed and the value is smaller
+ * than zero we decrease it by one to round -X.5 downwards.
+ * This leads to the following rounding:
+ * -1.2 => -1 1.2 => 1
+ * -1.5 => -2 1.5 => 2
+ * -1.7 => -2 1.7 => 2
+ * 2) If the output format is unsigned we will XOR the sign bit. This
+ * will do the same as if we add 1<<31.
+ * 3) Afterwards we shift to the target depth. It's necessary to left-shift
+ * on signed values here to get arithmetical shifting.
+ * 4) This is then written into our target array by the corresponding write
+ * function for the target width.
+ */
+
#define MAKE_PACK_FUNC(name, stride, sign, WRITE_FUNC) \
static void \
MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst, \
gint scale, gint count) \
{ \
guint8 *p = (guint8 *)dst; \
- guint32 tmp; \
- for (;count; count--) { \
- tmp = (*src++ ^ (sign)) >> scale; \
- WRITE_FUNC (p, tmp); \
- p+=stride; \
+ gint32 tmp; \
+ if (scale > 0) { \
+ guint32 bias = 1 << (scale - 1); \
+ for (;count; count--) { \
+ tmp = *src++; \
+ if (tmp > 0 && G_MAXINT32 - tmp < bias) \
+ tmp = G_MAXINT32; \
+ else \
+ tmp += bias; \
+ if (sign == 0 && tmp < 0) \
+ tmp--; \
+ tmp = ((tmp) ^ (sign)) >> scale; \
+ WRITE_FUNC (p, tmp); \
+ p+=stride; \
+ } \
+ } else { \
+ for (;count; count--) { \
+ tmp = (*src++ ^ (sign)); \
+ WRITE_FUNC (p, tmp); \
+ p+=stride; \
+ } \
} \
}