#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; \
+ } \
} \
}
}
/* 16 -> 8 signed */
{
- gint16 in[] = { 0, 255, 256, 257 };
- gint8 out[] = { 0, 0, 1, 1 };
+ gint16 in[] = { 0, 127, 128, 256, 256 + 127, 256 + 128 };
+ gint8 out[] = { 0, 0, 1, 1, 1, 2 };
RUN_CONVERSION ("16 bit to 8 signed",
in, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE),
24, TRUE), in, get_int_caps (1, "BYTE_ORDER", 8, 8, TRUE)
);
}
+
+ /* 16 bit signed <-> unsigned */
+ {
+ gint16 in[] = { 0, 128, -128 };
+ guint16 out[] = { 32768, 32896, 32640 };
+ RUN_CONVERSION ("16 signed to 16 unsigned",
+ in, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE),
+ out, get_int_caps (1, "BYTE_ORDER", 16, 16, FALSE)
+ );
+ RUN_CONVERSION ("16 unsigned to 16 signed",
+ out, get_int_caps (1, "BYTE_ORDER", 16, 16, FALSE),
+ in, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE)
+ );
+ }
+
+ /* 16 bit signed <-> 8 in 16 bit signed */
+ {
+ gint16 in[] = { 0, 64 << 8, -64 << 8 };
+ gint16 out[] = { 0, 64, -64 };
+ RUN_CONVERSION ("16 signed to 8 in 16 signed",
+ in, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE),
+ out, get_int_caps (1, "BYTE_ORDER", 16, 8, TRUE)
+ );
+ RUN_CONVERSION ("8 in 16 signed to 16 signed",
+ out, get_int_caps (1, "BYTE_ORDER", 16, 8, TRUE),
+ in, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE)
+ );
+ }
+
+ /* 16 bit unsigned <-> 8 in 16 bit unsigned */
+ {
+ guint16 in[] = { 1 << 15, (1 << 15) - (64 << 8), (1 << 15) + (64 << 8) };
+ guint16 out[] = { 1 << 7, (1 << 7) - 64, (1 << 7) + 64 };
+ RUN_CONVERSION ("16 unsigned to 8 in 16 unsigned",
+ in, get_int_caps (1, "BYTE_ORDER", 16, 16, FALSE),
+ out, get_int_caps (1, "BYTE_ORDER", 16, 8, FALSE)
+ );
+ RUN_CONVERSION ("8 in 16 unsigned to 16 unsigned",
+ out, get_int_caps (1, "BYTE_ORDER", 16, 8, FALSE),
+ in, get_int_caps (1, "BYTE_ORDER", 16, 16, FALSE)
+ );
+ }
+
+ /* 32 bit signed -> 16 bit signed for rounding check */
+ {
+ gint32 in[] = { 0, G_MININT32, G_MAXINT32,
+ (32 << 16), (32 << 16) + (1 << 15), (32 << 16) - (1 << 15),
+ (32 << 16) + (2 << 15), (32 << 16) - (2 << 15),
+ (-32 << 16) + (1 << 15), (-32 << 16) - (1 << 15),
+ (-32 << 16) + (2 << 15), (-32 << 16) - (2 << 15),
+ (-32 << 16)
+ };
+ gint16 out[] = { 0, G_MININT16, G_MAXINT16,
+ 32, 33, 32,
+ 33, 31,
+ -32, -33,
+ -31, -33,
+ -32
+ };
+ RUN_CONVERSION ("32 signed to 16 signed for rounding",
+ in, get_int_caps (1, "BYTE_ORDER", 32, 32, TRUE),
+ out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE)
+ );
+ }
+
+ /* 32 bit signed -> 16 bit unsigned for rounding check */
+ {
+ gint32 in[] = { 0, G_MININT32, G_MAXINT32,
+ (32 << 16), (32 << 16) + (1 << 15), (32 << 16) - (1 << 15),
+ (32 << 16) + (2 << 15), (32 << 16) - (2 << 15),
+ (-32 << 16) + (1 << 15), (-32 << 16) - (1 << 15),
+ (-32 << 16) + (2 << 15), (-32 << 16) - (2 << 15),
+ (-32 << 16)
+ };
+ guint16 out[] = { (1 << 15), 0, G_MAXUINT16,
+ (1 << 15) + 32, (1 << 15) + 33, (1 << 15) + 32,
+ (1 << 15) + 33, (1 << 15) + 31,
+ (1 << 15) - 31, (1 << 15) - 32,
+ (1 << 15) - 31, (1 << 15) - 33,
+ (1 << 15) - 32
+ };
+ RUN_CONVERSION ("32 signed to 16 unsigned for rounding",
+ in, get_int_caps (1, "BYTE_ORDER", 32, 32, TRUE),
+ out, get_int_caps (1, "BYTE_ORDER", 16, 16, FALSE)
+ );
+ }
}
GST_END_TEST;
gdouble out[] = { 0.0,
4.6566128752457969e-10 * (gdouble) (-32768L << 16), /* ~ -1.0 */
4.6566128752457969e-10 * (gdouble) (16384L << 16), /* ~ 0.5 */
- 4.6566128752457969e-10 * (gdouble) (-16384L << 16), /* ~ -0.5 */
+ 4.6566128752457969e-10 * (gdouble) (-16384L << 16), /* ~ -0.5 */
};
RUN_CONVERSION ("16 signed to 64 float",
gdouble out[] = { 0.0,
4.6566128752457969e-10 * (gdouble) (-1L << 31), /* ~ -1.0 */
4.6566128752457969e-10 * (gdouble) (1L << 30), /* ~ 0.5 */
- 4.6566128752457969e-10 * (gdouble) (-1L << 30), /* ~ -0.5 */
+ 4.6566128752457969e-10 * (gdouble) (-1L << 30), /* ~ -0.5 */
};
RUN_CONVERSION ("32 signed to 64 float",