Bug 524109 - Added support for 24 bit wav files. r=cpearce
--- a/dom/media/test/manifest.js
+++ b/dom/media/test/manifest.js
@@ -149,16 +149,18 @@ var gPlayTests = [
// 8-bit samples
{ name:"r11025_u8_c1.wav", type:"audio/x-wav", duration:1.0 },
// 8-bit samples, file is truncated
{ name:"r11025_u8_c1_trunc.wav", type:"audio/x-wav", duration:1.8 },
// file has trailing non-PCM data
{ name:"r11025_s16_c1_trailing.wav", type:"audio/x-wav", duration:1.0 },
// file with list chunk
{ name:"r16000_u8_c1_list.wav", type:"audio/x-wav", duration:4.2 },
+ // 24-bit samples
+ { name:"wavedata_s24.wav", type:"audio/x-wav", duration:1.0 },
// Ogg stream without eof marker
{ name:"bug461281.ogg", type:"application/ogg", duration:2.208 },
// oggz-chop stream
{ name:"bug482461.ogv", type:"video/ogg", duration:4.34 },
// Theora only oggz-chop stream
{ name:"bug482461-theora.ogv", type:"video/ogg", duration:4.138 },
--- a/dom/media/test/mochitest.ini
+++ b/dom/media/test/mochitest.ini
@@ -550,16 +550,18 @@ support-files =
wave_metadata_bad_no_null.wav
wave_metadata_bad_no_null.wav^headers^
wave_metadata_bad_utf8.wav
wave_metadata_bad_utf8.wav^headers^
wave_metadata_unknown_tag.wav
wave_metadata_unknown_tag.wav^headers^
wave_metadata_utf8.wav
wave_metadata_utf8.wav^headers^
+ wavedata_s24.wav
+ wavedata_s24.wav^headers^
wavedata_s16.wav
wavedata_s16.wav^headers^
wavedata_u8.wav
wavedata_u8.wav^headers^
[test_access_control.html]
skip-if = buildapp == 'b2g' && toolkit != 'gonk' # bug 1082984
[test_aspectratio_mp4.html]
new file mode 100644
index 0000000000000000000000000000000000000000..dbdb6aac1ec3edc52909e529e591f578b36df2ee
GIT binary patch
literal 33071
zc%1FXAr6C300Yo2T!1;`+ys&nOpIi9f@u<h!{NtH4xe-EwNEsCzxw|EOFoa`IWOz2
zPI4)|wn<n1Dov(w9jmglf0Hd|HUIzs00000000000000000000000000000000000
G;BOtnXNleb
new file mode 100644
--- /dev/null
+++ b/dom/media/test/wavedata_s24.wav^headers^
@@ -0,0 +1,1 @@
+Cache-Control: no-store
--- a/dom/media/wave/WaveReader.cpp
+++ b/dom/media/wave/WaveReader.cpp
@@ -75,16 +75,30 @@ namespace {
uint32_t
ReadUint32LE(const char** aBuffer)
{
uint32_t result = LittleEndian::readUint32(*aBuffer);
*aBuffer += sizeof(uint32_t);
return result;
}
+ int32_t
+ ReadInt24LE(const char** aBuffer)
+ {
+ int32_t result = int32_t((uint8_t((*aBuffer)[2]) << 16) |
+ (uint8_t((*aBuffer)[1]) << 8 ) |
+ (uint8_t((*aBuffer)[0])));
+ if (((*aBuffer)[2] & 0x80) == 0x80) {
+ result = (result | 0xff000000);
+ }
+
+ *aBuffer += 3 * sizeof(char);
+ return result;
+ }
+
uint16_t
ReadUint16LE(const char** aBuffer)
{
uint16_t result = LittleEndian::readUint16(*aBuffer);
*aBuffer += sizeof(uint16_t);
return result;
}
@@ -143,16 +157,17 @@ nsresult WaveReader::ReadMetadata(MediaI
*aTags = tags.forget();
return NS_OK;
}
template <typename T> T UnsignedByteToAudioSample(uint8_t aValue);
template <typename T> T SignedShortToAudioSample(int16_t aValue);
+template <typename T> T Signed24bIntToAudioSample(int32_t aValue);
template <> inline float
UnsignedByteToAudioSample<float>(uint8_t aValue)
{
return aValue * (2.0f / UINT8_MAX) - 1.0f;
}
template <> inline int16_t
UnsignedByteToAudioSample<int16_t>(uint8_t aValue)
@@ -166,29 +181,44 @@ SignedShortToAudioSample<float>(int16_t
return AudioSampleToFloat(aValue);
}
template <> inline int16_t
SignedShortToAudioSample<int16_t>(int16_t aValue)
{
return aValue;
}
+template <> inline float
+Signed24bIntToAudioSample<float>(int32_t aValue)
+{
+ return aValue / 8388608.0f;
+}
+
+template <> inline int16_t
+Signed24bIntToAudioSample<int16_t>(int32_t aValue)
+{
+ return aValue / 256;
+}
+
bool WaveReader::DecodeAudioData()
{
MOZ_ASSERT(OnTaskQueue());
int64_t pos = GetPosition() - mWavePCMOffset;
int64_t len = GetDataLength();
int64_t remaining = len - pos;
NS_ASSERTION(remaining >= 0, "Current wave position is greater than wave file length");
- static const int64_t BLOCK_SIZE = 4096;
+ static const int64_t BLOCK_SIZE = 6144;
int64_t readSize = std::min(BLOCK_SIZE, remaining);
int64_t frames = readSize / mFrameSize;
+ MOZ_ASSERT(BLOCK_SIZE % 3 == 0);
+ MOZ_ASSERT(BLOCK_SIZE % 2 == 0);
+
static_assert(uint64_t(BLOCK_SIZE) < UINT_MAX /
sizeof(AudioDataValue) / MAX_CHANNELS,
"bufferSize calculation could overflow.");
const size_t bufferSize = static_cast<size_t>(frames * mChannels);
auto sampleBuffer = MakeUnique<AudioDataValue[]>(bufferSize);
static_assert(uint64_t(BLOCK_SIZE) < UINT_MAX / sizeof(char),
"BLOCK_SIZE too large for enumerator.");
@@ -204,16 +234,19 @@ bool WaveReader::DecodeAudioData()
for (int i = 0; i < frames; ++i) {
for (unsigned int j = 0; j < mChannels; ++j) {
if (mSampleFormat == FORMAT_U8) {
uint8_t v = ReadUint8(&d);
*s++ = UnsignedByteToAudioSample<AudioDataValue>(v);
} else if (mSampleFormat == FORMAT_S16) {
int16_t v = ReadInt16LE(&d);
*s++ = SignedShortToAudioSample<AudioDataValue>(v);
+ } else if (mSampleFormat == FORMAT_S24) {
+ int32_t v = ReadInt24LE(&d);
+ *s++ = Signed24bIntToAudioSample<AudioDataValue>(v);
}
}
}
double posTime = BytesToTime(pos);
double readSizeTime = BytesToTime(readSize);
NS_ASSERTION(posTime <= INT64_MAX / USECS_PER_S, "posTime overflow");
NS_ASSERTION(readSizeTime <= INT64_MAX / USECS_PER_S, "readSizeTime overflow");
@@ -417,32 +450,35 @@ WaveReader::LoadFormatChunk(uint32_t aCh
// RIFF chunks are always word (two byte) aligned.
MOZ_ASSERT(mResource.Tell() % 2 == 0,
"LoadFormatChunk left resource unaligned");
// Make sure metadata is fairly sane. The rate check is fairly arbitrary,
// but the channels check is intentionally limited to mono or stereo
// when the media is intended for direct playback because that's what the
// audio backend currently supports.
- unsigned int actualFrameSize = (sampleFormat == 8 ? 1 : 2) * channels;
+ unsigned int actualFrameSize = sampleFormat * channels / 8;
if (rate < 100 || rate > 96000 ||
(((channels < 1 || channels > MAX_CHANNELS) ||
- (frameSize != 1 && frameSize != 2 && frameSize != 4)) &&
+ (frameSize != 1 && frameSize != 2 && frameSize != 3 &&
+ frameSize != 4 && frameSize != 6)) &&
!mIgnoreAudioOutputFormat) ||
- (sampleFormat != 8 && sampleFormat != 16) ||
+ (sampleFormat != 8 && sampleFormat != 16 && sampleFormat != 24) ||
frameSize != actualFrameSize) {
NS_WARNING("Invalid WAVE metadata");
return false;
}
mSampleRate = rate;
mChannels = channels;
mFrameSize = frameSize;
if (sampleFormat == 8) {
mSampleFormat = FORMAT_U8;
+ } else if (sampleFormat == 24) {
+ mSampleFormat = FORMAT_S24;
} else {
mSampleFormat = FORMAT_S16;
}
return true;
}
bool
WaveReader::FindDataOffset(uint32_t aChunkSize)
--- a/dom/media/wave/WaveReader.h
+++ b/dom/media/wave/WaveReader.h
@@ -71,17 +71,18 @@ private:
// Size of a single audio frame, which includes a sample for each channel
// (interleaved).
uint32_t mFrameSize;
// The sample format of the PCM data. AudioStream::SampleFormat doesn't
// support U8.
enum {
FORMAT_U8,
- FORMAT_S16
+ FORMAT_S16,
+ FORMAT_S24
} mSampleFormat;
// Size of PCM data stored in the WAVE as reported by the data chunk in
// the media.
int64_t mWaveLength;
// Start offset of the PCM data in the media stream. Extends mWaveLength
// bytes.