--- a/dom/media/AudioConverter.cpp
+++ b/dom/media/AudioConverter.cpp
@@ -68,27 +68,27 @@ AudioConverter::CanWorkInPlace() const
// We should be able to work in place if 1s of audio input takes less space
// than 1s of audio output. However, as we downmix before resampling we can't
// perform any upsampling in place (e.g. if incoming rate >= outgoing rate)
return (!needDownmix || canDownmixInPlace) &&
(!needResample || canResampleInPlace);
}
size_t
-AudioConverter::ProcessInternal(void* aOut, const void* aIn, size_t aBytes)
+AudioConverter::ProcessInternal(void* aOut, const void* aIn, size_t aFrames)
{
if (mIn.Channels() > mOut.Channels()) {
- return DownmixAudio(aOut, aIn, aBytes);
+ return DownmixAudio(aOut, aIn, aFrames);
} else if (mIn.Layout() != mOut.Layout() &&
CanReorderAudio()) {
- ReOrderInterleavedChannels(aOut, aIn, aBytes);
+ ReOrderInterleavedChannels(aOut, aIn, aFrames);
} else if (aIn != aOut) {
- memmove(aOut, aIn, aBytes);
+ memmove(aOut, aIn, FramesOutToBytes(aFrames));
}
- return aBytes;
+ return aFrames;
}
// Reorder interleaved channels.
// Can work in place (e.g aOut == aIn).
template <class AudioDataType>
void
_ReOrderInterleavedChannels(AudioDataType* aOut, const AudioDataType* aIn,
uint32_t aFrames, uint32_t aChannels,
@@ -105,95 +105,90 @@ void
}
aOut += aChannels;
aIn += aChannels;
}
}
void
AudioConverter::ReOrderInterleavedChannels(void* aOut, const void* aIn,
- size_t aDataSize) const
+ size_t aFrames) const
{
MOZ_DIAGNOSTIC_ASSERT(mIn.Channels() == mOut.Channels());
if (mOut.Layout() == mIn.Layout()) {
return;
}
if (mOut.Channels() == 1) {
// If channel count is 1, planar and non-planar formats are the same and
// there's nothing to reorder.
if (aOut != aIn) {
- memmove(aOut, aIn, aDataSize);
+ memmove(aOut, aIn, FramesOutToBytes(aFrames));
}
return;
}
uint32_t bits = AudioConfig::FormatToBits(mOut.Format());
switch (bits) {
case 8:
_ReOrderInterleavedChannels((uint8_t*)aOut, (const uint8_t*)aIn,
- aDataSize/sizeof(uint8_t)/mIn.Channels(),
- mIn.Channels(), mChannelOrderMap);
+ aFrames, mIn.Channels(), mChannelOrderMap);
break;
case 16:
_ReOrderInterleavedChannels((int16_t*)aOut,(const int16_t*)aIn,
- aDataSize/sizeof(int16_t)/mIn.Channels(),
- mIn.Channels(), mChannelOrderMap);
+ aFrames, mIn.Channels(), mChannelOrderMap);
break;
default:
MOZ_DIAGNOSTIC_ASSERT(AudioConfig::SampleSize(mOut.Format()) == 4);
_ReOrderInterleavedChannels((int32_t*)aOut,(const int32_t*)aIn,
- aDataSize/sizeof(int32_t)/mIn.Channels(),
- mIn.Channels(), mChannelOrderMap);
+ aFrames, mIn.Channels(), mChannelOrderMap);
break;
}
}
static inline int16_t clipTo15(int32_t aX)
{
return aX < -32768 ? -32768 : aX <= 32767 ? aX : 32767;
}
size_t
-AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const
+AudioConverter::DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const
{
MOZ_ASSERT(mIn.Format() == AudioConfig::FORMAT_S16 ||
mIn.Format() == AudioConfig::FORMAT_FLT);
MOZ_ASSERT(mIn.Channels() >= mOut.Channels());
MOZ_ASSERT(mIn.Layout() == AudioConfig::ChannelLayout(mIn.Channels()),
"Can only downmix input data in SMPTE layout");
MOZ_ASSERT(mOut.Layout() == AudioConfig::ChannelLayout(2) ||
mOut.Layout() == AudioConfig::ChannelLayout(1));
uint32_t channels = mIn.Channels();
- uint32_t frames =
- aDataSize / AudioConfig::SampleSize(mOut.Format()) / channels;
if (channels == 1 && mOut.Channels() == 1) {
if (aOut != aIn) {
- memmove(aOut, aIn, aDataSize);
+ memmove(aOut, aIn, FramesOutToBytes(aFrames));
}
- return aDataSize;
+ return aFrames;
}
if (channels > 2) {
if (mIn.Format() == AudioConfig::FORMAT_FLT) {
// Downmix matrix. Per-row normalization 1 for rows 3,4 and 2 for rows 5-8.
static const float dmatrix[6][8][2]= {
/*3*/{{0.5858f,0},{0,0.5858f},{0.4142f,0.4142f}},
/*4*/{{0.4226f,0},{0,0.4226f},{0.366f, 0.2114f},{0.2114f,0.366f}},
/*5*/{{0.6510f,0},{0,0.6510f},{0.4600f,0.4600f},{0.5636f,0.3254f},{0.3254f,0.5636f}},
/*6*/{{0.5290f,0},{0,0.5290f},{0.3741f,0.3741f},{0.3741f,0.3741f},{0.4582f,0.2645f},{0.2645f,0.4582f}},
/*7*/{{0.4553f,0},{0,0.4553f},{0.3220f,0.3220f},{0.3220f,0.3220f},{0.2788f,0.2788f},{0.3943f,0.2277f},{0.2277f,0.3943f}},
/*8*/{{0.3886f,0},{0,0.3886f},{0.2748f,0.2748f},{0.2748f,0.2748f},{0.3366f,0.1943f},{0.1943f,0.3366f},{0.3366f,0.1943f},{0.1943f,0.3366f}},
};
// Re-write the buffer with downmixed data
const float* in = static_cast<const float*>(aIn);
float* out = static_cast<float*>(aOut);
- for (uint32_t i = 0; i < frames; i++) {
+ for (uint32_t i = 0; i < aFrames; i++) {
float sampL = 0.0;
float sampR = 0.0;
for (uint32_t j = 0; j < channels; j++) {
sampL += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][0];
sampR += in[i*mIn.Channels()+j]*dmatrix[mIn.Channels()-3][j][1];
}
*out++ = sampL;
*out++ = sampR;
@@ -207,17 +202,17 @@ AudioConverter::DownmixAudio(void* aOut,
/*5*/{{10663,0},{0, 10663},{7540,7540},{9234,5331},{5331,9234}},
/*6*/{{8668, 0},{0, 8668},{6129,6129},{6129,6129},{7507,4335},{4335,7507}},
/*7*/{{7459, 0},{0, 7459},{5275,5275},{5275,5275},{4568,4568},{6460,3731},{3731,6460}},
/*8*/{{6368, 0},{0, 6368},{4502,4502},{4502,4502},{5514,3184},{3184,5514},{5514,3184},{3184,5514}}
};
// Re-write the buffer with downmixed data
const int16_t* in = static_cast<const int16_t*>(aIn);
int16_t* out = static_cast<int16_t*>(aOut);
- for (uint32_t i = 0; i < frames; i++) {
+ for (uint32_t i = 0; i < aFrames; i++) {
int32_t sampL = 0;
int32_t sampR = 0;
for (uint32_t j = 0; j < channels; j++) {
sampL+=in[i*channels+j]*dmatrix[channels-3][j][0];
sampR+=in[i*channels+j]*dmatrix[channels-3][j][1];
}
*out++ = clipTo15((sampL + 8192)>>14);
*out++ = clipTo15((sampR + 8192)>>14);
@@ -231,65 +226,80 @@ AudioConverter::DownmixAudio(void* aOut,
aIn = aOut;
channels = 2;
}
if (mOut.Channels() == 1) {
if (mIn.Format() == AudioConfig::FORMAT_FLT) {
const float* in = static_cast<const float*>(aIn);
float* out = static_cast<float*>(aOut);
- for (uint32_t fIdx = 0; fIdx < frames; ++fIdx) {
+ for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
float sample = 0.0;
// The sample of the buffer would be interleaved.
sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
*out++ = sample;
}
} else if (mIn.Format() == AudioConfig::FORMAT_S16) {
const int16_t* in = static_cast<const int16_t*>(aIn);
int16_t* out = static_cast<int16_t*>(aOut);
- for (uint32_t fIdx = 0; fIdx < frames; ++fIdx) {
+ for (uint32_t fIdx = 0; fIdx < aFrames; ++fIdx) {
int32_t sample = 0.0;
// The sample of the buffer would be interleaved.
sample = (in[fIdx*channels] + in[fIdx*channels + 1]) * 0.5;
*out++ = sample;
}
} else {
MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
}
}
- return (size_t)frames * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels();
+ return aFrames;
}
size_t
-AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aDataSize)
+AudioConverter::ResampleAudio(void* aOut, const void* aIn, size_t aFrames)
{
if (!mResampler) {
return 0;
}
- uint32_t frames =
- aDataSize / AudioConfig::SampleSize(mOut.Format()) / mOut.Channels();
- uint32_t outframes = ResampleRecipientFrames(frames);
- uint32_t inframes = frames;
+ uint32_t outframes = ResampleRecipientFrames(aFrames);
+ uint32_t inframes = aFrames;
if (mOut.Format() == AudioConfig::FORMAT_FLT) {
const float* in = reinterpret_cast<const float*>(aIn);
float* out = reinterpret_cast<float*>(aOut);
speex_resampler_process_interleaved_float(mResampler, in, &inframes,
out, &outframes);
} else if (mOut.Format() == AudioConfig::FORMAT_S16) {
const int16_t* in = reinterpret_cast<const int16_t*>(aIn);
int16_t* out = reinterpret_cast<int16_t*>(aOut);
speex_resampler_process_interleaved_int(mResampler, in, &inframes,
out, &outframes);
} else {
MOZ_DIAGNOSTIC_ASSERT(false, "Unsupported data type");
}
- MOZ_ASSERT(inframes == frames, "Some frames will be dropped");
- return (size_t)outframes * AudioConfig::SampleSize(mOut.Format()) * mOut.Channels();
+ MOZ_ASSERT(inframes == aFrames, "Some frames will be dropped");
+ return outframes;
}
size_t
AudioConverter::ResampleRecipientFrames(size_t aFrames) const
{
return (uint64_t)aFrames * mOut.Rate() / mIn.Rate() + 1;
}
+size_t
+AudioConverter::FramesOutToSamples(size_t aFrames) const
+{
+ return aFrames * mOut.Channels();
+}
+
+size_t
+AudioConverter::SamplesInToFrames(size_t aSamples) const
+{
+ return aSamples / mIn.Channels();
+}
+
+size_t
+AudioConverter::FramesOutToBytes(size_t aFrames) const
+{
+ return FramesOutToSamples(aFrames) * AudioConfig::SampleSize(mOut.Format());
+}
} // namespace mozilla
--- a/dom/media/AudioConverter.h
+++ b/dom/media/AudioConverter.h
@@ -124,74 +124,73 @@ public:
// Conversion will be done in place if possible. Otherwise a new buffer will
// be returned.
template <AudioConfig::SampleFormat Format, typename Value>
AudioDataBuffer<Format, Value> Process(AudioDataBuffer<Format, Value>&& aBuffer)
{
MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
AudioDataBuffer<Format, Value> buffer = Move(aBuffer);
if (CanWorkInPlace()) {
- size_t bytes = ProcessInternal(buffer.Data(), buffer.Data(), buffer.Size());
- if (bytes && mIn.Rate() != mOut.Rate()) {
- bytes = ResampleAudio(buffer.Data(), buffer.Data(), bytes);
+ size_t frames = SamplesInToFrames(buffer.Length());
+ frames = ProcessInternal(buffer.Data(), buffer.Data(), frames);
+ if (frames && mIn.Rate() != mOut.Rate()) {
+ frames = ResampleAudio(buffer.Data(), buffer.Data(), frames);
}
AlignedBuffer<Value> temp = buffer.Forget();
- temp.SetLength(bytes / AudioConfig::SampleSize(mOut.Format()));
+ temp.SetLength(FramesOutToSamples(frames));
return AudioDataBuffer<Format, Value>(Move(temp));;
}
return Process(buffer);
}
template <AudioConfig::SampleFormat Format, typename Value>
AudioDataBuffer<Format, Value> Process(const AudioDataBuffer<Format, Value>& aBuffer)
{
MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format() && mIn.Format() == Format);
// Perform the downmixing / reordering in temporary buffer.
- uint32_t frames = aBuffer.Length() / mIn.Channels();
+ size_t frames = SamplesInToFrames(aBuffer.Length());
AlignedBuffer<Value> temp1;
- if (!temp1.SetLength(frames * mOut.Channels())) {
+ if (!temp1.SetLength(FramesOutToSamples(frames))) {
return AudioDataBuffer<Format, Value>(Move(temp1));
}
- size_t bytes = ProcessInternal(temp1.Data(), aBuffer.Data(), aBuffer.Size());
- if (!bytes || mIn.Rate() == mOut.Rate()) {
- temp1.SetLength(bytes / AudioConfig::SampleSize(mOut.Format()));
+ frames = ProcessInternal(temp1.Data(), aBuffer.Data(), frames);
+ if (!frames || mIn.Rate() == mOut.Rate()) {
+ temp1.SetLength(FramesOutToSamples(frames));
return AudioDataBuffer<Format, Value>(Move(temp1));
}
// At this point, temp1 contains the buffer reordered and downmixed.
// If we are downsampling we can re-use it.
AlignedBuffer<Value>* outputBuffer = &temp1;
AlignedBuffer<Value> temp2;
if (mOut.Rate() > mIn.Rate()) {
// We are upsampling, we can't work in place. Allocate another temporary
// buffer where the upsampling will occur.
- temp2.SetLength(ResampleRecipientFrames(frames) * mOut.Channels());
+ temp2.SetLength(FramesOutToSamples(ResampleRecipientFrames(frames)));
outputBuffer = &temp2;
}
- bytes = ResampleAudio(outputBuffer->Data(), temp1.Data(), bytes);
- outputBuffer->SetLength(bytes / AudioConfig::SampleSize(mOut.Format()));
+ frames = ResampleAudio(outputBuffer->Data(), temp1.Data(), frames);
+ outputBuffer->SetLength(FramesOutToSamples(frames));
return AudioDataBuffer<Format, Value>(Move(*outputBuffer));
}
// Attempt to convert the AudioDataBuffer in place.
// Will return 0 if the conversion wasn't possible.
template <typename Value>
- size_t Process(Value* aBuffer, size_t aSamples)
+ size_t Process(Value* aBuffer, size_t aFrames)
{
MOZ_DIAGNOSTIC_ASSERT(mIn.Format() == mOut.Format());
if (!CanWorkInPlace()) {
return 0;
}
- size_t bytes =
- ProcessInternal(aBuffer, aBuffer,
- aSamples * AudioConfig::SampleSize(mIn.Format()));
- if (bytes && mIn.Rate() != mOut.Rate()) {
- bytes = ResampleAudio(aBuffer, aBuffer, bytes);
+ size_t frames = ProcessInternal(aBuffer, aBuffer, aFrames);
+ if (frames && mIn.Rate() != mOut.Rate()) {
+ frames = ResampleAudio(aBuffer, aBuffer, aFrames);
}
- return bytes;
+ return frames;
}
bool CanWorkInPlace() const;
bool CanReorderAudio() const
{
return mIn.Layout().MappingTable(mOut.Layout());
}
@@ -202,25 +201,29 @@ private:
const AudioConfig mIn;
const AudioConfig mOut;
uint8_t mChannelOrderMap[MAX_AUDIO_CHANNELS];
/**
* ProcessInternal
* Parameters:
* aOut : destination buffer where converted samples will be copied
* aIn : source buffer
- * aBytes: size in bytes of source buffer
+ * aSamples: number of frames in source buffer
*
- * Return Value: size in bytes of samples converted or 0 if error
+ * Return Value: number of frames converted or 0 if error
*/
- size_t ProcessInternal(void* aOut, const void* aIn, size_t aBytes);
- void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aDataSize) const;
- size_t DownmixAudio(void* aOut, const void* aIn, size_t aDataSize) const;
+ size_t ProcessInternal(void* aOut, const void* aIn, size_t aFrames);
+ void ReOrderInterleavedChannels(void* aOut, const void* aIn, size_t aFrames) const;
+ size_t DownmixAudio(void* aOut, const void* aIn, size_t aFrames) const;
+
+ size_t FramesOutToSamples(size_t aFrames) const;
+ size_t SamplesInToFrames(size_t aSamples) const;
+ size_t FramesOutToBytes(size_t aFrames) const;
// Resampler context.
SpeexResamplerState* mResampler;
- size_t ResampleAudio(void* aOut, const void* aIn, size_t aDataSize);
+ size_t ResampleAudio(void* aOut, const void* aIn, size_t aFrames);
size_t ResampleRecipientFrames(size_t aFrames) const;
};
} // namespace mozilla
#endif /* AudioConverter_h */