Chromium Code Reviews| Index: services/media/framework/parts/lpcm_reformatter.cc |
| diff --git a/services/media/framework/parts/lpcm_reformatter.cc b/services/media/framework/parts/lpcm_reformatter.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..6b175b6c8119029f8af1bfe594720aeefa3a3bcb |
| --- /dev/null |
| +++ b/services/media/framework/parts/lpcm_reformatter.cc |
| @@ -0,0 +1,277 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "base/logging.h" |
| +#include "services/media/framework/parts/lpcm_reformatter.h" |
| + |
| +namespace mojo { |
| +namespace media { |
| + |
| +LpcmReformatter* LpcmReformatter::NewImpl( |
| + const LpcmStreamType& in_type, |
| + const LpcmStreamTypeSet& out_type) { |
| + switch (in_type.sample_format()) { |
|
johngro
2016/01/26 23:47:29
up to you, but you can reduce the amount of duplic
dalesat
2016/01/28 18:49:16
Acknowledged.
|
| + case LpcmStreamType::SampleFormat::kUnsigned8: |
| + switch (out_type.sample_format()) { |
| + case LpcmStreamType::SampleFormat::kUnsigned8: |
| + case LpcmStreamType::SampleFormat::kAny: |
| + return new LpcmReformatterImpl<uint8_t, uint8_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kSigned16: |
| + return new LpcmReformatterImpl<uint8_t, int16_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kSigned24In32: |
| + return new LpcmReformatterImpl<uint8_t, int32_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kFloat: |
| + return new LpcmReformatterImpl<uint8_t, float>( |
| + in_type, out_type); |
| + default: |
| + NOTREACHED() << "unsupported sample format"; |
| + return nullptr; |
| + } |
| + case LpcmStreamType::SampleFormat::kSigned16: |
| + switch (out_type.sample_format()) { |
| + case LpcmStreamType::SampleFormat::kUnsigned8: |
| + return new LpcmReformatterImpl<int16_t, uint8_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kSigned16: |
| + case LpcmStreamType::SampleFormat::kAny: |
| + return new LpcmReformatterImpl<int16_t, int16_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kSigned24In32: |
| + return new LpcmReformatterImpl<int16_t, int32_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kFloat: |
| + return new LpcmReformatterImpl<int16_t, float>( |
| + in_type, out_type); |
| + default: |
| + NOTREACHED() << "unsupported sample format"; |
| + return nullptr; |
| + } |
| + case LpcmStreamType::SampleFormat::kSigned24In32: |
| + switch (out_type.sample_format()) { |
| + case LpcmStreamType::SampleFormat::kUnsigned8: |
| + return new LpcmReformatterImpl<int32_t, uint8_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kSigned16: |
| + return new LpcmReformatterImpl<int32_t, int16_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kSigned24In32: |
| + case LpcmStreamType::SampleFormat::kAny: |
| + return new LpcmReformatterImpl<int32_t, int32_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kFloat: |
| + return new LpcmReformatterImpl<int32_t, float>( |
| + in_type, out_type); |
| + default: |
| + NOTREACHED() << "unsupported sample format"; |
| + return nullptr; |
| + } |
| + case LpcmStreamType::SampleFormat::kFloat: |
| + switch (out_type.sample_format()) { |
| + case LpcmStreamType::SampleFormat::kUnsigned8: |
| + return new LpcmReformatterImpl<float, uint8_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kSigned16: |
| + return new LpcmReformatterImpl<float, int16_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kSigned24In32: |
| + return new LpcmReformatterImpl<float, int32_t>( |
| + in_type, out_type); |
| + case LpcmStreamType::SampleFormat::kFloat: |
| + case LpcmStreamType::SampleFormat::kAny: |
| + return new LpcmReformatterImpl<float, float>(in_type, out_type); |
| + default: |
| + NOTREACHED() << "unsupported sample format"; |
| + return nullptr; |
| + } |
| + default: |
| + NOTREACHED() << "unsupported sample format"; |
| + return nullptr; |
| + } |
| +} |
| + |
| +template<typename TIn, typename TOut> |
| +LpcmReformatterImpl<TIn, TOut>::LpcmReformatterImpl( |
| + const LpcmStreamType& in_type, |
| + const LpcmStreamTypeSet& out_type) : |
| + in_type_(in_type), |
| + out_type_( |
| + out_type.sample_format() == LpcmStreamType::SampleFormat::kAny ? |
| + in_type.sample_format() : |
| + out_type.sample_format(), |
| + in_type.channels(), |
| + in_type.frames_per_second()) {} |
| + |
| +template<typename TIn, typename TOut> |
| +LpcmReformatterImpl<TIn, TOut>::~LpcmReformatterImpl() {} |
| + |
| +namespace { |
| + |
| +// TODO(dalesat): Limit, optimize. |
| + |
| +template<typename TIn, typename TOut> |
| +inline void CopySample(TOut* dest, TIn* source) { |
| + *dest = static_cast<TOut>(*source); |
| +} |
| + |
| +inline void CopySample(uint8_t* dest, int16_t* source) { |
| + *dest = static_cast<uint8_t>((*source >> 8) ^ 0x80); |
| +} |
| + |
| +inline void CopySample(uint8_t* dest, int32_t* source) { |
| + *dest = static_cast<uint8_t>((*source >> 16) ^ 0x80); |
| +} |
| + |
| +inline void CopySample(uint8_t* dest, float* source) { |
|
johngro
2016/01/26 23:47:29
Source needs to be clamped to the range [-1.0, 1.0
dalesat
2016/01/28 18:49:15
Done.
|
| + *dest = static_cast<uint8_t>((*source * 0x7f) + 128); |
| +} |
| + |
| +inline void CopySample(int16_t* dest, uint8_t* source) { |
| + *dest = static_cast<int16_t>(*source ^ 0x80) << 8; |
| +} |
| + |
| +inline void CopySample(int16_t* dest, int32_t* source) { |
| + *dest = static_cast<int16_t>(*source >> 8); |
| +} |
| + |
| +inline void CopySample(int16_t* dest, float* source) { |
| + *dest = static_cast<int16_t>(*source * 0x7fff); |
| +} |
| + |
| +inline void CopySample(int32_t* dest, uint8_t* source) { |
| + *dest = static_cast<int32_t>(*source ^ 0x80) << 16; |
| +} |
| + |
| +inline void CopySample(int32_t* dest, int16_t* source) { |
| + *dest = static_cast<int32_t>(*source << 8); |
| +} |
| + |
| +inline void CopySample(int32_t* dest, float* source) { |
| + *dest = static_cast<int32_t>(*source * 0x7fffff); |
| +} |
| + |
| +inline void CopySample(float* dest, uint8_t* source) { |
| + *dest = static_cast<float>(*source ^ 0x80) / 0x80; |
| +} |
| + |
| +inline void CopySample(float* dest, int16_t* source) { |
| + *dest = static_cast<float>(*source) / 0x8000; |
| +} |
| + |
| +inline void CopySample(float* dest, int32_t* source) { |
| + *dest = static_cast<float>(*source) / 0x800000; |
| +} |
| + |
| +template<typename TIn, typename TOut> |
| +inline void MixSample(TOut* dest, TIn* source) { |
| + *dest += static_cast<TOut>(*source); |
| +} |
| + |
| +inline void MixSample(uint8_t* dest, int16_t* source) { |
| + *dest += static_cast<uint8_t>((*source >> 8) ^ 0x80); |
| +} |
| + |
| +inline void MixSample(uint8_t* dest, int32_t* source) { |
| + *dest += static_cast<uint8_t>((*source >> 16) ^ 0x80); |
| +} |
| + |
| +inline void MixSample(uint8_t* dest, float* source) { |
| + *dest += static_cast<uint8_t>((*source * 0x7f) + 128); |
| +} |
| + |
| +inline void MixSample(int16_t* dest, uint8_t* source) { |
| + *dest += static_cast<int16_t>(*source ^ 0x80) << 8; |
| +} |
| + |
| +inline void MixSample(int16_t* dest, int32_t* source) { |
| + *dest += static_cast<int16_t>(*source >> 8); |
| +} |
| + |
| +inline void MixSample(int16_t* dest, float* source) { |
| + *dest += static_cast<int16_t>(*source * 0x7fff); |
| +} |
| + |
| +inline void MixSample(int32_t* dest, uint8_t* source) { |
| + *dest += static_cast<int32_t>(*source ^ 0x80) << 16; |
| +} |
| + |
| +inline void MixSample(int32_t* dest, int16_t* source) { |
| + *dest += static_cast<int32_t>(*source << 8); |
| +} |
| + |
| +inline void MixSample(int32_t* dest, float* source) { |
| + *dest += static_cast<int32_t>(*source * 0x7fffff); |
| +} |
| + |
| +inline void MixSample(float* dest, uint8_t* source) { |
| + *dest += static_cast<float>(*source ^ 0x80) / 0x80; |
| +} |
| + |
| +inline void MixSample(float* dest, int16_t* source) { |
| + *dest += static_cast<float>(*source) / 0x8000; |
| +} |
| + |
| +inline void MixSample(float* dest, int32_t* source) { |
| + *dest += static_cast<float>(*source) / 0x800000; |
| +} |
| + |
| +} // namespace |
| + |
| +template<typename TIn, typename TOut> |
| +const LpcmStreamType& LpcmReformatterImpl<TIn, TOut>::input_stream_type() |
| + const { |
| + return in_type_; |
| +} |
| + |
| +template<typename TIn, typename TOut> |
| +const LpcmStreamType& LpcmReformatterImpl<TIn, TOut>::output_stream_type() |
| + const { |
| + return out_type_; |
| +} |
| + |
| +template<typename TIn, typename TOut> |
| +void LpcmReformatterImpl<TIn, TOut>::TransformFrames( |
| + LpcmFrames* source, |
| + LpcmFrames* dest, |
| + bool mix) { |
| + DCHECK(source); |
| + DCHECK(dest); |
| + DCHECK(source->buffer()); |
| + DCHECK(source->frame_count()); |
| + DCHECK(dest->buffer()); |
| + DCHECK(dest->frame_count()); |
| + |
| + uint64_t frame_count = std::min(source->frame_count(), dest->frame_count()); |
| + |
| + uint8_t* in_channel = reinterpret_cast<uint8_t*>(source->buffer()); |
| + uint8_t* out_channel = reinterpret_cast<uint8_t*>(dest->buffer()); |
|
johngro
2016/01/26 23:47:29
FWIW - when casing a pointer to a PoD to another p
|
| + |
| + for (uint32_t channel = 0; channel < in_type_.channels(); channel++) { |
| + TIn* in_sample = reinterpret_cast<TIn*>(in_channel); |
| + TOut* out_sample = reinterpret_cast<TOut*>(out_channel); |
| + if (mix) { |
|
johngro
2016/01/26 23:47:29
if you are going to put the mix decision in here,
dalesat
2016/01/28 18:49:16
The outer loop is per-channel. The test will happe
johngro
2016/02/01 22:38:16
Acknowledged.
|
| + for (uint64_t sample = 0; sample < frame_count; sample++) { |
| + MixSample(out_sample, in_sample); |
| + in_sample += in_type_.channels(); |
| + out_sample += out_type_.channels(); |
| + } |
| + } else { |
| + for (uint64_t sample = 0; sample < frame_count; sample++) { |
| + CopySample(out_sample, in_sample); |
| + in_sample += in_type_.channels(); |
| + out_sample += out_type_.channels(); |
| + } |
| + } |
| + in_channel += in_type_.sample_size(); |
| + out_channel += out_type_.sample_size(); |
| + } |
| + |
| + source->advance(frame_count); |
| + dest->advance(frame_count); |
| +} |
| + |
| +} // namespace media |
| +} // namespace mojo |