From bb1d6ef24727b9ee47843143658cd807f290e90c Mon Sep 17 00:00:00 2001 From: beveloper Date: Sat, 27 Dec 2003 14:51:14 +0000 Subject: [PATCH] raw decoder supports many samples types now, and support for them has been added to the file readers, you can now play 24 bit integer or 64 bit floating point files git-svn-id: file:///srv/svn/repos/haiku/trunk/current@5770 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/media/RawFormats.h | 4 +- src/add-ons/media/plugins/aiff_reader/aiff.h | 4 + .../media/plugins/aiff_reader/aiff_reader.cpp | 9 +- .../media/plugins/au_reader/au_reader.cpp | 7 +- .../plugins/raw_decoder/AudioConversion.cpp | 211 +++++++++ .../plugins/raw_decoder/AudioConversion.h | 54 +++ src/add-ons/media/plugins/raw_decoder/Jamfile | 1 + .../plugins/raw_decoder/RawDecoderPlugin.cpp | 426 ++++++++++++++++-- .../plugins/raw_decoder/RawDecoderPlugin.h | 21 +- .../plugins/wav_reader/WavReaderPlugin.cpp | 10 +- src/kits/media/MediaRoster.cpp | 5 +- 11 files changed, 708 insertions(+), 44 deletions(-) create mode 100644 src/add-ons/media/plugins/raw_decoder/AudioConversion.cpp create mode 100644 src/add-ons/media/plugins/raw_decoder/AudioConversion.h diff --git a/headers/private/media/RawFormats.h b/headers/private/media/RawFormats.h index af3bfc9184..e3419e8769 100644 --- a/headers/private/media/RawFormats.h +++ b/headers/private/media/RawFormats.h @@ -14,10 +14,10 @@ enum { B_AUDIO_FORMAT_UINT8 = 0x0011, B_AUDIO_FORMAT_INT8 = 0x0001, B_AUDIO_FORMAT_INT16 = 0x0002, - B_AUDIO_FORMAT_INT24 = 0x0003, + B_AUDIO_FORMAT_INT24 = 0x1003, B_AUDIO_FORMAT_INT32 = 0x0004, B_AUDIO_FORMAT_FLOAT32 = 0x0024, - B_AUDIO_FORMAT_FLOAT64 = 0x0028, + B_AUDIO_FORMAT_FLOAT64 = 0x1008, B_AUDIO_FORMAT_MASK = 0xffff, B_AUDIO_FORMAT_SIZE_MASK = 0xf, B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE = 0x100000, diff --git a/src/add-ons/media/plugins/aiff_reader/aiff.h b/src/add-ons/media/plugins/aiff_reader/aiff.h index 3742906982..c9e58031a4 100644 --- a/src/add-ons/media/plugins/aiff_reader/aiff.h +++ b/src/add-ons/media/plugins/aiff_reader/aiff.h @@ -70,6 +70,10 @@ inline const char * string_for_compression(uint32 compression) case 'Qclp': return "Qualcomm PureVoice"; case 'rt24': return "RT24 50:1"; case 'rt29': return "RT29 50:1"; + case 'G722': return "G722"; + case 'G726': return "G726"; + case 'G728': return "G728"; + case 'GSM ': return "GSM"; default: sprintf(s, "unknown compression %c%c%c%c", (int)((compression >> 24) & 0xff), diff --git a/src/add-ons/media/plugins/aiff_reader/aiff_reader.cpp b/src/add-ons/media/plugins/aiff_reader/aiff_reader.cpp index 016f01e6d8..35ee7a20eb 100644 --- a/src/add-ons/media/plugins/aiff_reader/aiff_reader.cpp +++ b/src/add-ons/media/plugins/aiff_reader/aiff_reader.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "RawFormats.h" #include "aiff_reader.h" #define TRACE_THIS 1 @@ -36,7 +37,7 @@ aiffReader::~aiffReader() const char * aiffReader::Copyright() { - return ".au & .snd reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen"; + return "AIFF & AIFF-C reader, " B_UTF8_COPYRIGHT " by Marcus Overhagen"; } @@ -222,8 +223,7 @@ aiffReader::Sniff(int32 *streamCount) fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; break; case 3: - // XXX broken - fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; + fFormat.u.raw_audio.format = B_AUDIO_FORMAT_INT24; break; case 4: fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; @@ -240,8 +240,7 @@ aiffReader::Sniff(int32 *streamCount) fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; break; case FOURCC('f','l','6','4'): - // XXX broken - fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; + fFormat.u.raw_audio.format = B_AUDIO_FORMAT_FLOAT64; break; default: TRACE("aiffReader::Sniff: unknown raw format\n"); diff --git a/src/add-ons/media/plugins/au_reader/au_reader.cpp b/src/add-ons/media/plugins/au_reader/au_reader.cpp index c65ef64183..8e09b5f140 100644 --- a/src/add-ons/media/plugins/au_reader/au_reader.cpp +++ b/src/add-ons/media/plugins/au_reader/au_reader.cpp @@ -4,6 +4,7 @@ #include #include #include +#include "RawFormats.h" #include "au_reader.h" #define TRACE_THIS 1 @@ -204,8 +205,7 @@ auReader::Sniff(int32 *streamCount) fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; break; case SND_FORMAT_LINEAR_24: - // XXX broken - fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; + fFormat.u.raw_audio.format = B_AUDIO_FORMAT_INT24; break; case SND_FORMAT_LINEAR_32: fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; @@ -214,8 +214,7 @@ auReader::Sniff(int32 *streamCount) fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; break; case SND_FORMAT_DOUBLE: - // XXX broken - fFormat.u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; + fFormat.u.raw_audio.format = B_AUDIO_FORMAT_FLOAT64; break; default: TRACE("WavReader::Sniff: unhandled raw format\n"); diff --git a/src/add-ons/media/plugins/raw_decoder/AudioConversion.cpp b/src/add-ons/media/plugins/raw_decoder/AudioConversion.cpp new file mode 100644 index 0000000000..c9405aee35 --- /dev/null +++ b/src/add-ons/media/plugins/raw_decoder/AudioConversion.cpp @@ -0,0 +1,211 @@ +#include +#include +#include "AudioConversion.h" +#include "RawFormats.h" + +// XXX GCC doesn't always generate nice code... + +typedef float float32; +typedef double float64; + +class uint8_sample +{ +public: + inline operator uint8() { return data; } + inline operator int8() { return (int32)data - 128; } + inline operator int16() { return ((int32)data - 128) << 8; } + inline operator int32() { return ((int32)data - 128) << 24; } + inline operator float() { return ((int32)data - 128) * (1.0f / 127.0f); } +private: + uint8 data; +} _PACKED; + +class int8_sample +{ +public: + inline operator uint8() { return (int32)data + 128; } + inline operator int8() { return data; } + inline operator int16() { return (int16)data << 8; } + inline operator int32() { return (int32)data << 24; } + inline operator float() { return (int32)data * (1.0f / 127.0f); } +private: + int8 data; +} _PACKED; + +class int16_sample +{ +public: + inline operator uint8() { return (uint8)((int8)(data >> 8) + 128); } + inline operator int8() { return (int8)(data >> 8); } + inline operator int16() { return data; } + inline operator int32() { return (int32)data << 16; } + inline operator float() { return data * (1.0f / 32767.0f); } +private: + int16 data; +} _PACKED; + +class int24_sample +{ +public: +#if B_HOST_IS_LENDIAN + inline operator uint8() { return (int32)data[2] + 128; } + inline operator int8() { return (int8)data[2]; } + inline operator int16() { return (int16)((uint32)data[2] << 8 | (uint32)data[1]); } + inline operator int32() { return (int32)((uint32)data[2] << 24 | (uint32)data[1] << 16 | (uint32)data[0] << 8); } + inline operator float() { return (int32)((uint32)data[2] << 24 | (uint32)data[1] << 16 | (uint32)data[0] << 8) * (1.0f / 2147483647.0f); } +#else + inline operator uint8() { return (int32)data[0] + 128; } + inline operator int8() { return (int8)data[1]; } + inline operator int16() { return (int16)((uint32)data[0] << 8 | (uint32)data[1]); } + inline operator int32() { return (int32)((uint32)data[0] << 24 | (uint32)data[1] << 16 | (uint32)data[2] << 8); } + inline operator float() { return (int32)((uint32)data[0] << 24 | (uint32)data[1] << 16 | (uint32)data[2] << 8) * (1.0f / 2147483647.0f); } +#endif +private: + uint8 data[3]; +} _PACKED; + +class int32_sample +{ +public: + inline operator uint8() { return (int8)(data >> 24) + 128; } + inline operator int8() { return (int8)(data >> 24); } + inline operator int16() { return (int16)(data >> 16); } + inline operator int32() { return data; } + inline operator float() { return data * (1.0f / 2147483647.0f); } +private: + int32 data; +} _PACKED; + +class float32_sample +{ +public: + inline operator uint8() { return (int32)(data * 127.0f) + 128; } + inline operator int8() { return (int8)(data * 127.0f); } + inline operator int16() { return (int16)(data * 32767.0f); } + inline operator int32() { return (int32)(data * 2147483647.0f); } + inline operator float() { return data; } +private: + float32 data; +} _PACKED; + +class float64_sample +{ +public: + inline operator uint8() { return (int32)(data * 127.0) + 128; } + inline operator int8() { return (int8)(data * 127.0); } + inline operator int16() { return (int16)(data * 32767.0); } + inline operator int32() { return (int32)(data * 2147483647.0); } + inline operator float() { return data; } +private: + float64 data; +} _PACKED; + +#define CONVERT(src_type, dst_type) \ +void src_type##_to_##dst_type (void *dst, void *src, int32 count) \ +{ \ + register src_type##_sample *s = (src_type##_sample *) src; \ + register dst_type *d = (dst_type *) dst; \ + register int32 c = count >> 4; \ + if (!c) goto fin1; \ + do { \ + d[0] = s[0]; d[1] = s[1]; \ + d[2] = s[2]; d[3] = s[3]; \ + d[4] = s[4]; d[5] = s[5]; \ + d[6] = s[6]; d[7] = s[7]; \ + d[8] = s[8]; d[9] = s[9]; \ + d[10] = s[10]; d[11] = s[11]; \ + d[12] = s[12]; d[13] = s[13]; \ + d[14] = s[14]; d[15] = s[15]; \ + s += 16; d += 16; \ + } while (--c); \ +fin1: \ + c = count & 15; \ + if (!c) goto fin2; \ + do { \ + *(d++) = *(s++); \ + } while (--c); \ +fin2: \ + ; \ +} + + +CONVERT(uint8, uint8) +CONVERT(uint8, int8) +CONVERT(uint8, int16) +CONVERT(uint8, int32) +CONVERT(uint8, float32) + +CONVERT(int8, uint8) +CONVERT(int8, int8) +CONVERT(int8, int16) +CONVERT(int8, int32) +CONVERT(int8, float32) + +CONVERT(int16, uint8) +CONVERT(int16, int8) +CONVERT(int16, int16) +CONVERT(int16, int32) +CONVERT(int16, float32) + +CONVERT(int24, uint8) +CONVERT(int24, int8) +CONVERT(int24, int16) +CONVERT(int24, int32) +CONVERT(int24, float32) + +CONVERT(int32, uint8) +CONVERT(int32, int8) +CONVERT(int32, int16) +CONVERT(int32, int32) +CONVERT(int32, float32) + +CONVERT(float32, uint8) +CONVERT(float32, int8) +CONVERT(float32, int16) +CONVERT(float32, int32) +CONVERT(float32, float32) + +CONVERT(float64, uint8) +CONVERT(float64, int8) +CONVERT(float64, int16) +CONVERT(float64, int32) +CONVERT(float64, float32) + +void +swap_int16(void *data, int32 count) +{ + swap_data(B_INT16_TYPE, data, count * 2, B_SWAP_ALWAYS); +} + +void +swap_int24(void *data, int32 count) +{ + register int32 c = count; + register uint8 *d = (uint8 *)data; + if (!c) + return; + do { + register uint8 temp = d[0]; + d[0] = d[2]; + d[2] = temp; + d += 3; + } while (--c); +} + +void +swap_int32(void *data, int32 count) +{ + swap_data(B_INT32_TYPE, data, count * 4, B_SWAP_ALWAYS); +} + +void +swap_float32(void *data, int32 count) +{ + swap_data(B_FLOAT_TYPE, data, count * 4, B_SWAP_ALWAYS); +} + +void +swap_float64(void *data, int32 count) +{ + swap_data(B_INT64_TYPE, data, count * 8, B_SWAP_ALWAYS); +} diff --git a/src/add-ons/media/plugins/raw_decoder/AudioConversion.h b/src/add-ons/media/plugins/raw_decoder/AudioConversion.h new file mode 100644 index 0000000000..d63b2570cc --- /dev/null +++ b/src/add-ons/media/plugins/raw_decoder/AudioConversion.h @@ -0,0 +1,54 @@ +#ifndef _AUDIO_CONVERSION_H +#define _AUDIO_CONVERSION_H + +#include + +void uint8_to_uint8(void *dst, void *src, int32 count); +void uint8_to_int8(void *dst, void *src, int32 count); +void uint8_to_int16(void *dst, void *src, int32 count); +void uint8_to_int32(void *dst, void *src, int32 count); +void uint8_to_float32(void *dst, void *src, int32 count); + +void int8_to_uint8(void *dst, void *src, int32 count); +void int8_to_int8(void *dst, void *src, int32 count); +void int8_to_int16(void *dst, void *src, int32 count); +void int8_to_int32(void *dst, void *src, int32 count); +void int8_to_float32(void *dst, void *src, int32 count); + +void int16_to_uint8(void *dst, void *src, int32 count); +void int16_to_int8(void *dst, void *src, int32 count); +void int16_to_int16(void *dst, void *src, int32 count); +void int16_to_int32(void *dst, void *src, int32 count); +void int16_to_float32(void *dst, void *src, int32 count); + +void int24_to_uint8(void *dst, void *src, int32 count); +void int24_to_int8(void *dst, void *src, int32 count); +void int24_to_int16(void *dst, void *src, int32 count); +void int24_to_int32(void *dst, void *src, int32 count); +void int24_to_float32(void *dst, void *src, int32 count); + +void int32_to_uint8(void *dst, void *src, int32 count); +void int32_to_int8(void *dst, void *src, int32 count); +void int32_to_int16(void *dst, void *src, int32 count); +void int32_to_int32(void *dst, void *src, int32 count); +void int32_to_float32(void *dst, void *src, int32 count); + +void float32_to_uint8(void *dst, void *src, int32 count); +void float32_to_int8(void *dst, void *src, int32 count); +void float32_to_int16(void *dst, void *src, int32 count); +void float32_to_int32(void *dst, void *src, int32 count); +void float32_to_float32(void *dst, void *src, int32 count); + +void float64_to_uint8(void *dst, void *src, int32 count); +void float64_to_int8(void *dst, void *src, int32 count); +void float64_to_int16(void *dst, void *src, int32 count); +void float64_to_int32(void *dst, void *src, int32 count); +void float64_to_float32(void *dst, void *src, int32 count); + +void swap_int16(void *data, int32 count); +void swap_int24(void *data, int32 count); +void swap_int32(void *data, int32 count); +void swap_float32(void *data, int32 count); +void swap_float64(void *data, int32 count); + +#endif // _AUDIO_CONVERSION_H diff --git a/src/add-ons/media/plugins/raw_decoder/Jamfile b/src/add-ons/media/plugins/raw_decoder/Jamfile index 8ba14a5112..e5fc7930c0 100644 --- a/src/add-ons/media/plugins/raw_decoder/Jamfile +++ b/src/add-ons/media/plugins/raw_decoder/Jamfile @@ -3,6 +3,7 @@ SubDir OBOS_TOP src add-ons media plugins raw_decoder ; UsePrivateHeaders media ; Addon raw_decoder : media plugins : + AudioConversion.cpp RawDecoderPlugin.cpp ; diff --git a/src/add-ons/media/plugins/raw_decoder/RawDecoderPlugin.cpp b/src/add-ons/media/plugins/raw_decoder/RawDecoderPlugin.cpp index 4225d4db2c..28ab1124b0 100644 --- a/src/add-ons/media/plugins/raw_decoder/RawDecoderPlugin.cpp +++ b/src/add-ons/media/plugins/raw_decoder/RawDecoderPlugin.cpp @@ -1,13 +1,17 @@ #include #include #include +#include +#include +#include "RawFormats.h" #include "RawDecoderPlugin.h" +#include "AudioConversion.h" #define TRACE_THIS 1 #if TRACE_THIS #define TRACE printf #else - #define TRACE TRACE(a...) + #define TRACE(a...) #endif @@ -15,15 +19,49 @@ status_t RawDecoder::Setup(media_format *ioEncodedFormat, const void *infoBuffer, int32 infoSize) { + char s[200]; + string_for_format(*ioEncodedFormat, s, sizeof(s)); + TRACE("RawDecoder::Setup: %s\n", s); + if (ioEncodedFormat->type != B_MEDIA_RAW_AUDIO && ioEncodedFormat->type != B_MEDIA_RAW_VIDEO) return B_ERROR; fInputFormat = *ioEncodedFormat; - if (ioEncodedFormat->type == B_MEDIA_RAW_VIDEO) - fFrameSize = ioEncodedFormat->u.raw_video.display.line_count * ioEncodedFormat->u.raw_video.display.bytes_per_row; - else - fFrameSize = (ioEncodedFormat->u.raw_audio.format & 0xf) * ioEncodedFormat->u.raw_audio.channel_count; + if (ioEncodedFormat->type == B_MEDIA_RAW_VIDEO) { + fInputSampleSize = ioEncodedFormat->u.raw_video.display.line_count * ioEncodedFormat->u.raw_video.display.bytes_per_row; + fInputFrameSize = fInputSampleSize; + } else { + fInputSampleSize = (ioEncodedFormat->u.raw_audio.format & B_AUDIO_FORMAT_SIZE_MASK); + fInputFrameSize = fInputSampleSize * ioEncodedFormat->u.raw_audio.channel_count; + } + + // since ioEncodedFormat is later passed to the application by BMediaTrack::EncodedFormat() + // we need to remove non public format specifications + + // remove non format bits, like channel order + ioEncodedFormat->u.raw_audio.format &= B_AUDIO_FORMAT_MASK; + + switch (ioEncodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_UINT8: + case B_AUDIO_FORMAT_INT8: + case B_AUDIO_FORMAT_INT16: + case B_AUDIO_FORMAT_INT32: + case B_AUDIO_FORMAT_FLOAT32: + break; // ok to pass through + + case B_AUDIO_FORMAT_INT24: + ioEncodedFormat->u.raw_audio.format = B_AUDIO_FORMAT_INT32; + break; + + case B_AUDIO_FORMAT_FLOAT64: + ioEncodedFormat->u.raw_audio.format = B_AUDIO_FORMAT_FLOAT32; + break; + + default: + TRACE("RawDecoder::Setup: unknown input format\n"); + return B_ERROR; + } return B_OK; } @@ -35,19 +73,331 @@ RawDecoder::NegotiateOutputFormat(media_format *ioDecodedFormat) // BeBook says: The codec will find and return in ioFormat its best matching format // => This means, we never return an error, and always change the format values // that we don't support to something more applicable - + if (ioDecodedFormat->type == B_MEDIA_RAW_VIDEO) + return NegotiateVideoOutputFormat(ioDecodedFormat); + if (ioDecodedFormat->type == B_MEDIA_RAW_AUDIO) + return NegotiateAudioOutputFormat(ioDecodedFormat); + return B_ERROR; +} + + +status_t +RawDecoder::NegotiateVideoOutputFormat(media_format *ioDecodedFormat) +{ + return B_ERROR; +} + + +status_t +RawDecoder::NegotiateAudioOutputFormat(media_format *ioDecodedFormat) +{ char s[1024]; + + string_for_format(*ioDecodedFormat, s, sizeof(s)); + TRACE("RawDecoder::NegotiateAudioOutputFormat enter: %s\n", s); + + ioDecodedFormat->type = B_MEDIA_RAW_AUDIO; + switch (ioDecodedFormat->u.raw_audio.format) { + case media_raw_audio_format::B_AUDIO_FLOAT: + case media_raw_audio_format::B_AUDIO_SHORT: + case media_raw_audio_format::B_AUDIO_UCHAR: + case media_raw_audio_format::B_AUDIO_CHAR: + ioDecodedFormat->u.raw_audio.valid_bits = 0; + break; // we can produce this on request + + case media_raw_audio_format::B_AUDIO_INT: + ioDecodedFormat->u.raw_audio.valid_bits = fInputFormat.u.raw_audio.valid_bits; + break; // we can produce this on request + + default: + switch (fInputFormat.u.raw_audio.format & B_AUDIO_FORMAT_MASK) { + case media_raw_audio_format::B_AUDIO_SHORT: + case media_raw_audio_format::B_AUDIO_UCHAR: + case media_raw_audio_format::B_AUDIO_CHAR: + ioDecodedFormat->u.raw_audio.format = fInputFormat.u.raw_audio.format & B_AUDIO_FORMAT_MASK; + ioDecodedFormat->u.raw_audio.valid_bits = 0; + break; + + case media_raw_audio_format::B_AUDIO_INT: + case B_AUDIO_FORMAT_INT24: + ioDecodedFormat->u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; + ioDecodedFormat->u.raw_audio.valid_bits = fInputFormat.u.raw_audio.valid_bits; + break; + + case media_raw_audio_format::B_AUDIO_FLOAT: + case B_AUDIO_FORMAT_FLOAT64: + default: + ioDecodedFormat->u.raw_audio.format = media_raw_audio_format::B_AUDIO_FLOAT; + ioDecodedFormat->u.raw_audio.valid_bits = 0; + break; + } + break; + } + + fFrameRate = (int32) ioDecodedFormat->u.raw_audio.frame_rate; + ioDecodedFormat->u.raw_audio.frame_rate = fInputFormat.u.raw_audio.frame_rate; + ioDecodedFormat->u.raw_audio.channel_count = fInputFormat.u.raw_audio.channel_count; + + fOutputSampleSize = (ioDecodedFormat->u.raw_audio.format & B_AUDIO_FORMAT_SIZE_MASK); + fOutputFrameSize = fOutputSampleSize * ioDecodedFormat->u.raw_audio.channel_count; + + if (ioDecodedFormat->u.raw_audio.byte_order == 0) + ioDecodedFormat->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN; + + ioDecodedFormat->u.raw_audio.channel_mask = 0; + ioDecodedFormat->u.raw_audio.matrix_mask = 0; + + if (ioDecodedFormat->u.raw_audio.buffer_size < 128 || ioDecodedFormat->u.raw_audio.buffer_size > 65536) { + ioDecodedFormat->u.raw_audio.buffer_size = BMediaRoster::Roster()->AudioBufferSizeFor( + ioDecodedFormat->u.raw_audio.channel_count, + ioDecodedFormat->u.raw_audio.format, + ioDecodedFormat->u.raw_audio.frame_rate); + } else { + // round down to exact multiple of output frame size + ioDecodedFormat->u.raw_audio.buffer_size = (ioDecodedFormat->u.raw_audio.buffer_size / fOutputFrameSize) * fOutputFrameSize; + } + + fOutputBufferFrameCount = ioDecodedFormat->u.raw_audio.buffer_size / fOutputFrameSize; + + // setup input swapping function + if (fInputFormat.u.raw_audio.byte_order == B_MEDIA_HOST_ENDIAN) { + fSwapInput = 0; + } else { + switch (fInputFormat.u.raw_audio.format & B_AUDIO_FORMAT_MASK) { + case B_AUDIO_FORMAT_INT16: + fSwapInput = &swap_int16; + break; + case B_AUDIO_FORMAT_INT24: + fSwapInput = &swap_int24; + break; + case B_AUDIO_FORMAT_INT32: + fSwapInput = &swap_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fSwapInput = &swap_float32; + break; + case B_AUDIO_FORMAT_FLOAT64: + fSwapInput = &swap_float64; + break; + case B_AUDIO_FORMAT_UINT8: + case B_AUDIO_FORMAT_INT8: + fSwapInput = 0; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown input format\n"); + break; + } + } + + // setup output swapping function + if (ioDecodedFormat->u.raw_audio.byte_order == B_MEDIA_HOST_ENDIAN) { + fSwapOutput = 0; + } else { + switch (ioDecodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_INT16: + fSwapOutput = &swap_int16; + break; + case B_AUDIO_FORMAT_INT32: + fSwapOutput = &swap_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fSwapOutput = &swap_float32; + break; + case B_AUDIO_FORMAT_UINT8: + case B_AUDIO_FORMAT_INT8: + fSwapOutput = 0; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown output format\n"); + break; + } + } + + // setup sample conversation function + switch (fInputFormat.u.raw_audio.format & B_AUDIO_FORMAT_MASK) { + case B_AUDIO_FORMAT_UINT8: + switch (ioDecodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_UINT8: + fConvert = &uint8_to_uint8; + break; + case B_AUDIO_FORMAT_INT8: + fConvert = &uint8_to_int8; + break; + case B_AUDIO_FORMAT_INT16: + fConvert = &uint8_to_int16; + break; + case B_AUDIO_FORMAT_INT32: + fConvert = &uint8_to_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fConvert = &uint8_to_float32; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown output format\n"); + break; + } + break; + + case B_AUDIO_FORMAT_INT8: + switch (ioDecodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_UINT8: + fConvert = &int8_to_uint8; + break; + case B_AUDIO_FORMAT_INT8: + fConvert = &int8_to_int8; + break; + case B_AUDIO_FORMAT_INT16: + fConvert = &int8_to_int16; + break; + case B_AUDIO_FORMAT_INT32: + fConvert = &int8_to_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fConvert = &int8_to_float32; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown output format\n"); + break; + } + break; + + case B_AUDIO_FORMAT_INT16: + switch (ioDecodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_UINT8: + fConvert = &int16_to_uint8; + break; + case B_AUDIO_FORMAT_INT8: + fConvert = &int16_to_int8; + break; + case B_AUDIO_FORMAT_INT16: + fConvert = &int16_to_int16; + break; + case B_AUDIO_FORMAT_INT32: + fConvert = &int16_to_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fConvert = &int16_to_float32; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown output format\n"); + break; + } + break; + + case B_AUDIO_FORMAT_INT24: + switch (ioDecodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_UINT8: + fConvert = &int24_to_uint8; + break; + case B_AUDIO_FORMAT_INT8: + fConvert = &int24_to_int8; + break; + case B_AUDIO_FORMAT_INT16: + fConvert = &int24_to_int16; + break; + case B_AUDIO_FORMAT_INT32: + fConvert = &int24_to_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fConvert = &int24_to_float32; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown output format\n"); + break; + } + break; + + case B_AUDIO_FORMAT_INT32: + switch (ioDecodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_UINT8: + fConvert = &int32_to_uint8; + break; + case B_AUDIO_FORMAT_INT8: + fConvert = &int32_to_int8; + break; + case B_AUDIO_FORMAT_INT16: + fConvert = &int32_to_int16; + break; + case B_AUDIO_FORMAT_INT32: + fConvert = &int32_to_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fConvert = &int32_to_float32; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown output format\n"); + break; + } + break; + + case B_AUDIO_FORMAT_FLOAT32: + switch (ioDecodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_UINT8: + fConvert = &float32_to_uint8; + break; + case B_AUDIO_FORMAT_INT8: + fConvert = &float32_to_int8; + break; + case B_AUDIO_FORMAT_INT16: + fConvert = &float32_to_int16; + break; + case B_AUDIO_FORMAT_INT32: + fConvert = &float32_to_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fConvert = &float32_to_float32; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown output format\n"); + break; + } + break; + + case B_AUDIO_FORMAT_FLOAT64: + switch (ioDecodedFormat->u.raw_audio.format) { + case B_AUDIO_FORMAT_UINT8: + fConvert = &float64_to_uint8; + break; + case B_AUDIO_FORMAT_INT8: + fConvert = &float64_to_int8; + break; + case B_AUDIO_FORMAT_INT16: + fConvert = &float64_to_int16; + break; + case B_AUDIO_FORMAT_INT32: + fConvert = &float64_to_int32; + break; + case B_AUDIO_FORMAT_FLOAT32: + fConvert = &float64_to_float32; + break; + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown output format\n"); + break; + } + break; + + default: + debugger("RawDecoder::NegotiateAudioOutputFormat unkown input format\n"); + break; + } + + fChunkBuffer = 0; + fChunkSize = 0; + fStartTime = 0; string_for_format(*ioDecodedFormat, s, sizeof(s)); - printf("RawDecoder::NegotiateOutputFormat enter: %s\n", s); - - // XXX we should allow different buffer size, sample format and byte order and do translation in decode! - - *ioDecodedFormat = fInputFormat; - - string_for_format(*ioDecodedFormat, s, sizeof(s)); - printf("RawDecoder::NegotiateOutputFormat leave: %s\n", s); - + TRACE("RawDecoder::NegotiateAudioOutputFormat leave: %s\n", s); +/* + TRACE("fFrameRate %ld\n", fFrameRate); + TRACE("fInputFrameSize %ld\n", fInputFrameSize); + TRACE("fOutputFrameSize %ld\n", fOutputFrameSize); + TRACE("fInputSampleSize %ld\n", fInputSampleSize); + TRACE("fOutputSampleSize %ld\n", fOutputSampleSize); + TRACE("fOutputBufferFrameCount %ld\n", fOutputBufferFrameCount); + TRACE("fSwapInput %p\n", fSwapInput); + TRACE("fConvert %p\n", fConvert); + TRACE("fSwapOutput %p\n", fSwapOutput); +*/ return B_OK; } @@ -57,6 +407,8 @@ RawDecoder::Seek(uint32 seekTo, int64 seekFrame, int64 *frame, bigtime_t seekTime, bigtime_t *time) { + fChunkSize = 0; + fStartTime = *time; return B_OK; } @@ -65,18 +417,38 @@ status_t RawDecoder::Decode(void *buffer, int64 *frameCount, media_header *mediaHeader, media_decode_info *info /* = 0 */) { - void *chunkBuffer; - int32 chunkSize; - status_t err; - - err = GetNextChunk(&chunkBuffer, &chunkSize, mediaHeader); - if (err != B_OK) - return err; + char *output_buffer = (char *)buffer; + mediaHeader->start_time = fStartTime; + *frameCount = 0; + while (*frameCount < fOutputBufferFrameCount) { + if (fChunkSize == 0) { + media_header mh; + status_t err; + err = GetNextChunk((void **)&fChunkBuffer, &fChunkSize, &mh); + if (err != B_OK || fChunkSize < fInputFrameSize) { + fChunkSize = 0; + break; + } + if (fSwapInput) + fSwapInput(fChunkBuffer, fChunkSize / fInputSampleSize); + fStartTime = mh.start_time; + continue; + } + int32 frames = min_c(fOutputBufferFrameCount - *frameCount, fChunkSize / fInputFrameSize); + int32 samples = frames * fInputFormat.u.raw_audio.channel_count; + fConvert(output_buffer, fChunkBuffer, samples); + fChunkBuffer += frames * fInputFrameSize; + fChunkSize -= frames * fInputFrameSize; + output_buffer += frames * fOutputFrameSize; + *frameCount += frames; + fStartTime += (1000000LL * frames) / fFrameRate; + } + // XXX should change channel order here for + // B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE and B_AUDIO_FORMAT_CHANNEL_ORDER_AIFF - memcpy(buffer, chunkBuffer, chunkSize); - *frameCount = chunkSize / fFrameSize; - - return B_OK; + if (fSwapOutput) + fSwapOutput(buffer, *frameCount * fInputFormat.u.raw_audio.channel_count); + return *frameCount ? B_OK : B_ERROR; } @@ -89,7 +461,7 @@ RawDecoderPlugin::NewDecoder() status_t RawDecoderPlugin::RegisterPlugin() { - PublishDecoder("audiocodec/raw", "raw", "RAW audio decoder", "{ WAV : 0x1 }, { QT : 0x20776172, 0x736f7774, 0x74776f73 }"); + PublishDecoder("audiocodec/raw", "raw", "RAW audio decoder"); PublishDecoder("videocodec/raw", "raw", "RAW video decoder"); return B_OK; } diff --git a/src/add-ons/media/plugins/raw_decoder/RawDecoderPlugin.h b/src/add-ons/media/plugins/raw_decoder/RawDecoderPlugin.h index b5b91524d5..6e98cfee92 100644 --- a/src/add-ons/media/plugins/raw_decoder/RawDecoderPlugin.h +++ b/src/add-ons/media/plugins/raw_decoder/RawDecoderPlugin.h @@ -14,8 +14,27 @@ public: status_t Decode(void *buffer, int64 *frameCount, media_header *mediaHeader, media_decode_info *info); + private: - int32 fFrameSize; + status_t NegotiateVideoOutputFormat(media_format *ioDecodedFormat); + status_t NegotiateAudioOutputFormat(media_format *ioDecodedFormat); + +private: + int32 fFrameRate; + int32 fInputFrameSize; + int32 fOutputFrameSize; + int32 fInputSampleSize; + int32 fOutputSampleSize; + int32 fOutputBufferFrameCount; + void (*fSwapInput)(void *data, int32 count); + void (*fConvert)(void *dst, void *src, int32 count); + void (*fSwapOutput)(void *data, int32 count); + + char * fChunkBuffer; + int32 fChunkSize; + + bigtime_t fStartTime; + media_format fInputFormat; }; diff --git a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp index fb1c460c32..de4edb8d04 100644 --- a/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp +++ b/src/add-ons/media/plugins/wav_reader/WavReaderPlugin.cpp @@ -5,6 +5,7 @@ #include #include #include "WavReaderPlugin.h" +#include "RawFormats.h" #define TRACE_THIS 1 #if TRACE_THIS @@ -258,21 +259,22 @@ WavReader::AllocateCookie(int32 streamNumber, void **cookie) data->format.u.raw_audio.channel_count = fChannelCount; switch (fBitsPerSample) { case 8: - data->format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_UCHAR; + data->format.u.raw_audio.format = B_AUDIO_FORMAT_UINT8; break; case 16: - data->format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_SHORT; + data->format.u.raw_audio.format = B_AUDIO_FORMAT_INT16; break; case 24: - data->format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; + data->format.u.raw_audio.format = B_AUDIO_FORMAT_INT24; break; case 32: - data->format.u.raw_audio.format = media_raw_audio_format::B_AUDIO_INT; + data->format.u.raw_audio.format = B_AUDIO_FORMAT_INT32; break; default: TRACE("WavReader::AllocateCookie: unhandled bits per sample %d\n", fBitsPerSample); return B_ERROR; } + data->format.u.raw_audio.format |= B_AUDIO_FORMAT_CHANNEL_ORDER_WAVE; data->format.u.raw_audio.byte_order = B_MEDIA_LITTLE_ENDIAN; data->format.u.raw_audio.buffer_size = data->buffersize; } else { diff --git a/src/kits/media/MediaRoster.cpp b/src/kits/media/MediaRoster.cpp index f4699c25bd..84c2371652 100644 --- a/src/kits/media/MediaRoster.cpp +++ b/src/kits/media/MediaRoster.cpp @@ -2696,7 +2696,10 @@ BMediaRoster::AudioBufferSizeFor(int32 channel_count, bus_type bus_kind) { UNIMPLEMENTED(); - return 4096; + int size = 4096; + int framesize = (sample_format & 0xf) * channel_count; + size = (size / framesize) * framesize; + return size; }