Commit 34e0ac22 authored by pwestin's avatar pwestin Committed by Commit bot

Adding new function ReadFrames() that returns the audio frame in planar

format int32.

BUG=

Review URL: https://codereview.chromium.org/600143002

Cr-Commit-Position: refs/heads/master@{#297340}
parent 6ae2b341
...@@ -243,6 +243,90 @@ void AudioBuffer::ReadFrames(int frames_to_copy, ...@@ -243,6 +243,90 @@ void AudioBuffer::ReadFrames(int frames_to_copy,
source_data, dest_frame_offset, frames_to_copy, bytes_per_channel); source_data, dest_frame_offset, frames_to_copy, bytes_per_channel);
} }
static inline int32 ConvertS16ToS32(int16 value) {
return static_cast<int32>(value) << 16;
}
static inline int32 ConvertF32ToS32(float value) {
return static_cast<int32>(value < 0
? (-value) * std::numeric_limits<int32>::min()
: value * std::numeric_limits<int32>::max());
}
template <class Target, typename Converter>
void InterleaveToS32(const std::vector<uint8*>& channel_data,
size_t frames_to_copy,
int trim_start,
int32* dest_data,
Converter convert_func) {
for (size_t ch = 0; ch < channel_data.size(); ++ch) {
const Target* source_data =
reinterpret_cast<const Target*>(channel_data[ch]) + trim_start;
for (size_t i = 0, offset = ch; i < frames_to_copy;
++i, offset += channel_data.size()) {
dest_data[offset] = convert_func(source_data[i]);
}
}
}
void AudioBuffer::ReadFramesInterleavedS32(int frames_to_copy,
int32* dest_data) {
DCHECK_LE(frames_to_copy, adjusted_frame_count_);
switch (sample_format_) {
case kSampleFormatU8:
NOTIMPLEMENTED();
break;
case kSampleFormatS16:
// Format is interleaved signed16. Convert each value into int32 and
// insert into output channel data.
InterleaveToS32<int16>(channel_data_,
frames_to_copy * channel_count_,
trim_start_,
dest_data,
ConvertS16ToS32);
break;
case kSampleFormatS32: {
// Format is interleaved signed32; just copy the data.
const int32* source_data =
reinterpret_cast<const int32*>(channel_data_[0]) + trim_start_;
memcpy(dest_data,
source_data,
frames_to_copy * channel_count_ * sizeof(int32));
} break;
case kSampleFormatF32:
// Format is interleaved float. Convert each value into int32 and insert
// into output channel data.
InterleaveToS32<float>(channel_data_,
frames_to_copy * channel_count_,
trim_start_,
dest_data,
ConvertF32ToS32);
break;
case kSampleFormatPlanarS16:
// Format is planar signed 16 bit. Convert each value into int32 and
// insert into output channel data.
InterleaveToS32<int16>(channel_data_,
frames_to_copy,
trim_start_,
dest_data,
ConvertS16ToS32);
break;
case kSampleFormatPlanarF32:
// Format is planar float. Convert each value into int32 and insert into
// output channel data.
InterleaveToS32<float>(channel_data_,
frames_to_copy,
trim_start_,
dest_data,
ConvertF32ToS32);
break;
case kUnknownSampleFormat:
NOTREACHED();
break;
}
}
void AudioBuffer::TrimStart(int frames_to_trim) { void AudioBuffer::TrimStart(int frames_to_trim) {
CHECK_GE(frames_to_trim, 0); CHECK_GE(frames_to_trim, 0);
CHECK_LE(frames_to_trim, adjusted_frame_count_); CHECK_LE(frames_to_trim, adjusted_frame_count_);
......
...@@ -73,6 +73,11 @@ class MEDIA_EXPORT AudioBuffer ...@@ -73,6 +73,11 @@ class MEDIA_EXPORT AudioBuffer
int dest_frame_offset, int dest_frame_offset,
AudioBus* dest); AudioBus* dest);
// Copy |frames_to_copy| frames into |dest|, |frames_to_copy| is the number of
// frames to copy. The frames are converted from their source format into
// interleaved int32.
void ReadFramesInterleavedS32(int frames_to_copy, int32* dest);
// Trim an AudioBuffer by removing |frames_to_trim| frames from the start. // Trim an AudioBuffer by removing |frames_to_trim| frames from the start.
// Timestamp and duration are adjusted to reflect the fewer frames. // Timestamp and duration are adjusted to reflect the fewer frames.
// Note that repeated calls to TrimStart() may result in timestamp() and // Note that repeated calls to TrimStart() may result in timestamp() and
......
...@@ -451,4 +451,91 @@ TEST(AudioBufferTest, TrimRangeInterleaved) { ...@@ -451,4 +451,91 @@ TEST(AudioBufferTest, TrimRangeInterleaved) {
TrimRangeTest(kSampleFormatF32); TrimRangeTest(kSampleFormatF32);
} }
static scoped_refptr<AudioBuffer> MakeReadFramesInterleavedTestBuffer(
SampleFormat sample_format,
int sample_rate,
ChannelLayout channel_layout,
int channel_count,
int frames) {
switch (sample_format) {
case kSampleFormatS16:
case kSampleFormatPlanarS16:
return MakeAudioBuffer<int16>(sample_format,
channel_layout,
channel_count,
sample_rate,
0,
1,
frames,
base::TimeDelta::FromSeconds(0));
case kSampleFormatS32:
return MakeAudioBuffer<int32>(kSampleFormatS32,
channel_layout,
channel_count,
sample_rate,
0,
65536,
frames,
base::TimeDelta::FromSeconds(0));
case kSampleFormatF32:
case kSampleFormatPlanarF32:
return MakeAudioBuffer<float>(
sample_format,
channel_layout,
channel_count,
sample_rate,
0.0f,
65536.0f / std::numeric_limits<int32>::max(),
frames,
base::TimeDelta::FromSeconds(0));
case kSampleFormatU8:
case kUnknownSampleFormat:
EXPECT_FALSE(true);
break;
}
return AudioBuffer::CreateEOSBuffer();
}
static void ReadFramesInterleavedS32Test(SampleFormat sample_format) {
const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0;
const int channels = ChannelLayoutToChannelCount(channel_layout);
const int frames = kSampleRate / 100;
const base::TimeDelta duration = base::TimeDelta::FromMilliseconds(10);
scoped_refptr<AudioBuffer> buffer = MakeReadFramesInterleavedTestBuffer(
sample_format, kSampleRate, channel_layout, channels, frames);
EXPECT_EQ(frames, buffer->frame_count());
EXPECT_EQ(duration, buffer->duration());
int32* dest = new int32[frames * channels];
buffer->ReadFramesInterleavedS32(frames, dest);
int count = 0;
for (int i = 0; i < frames; ++i) {
for (int ch = 0; ch < channels; ++ch) {
EXPECT_EQ(dest[count++], (frames * ch + i) << 16);
}
}
delete[] dest;
}
TEST(AudioBufferTest, ReadFramesInterleavedS32FromS16) {
ReadFramesInterleavedS32Test(kSampleFormatS16);
}
TEST(AudioBufferTest, ReadFramesInterleavedS32FromS32) {
ReadFramesInterleavedS32Test(kSampleFormatS32);
}
TEST(AudioBufferTest, ReadFramesInterleavedS32FromF32) {
ReadFramesInterleavedS32Test(kSampleFormatF32);
}
TEST(AudioBufferTest, ReadFramesInterleavedS32FromPlanarS16) {
ReadFramesInterleavedS32Test(kSampleFormatPlanarS16);
}
TEST(AudioBufferTest, ReadFramesInterleavedS32FromPlanarF32) {
ReadFramesInterleavedS32Test(kSampleFormatPlanarF32);
}
} // namespace media } // namespace media
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment