with some minor changes

Original commit message from CVS:
Patch by: René Stadler <mail at renestadler dot de>
with some minor changes
* gst-libs/gst/floatcast/floatcast.h:
Use more efficient float endianness conversion functions that don't
involve 2 function calls per value.
* gst/audioconvert/audioconvert.c: (audio_convert_get_func_index),
(check_default), (audio_convert_prepare_context):
* gst/audioconvert/gstaudioconvert.c:
(gst_audio_convert_parse_caps), (make_lossless_changes):
Support non-native endianness floats as input and output.
Fixes #339838.
* tests/check/elements/audioconvert.c: (verify_convert),
(GST_START_TEST):
Add unit tests for the non-native endianness float conversions.
This commit is contained in:
René Stadler 2007-03-29 18:42:34 +00:00 committed by Sebastian Dröge
parent 76462ceb45
commit 6ac8ff9ec3
5 changed files with 254 additions and 163 deletions

View file

@ -1,3 +1,21 @@
2007-03-29 Sebastian Dröge <slomo@circular-chaos.org>
Patch by: René Stadler <mail at renestadler dot de>
with some minor changes
* gst-libs/gst/floatcast/floatcast.h:
Use more efficient float endianness conversion functions that don't
involve 2 function calls per value.
* gst/audioconvert/audioconvert.c: (audio_convert_get_func_index),
(check_default), (audio_convert_prepare_context):
* gst/audioconvert/gstaudioconvert.c:
(gst_audio_convert_parse_caps), (make_lossless_changes):
Support non-native endianness floats as input and output.
Fixes #339838.
* tests/check/elements/audioconvert.c: (verify_convert),
(GST_START_TEST):
Add unit tests for the non-native endianness float conversions.
2007-03-29 Wim Taymans <wim@fluendo.com> 2007-03-29 Wim Taymans <wim@fluendo.com>
* gst-libs/gst/rtp/gstbasertpdepayload.c: * gst-libs/gst/rtp/gstbasertpdepayload.c:

View file

@ -65,23 +65,29 @@ G_BEGIN_DECLS
inline static gfloat inline static gfloat
GFLOAT_SWAP_LE_BE(gfloat in) GFLOAT_SWAP_LE_BE(gfloat in)
{ {
gint32 swap; union
gfloat out; {
memcpy(&swap, &in, 4); guint32 i;
swap = GUINT32_SWAP_LE_BE_CONSTANT (swap); gfloat f;
memcpy(&out, &swap, 4); } u;
return out;
u.f = in;
u.i = GUINT32_SWAP_LE_BE (u.i);
return u.f;
} }
inline static gdouble inline static gdouble
GDOUBLE_SWAP_LE_BE(gdouble in) GDOUBLE_SWAP_LE_BE(gdouble in)
{ {
gint64 swap; union
gdouble out; {
memcpy(&swap, &in, 8); guint64 i;
swap = GUINT64_SWAP_LE_BE_CONSTANT (swap); gdouble d;
memcpy(&out, &swap, 8); } u;
return out;
u.d = in;
u.i = GUINT64_SWAP_LE_BE (u.i);
return u.d;
} }
#if G_BYTE_ORDER == G_LITTLE_ENDIAN #if G_BYTE_ORDER == G_LITTLE_ENDIAN

View file

@ -27,6 +27,7 @@
#include "gstchannelmix.h" #include "gstchannelmix.h"
#include "audioconvert.h" #include "audioconvert.h"
#include "gst/floatcast/floatcast.h"
/* int to float/double conversion: int2xxx(i) = 1 / (2^31-1) * i */ /* int to float/double conversion: int2xxx(i) = 1 / (2^31-1) * i */
#define INT2FLOAT(i) (4.6566128752457969e-10 * ((gfloat)i)) #define INT2FLOAT(i) (4.6566128752457969e-10 * ((gfloat)i))
@ -41,7 +42,8 @@
#define MAKE_UNPACK_FUNC_NAME(name) \ #define MAKE_UNPACK_FUNC_NAME(name) \
audio_convert_unpack_##name audio_convert_unpack_##name
#define MAKE_UNPACK_FUNC(name, stride, sign, READ_FUNC) \ /* unpack from integer to signed integer 32 */
#define MAKE_UNPACK_FUNC_II(name, stride, sign, READ_FUNC) \
static void \ static void \
MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst, \ MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst, \
gint scale, gint count) \ gint scale, gint count) \
@ -52,44 +54,28 @@ MAKE_UNPACK_FUNC_NAME (name) (guint8 *src, gint32 *dst, \
} \ } \
} }
/* special unpack code for float/double */ /* unpack from float to signed integer 32 */
static void #define MAKE_UNPACK_FUNC_FI(name, type, READ_FUNC) \
MAKE_UNPACK_FUNC_NAME (float) (gfloat * src, gint32 * dst, gint s, gint count) static void \
{ MAKE_UNPACK_FUNC_NAME (name) (type * src, gint32 * dst, gint s, gint count) \
gdouble temp; { \
gdouble temp; \
for (; count; count--) { \
/* blow up to 32 bit */ for (; count; count--) { \
temp = (*src++ * 2147483647.0) + 0.5; /* blow up to 32 bit */ \
*dst++ = (gint32) CLAMP (temp, G_MININT32, G_MAXINT32); temp = (READ_FUNC (*src++) * 2147483647.0) + 0.5; \
} *dst++ = (gint32) CLAMP (temp, G_MININT32, G_MAXINT32); \
} \
} }
static void /* unpack from float to float 64 (double) */
MAKE_UNPACK_FUNC_NAME (double) (gdouble * src, gint32 * dst, gint s, gint count) #define MAKE_UNPACK_FUNC_FF(name, type, FUNC) \
{ static void \
gdouble temp; MAKE_UNPACK_FUNC_NAME (name) (type * src, gdouble * dst, gint s, \
gint count) \
for (; count; count--) { { \
/* blow up to 32 bit */ for (; count; count--) \
temp = (*src++ * 2147483647.0) + 0.5; *dst++ = (gdouble) FUNC (*src++); \
*dst++ = (gint32) CLAMP (temp, G_MININT32, G_MAXINT32);
}
}
static void
MAKE_UNPACK_FUNC_NAME (float_hq) (gfloat * src, gdouble * dst, gint s,
gint count)
{
for (; count; count--)
*dst++ = (gdouble) (*src++);
}
static void
MAKE_UNPACK_FUNC_NAME (double_hq) (gdouble * src, gdouble * dst, gint s,
gint count)
{
memcpy (dst, src, count * sizeof (gdouble));
} }
#define READ8(p) GST_READ_UINT8(p) #define READ8(p) GST_READ_UINT8(p)
@ -100,20 +86,31 @@ MAKE_UNPACK_FUNC_NAME (double_hq) (gdouble * src, gdouble * dst, gint s,
#define READ32_FROM_LE(p) GST_READ_UINT32_LE (p) #define READ32_FROM_LE(p) GST_READ_UINT32_LE (p)
#define READ32_FROM_BE(p) GST_READ_UINT32_BE (p) #define READ32_FROM_BE(p) GST_READ_UINT32_BE (p)
MAKE_UNPACK_FUNC (u8, 1, SIGNED, READ8); MAKE_UNPACK_FUNC_II (u8, 1, SIGNED, READ8);
MAKE_UNPACK_FUNC (s8, 1, 0, READ8); MAKE_UNPACK_FUNC_II (s8, 1, 0, READ8);
MAKE_UNPACK_FUNC (u16_le, 2, SIGNED, READ16_FROM_LE); MAKE_UNPACK_FUNC_II (u16_le, 2, SIGNED, READ16_FROM_LE);
MAKE_UNPACK_FUNC (s16_le, 2, 0, READ16_FROM_LE); MAKE_UNPACK_FUNC_II (s16_le, 2, 0, READ16_FROM_LE);
MAKE_UNPACK_FUNC (u16_be, 2, SIGNED, READ16_FROM_BE); MAKE_UNPACK_FUNC_II (u16_be, 2, SIGNED, READ16_FROM_BE);
MAKE_UNPACK_FUNC (s16_be, 2, 0, READ16_FROM_BE); MAKE_UNPACK_FUNC_II (s16_be, 2, 0, READ16_FROM_BE);
MAKE_UNPACK_FUNC (u24_le, 3, SIGNED, READ24_FROM_LE); MAKE_UNPACK_FUNC_II (u24_le, 3, SIGNED, READ24_FROM_LE);
MAKE_UNPACK_FUNC (s24_le, 3, 0, READ24_FROM_LE); MAKE_UNPACK_FUNC_II (s24_le, 3, 0, READ24_FROM_LE);
MAKE_UNPACK_FUNC (u24_be, 3, SIGNED, READ24_FROM_BE); MAKE_UNPACK_FUNC_II (u24_be, 3, SIGNED, READ24_FROM_BE);
MAKE_UNPACK_FUNC (s24_be, 3, 0, READ24_FROM_BE); MAKE_UNPACK_FUNC_II (s24_be, 3, 0, READ24_FROM_BE);
MAKE_UNPACK_FUNC (u32_le, 4, SIGNED, READ32_FROM_LE); MAKE_UNPACK_FUNC_II (u32_le, 4, SIGNED, READ32_FROM_LE);
MAKE_UNPACK_FUNC (s32_le, 4, 0, READ32_FROM_LE); MAKE_UNPACK_FUNC_II (s32_le, 4, 0, READ32_FROM_LE);
MAKE_UNPACK_FUNC (u32_be, 4, SIGNED, READ32_FROM_BE); MAKE_UNPACK_FUNC_II (u32_be, 4, SIGNED, READ32_FROM_BE);
MAKE_UNPACK_FUNC (s32_be, 4, 0, READ32_FROM_BE); MAKE_UNPACK_FUNC_II (s32_be, 4, 0, READ32_FROM_BE);
MAKE_UNPACK_FUNC_FI (float_le, gfloat, GFLOAT_FROM_LE);
MAKE_UNPACK_FUNC_FI (float_be, gfloat, GFLOAT_FROM_BE);
MAKE_UNPACK_FUNC_FI (double_le, gdouble, GDOUBLE_FROM_LE);
MAKE_UNPACK_FUNC_FI (double_be, gdouble, GDOUBLE_FROM_BE);
MAKE_UNPACK_FUNC_FF (float_hq_le, gfloat, GFLOAT_FROM_LE);
MAKE_UNPACK_FUNC_FF (float_hq_be, gfloat, GFLOAT_FROM_BE);
MAKE_UNPACK_FUNC_FF (double_hq_le, gdouble, GDOUBLE_FROM_LE);
MAKE_UNPACK_FUNC_FF (double_hq_be, gdouble, GDOUBLE_FROM_BE);
/* One of the double_hq_* functions generated above is ineffecient, but it's
* never used anyway. The same is true for one of the s32_* functions. */
/*** /***
* packing code * packing code
@ -144,7 +141,8 @@ audio_convert_pack_##name
* function for the target width. * function for the target width.
*/ */
#define MAKE_PACK_FUNC(name, stride, sign, WRITE_FUNC) \ /* pack from signed integer 32 to integer */
#define MAKE_PACK_FUNC_II(name, stride, sign, WRITE_FUNC) \
static void \ static void \
MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst, \ MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst, \
gint scale, gint count) \ gint scale, gint count) \
@ -174,35 +172,24 @@ MAKE_PACK_FUNC_NAME (name) (gint32 *src, gpointer dst, \
} \ } \
} }
/* special pack code for float/double */ /* pack from signed integer 32 to float */
static void #define MAKE_PACK_FUNC_IF(name, type, FUNC, FUNC2) \
MAKE_PACK_FUNC_NAME (float) (gint32 * src, gfloat * dst, gint scale, gint count) static void \
{ MAKE_PACK_FUNC_NAME (name) (gint32 * src, type * dst, gint scale, \
for (; count; count--) gint count) \
*dst++ = INT2FLOAT (*src++); { \
for (; count; count--) \
*dst++ = FUNC (FUNC2 (*src++)); \
} }
static void /* pack from float 64 (double) to float */
MAKE_PACK_FUNC_NAME (double) (gint32 * src, gdouble * dst, gint scale, #define MAKE_PACK_FUNC_FF(name, type, FUNC) \
gint count) static void \
{ MAKE_PACK_FUNC_NAME (name) (gdouble * src, type * dst, gint s, \
for (; count; count--) { gint count) \
*dst++ = INT2DOUBLE (*src++); { \
} for (; count; count--) \
} *dst++ = FUNC ((type) (*src++)); \
static void
MAKE_PACK_FUNC_NAME (float_hq) (gdouble * src, gfloat * dst, gint s, gint count)
{
for (; count; count--)
*dst++ = (gfloat) (*src++);
}
static void
MAKE_PACK_FUNC_NAME (double_hq) (gdouble * src, gdouble * dst, gint s,
gint count)
{
memcpy (dst, src, count * sizeof (gdouble));
} }
#define WRITE8(p, v) GST_WRITE_UINT8 (p, v) #define WRITE8(p, v) GST_WRITE_UINT8 (p, v)
@ -213,20 +200,30 @@ MAKE_PACK_FUNC_NAME (double_hq) (gdouble * src, gdouble * dst, gint s,
#define WRITE32_TO_LE(p,v) GST_WRITE_UINT32_LE (p, (guint32)(v)) #define WRITE32_TO_LE(p,v) GST_WRITE_UINT32_LE (p, (guint32)(v))
#define WRITE32_TO_BE(p,v) GST_WRITE_UINT32_BE (p, (guint32)(v)) #define WRITE32_TO_BE(p,v) GST_WRITE_UINT32_BE (p, (guint32)(v))
MAKE_PACK_FUNC (u8, 1, SIGNED, WRITE8); MAKE_PACK_FUNC_II (u8, 1, SIGNED, WRITE8);
MAKE_PACK_FUNC (s8, 1, 0, WRITE8); MAKE_PACK_FUNC_II (s8, 1, 0, WRITE8);
MAKE_PACK_FUNC (u16_le, 2, SIGNED, WRITE16_TO_LE); MAKE_PACK_FUNC_II (u16_le, 2, SIGNED, WRITE16_TO_LE);
MAKE_PACK_FUNC (s16_le, 2, 0, WRITE16_TO_LE); MAKE_PACK_FUNC_II (s16_le, 2, 0, WRITE16_TO_LE);
MAKE_PACK_FUNC (u16_be, 2, SIGNED, WRITE16_TO_BE); MAKE_PACK_FUNC_II (u16_be, 2, SIGNED, WRITE16_TO_BE);
MAKE_PACK_FUNC (s16_be, 2, 0, WRITE16_TO_BE); MAKE_PACK_FUNC_II (s16_be, 2, 0, WRITE16_TO_BE);
MAKE_PACK_FUNC (u24_le, 3, SIGNED, WRITE24_TO_LE); MAKE_PACK_FUNC_II (u24_le, 3, SIGNED, WRITE24_TO_LE);
MAKE_PACK_FUNC (s24_le, 3, 0, WRITE24_TO_LE); MAKE_PACK_FUNC_II (s24_le, 3, 0, WRITE24_TO_LE);
MAKE_PACK_FUNC (u24_be, 3, SIGNED, WRITE24_TO_BE); MAKE_PACK_FUNC_II (u24_be, 3, SIGNED, WRITE24_TO_BE);
MAKE_PACK_FUNC (s24_be, 3, 0, WRITE24_TO_BE); MAKE_PACK_FUNC_II (s24_be, 3, 0, WRITE24_TO_BE);
MAKE_PACK_FUNC (u32_le, 4, SIGNED, WRITE32_TO_LE); MAKE_PACK_FUNC_II (u32_le, 4, SIGNED, WRITE32_TO_LE);
MAKE_PACK_FUNC (s32_le, 4, 0, WRITE32_TO_LE); MAKE_PACK_FUNC_II (s32_le, 4, 0, WRITE32_TO_LE);
MAKE_PACK_FUNC (u32_be, 4, SIGNED, WRITE32_TO_BE); MAKE_PACK_FUNC_II (u32_be, 4, SIGNED, WRITE32_TO_BE);
MAKE_PACK_FUNC (s32_be, 4, 0, WRITE32_TO_BE); MAKE_PACK_FUNC_II (s32_be, 4, 0, WRITE32_TO_BE);
MAKE_PACK_FUNC_IF (float_le, gfloat, GFLOAT_TO_LE, INT2FLOAT);
MAKE_PACK_FUNC_IF (float_be, gfloat, GFLOAT_TO_BE, INT2FLOAT);
MAKE_PACK_FUNC_IF (double_le, gdouble, GDOUBLE_TO_LE, INT2DOUBLE);
MAKE_PACK_FUNC_IF (double_be, gdouble, GDOUBLE_TO_BE, INT2DOUBLE);
MAKE_PACK_FUNC_FF (float_hq_le, gfloat, GFLOAT_TO_LE);
MAKE_PACK_FUNC_FF (float_hq_be, gfloat, GFLOAT_TO_BE);
/* For double_hq, packing and unpacking is the same, so we reuse the unpacking
* functions here. */
#define audio_convert_pack_double_hq_le MAKE_UNPACK_FUNC_NAME (double_hq_le)
#define audio_convert_pack_double_hq_be MAKE_UNPACK_FUNC_NAME (double_hq_be)
static AudioConvertUnpack unpack_funcs[] = { static AudioConvertUnpack unpack_funcs[] = {
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u8), (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u8),
@ -245,10 +242,14 @@ static AudioConvertUnpack unpack_funcs[] = {
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_le), (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_le),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u32_be), (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (u32_be),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_be), (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (s32_be),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float), (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_le),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double), (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_be),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_hq), (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_le),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_hq), (AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_be),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_hq_le),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (float_hq_be),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_hq_le),
(AudioConvertUnpack) MAKE_UNPACK_FUNC_NAME (double_hq_be),
}; };
static AudioConvertPack pack_funcs[] = { static AudioConvertPack pack_funcs[] = {
@ -268,10 +269,14 @@ static AudioConvertPack pack_funcs[] = {
(AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_le), (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_le),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (u32_be), (AudioConvertPack) MAKE_PACK_FUNC_NAME (u32_be),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_be), (AudioConvertPack) MAKE_PACK_FUNC_NAME (s32_be),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (float), (AudioConvertPack) MAKE_PACK_FUNC_NAME (float_le),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (double), (AudioConvertPack) MAKE_PACK_FUNC_NAME (float_be),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (float_hq), (AudioConvertPack) MAKE_PACK_FUNC_NAME (double_le),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (double_hq), (AudioConvertPack) MAKE_PACK_FUNC_NAME (double_be),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (float_hq_le),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (float_hq_be),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (double_hq_le),
(AudioConvertPack) MAKE_PACK_FUNC_NAME (double_hq_be),
}; };
static gint static gint
@ -285,7 +290,9 @@ audio_convert_get_func_index (AudioConvertFmt * fmt)
index += fmt->sign ? 1 : 0; index += fmt->sign ? 1 : 0;
} else { } else {
/* this is float/double */ /* this is float/double */
index = (fmt->width == 32) ? 16 : 17; index = 16;
index += (fmt->width == 32) ? 0 : 2;
index += (fmt->endianness == G_LITTLE_ENDIAN) ? 0 : 1;
} }
return index; return index;
} }
@ -297,7 +304,7 @@ check_default (AudioConvertCtx * ctx, AudioConvertFmt * fmt)
return (fmt->width == 32 && fmt->depth == 32 && return (fmt->width == 32 && fmt->depth == 32 &&
fmt->endianness == G_BYTE_ORDER && fmt->sign == TRUE); fmt->endianness == G_BYTE_ORDER && fmt->sign == TRUE);
} else { } else {
return (fmt->width == 64); return (fmt->width == 64 && fmt->endianness == G_BYTE_ORDER);
} }
} }
@ -332,12 +339,10 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in,
gst_channel_mix_setup_matrix (ctx); gst_channel_mix_setup_matrix (ctx);
idx_in = audio_convert_get_func_index (in); idx_in = audio_convert_get_func_index (in);
if (!(ctx->unpack = unpack_funcs[idx_in])) ctx->unpack = unpack_funcs[idx_in];
goto not_supported;
idx_out = audio_convert_get_func_index (out); idx_out = audio_convert_get_func_index (out);
if (!(ctx->pack = pack_funcs[idx_out])) ctx->pack = pack_funcs[idx_out];
goto not_supported;
/* if both formats are float/double use double as intermediate format and /* if both formats are float/double use double as intermediate format and
* and switch mixing */ * and switch mixing */
@ -347,10 +352,10 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in,
} else { } else {
GST_INFO ("use float mixing"); GST_INFO ("use float mixing");
ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_float; ctx->channel_mix = (AudioConvertMix) gst_channel_mix_mix_float;
if (!(ctx->unpack = unpack_funcs[idx_in + 2])) /* Bump the pack/unpack function indices by 4 to use double as intermediary
goto not_supported; * format (float_hq_*, double_hq_* functions).*/
if (!(ctx->pack = pack_funcs[idx_out + 2])) ctx->unpack = unpack_funcs[idx_in + 4];
goto not_supported; ctx->pack = pack_funcs[idx_out + 4];
} }
GST_INFO ("unitsizes: %d -> %d", in->unit_size, out->unit_size); GST_INFO ("unitsizes: %d -> %d", in->unit_size, out->unit_size);
@ -368,12 +373,6 @@ audio_convert_prepare_context (AudioConvertCtx * ctx, AudioConvertFmt * in,
ctx->out_scale = (out->is_int) ? (32 - out->depth) : 0; ctx->out_scale = (out->is_int) ? (32 - out->depth) : 0;
return TRUE; return TRUE;
not_supported:
{
GST_INFO ("missing pack/unpack function");
return FALSE;
}
} }
gboolean gboolean

View file

@ -129,12 +129,12 @@ GST_STATIC_CAPS ( \
"audio/x-raw-float, " \ "audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 8 ], " \ "channels = (int) [ 1, 8 ], " \
"endianness = (int) BYTE_ORDER, " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) 64;" \ "width = (int) 64;" \
"audio/x-raw-float, " \ "audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 8 ], " \ "channels = (int) [ 1, 8 ], " \
"endianness = (int) BYTE_ORDER, " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) 32;" \ "width = (int) 32;" \
"audio/x-raw-int, " \ "audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \
@ -267,6 +267,11 @@ gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
goto no_values; goto no_values;
if (!gst_structure_get_int (structure, "rate", &fmt->rate)) if (!gst_structure_get_int (structure, "rate", &fmt->rate))
goto no_values; goto no_values;
/* width != 8 needs an endianness field */
if (fmt->width != 8) {
if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
goto no_values;
}
if (fmt->is_int) { if (fmt->is_int) {
/* int specific fields */ /* int specific fields */
@ -275,11 +280,6 @@ gst_audio_convert_parse_caps (const GstCaps * caps, AudioConvertFmt * fmt)
if (!gst_structure_get_int (structure, "depth", &fmt->depth)) if (!gst_structure_get_int (structure, "depth", &fmt->depth))
goto no_values; goto no_values;
/* width != 8 can have an endianness field */
if (fmt->width != 8) {
if (!gst_structure_get_int (structure, "endianness", &fmt->endianness))
goto no_values;
}
/* depth cannot be bigger than the width */ /* depth cannot be bigger than the width */
if (fmt->depth > fmt->width) if (fmt->depth > fmt->width)
goto not_allowed; goto not_allowed;
@ -379,31 +379,30 @@ set_structure_widths_32_and_64 (GstStructure * s)
static GstStructure * static GstStructure *
make_lossless_changes (GstStructure * s, gboolean isfloat) make_lossless_changes (GstStructure * s, gboolean isfloat)
{ {
GValue list = { 0 };
GValue val = { 0 };
int i;
const gint endian[] = { G_LITTLE_ENDIAN, G_BIG_ENDIAN };
const gboolean booleans[] = { TRUE, FALSE };
g_value_init (&list, GST_TYPE_LIST);
g_value_init (&val, G_TYPE_INT);
for (i = 0; i < 2; i++) {
g_value_set_int (&val, endian[i]);
gst_value_list_append_value (&list, &val);
}
gst_structure_set_value (s, "endianness", &list);
g_value_unset (&val);
g_value_unset (&list);
if (isfloat) { if (isfloat) {
/* float doesn't have a depth or signedness field and only supports /* float doesn't have a depth or signedness field and only supports
* widths of 32/64 and native endianness */ * widths of 32 and 64 bits */
gst_structure_remove_field (s, "depth"); gst_structure_remove_field (s, "depth");
gst_structure_remove_field (s, "signed"); gst_structure_remove_field (s, "signed");
set_structure_widths_32_and_64 (s); set_structure_widths_32_and_64 (s);
gst_structure_set (s, "endianness", G_TYPE_INT, G_BYTE_ORDER, NULL);
} else { } else {
/* int supports either endian, and signed or unsigned. GValues are a pain */ /* int supports signed and unsigned. GValues are a pain */
GValue list = { 0 };
GValue val = { 0 };
int i;
const gint endian[] = { G_LITTLE_ENDIAN, G_BIG_ENDIAN };
const gboolean booleans[] = { TRUE, FALSE };
g_value_init (&list, GST_TYPE_LIST);
g_value_init (&val, G_TYPE_INT);
for (i = 0; i < 2; i++) {
g_value_set_int (&val, endian[i]);
gst_value_list_append_value (&list, &val);
}
gst_structure_set_value (s, "endianness", &list);
g_value_unset (&val);
g_value_unset (&list);
g_value_init (&list, GST_TYPE_LIST); g_value_init (&list, GST_TYPE_LIST);
g_value_init (&val, G_TYPE_BOOLEAN); g_value_init (&val, G_TYPE_BOOLEAN);
for (i = 0; i < 2; i++) { for (i = 0; i < 2; i++) {

View file

@ -22,6 +22,7 @@
#include <unistd.h> #include <unistd.h>
#include <gst/floatcast/floatcast.h>
#include <gst/check/gstcheck.h> #include <gst/check/gstcheck.h>
#include <gst/audio/multichannel.h> #include <gst/audio/multichannel.h>
@ -36,7 +37,7 @@ GstPad *mysrcpad, *mysinkpad;
"audio/x-raw-float, " \ "audio/x-raw-float, " \
"rate = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \
"channels = (int) [ 1, 8 ], " \ "channels = (int) [ 1, 8 ], " \
"endianness = (int) BYTE_ORDER, " \ "endianness = (int) { LITTLE_ENDIAN, BIG_ENDIAN }, " \
"width = (int) { 32, 64 };" \ "width = (int) { 32, 64 };" \
"audio/x-raw-int, " \ "audio/x-raw-int, " \
"rate = (int) [ 1, MAX ], " \ "rate = (int) [ 1, MAX ], " \
@ -324,6 +325,8 @@ verify_convert (const gchar * which, void *in, int inlength,
fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), outlength); fail_unless_equals_int (GST_BUFFER_SIZE (outbuffer), outlength);
if (memcmp (GST_BUFFER_DATA (outbuffer), out, outlength) != 0) { if (memcmp (GST_BUFFER_DATA (outbuffer), out, outlength) != 0) {
g_print ("\nInput data:\n");
gst_util_dump_mem (in, inlength);
g_print ("\nConverted data:\n"); g_print ("\nConverted data:\n");
gst_util_dump_mem (GST_BUFFER_DATA (outbuffer), outlength); gst_util_dump_mem (GST_BUFFER_DATA (outbuffer), outlength);
g_print ("\nExpected data:\n"); g_print ("\nExpected data:\n");
@ -487,6 +490,7 @@ GST_START_TEST (test_int_conversion)
} }
/* 16 bit signed <-> 8 in 16 bit signed */ /* 16 bit signed <-> 8 in 16 bit signed */
/* NOTE: if audioconvert was doing dithering we'd have a problem */
{ {
gint16 in[] = { 0, 64 << 8, -64 << 8 }; gint16 in[] = { 0, 64 << 8, -64 << 8 };
gint16 out[] = { 0, 64, -64 }; gint16 out[] = { 0, 64, -64 };
@ -501,6 +505,7 @@ GST_START_TEST (test_int_conversion)
} }
/* 16 bit unsigned <-> 8 in 16 bit unsigned */ /* 16 bit unsigned <-> 8 in 16 bit unsigned */
/* NOTE: if audioconvert was doing dithering we'd have a problem */
{ {
guint16 in[] = { 1 << 15, (1 << 15) - (64 << 8), (1 << 15) + (64 << 8) }; guint16 in[] = { 1 << 15, (1 << 15) - (64 << 8), (1 << 15) + (64 << 8) };
guint16 out[] = { 1 << 7, (1 << 7) - 64, (1 << 7) + 64 }; guint16 out[] = { 1 << 7, (1 << 7) - 64, (1 << 7) + 64 };
@ -515,6 +520,7 @@ GST_START_TEST (test_int_conversion)
} }
/* 32 bit signed -> 16 bit signed for rounding check */ /* 32 bit signed -> 16 bit signed for rounding check */
/* NOTE: if audioconvert was doing dithering we'd have a problem */
{ {
gint32 in[] = { 0, G_MININT32, G_MAXINT32, gint32 in[] = { 0, G_MININT32, G_MAXINT32,
(32 << 16), (32 << 16) + (1 << 15), (32 << 16) - (1 << 15), (32 << 16), (32 << 16) + (1 << 15), (32 << 16) - (1 << 15),
@ -537,6 +543,7 @@ GST_START_TEST (test_int_conversion)
} }
/* 32 bit signed -> 16 bit unsigned for rounding check */ /* 32 bit signed -> 16 bit unsigned for rounding check */
/* NOTE: if audioconvert was doing dithering we'd have a problem */
{ {
gint32 in[] = { 0, G_MININT32, G_MAXINT32, gint32 in[] = { 0, G_MININT32, G_MAXINT32,
(32 << 16), (32 << 16) + (1 << 15), (32 << 16) - (1 << 15), (32 << 16), (32 << 16) + (1 << 15), (32 << 16) - (1 << 15),
@ -561,22 +568,34 @@ GST_START_TEST (test_int_conversion)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_float_conversion) GST_START_TEST (test_float_conversion)
{ {
/* 32 float <-> 16 signed */ /* 32 float <-> 16 signed */
/* NOTE: if audioconvert was doing dithering we'd have a problem */ /* NOTE: if audioconvert was doing dithering we'd have a problem */
{ {
gfloat in[] = { 0.0, 1.0, -1.0, 0.5, -0.5, 1.1, -1.1 }; gfloat in_le[] =
{ GFLOAT_TO_LE (0.0), GFLOAT_TO_LE (1.0), GFLOAT_TO_LE (-1.0),
GFLOAT_TO_LE (0.5), GFLOAT_TO_LE (-0.5), GFLOAT_TO_LE (1.1),
GFLOAT_TO_LE (-1.1)
};
gfloat in_be[] =
{ GFLOAT_TO_BE (0.0), GFLOAT_TO_BE (1.0), GFLOAT_TO_BE (-1.0),
GFLOAT_TO_BE (0.5), GFLOAT_TO_BE (-0.5), GFLOAT_TO_BE (1.1),
GFLOAT_TO_BE (-1.1)
};
gint16 out[] = { 0, 32767, -32768, 16384, -16384, 32767, -32768 }; gint16 out[] = { 0, 32767, -32768, 16384, -16384, 32767, -32768 };
/* only one direction conversion, the other direction does /* only one direction conversion, the other direction does
* not produce exactly the same as the input due to floating * not produce exactly the same as the input due to floating
* point rounding errors etc. */ * point rounding errors etc. */
RUN_CONVERSION ("32 float to 16 signed", RUN_CONVERSION ("32 float le to 16 signed",
in, get_float_caps (1, "BYTE_ORDER", 32), in_le, get_float_caps (1, "LITTLE_ENDIAN", 32),
out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE));
RUN_CONVERSION ("32 float be to 16 signed",
in_be, get_float_caps (1, "BIG_ENDIAN", 32),
out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE)); out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE));
} }
{ {
gint16 in[] = { 0, -32768, 16384, -16384 }; gint16 in[] = { 0, -32768, 16384, -16384 };
gfloat out[] = { 0.0, -1.0, 0.5, -0.5 }; gfloat out[] = { 0.0, -1.0, 0.5, -0.5 };
@ -589,14 +608,26 @@ GST_START_TEST (test_float_conversion)
/* 64 float <-> 16 signed */ /* 64 float <-> 16 signed */
/* NOTE: if audioconvert was doing dithering we'd have a problem */ /* NOTE: if audioconvert was doing dithering we'd have a problem */
{ {
gdouble in[] = { 0.0, 1.0, -1.0, 0.5, -0.5, 1.1, -1.1 }; gdouble in_le[] =
{ GDOUBLE_TO_LE (0.0), GDOUBLE_TO_LE (1.0), GDOUBLE_TO_LE (-1.0),
GDOUBLE_TO_LE (0.5), GDOUBLE_TO_LE (-0.5), GDOUBLE_TO_LE (1.1),
GDOUBLE_TO_LE (-1.1)
};
gdouble in_be[] =
{ GDOUBLE_TO_BE (0.0), GDOUBLE_TO_BE (1.0), GDOUBLE_TO_BE (-1.0),
GDOUBLE_TO_BE (0.5), GDOUBLE_TO_BE (-0.5), GDOUBLE_TO_BE (1.1),
GDOUBLE_TO_BE (-1.1)
};
gint16 out[] = { 0, 32767, -32768, 16384, -16384, 32767, -32768 }; gint16 out[] = { 0, 32767, -32768, 16384, -16384, 32767, -32768 };
/* only one direction conversion, the other direction does /* only one direction conversion, the other direction does
* not produce exactly the same as the input due to floating * not produce exactly the same as the input due to floating
* point rounding errors etc. */ * point rounding errors etc. */
RUN_CONVERSION ("64 float to 16 signed", RUN_CONVERSION ("64 float LE to 16 signed",
in, get_float_caps (1, "BYTE_ORDER", 64), in_le, get_float_caps (1, "LITTLE_ENDIAN", 64),
out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE));
RUN_CONVERSION ("64 float BE to 16 signed",
in_be, get_float_caps (1, "BIG_ENDIAN", 64),
out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE)); out, get_int_caps (1, "BYTE_ORDER", 16, 16, TRUE));
} }
{ {
@ -637,6 +668,44 @@ GST_START_TEST (test_float_conversion)
out, get_float_caps (1, "BYTE_ORDER", 32), out, get_float_caps (1, "BYTE_ORDER", 32),
in, get_float_caps (1, "BYTE_ORDER", 64)); in, get_float_caps (1, "BYTE_ORDER", 64));
} }
/* 32-bit float little endian <-> big endian */
{
gfloat le[] = { GFLOAT_TO_LE (0.0), GFLOAT_TO_LE (1.0), GFLOAT_TO_LE (-1.0),
GFLOAT_TO_LE (0.5), GFLOAT_TO_LE (-0.5)
};
gfloat be[] = { GFLOAT_TO_BE (0.0), GFLOAT_TO_BE (1.0), GFLOAT_TO_BE (-1.0),
GFLOAT_TO_BE (0.5), GFLOAT_TO_BE (-0.5)
};
RUN_CONVERSION ("32 float LE to BE",
le, get_float_caps (1, "LITTLE_ENDIAN", 32),
be, get_float_caps (1, "BIG_ENDIAN", 32));
RUN_CONVERSION ("32 float BE to LE",
be, get_float_caps (1, "BIG_ENDIAN", 32),
le, get_float_caps (1, "LITTLE_ENDIAN", 32));
}
/* 64-bit float little endian <-> big endian */
{
gdouble le[] =
{ GDOUBLE_TO_LE (0.0), GDOUBLE_TO_LE (1.0), GDOUBLE_TO_LE (-1.0),
GDOUBLE_TO_LE (0.5), GDOUBLE_TO_LE (-0.5)
};
gdouble be[] =
{ GDOUBLE_TO_BE (0.0), GDOUBLE_TO_BE (1.0), GDOUBLE_TO_BE (-1.0),
GDOUBLE_TO_BE (0.5), GDOUBLE_TO_BE (-0.5)
};
RUN_CONVERSION ("64 float LE to BE",
le, get_float_caps (1, "LITTLE_ENDIAN", 64),
be, get_float_caps (1, "BIG_ENDIAN", 64));
RUN_CONVERSION ("64 float BE to LE",
be, get_float_caps (1, "BIG_ENDIAN", 64),
le, get_float_caps (1, "LITTLE_ENDIAN", 64));
}
} }
GST_END_TEST; GST_END_TEST;