From efb50cabe6a479fad1f440474a1eb1f47e0ce58f Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 26 Jun 2015 23:05:16 +0200 Subject: audio: remove bitmask format definition mess Audio formats used a semi-clever schema to encode the properties of the PCM encoding as bitfields into the format integer value. The af_fmt_change_bits() implementation becomes a bit weird, but it's an improvement to the rest of the code. (I've always disliked it, so why not get rid of it.) --- audio/format.c | 88 ++++++++++++++++++++++++++++++++++------------------------ audio/format.h | 84 +++++++++++++++++++------------------------------------ 2 files changed, 80 insertions(+), 92 deletions(-) diff --git a/audio/format.c b/audio/format.c index 98957f9bd4..131f4d06eb 100644 --- a/audio/format.c +++ b/audio/format.c @@ -29,13 +29,16 @@ int af_fmt2bps(int format) { - switch (format & AF_FORMAT_BITS_MASK) { - case AF_FORMAT_8BIT: return 1; - case AF_FORMAT_16BIT: return 2; - case AF_FORMAT_24BIT: return 3; - case AF_FORMAT_32BIT: return 4; - case AF_FORMAT_64BIT: return 8; + switch (af_fmt_from_planar(format)) { + case AF_FORMAT_U8: return 1; + case AF_FORMAT_S16: return 2; + case AF_FORMAT_S24: return 3; + case AF_FORMAT_S32: return 4; + case AF_FORMAT_FLOAT: return 4; + case AF_FORMAT_DOUBLE: return 8; } + if (af_fmt_is_spdif(format)) + return 2; return 0; } @@ -44,25 +47,18 @@ int af_fmt2bits(int format) return af_fmt2bps(format) * 8; } -static int bits_to_mask(int bits) -{ - switch (bits) { - case 8: return AF_FORMAT_8BIT; - case 16: return AF_FORMAT_16BIT; - case 24: return AF_FORMAT_24BIT; - case 32: return AF_FORMAT_32BIT; - case 64: return AF_FORMAT_64BIT; - } - return 0; -} - int af_fmt_change_bits(int format, int bits) { - if (!af_fmt_is_valid(format)) + if (!af_fmt_is_valid(format) || !bits) return 0; - int mask = bits_to_mask(bits); - format = (format & ~AF_FORMAT_BITS_MASK) | mask; - return af_fmt_is_valid(format) ? format : 0; + for (int fmt = 1; fmt < AF_FORMAT_COUNT; fmt++) { + if (af_fmt2bits(fmt) == bits && + af_fmt_is_float(fmt) == af_fmt_is_float(format) && + af_fmt_is_planar(fmt) == af_fmt_is_planar(format) && + af_fmt_is_spdif(fmt) == af_fmt_is_planar(format)) + return fmt; + } + return 0; } // All formats are considered signed, except explicitly unsigned int formats. @@ -71,6 +67,29 @@ bool af_fmt_unsigned(int format) return format == AF_FORMAT_U8 || format == AF_FORMAT_U8P; } +bool af_fmt_is_float(int format) +{ + format = af_fmt_from_planar(format); + return format == AF_FORMAT_FLOAT || format == AF_FORMAT_DOUBLE; +} + +// true for both unsigned and signed ints +bool af_fmt_is_int(int format) +{ + return format && !af_fmt_is_spdif(format) && !af_fmt_is_float(format); +} + +// false for interleaved and AF_FORMAT_UNKNOWN +bool af_fmt_is_planar(int format) +{ + return format && af_fmt_to_planar(format) == format; +} + +bool af_fmt_is_spdif(int format) +{ + return af_format_sample_alignment(format) > 1; +} + static const int planar_formats[][2] = { {AF_FORMAT_U8P, AF_FORMAT_U8}, {AF_FORMAT_S16P, AF_FORMAT_S16}, @@ -132,11 +151,7 @@ const struct af_fmt_entry af_fmtstr_table[] = { bool af_fmt_is_valid(int format) { - for (int i = 0; af_fmtstr_table[i].name; i++) { - if (af_fmtstr_table[i].format == format) - return true; - } - return false; + return format > 0 && format < AF_FORMAT_COUNT; } const char *af_fmt_to_str(int format) @@ -190,28 +205,27 @@ int af_format_conversion_score(int dst_format, int src_format) if (AF_FORMAT_IS_SPECIAL(dst_format) || AF_FORMAT_IS_SPECIAL(src_format)) return INT_MIN; int score = 1024; - if (FMT_DIFF(AF_FORMAT_INTERLEAVING_MASK, dst_format, src_format)) + if (af_fmt_is_planar(dst_format) != af_fmt_is_planar(src_format)) score -= 1; // has to (de-)planarize - if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format)) { - int dst_bits = dst_format & AF_FORMAT_BITS_MASK; - if ((dst_format & AF_FORMAT_TYPE_MASK) == AF_FORMAT_F) { + if (af_fmt_is_float(dst_format) != af_fmt_is_float(src_format)) { + int dst_bits = af_fmt2bits(dst_format); + if (af_fmt_is_float(dst_format)) { // For int->float, always prefer 32 bit float. - score -= dst_bits == AF_FORMAT_32BIT ? 8 : 0; + score -= dst_bits == 32 ? 8 : 0; } else { // For float->int, always prefer highest bit depth int - score -= 8 * (AF_FORMAT_64BIT - dst_bits); + score -= 8 * (64 - dst_bits); } + // Has to convert float<->int - Consider this the worst case. + score -= 2048; } else { - int bits = FMT_DIFF(AF_FORMAT_BITS_MASK, dst_format, src_format); + int bits = af_fmt2bits(dst_format) - af_fmt2bits(src_format); if (bits > 0) { score -= 8 * bits; // has to add padding } else if (bits < 0) { score -= 1024 - 8 * bits; // has to reduce bit depth } } - // Consider this the worst case. - if (FMT_DIFF(AF_FORMAT_TYPE_MASK, dst_format, src_format)) - score -= 2048; // has to convert float<->int return score; } diff --git a/audio/format.h b/audio/format.h index 060b191c2b..36a005500e 100644 --- a/audio/format.h +++ b/audio/format.h @@ -26,69 +26,39 @@ #include "misc/bstr.h" -// Bits used -// Some code assumes they're sorted by size. -#define AF_FORMAT_8BIT (0<<1) -#define AF_FORMAT_16BIT (1<<1) -#define AF_FORMAT_24BIT (2<<1) -#define AF_FORMAT_32BIT (3<<1) -#define AF_FORMAT_64BIT (4<<1) -#define AF_FORMAT_BITS_MASK (7<<1) - -// Fixed/floating point/special -#define AF_FORMAT_I (1<<4) // Int -#define AF_FORMAT_F (2<<4) // Foating point -#define AF_FORMAT_S (4<<4) // special (IEC61937) -#define AF_FORMAT_TYPE_MASK (7<<4) - -// Interleaving (planar formats have data for each channel in separate planes) -#define AF_FORMAT_INTERLEAVED (0<<7) // must be 0 -#define AF_FORMAT_PLANAR (1<<7) -#define AF_FORMAT_INTERLEAVING_MASK (1<<7) - -#define AF_FORMAT_S_CODEC(n) ((n)<<8) -#define AF_FORMAT_S_CODEC_MASK (15 <<8) // 16 codecs max. - -#define AF_FORMAT_MASK ((1<<12)-1) - -#define AF_INTP (AF_FORMAT_I|AF_FORMAT_PLANAR) -#define AF_FLTP (AF_FORMAT_F|AF_FORMAT_PLANAR) -#define AF_FORMAT_S_(n) (AF_FORMAT_S_CODEC(n)|AF_FORMAT_S|AF_FORMAT_16BIT) - -// actual sample formats enum af_format { - AF_FORMAT_UNKNOWN = 0, + AF_FORMAT_UNKNOWN = 0, - AF_FORMAT_U8 = AF_FORMAT_I|AF_FORMAT_8BIT, - AF_FORMAT_S16 = AF_FORMAT_I|AF_FORMAT_16BIT, - AF_FORMAT_S24 = AF_FORMAT_I|AF_FORMAT_24BIT, - AF_FORMAT_S32 = AF_FORMAT_I|AF_FORMAT_32BIT, - - AF_FORMAT_FLOAT = AF_FORMAT_F|AF_FORMAT_32BIT, - AF_FORMAT_DOUBLE = AF_FORMAT_F|AF_FORMAT_64BIT, + AF_FORMAT_U8, + AF_FORMAT_S16, + AF_FORMAT_S24, + AF_FORMAT_S32, + AF_FORMAT_FLOAT, + AF_FORMAT_DOUBLE, // Planar variants - AF_FORMAT_U8P = AF_INTP|AF_FORMAT_8BIT, - AF_FORMAT_S16P = AF_INTP|AF_FORMAT_16BIT, - AF_FORMAT_S32P = AF_INTP|AF_FORMAT_32BIT, - AF_FORMAT_FLOATP = AF_FLTP|AF_FORMAT_32BIT, - AF_FORMAT_DOUBLEP = AF_FLTP|AF_FORMAT_64BIT, + AF_FORMAT_U8P, + AF_FORMAT_S16P, + AF_FORMAT_S32P, + AF_FORMAT_FLOATP, + AF_FORMAT_DOUBLEP, // All of these use IEC61937 framing, and otherwise pretend to be like PCM. - AF_FORMAT_S_AAC = AF_FORMAT_S_(0), - AF_FORMAT_S_AC3 = AF_FORMAT_S_(1), - AF_FORMAT_S_DTS = AF_FORMAT_S_(2), - AF_FORMAT_S_DTSHD = AF_FORMAT_S_(3), - AF_FORMAT_S_EAC3 = AF_FORMAT_S_(4), - AF_FORMAT_S_MP3 = AF_FORMAT_S_(5), - AF_FORMAT_S_TRUEHD = AF_FORMAT_S_(6), + AF_FORMAT_S_AAC, + AF_FORMAT_S_AC3, + AF_FORMAT_S_DTS, + AF_FORMAT_S_DTSHD, + AF_FORMAT_S_EAC3, + AF_FORMAT_S_MP3, + AF_FORMAT_S_TRUEHD, + + AF_FORMAT_COUNT }; -#define AF_FORMAT_IS_IEC61937(f) (((f) & AF_FORMAT_TYPE_MASK) == AF_FORMAT_S) -#define AF_FORMAT_IS_SPECIAL(f) AF_FORMAT_IS_IEC61937(f) -#define AF_FORMAT_IS_FLOAT(f) (!!((f) & AF_FORMAT_F)) -// false for interleaved and AF_FORMAT_UNKNOWN -#define AF_FORMAT_IS_PLANAR(f) (!!((f) & AF_FORMAT_PLANAR)) +#define AF_FORMAT_IS_IEC61937(f) af_fmt_is_spdif(f) +#define AF_FORMAT_IS_SPECIAL(f) af_fmt_is_spdif(f) +#define AF_FORMAT_IS_FLOAT(f) af_fmt_is_float(f) +#define AF_FORMAT_IS_PLANAR(f) af_fmt_is_planar(f) struct af_fmt_entry { const char *name; @@ -105,6 +75,10 @@ int af_fmt2bits(int format); int af_fmt_change_bits(int format, int bits); bool af_fmt_unsigned(int format); +bool af_fmt_is_float(int format); +bool af_fmt_is_int(int format); +bool af_fmt_is_planar(int format); +bool af_fmt_is_spdif(int format); int af_fmt_to_planar(int format); int af_fmt_from_planar(int format); -- cgit v1.2.3