diff options
author | falken@chromium.org <falken@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-02 10:52:23 +0000 |
---|---|---|
committer | falken@chromium.org <falken@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-05-02 10:52:23 +0000 |
commit | e0f29eaa8757acf9ea533d19867d9553b3d54bbe (patch) | |
tree | 20104f695bb13b7cc02747670b945126c3661c52 | |
parent | b8c872c15ec4dc1ffc9c8c7873ba682b2eee8951 (diff) | |
download | chromium_src-e0f29eaa8757acf9ea533d19867d9553b3d54bbe.zip chromium_src-e0f29eaa8757acf9ea533d19867d9553b3d54bbe.tar.gz chromium_src-e0f29eaa8757acf9ea533d19867d9553b3d54bbe.tar.bz2 |
Revert of Remove AudioBuffer::set_duration(), instead base on frames. (https://codereview.chromium.org/261533002/)
Reason for revert:
This seems to have broken the chromium.webkit WebKit Win x64 Builder bot.
Log: http://build.chromium.org/p/chromium.webkit/builders/WebKit%20Win%20x64%20Builder/builds/6453
Snippet from log:
c:\b\build\slave\webkit-win-latest-rel-x64\build\src\media\base\audio_buffer.cc(16) : error C2220: warning treated as error - no 'object' file generated
c:\b\build\slave\webkit-win-latest-rel-x64\build\src\media\base\audio_buffer.cc(16) : warning C4723: potential divide by 0
Original issue's description:
> Remove AudioBuffer::set_duration(), instead base on frames.
>
> wolenetz@ asked on https://codereview.chromium.org/251893002/ why
> we allow set_duration() to be called. It used to be required since
> AudioBuffers had no concept of sample rate. However, we now attach
> a sample rate to every AudioBuffer which allows us to enforce a
> valid duration for every buffer.
>
> This CL also aligns MakeAudioBuffer() to do the same thing with
> planar and interleaved data for the sake of easier testing.
>
> BUG=none
> TEST=media_unittests
> NOTRY=true
>
> Committed: https://src.chromium.org/viewvc/chrome?view=rev&revision=267779
TBR=jrummell@chromium.org,dmichael@chromium.org,dalecurtis@chromium.org
NOTREECHECKS=true
NOTRY=true
BUG=none
Review URL: https://codereview.chromium.org/265943002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267788 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | content/renderer/pepper/content_decryptor_delegate.cc | 4 | ||||
-rw-r--r-- | media/base/audio_buffer.cc | 50 | ||||
-rw-r--r-- | media/base/audio_buffer.h | 12 | ||||
-rw-r--r-- | media/base/audio_buffer_converter.cc | 2 | ||||
-rw-r--r-- | media/base/audio_buffer_converter_unittest.cc | 1 | ||||
-rw-r--r-- | media/base/audio_buffer_queue_unittest.cc | 216 | ||||
-rw-r--r-- | media/base/audio_buffer_unittest.cc | 298 | ||||
-rw-r--r-- | media/base/audio_discard_helper.cc | 4 | ||||
-rw-r--r-- | media/base/audio_discard_helper_unittest.cc | 1 | ||||
-rw-r--r-- | media/base/audio_splicer.cc | 33 | ||||
-rw-r--r-- | media/base/audio_splicer_unittest.cc | 35 | ||||
-rw-r--r-- | media/base/test_helpers.cc | 53 | ||||
-rw-r--r-- | media/base/test_helpers.h | 43 | ||||
-rw-r--r-- | media/filters/audio_renderer_algorithm_unittest.cc | 3 | ||||
-rw-r--r-- | media/filters/audio_renderer_impl_unittest.cc | 3 | ||||
-rw-r--r-- | media/filters/decrypting_audio_decoder.cc | 2 | ||||
-rw-r--r-- | media/filters/decrypting_audio_decoder_unittest.cc | 3 | ||||
-rw-r--r-- | media/filters/ffmpeg_audio_decoder_unittest.cc | 2 |
18 files changed, 449 insertions, 316 deletions
diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc index a36cf6f..a10b741 100644 --- a/content/renderer/pepper/content_decryptor_delegate.cc +++ b/content/renderer/pepper/content_decryptor_delegate.cc @@ -1026,7 +1026,9 @@ bool ContentDecryptorDelegate::DeserializeAudioFrames( audio_samples_per_second_, frame_count, &channel_ptrs[0], - base::TimeDelta::FromMicroseconds(timestamp)); + base::TimeDelta::FromMicroseconds(timestamp), + base::TimeDelta::FromMicroseconds(audio_samples_per_second_ / + frame_count)); frames->push_back(frame); cur += frame_size; diff --git a/media/base/audio_buffer.cc b/media/base/audio_buffer.cc index 25e8dbe..4b972b9 100644 --- a/media/base/audio_buffer.cc +++ b/media/base/audio_buffer.cc @@ -11,11 +11,6 @@ namespace media { -static base::TimeDelta CalculateDuration(int frames, double sample_rate) { - return base::TimeDelta::FromMicroseconds( - frames * base::Time::kMicrosecondsPerSecond / sample_rate); -} - AudioBuffer::AudioBuffer(SampleFormat sample_format, ChannelLayout channel_layout, int channel_count, @@ -23,7 +18,8 @@ AudioBuffer::AudioBuffer(SampleFormat sample_format, int frame_count, bool create_buffer, const uint8* const* data, - const base::TimeDelta timestamp) + const base::TimeDelta timestamp, + const base::TimeDelta duration) : sample_format_(sample_format), channel_layout_(channel_layout), channel_count_(channel_count), @@ -32,7 +28,7 @@ AudioBuffer::AudioBuffer(SampleFormat sample_format, trim_start_(0), end_of_stream_(!create_buffer && data == NULL && frame_count == 0), timestamp_(timestamp), - duration_(CalculateDuration(adjusted_frame_count_, sample_rate_)) { + duration_(duration) { CHECK_GE(channel_count_, 0); CHECK_LE(channel_count_, limits::kMaxChannels); CHECK_GE(frame_count, 0); @@ -95,7 +91,8 @@ scoped_refptr<AudioBuffer> AudioBuffer::CopyFrom( int sample_rate, int frame_count, const uint8* const* data, - const base::TimeDelta timestamp) { + const base::TimeDelta timestamp, + const base::TimeDelta duration) { // If you hit this CHECK you likely have a bug in a demuxer. Go fix it. CHECK_GT(frame_count, 0); // Otherwise looks like an EOF buffer. CHECK(data[0]); @@ -106,7 +103,8 @@ scoped_refptr<AudioBuffer> AudioBuffer::CopyFrom( frame_count, true, data, - timestamp)); + timestamp, + duration)); } // static @@ -124,6 +122,7 @@ scoped_refptr<AudioBuffer> AudioBuffer::CreateBuffer( frame_count, true, NULL, + kNoTimestamp(), kNoTimestamp())); } @@ -133,7 +132,8 @@ scoped_refptr<AudioBuffer> AudioBuffer::CreateEmptyBuffer( int channel_count, int sample_rate, int frame_count, - const base::TimeDelta timestamp) { + const base::TimeDelta timestamp, + const base::TimeDelta duration) { CHECK_GT(frame_count, 0); // Otherwise looks like an EOF buffer. // Since data == NULL, format doesn't matter. return make_scoped_refptr(new AudioBuffer(kSampleFormatF32, @@ -143,7 +143,8 @@ scoped_refptr<AudioBuffer> AudioBuffer::CreateEmptyBuffer( frame_count, false, NULL, - timestamp)); + timestamp, + duration)); } // static @@ -155,6 +156,7 @@ scoped_refptr<AudioBuffer> AudioBuffer::CreateEOSBuffer() { 0, false, NULL, + kNoTimestamp(), kNoTimestamp())); } @@ -244,23 +246,33 @@ void AudioBuffer::TrimStart(int frames_to_trim) { CHECK_GE(frames_to_trim, 0); CHECK_LE(frames_to_trim, adjusted_frame_count_); - // Adjust the number of frames in this buffer and where the start really is. + // Adjust timestamp_ and duration_ to reflect the smaller number of frames. + double offset = static_cast<double>(duration_.InMicroseconds()) * + frames_to_trim / adjusted_frame_count_; + base::TimeDelta offset_as_time = + base::TimeDelta::FromMicroseconds(static_cast<int64>(offset)); + timestamp_ += offset_as_time; + duration_ -= offset_as_time; + + // Finally adjust the number of frames in this buffer and where the start + // really is. adjusted_frame_count_ -= frames_to_trim; trim_start_ += frames_to_trim; - - // Adjust timestamp_ and duration_ to reflect the smaller number of frames. - const base::TimeDelta old_duration = duration_; - duration_ = CalculateDuration(adjusted_frame_count_, sample_rate_); - timestamp_ += old_duration - duration_; } void AudioBuffer::TrimEnd(int frames_to_trim) { CHECK_GE(frames_to_trim, 0); CHECK_LE(frames_to_trim, adjusted_frame_count_); - // Adjust the number of frames and duration for this buffer. + // Adjust duration_ only to reflect the smaller number of frames. + double offset = static_cast<double>(duration_.InMicroseconds()) * + frames_to_trim / adjusted_frame_count_; + base::TimeDelta offset_as_time = + base::TimeDelta::FromMicroseconds(static_cast<int64>(offset)); + duration_ -= offset_as_time; + + // Finally adjust the number of frames in this buffer. adjusted_frame_count_ -= frames_to_trim; - duration_ = CalculateDuration(adjusted_frame_count_, sample_rate_); } } // namespace media diff --git a/media/base/audio_buffer.h b/media/base/audio_buffer.h index 4ccd3a8f..5d7ab7f 100644 --- a/media/base/audio_buffer.h +++ b/media/base/audio_buffer.h @@ -34,13 +34,16 @@ class MEDIA_EXPORT AudioBuffer // number of buffers must be equal to |channel_count|. |frame_count| is the // number of frames in each buffer. |data| must not be null and |frame_count| // must be >= 0. + // + // TODO(jrummell): Compute duration rather than pass it in. static scoped_refptr<AudioBuffer> CopyFrom(SampleFormat sample_format, ChannelLayout channel_layout, int channel_count, int sample_rate, int frame_count, const uint8* const* data, - const base::TimeDelta timestamp); + const base::TimeDelta timestamp, + const base::TimeDelta duration); // Create an AudioBuffer with |frame_count| frames. Buffer is allocated, but // not initialized. Timestamp and duration are set to kNoTimestamp(). @@ -56,7 +59,8 @@ class MEDIA_EXPORT AudioBuffer int channel_count, int sample_rate, int frame_count, - const base::TimeDelta timestamp); + const base::TimeDelta timestamp, + const base::TimeDelta duration); // Create a AudioBuffer indicating we've reached end of stream. // Calling any method other than end_of_stream() on the resulting buffer @@ -98,6 +102,7 @@ class MEDIA_EXPORT AudioBuffer base::TimeDelta timestamp() const { return timestamp_; } base::TimeDelta duration() const { return duration_; } void set_timestamp(base::TimeDelta timestamp) { timestamp_ = timestamp; } + void set_duration(base::TimeDelta duration) { duration_ = duration; } // If there's no data in this buffer, it represents end of stream. bool end_of_stream() const { return end_of_stream_; } @@ -121,7 +126,8 @@ class MEDIA_EXPORT AudioBuffer int frame_count, bool create_buffer, const uint8* const* data, - const base::TimeDelta timestamp); + const base::TimeDelta timestamp, + const base::TimeDelta duration); virtual ~AudioBuffer(); diff --git a/media/base/audio_buffer_converter.cc b/media/base/audio_buffer_converter.cc index 59c6681..74e570d 100644 --- a/media/base/audio_buffer_converter.cc +++ b/media/base/audio_buffer_converter.cc @@ -227,6 +227,8 @@ void AudioBufferConverter::ConvertIfPossible() { // Compute the timestamp. output_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); + output_buffer->set_duration( + timestamp_helper_.GetFrameDuration(request_frames)); timestamp_helper_.AddFrames(request_frames); queued_outputs_.push_back(output_buffer); diff --git a/media/base/audio_buffer_converter_unittest.cc b/media/base/audio_buffer_converter_unittest.cc index 3445996..c5c816c 100644 --- a/media/base/audio_buffer_converter_unittest.cc +++ b/media/base/audio_buffer_converter_unittest.cc @@ -29,6 +29,7 @@ static scoped_refptr<AudioBuffer> MakeTestBuffer(int sample_rate, 0, 1, frames, + base::TimeDelta::FromSeconds(0), base::TimeDelta::FromSeconds(0)); } diff --git a/media/base/audio_buffer_queue_unittest.cc b/media/base/audio_buffer_queue_unittest.cc index e6a148a..fc04857 100644 --- a/media/base/audio_buffer_queue_unittest.cc +++ b/media/base/audio_buffer_queue_unittest.cc @@ -5,6 +5,7 @@ #include "base/basictypes.h" #include "base/logging.h" #include "base/memory/scoped_ptr.h" +#include "base/strings/stringprintf.h" #include "base/time/time.h" #include "media/base/audio_buffer.h" #include "media/base/audio_buffer_queue.h" @@ -17,18 +18,15 @@ namespace media { const int kSampleRate = 44100; -static void VerifyBus(AudioBus* bus, - int offset, - int frames, - int buffer_size, - float start, - float increment) { - for (int ch = 0; ch < bus->channels(); ++ch) { - const float v = start + ch * buffer_size * increment; - for (int i = offset; i < frames; ++i) { - ASSERT_FLOAT_EQ(v + (i - offset) * increment, bus->channel(ch)[i]) - << "i=" << i << ", ch=" << ch; - } +static void VerifyResult(float* channel_data, + int frames, + float start, + float increment) { + for (int i = 0; i < frames; ++i) { + SCOPED_TRACE(base::StringPrintf( + "i=%d/%d start=%f, increment=%f", i, frames, start, increment)); + ASSERT_EQ(start, channel_data[i]); + start += increment; } } @@ -36,16 +34,18 @@ template <typename T> static scoped_refptr<AudioBuffer> MakeTestBuffer(SampleFormat format, ChannelLayout channel_layout, T start, - T step, + T end, int frames) { + const base::TimeDelta kNoTime = kNoTimestamp(); return MakeAudioBuffer<T>(format, channel_layout, ChannelLayoutToChannelCount(channel_layout), kSampleRate, start, - step, + end, frames, - kNoTimestamp()); + kNoTime, + kNoTime); } TEST(AudioBufferQueueTest, AppendAndClear) { @@ -96,7 +96,7 @@ TEST(AudioBufferQueueTest, IteratorCheck) { EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get())); EXPECT_EQ(4, buffer.frames()); - VerifyBus(bus.get(), 0, 4, bus->frames(), 10, 1); + VerifyResult(bus->channel(0), 4, 10.0f, 1.0f); buffer.Append(MakeTestBuffer<float>( kSampleFormatF32, channel_layout, 20.0f, 1.0f, 8)); @@ -108,7 +108,7 @@ TEST(AudioBufferQueueTest, IteratorCheck) { buffer.SeekFrames(16); EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get())); EXPECT_EQ(0, buffer.frames()); - VerifyBus(bus.get(), 0, 4, bus->frames(), 34, 1); + VerifyResult(bus->channel(0), 4, 34.0f, 1.0f); buffer.Append(MakeTestBuffer<float>( kSampleFormatF32, channel_layout, 40.0f, 1.0f, 8)); @@ -118,13 +118,13 @@ TEST(AudioBufferQueueTest, IteratorCheck) { EXPECT_EQ(16, buffer.frames()); EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get())); - VerifyBus(bus.get(), 0, 4, bus->frames(), 40, 1); + VerifyResult(bus->channel(0), 4, 40.0f, 1.0f); // Read off the end of the buffer. EXPECT_EQ(12, buffer.frames()); buffer.SeekFrames(8); EXPECT_EQ(4, buffer.ReadFrames(100, 0, bus.get())); - VerifyBus(bus.get(), 0, 4, bus->frames(), 54, 1); + VerifyResult(bus->channel(0), 4, 54.0f, 1.0f); } TEST(AudioBufferQueueTest, Seek) { @@ -162,17 +162,19 @@ TEST(AudioBufferQueueTest, ReadF32) { MakeTestBuffer<float>(kSampleFormatF32, channel_layout, 33.0f, 1.0f, 60)); EXPECT_EQ(76, buffer.frames()); - // Read 3 frames from the buffer. + // Read 3 frames from the buffer. F32 is interleaved, so ch[0] should be + // 1, 3, 5, and ch[1] should be 2, 4, 6. scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); EXPECT_EQ(3, buffer.ReadFrames(3, 0, bus.get())); EXPECT_EQ(73, buffer.frames()); - VerifyBus(bus.get(), 0, 3, 6, 1, 1); + VerifyResult(bus->channel(0), 3, 1.0f, 2.0f); + VerifyResult(bus->channel(1), 3, 2.0f, 2.0f); // Now read 5 frames, which will span buffers. Append the data into AudioBus. EXPECT_EQ(5, buffer.ReadFrames(5, 3, bus.get())); EXPECT_EQ(68, buffer.frames()); - VerifyBus(bus.get(), 0, 6, 6, 1, 1); - VerifyBus(bus.get(), 6, 2, 10, 13, 1); + VerifyResult(bus->channel(0), 8, 1.0f, 2.0f); + VerifyResult(bus->channel(1), 8, 2.0f, 2.0f); // Now skip into the third buffer. buffer.SeekFrames(20); @@ -180,24 +182,30 @@ TEST(AudioBufferQueueTest, ReadF32) { // Now read 2 frames, which are in the third buffer. EXPECT_EQ(2, buffer.ReadFrames(2, 0, bus.get())); - VerifyBus(bus.get(), 0, 2, 60, 45, 1); + VerifyResult(bus->channel(0), 2, 57.0f, 2.0f); + VerifyResult(bus->channel(1), 2, 58.0f, 2.0f); } TEST(AudioBufferQueueTest, ReadU8) { const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0; const int channels = ChannelLayoutToChannelCount(channel_layout); - const int frames = 4; AudioBufferQueue buffer; // Add 4 frames of data. buffer.Append( - MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 128, 1, frames)); + MakeTestBuffer<uint8>(kSampleFormatU8, channel_layout, 128, 1, 4)); - // Read all 4 frames from the buffer. - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, frames); - EXPECT_EQ(frames, buffer.ReadFrames(frames, 0, bus.get())); + // Read all 4 frames from the buffer. Data is interleaved, so ch[0] should be + // 128, 132, 136, 140, other channels similar. However, values are converted + // from [0, 255] to [-1.0, 1.0] with a bias of 128. Thus the first buffer + // value should be 0.0, then 1/127, 2/127, etc. + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); + EXPECT_EQ(4, buffer.ReadFrames(4, 0, bus.get())); EXPECT_EQ(0, buffer.frames()); - VerifyBus(bus.get(), 0, frames, bus->frames(), 0, 1.0f / 127.0f); + VerifyResult(bus->channel(0), 4, 0.0f, 4.0f / 127.0f); + VerifyResult(bus->channel(1), 4, 1.0f / 127.0f, 4.0f / 127.0f); + VerifyResult(bus->channel(2), 4, 2.0f / 127.0f, 4.0f / 127.0f); + VerifyResult(bus->channel(3), 4, 3.0f / 127.0f, 4.0f / 127.0f); } TEST(AudioBufferQueueTest, ReadS16) { @@ -212,13 +220,14 @@ TEST(AudioBufferQueueTest, ReadS16) { MakeTestBuffer<int16>(kSampleFormatS16, channel_layout, 9, 1, 20)); EXPECT_EQ(24, buffer.frames()); - // Read 6 frames from the buffer. - const int frames = 6; - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, buffer.frames()); - EXPECT_EQ(frames, buffer.ReadFrames(frames, 0, bus.get())); + // Read 6 frames from the buffer. Data is interleaved, so ch[0] should be + // 1, 3, 5, 7, 9, 11, and ch[1] should be 2, 4, 6, 8, 10, 12. + // Data is converted to float from -1.0 to 1.0 based on int16 range. + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); + EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get())); EXPECT_EQ(18, buffer.frames()); - VerifyBus(bus.get(), 0, 4, 4, 1.0f / kint16max, 1.0f / kint16max); - VerifyBus(bus.get(), 4, 2, 20, 9.0f / kint16max, 1.0f / kint16max); + VerifyResult(bus->channel(0), 6, 1.0f / kint16max, 2.0f / kint16max); + VerifyResult(bus->channel(1), 6, 2.0f / kint16max, 2.0f / kint16max); } TEST(AudioBufferQueueTest, ReadS32) { @@ -233,17 +242,20 @@ TEST(AudioBufferQueueTest, ReadS32) { MakeTestBuffer<int32>(kSampleFormatS32, channel_layout, 9, 1, 20)); EXPECT_EQ(24, buffer.frames()); - // Read 6 frames from the buffer. + // Read 6 frames from the buffer. Data is interleaved, so ch[0] should be + // 1, 3, 5, 7, 100, 106, and ch[1] should be 2, 4, 6, 8, 103, 109. + // Data is converted to float from -1.0 to 1.0 based on int32 range. scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get())); EXPECT_EQ(18, buffer.frames()); - VerifyBus(bus.get(), 0, 4, 4, 1.0f / kint32max, 1.0f / kint32max); - VerifyBus(bus.get(), 4, 2, 20, 9.0f / kint32max, 1.0f / kint32max); + VerifyResult(bus->channel(0), 6, 1.0f / kint32max, 2.0f / kint32max); + VerifyResult(bus->channel(1), 6, 2.0f / kint32max, 2.0f / kint32max); // Read the next 2 frames. EXPECT_EQ(2, buffer.ReadFrames(2, 0, bus.get())); EXPECT_EQ(16, buffer.frames()); - VerifyBus(bus.get(), 0, 2, 20, 11.0f / kint32max, 1.0f / kint32max); + VerifyResult(bus->channel(0), 2, 13.0f / kint32max, 2.0f / kint32max); + VerifyResult(bus->channel(1), 2, 14.0f / kint32max, 2.0f / kint32max); } TEST(AudioBufferQueueTest, ReadF32Planar) { @@ -258,12 +270,15 @@ TEST(AudioBufferQueueTest, ReadF32Planar) { kSampleFormatPlanarF32, channel_layout, 50.0f, 1.0f, 10)); EXPECT_EQ(14, buffer.frames()); - // Read 6 frames from the buffer. + // Read 6 frames from the buffer. F32 is planar, so ch[0] should be + // 1, 2, 3, 4, 50, 51, and ch[1] should be 5, 6, 7, 8, 60, 61. scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get())); EXPECT_EQ(8, buffer.frames()); - VerifyBus(bus.get(), 0, 4, 4, 1, 1); - VerifyBus(bus.get(), 4, 2, 10, 50, 1); + VerifyResult(bus->channel(0), 4, 1.0f, 1.0f); + VerifyResult(bus->channel(0) + 4, 2, 50.0f, 1.0f); + VerifyResult(bus->channel(1), 4, 5.0f, 1.0f); + VerifyResult(bus->channel(1) + 4, 2, 60.0f, 1.0f); } TEST(AudioBufferQueueTest, ReadS16Planar) { @@ -278,12 +293,16 @@ TEST(AudioBufferQueueTest, ReadS16Planar) { kSampleFormatPlanarS16, channel_layout, 100, 5, 20)); EXPECT_EQ(24, buffer.frames()); - // Read 6 frames from the buffer. + // Read 6 frames from the buffer. Data is planar, so ch[0] should be + // 1, 2, 3, 4, 100, 105, and ch[1] should be 5, 6, 7, 8, 200, 205. + // Data is converted to float from -1.0 to 1.0 based on int16 range. scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); EXPECT_EQ(6, buffer.ReadFrames(6, 0, bus.get())); EXPECT_EQ(18, buffer.frames()); - VerifyBus(bus.get(), 0, 4, 4, 1.0f / kint16max, 1.0f / kint16max); - VerifyBus(bus.get(), 4, 2, 20, 5.0f / kint16max, 1.0f / kint16max); + VerifyResult(bus->channel(0), 4, 1.0f / kint16max, 1.0f / kint16max); + VerifyResult(bus->channel(0) + 4, 2, 100.0f / kint16max, 5.0f / kint16max); + VerifyResult(bus->channel(1), 4, 5.0f / kint16max, 1.0f / kint16max); + VerifyResult(bus->channel(1) + 4, 2, 200.0f / kint16max, 5.0f / kint16max); } TEST(AudioBufferQueueTest, ReadManyChannels) { @@ -300,13 +319,14 @@ TEST(AudioBufferQueueTest, ReadManyChannels) { kSampleFormatF32, channel_layout, 16.0f * channels, 1.0f, 60)); EXPECT_EQ(76, buffer.frames()); - // Read 3 frames from the buffer. + // Read 3 frames from the buffer. F32 is interleaved, so ch[0] should be + // 1, 17, 33, and ch[1] should be 2, 18, 34. Just check a few channels. scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); EXPECT_EQ(30, buffer.ReadFrames(30, 0, bus.get())); EXPECT_EQ(46, buffer.frames()); - VerifyBus(bus.get(), 0, 6, 6, 0, 1); - VerifyBus(bus.get(), 6, 10, 10, 6 * channels, 1); - VerifyBus(bus.get(), 16, 14, 60, 16 * channels, 1); + for (int i = 0; i < channels; ++i) { + VerifyResult(bus->channel(i), 30, static_cast<float>(i), 8.0f); + } } TEST(AudioBufferQueueTest, Peek) { @@ -315,32 +335,43 @@ TEST(AudioBufferQueueTest, Peek) { AudioBufferQueue buffer; // Add 60 frames of data. - const int frames = 60; - buffer.Append(MakeTestBuffer<float>( - kSampleFormatF32, channel_layout, 0.0f, 1.0f, frames)); - EXPECT_EQ(frames, buffer.frames()); + buffer.Append( + MakeTestBuffer<float>(kSampleFormatF32, channel_layout, 0.0f, 1.0f, 60)); + EXPECT_EQ(60, buffer.frames()); // Peek at the first 30 frames. - scoped_ptr<AudioBus> bus1 = AudioBus::Create(channels, frames); - EXPECT_EQ(frames, buffer.frames()); - EXPECT_EQ(frames, buffer.PeekFrames(60, 0, 0, bus1.get())); + scoped_ptr<AudioBus> bus1 = AudioBus::Create(channels, 100); + EXPECT_EQ(60, buffer.frames()); + EXPECT_EQ(60, buffer.PeekFrames(100, 0, 0, bus1.get())); EXPECT_EQ(30, buffer.PeekFrames(30, 0, 0, bus1.get())); - EXPECT_EQ(frames, buffer.frames()); - VerifyBus(bus1.get(), 0, 30, bus1->frames(), 0, 1); + EXPECT_EQ(60, buffer.frames()); // Now read the next 30 frames (which should be the same as those peeked at). - scoped_ptr<AudioBus> bus2 = AudioBus::Create(channels, frames); + scoped_ptr<AudioBus> bus2 = AudioBus::Create(channels, 100); EXPECT_EQ(30, buffer.ReadFrames(30, 0, bus2.get())); - VerifyBus(bus2.get(), 0, 30, bus2->frames(), 0, 1); + for (int i = 0; i < channels; ++i) { + VerifyResult(bus1->channel(i), + 30, + static_cast<float>(i), + static_cast<float>(channels)); + VerifyResult(bus2->channel(i), + 30, + static_cast<float>(i), + static_cast<float>(channels)); + } // Peek 10 frames forward - bus1->Zero(); EXPECT_EQ(5, buffer.PeekFrames(5, 10, 0, bus1.get())); - VerifyBus(bus1.get(), 0, 5, bus1->frames(), 40, 1); + for (int i = 0; i < channels; ++i) { + VerifyResult(bus1->channel(i), + 5, + static_cast<float>(i + 40 * channels), + static_cast<float>(channels)); + } // Peek to the end of the buffer. EXPECT_EQ(30, buffer.frames()); - EXPECT_EQ(30, buffer.PeekFrames(60, 0, 0, bus1.get())); + EXPECT_EQ(30, buffer.PeekFrames(100, 0, 0, bus1.get())); EXPECT_EQ(30, buffer.PeekFrames(30, 0, 0, bus1.get())); } @@ -349,43 +380,36 @@ TEST(AudioBufferQueueTest, Time) { const int channels = ChannelLayoutToChannelCount(channel_layout); const base::TimeDelta start_time1; const base::TimeDelta start_time2 = base::TimeDelta::FromSeconds(30); + const base::TimeDelta duration = base::TimeDelta::FromSeconds(10); AudioBufferQueue buffer; scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); - scoped_refptr<AudioBuffer> audio_buffer = - MakeAudioBuffer<int16>(kSampleFormatS16, - channel_layout, - channels, - kSampleRate, - 1, - 1, - 10, - start_time1); - // Add two buffers (second one added later): // first: start=0s, duration=10s // second: start=30s, duration=10s - buffer.Append(audio_buffer); + buffer.Append(MakeAudioBuffer<int16>(kSampleFormatS16, + channel_layout, + channels, + kSampleRate, + 1, + 1, + 10, + start_time1, + duration)); EXPECT_EQ(10, buffer.frames()); // Check starting time. EXPECT_EQ(start_time1, buffer.current_time()); // Read 2 frames, should be 2s in (since duration is 1s per sample). - int frames_read = 2; - EXPECT_EQ(frames_read, buffer.ReadFrames(frames_read, 0, bus.get())); - EXPECT_EQ( - start_time1 + - frames_read * audio_buffer->duration() / audio_buffer->frame_count(), - buffer.current_time()); + EXPECT_EQ(2, buffer.ReadFrames(2, 0, bus.get())); + EXPECT_EQ(start_time1 + base::TimeDelta::FromSeconds(2), + buffer.current_time()); // Skip 2 frames. buffer.SeekFrames(2); - frames_read += 2; - EXPECT_EQ( - start_time1 + - frames_read * audio_buffer->duration() / audio_buffer->frame_count(), - buffer.current_time()); + EXPECT_EQ(start_time1 + base::TimeDelta::FromSeconds(4), + buffer.current_time()); // Add second buffer for more data. buffer.Append(MakeAudioBuffer<int16>(kSampleFormatS16, @@ -395,32 +419,28 @@ TEST(AudioBufferQueueTest, Time) { 1, 1, 10, - start_time2)); + start_time2, + duration)); EXPECT_EQ(16, buffer.frames()); // Read until almost the end of buffer1. - frames_read += 5; EXPECT_EQ(5, buffer.ReadFrames(5, 0, bus.get())); - EXPECT_EQ( - start_time1 + - frames_read * audio_buffer->duration() / audio_buffer->frame_count(), - buffer.current_time()); + EXPECT_EQ(start_time1 + base::TimeDelta::FromSeconds(9), + buffer.current_time()); // Read 1 value, so time moved to buffer2. EXPECT_EQ(1, buffer.ReadFrames(1, 0, bus.get())); EXPECT_EQ(start_time2, buffer.current_time()); // Read all 10 frames in buffer2, timestamp should be last time from buffer2. - frames_read = 10; EXPECT_EQ(10, buffer.ReadFrames(10, 0, bus.get())); - const base::TimeDelta expected_current_time = - start_time2 + - frames_read * audio_buffer->duration() / audio_buffer->frame_count(); - EXPECT_EQ(expected_current_time, buffer.current_time()); + EXPECT_EQ(start_time2 + base::TimeDelta::FromSeconds(10), + buffer.current_time()); // Try to read more frames (which don't exist), timestamp should remain. EXPECT_EQ(0, buffer.ReadFrames(5, 0, bus.get())); - EXPECT_EQ(expected_current_time, buffer.current_time()); + EXPECT_EQ(start_time2 + base::TimeDelta::FromSeconds(10), + buffer.current_time()); } TEST(AudioBufferQueueTest, NoTime) { diff --git a/media/base/audio_buffer_unittest.cc b/media/base/audio_buffer_unittest.cc index 55ff4ed..c40c076 100644 --- a/media/base/audio_buffer_unittest.cc +++ b/media/base/audio_buffer_unittest.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include "base/strings/string_util.h" +#include "base/strings/stringprintf.h" #include "media/base/audio_buffer.h" #include "media/base/audio_bus.h" #include "media/base/test_helpers.h" @@ -9,44 +11,39 @@ namespace media { -static const int kSampleRate = 48000; - -static void VerifyBus(AudioBus* bus, int frames, float start, float increment) { - for (int ch = 0; ch < bus->channels(); ++ch) { - const float v = start + ch * bus->frames() * increment; - for (int i = 0; i < frames; ++i) { - ASSERT_FLOAT_EQ(v + i * increment, bus->channel(ch)[i]) << "i=" << i - << ", ch=" << ch; - } +const static int kSampleRate = 44100; + +static void VerifyResult(float* channel_data, + int frames, + float start, + float increment) { + for (int i = 0; i < frames; ++i) { + SCOPED_TRACE(base::StringPrintf( + "i=%d/%d start=%f, increment=%f", i, frames, start, increment)); + ASSERT_EQ(channel_data[i], start); + start += increment; } } TEST(AudioBufferTest, CopyFrom) { - const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_MONO; - scoped_refptr<AudioBuffer> original_buffer = + const ChannelLayout channel_layout = CHANNEL_LAYOUT_MONO; + const int frames = 8; + const base::TimeDelta start_time; + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); + scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<uint8>(kSampleFormatU8, - kChannelLayout, - ChannelLayoutToChannelCount(kChannelLayout), + channel_layout, + ChannelLayoutToChannelCount(channel_layout), kSampleRate, 1, 1, - kSampleRate / 100, - base::TimeDelta()); - scoped_refptr<AudioBuffer> new_buffer = - AudioBuffer::CopyFrom(kSampleFormatU8, - original_buffer->channel_layout(), - original_buffer->channel_count(), - original_buffer->sample_rate(), - original_buffer->frame_count(), - &original_buffer->channel_data()[0], - original_buffer->timestamp()); - EXPECT_EQ(original_buffer->frame_count(), new_buffer->frame_count()); - EXPECT_EQ(original_buffer->timestamp(), new_buffer->timestamp()); - EXPECT_EQ(original_buffer->duration(), new_buffer->duration()); - EXPECT_EQ(original_buffer->sample_rate(), new_buffer->sample_rate()); - EXPECT_EQ(original_buffer->channel_count(), new_buffer->channel_count()); - EXPECT_EQ(original_buffer->channel_layout(), new_buffer->channel_layout()); - EXPECT_FALSE(original_buffer->end_of_stream()); + frames, + start_time, + duration); + EXPECT_EQ(frames, buffer->frame_count()); + EXPECT_EQ(buffer->timestamp(), start_time); + EXPECT_EQ(buffer->duration().InSeconds(), frames); + EXPECT_FALSE(buffer->end_of_stream()); } TEST(AudioBufferTest, CreateEOSBuffer) { @@ -58,7 +55,8 @@ TEST(AudioBufferTest, FrameSize) { const uint8 kTestData[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 }; - const base::TimeDelta kTimestamp = base::TimeDelta::FromMicroseconds(1337); + const base::TimeDelta kTimestampA = base::TimeDelta::FromMicroseconds(1337); + const base::TimeDelta kTimestampB = base::TimeDelta::FromMicroseconds(1234); const uint8* const data[] = { kTestData }; scoped_refptr<AudioBuffer> buffer = @@ -68,7 +66,8 @@ TEST(AudioBufferTest, FrameSize) { kSampleRate, 16, data, - kTimestamp); + kTimestampA, + kTimestampB); EXPECT_EQ(16, buffer->frame_count()); // 2 channels of 8-bit data buffer = AudioBuffer::CopyFrom(kSampleFormatF32, @@ -77,15 +76,17 @@ TEST(AudioBufferTest, FrameSize) { kSampleRate, 2, data, - kTimestamp); + kTimestampA, + kTimestampB); EXPECT_EQ(2, buffer->frame_count()); // now 4 channels of 32-bit data } TEST(AudioBufferTest, ReadU8) { const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0; const int channels = ChannelLayoutToChannelCount(channel_layout); - const int frames = 10; + const int frames = 4; const base::TimeDelta start_time; + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<uint8>(kSampleFormatU8, channel_layout, channels, @@ -93,16 +94,19 @@ TEST(AudioBufferTest, ReadU8) { 128, 1, frames, - start_time); - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, frames); - buffer->ReadFrames(frames, 0, 0, bus.get()); - VerifyBus(bus.get(), frames, 0, 1.0f / 127.0f); + start_time, + duration); - // Now read the same data one frame at a time. - bus->Zero(); - for (int i = 0; i < frames; ++i) - buffer->ReadFrames(1, i, i, bus.get()); - VerifyBus(bus.get(), frames, 0, 1.0f / 127.0f); + // Read all 4 frames from the buffer. Data is interleaved, so ch[0] should be + // 128, 132, 136, 140, other channels similar. However, values are converted + // from [0, 255] to [-1.0, 1.0] with a bias of 128. Thus the first buffer + // value should be 0.0, then 1/127, 2/127, etc. + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); + buffer->ReadFrames(frames, 0, 0, bus.get()); + VerifyResult(bus->channel(0), frames, 0.0f, 4.0f / 127.0f); + VerifyResult(bus->channel(1), frames, 1.0f / 127.0f, 4.0f / 127.0f); + VerifyResult(bus->channel(2), frames, 2.0f / 127.0f, 4.0f / 127.0f); + VerifyResult(bus->channel(3), frames, 3.0f / 127.0f, 4.0f / 127.0f); } TEST(AudioBufferTest, ReadS16) { @@ -110,6 +114,7 @@ TEST(AudioBufferTest, ReadS16) { const int channels = ChannelLayoutToChannelCount(channel_layout); const int frames = 10; const base::TimeDelta start_time; + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<int16>(kSampleFormatS16, channel_layout, channels, @@ -117,23 +122,32 @@ TEST(AudioBufferTest, ReadS16) { 1, 1, frames, - start_time); - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, frames); - buffer->ReadFrames(frames, 0, 0, bus.get()); - VerifyBus(bus.get(), frames, 1.0f / kint16max, 1.0f / kint16max); + start_time, + duration); + + // Read 6 frames from the buffer. Data is interleaved, so ch[0] should be 1, + // 3, 5, 7, 9, 11, and ch[1] should be 2, 4, 6, 8, 10, 12. Data is converted + // to float from -1.0 to 1.0 based on int16 range. + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); + buffer->ReadFrames(6, 0, 0, bus.get()); + VerifyResult(bus->channel(0), 6, 1.0f / kint16max, 2.0f / kint16max); + VerifyResult(bus->channel(1), 6, 2.0f / kint16max, 2.0f / kint16max); // Now read the same data one frame at a time. - bus->Zero(); - for (int i = 0; i < frames; ++i) + bus = AudioBus::Create(channels, 100); + for (int i = 0; i < frames; ++i) { buffer->ReadFrames(1, i, i, bus.get()); - VerifyBus(bus.get(), frames, 1.0f / kint16max, 1.0f / kint16max); + } + VerifyResult(bus->channel(0), frames, 1.0f / kint16max, 2.0f / kint16max); + VerifyResult(bus->channel(1), frames, 2.0f / kint16max, 2.0f / kint16max); } TEST(AudioBufferTest, ReadS32) { const ChannelLayout channel_layout = CHANNEL_LAYOUT_STEREO; const int channels = ChannelLayoutToChannelCount(channel_layout); - const int frames = 20; + const int frames = 6; const base::TimeDelta start_time; + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<int32>(kSampleFormatS32, channel_layout, channels, @@ -141,15 +155,22 @@ TEST(AudioBufferTest, ReadS32) { 1, 1, frames, - start_time); - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, frames); - buffer->ReadFrames(frames, 0, 0, bus.get()); - VerifyBus(bus.get(), frames, 1.0f / kint32max, 1.0f / kint32max); + start_time, + duration); - // Read second 10 frames. - bus->Zero(); - buffer->ReadFrames(10, 10, 0, bus.get()); - VerifyBus(bus.get(), 10, 11.0f / kint32max, 1.0f / kint32max); + // Read 6 frames from the buffer. Data is interleaved, so ch[0] should be 1, + // 3, 5, 7, 9, 11, and ch[1] should be 2, 4, 6, 8, 10, 12. Data is converted + // to float from -1.0 to 1.0 based on int32 range. + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); + buffer->ReadFrames(frames, 0, 0, bus.get()); + VerifyResult(bus->channel(0), frames, 1.0f / kint32max, 2.0f / kint32max); + VerifyResult(bus->channel(1), frames, 2.0f / kint32max, 2.0f / kint32max); + + // Now read 2 frames starting at frame offset 3. ch[0] should be 7, 9, and + // ch[1] should be 8, 10. + buffer->ReadFrames(2, 3, 0, bus.get()); + VerifyResult(bus->channel(0), 2, 7.0f / kint32max, 2.0f / kint32max); + VerifyResult(bus->channel(1), 2, 8.0f / kint32max, 2.0f / kint32max); } TEST(AudioBufferTest, ReadF32) { @@ -157,6 +178,7 @@ TEST(AudioBufferTest, ReadF32) { const int channels = ChannelLayoutToChannelCount(channel_layout); const int frames = 20; const base::TimeDelta start_time; + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<float>(kSampleFormatF32, channel_layout, channels, @@ -164,15 +186,21 @@ TEST(AudioBufferTest, ReadF32) { 1.0f, 1.0f, frames, - start_time); - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, frames); + start_time, + duration); + + // Read first 10 frames from the buffer. F32 is interleaved, so ch[0] should + // be 1, 3, 5, ... and ch[1] should be 2, 4, 6, ... + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); buffer->ReadFrames(10, 0, 0, bus.get()); - VerifyBus(bus.get(), 10, 1, 1); + VerifyResult(bus->channel(0), 10, 1.0f, 2.0f); + VerifyResult(bus->channel(1), 10, 2.0f, 2.0f); // Read second 10 frames. - bus->Zero(); + bus = AudioBus::Create(channels, 100); buffer->ReadFrames(10, 10, 0, bus.get()); - VerifyBus(bus.get(), 10, 11, 1); + VerifyResult(bus->channel(0), 10, 21.0f, 2.0f); + VerifyResult(bus->channel(1), 10, 22.0f, 2.0f); } TEST(AudioBufferTest, ReadS16Planar) { @@ -180,6 +208,7 @@ TEST(AudioBufferTest, ReadS16Planar) { const int channels = ChannelLayoutToChannelCount(channel_layout); const int frames = 20; const base::TimeDelta start_time; + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<int16>(kSampleFormatPlanarS16, channel_layout, @@ -188,25 +217,32 @@ TEST(AudioBufferTest, ReadS16Planar) { 1, 1, frames, - start_time); - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, frames); - buffer->ReadFrames(10, 0, 0, bus.get()); - VerifyBus(bus.get(), 10, 1.0f / kint16max, 1.0f / kint16max); + start_time, + duration); + + // Read 6 frames from the buffer. Data is planar, so ch[0] should be 1, 2, 3, + // 4, 5, 6, and ch[1] should be 21, 22, 23, 24, 25, 26. Data is converted to + // float from -1.0 to 1.0 based on int16 range. + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); + buffer->ReadFrames(6, 0, 0, bus.get()); + VerifyResult(bus->channel(0), 6, 1.0f / kint16max, 1.0f / kint16max); + VerifyResult(bus->channel(1), 6, 21.0f / kint16max, 1.0f / kint16max); // Read all the frames backwards, one by one. ch[0] should be 20, 19, ... - bus->Zero(); - for (int i = frames - 1; i >= 0; --i) - buffer->ReadFrames(1, i, i, bus.get()); - VerifyBus(bus.get(), frames, 1.0f / kint16max, 1.0f / kint16max); + bus = AudioBus::Create(channels, 100); + for (int i = 0; i < frames; ++i) { + buffer->ReadFrames(1, frames - i - 1, i, bus.get()); + } + VerifyResult(bus->channel(0), frames, 20.0f / kint16max, -1.0f / kint16max); + VerifyResult(bus->channel(1), frames, 40.0f / kint16max, -1.0f / kint16max); // Read 0 frames with different offsets. Existing data in AudioBus should be // unchanged. buffer->ReadFrames(0, 0, 0, bus.get()); - VerifyBus(bus.get(), frames, 1.0f / kint16max, 1.0f / kint16max); buffer->ReadFrames(0, 0, 10, bus.get()); - VerifyBus(bus.get(), frames, 1.0f / kint16max, 1.0f / kint16max); buffer->ReadFrames(0, 10, 0, bus.get()); - VerifyBus(bus.get(), frames, 1.0f / kint16max, 1.0f / kint16max); + VerifyResult(bus->channel(0), frames, 20.0f / kint16max, -1.0f / kint16max); + VerifyResult(bus->channel(1), frames, 40.0f / kint16max, -1.0f / kint16max); } TEST(AudioBufferTest, ReadF32Planar) { @@ -214,6 +250,7 @@ TEST(AudioBufferTest, ReadF32Planar) { const int channels = ChannelLayoutToChannelCount(channel_layout); const int frames = 100; const base::TimeDelta start_time; + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<float>(kSampleFormatPlanarF32, channel_layout, @@ -222,94 +259,103 @@ TEST(AudioBufferTest, ReadF32Planar) { 1.0f, 1.0f, frames, - start_time); + start_time, + duration); // Read all 100 frames from the buffer. F32 is planar, so ch[0] should be 1, // 2, 3, 4, ..., ch[1] should be 101, 102, 103, ..., and so on for all 4 // channels. scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); buffer->ReadFrames(frames, 0, 0, bus.get()); - VerifyBus(bus.get(), frames, 1, 1); + VerifyResult(bus->channel(0), frames, 1.0f, 1.0f); + VerifyResult(bus->channel(1), frames, 101.0f, 1.0f); + VerifyResult(bus->channel(2), frames, 201.0f, 1.0f); + VerifyResult(bus->channel(3), frames, 301.0f, 1.0f); // Now read 20 frames from the middle of the buffer. - bus->Zero(); + bus = AudioBus::Create(channels, 100); buffer->ReadFrames(20, 50, 0, bus.get()); - VerifyBus(bus.get(), 20, 51, 1); + VerifyResult(bus->channel(0), 20, 51.0f, 1.0f); + VerifyResult(bus->channel(1), 20, 151.0f, 1.0f); + VerifyResult(bus->channel(2), 20, 251.0f, 1.0f); + VerifyResult(bus->channel(3), 20, 351.0f, 1.0f); } TEST(AudioBufferTest, EmptyBuffer) { const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0; const int channels = ChannelLayoutToChannelCount(channel_layout); - const int frames = kSampleRate / 100; + const int frames = 100; const base::TimeDelta start_time; + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); scoped_refptr<AudioBuffer> buffer = AudioBuffer::CreateEmptyBuffer( - channel_layout, channels, kSampleRate, frames, start_time); + channel_layout, channels, kSampleRate, frames, start_time, duration); EXPECT_EQ(frames, buffer->frame_count()); EXPECT_EQ(start_time, buffer->timestamp()); - EXPECT_EQ(base::TimeDelta::FromMilliseconds(10), buffer->duration()); + EXPECT_EQ(frames, buffer->duration().InSeconds()); EXPECT_FALSE(buffer->end_of_stream()); // Read all 100 frames from the buffer. All data should be 0. - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, frames); + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); buffer->ReadFrames(frames, 0, 0, bus.get()); - VerifyBus(bus.get(), frames, 0, 0); + VerifyResult(bus->channel(0), frames, 0.0f, 0.0f); + VerifyResult(bus->channel(1), frames, 0.0f, 0.0f); + VerifyResult(bus->channel(2), frames, 0.0f, 0.0f); + VerifyResult(bus->channel(3), frames, 0.0f, 0.0f); } TEST(AudioBufferTest, Trim) { const ChannelLayout channel_layout = CHANNEL_LAYOUT_4_0; const int channels = ChannelLayoutToChannelCount(channel_layout); - const int frames = kSampleRate / 10; + const int frames = 100; const base::TimeDelta start_time; - const base::TimeDelta duration = base::TimeDelta::FromMilliseconds(100); + const base::TimeDelta duration = base::TimeDelta::FromSeconds(frames); scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<float>(kSampleFormatPlanarF32, channel_layout, channels, kSampleRate, - 0.0f, + 1.0f, 1.0f, frames, - start_time); + start_time, + duration); EXPECT_EQ(frames, buffer->frame_count()); EXPECT_EQ(start_time, buffer->timestamp()); - EXPECT_EQ(duration, buffer->duration()); - - const int ten_ms_of_frames = kSampleRate / 100; - const base::TimeDelta ten_ms = base::TimeDelta::FromMilliseconds(10); - - scoped_ptr<AudioBus> bus = AudioBus::Create(channels, frames); - buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get()); - VerifyBus(bus.get(), buffer->frame_count(), 0.0f, 1.0f); - - // Trim off 10ms of frames from the start. - buffer->TrimStart(ten_ms_of_frames); - EXPECT_EQ(start_time + ten_ms, buffer->timestamp()); - EXPECT_EQ(frames - ten_ms_of_frames, buffer->frame_count()); - EXPECT_EQ(duration - ten_ms, buffer->duration()); - buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get()); - VerifyBus(bus.get(), buffer->frame_count(), ten_ms_of_frames, 1.0f); - - // Trim off 10ms of frames from the end. - buffer->TrimEnd(ten_ms_of_frames); - EXPECT_EQ(start_time + ten_ms, buffer->timestamp()); - EXPECT_EQ(frames - 2 * ten_ms_of_frames, buffer->frame_count()); - EXPECT_EQ(duration - 2 * ten_ms, buffer->duration()); - buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get()); - VerifyBus(bus.get(), buffer->frame_count(), ten_ms_of_frames, 1.0f); - - // Trim off 40ms more from the start. - buffer->TrimStart(4 * ten_ms_of_frames); - EXPECT_EQ(start_time + 5 * ten_ms, buffer->timestamp()); - EXPECT_EQ(frames - 6 * ten_ms_of_frames, buffer->frame_count()); - EXPECT_EQ(duration - 6 * ten_ms, buffer->duration()); - buffer->ReadFrames(buffer->frame_count(), 0, 0, bus.get()); - VerifyBus(bus.get(), buffer->frame_count(), 5 * ten_ms_of_frames, 1.0f); - - // Trim off the final 40ms from the end. - buffer->TrimEnd(4 * ten_ms_of_frames); - EXPECT_EQ(0, buffer->frame_count()); - EXPECT_EQ(start_time + 5 * ten_ms, buffer->timestamp()); - EXPECT_EQ(base::TimeDelta(), buffer->duration()); + EXPECT_EQ(frames, buffer->duration().InSeconds()); + + scoped_ptr<AudioBus> bus = AudioBus::Create(channels, 100); + buffer->ReadFrames(20, 0, 0, bus.get()); + VerifyResult(bus->channel(0), 20, 1.0f, 1.0f); + + // Trim off 10 frames from the start. + buffer->TrimStart(10); + EXPECT_EQ(buffer->frame_count(), frames - 10); + EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(10)); + EXPECT_EQ(buffer->duration(), base::TimeDelta::FromSeconds(90)); + buffer->ReadFrames(20, 0, 0, bus.get()); + VerifyResult(bus->channel(0), 20, 11.0f, 1.0f); + + // Trim off 10 frames from the end. + buffer->TrimEnd(10); + EXPECT_EQ(buffer->frame_count(), frames - 20); + EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(10)); + EXPECT_EQ(buffer->duration(), base::TimeDelta::FromSeconds(80)); + buffer->ReadFrames(20, 0, 0, bus.get()); + VerifyResult(bus->channel(0), 20, 11.0f, 1.0f); + + // Trim off 50 more from the start. + buffer->TrimStart(50); + EXPECT_EQ(buffer->frame_count(), frames - 70); + EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(60)); + EXPECT_EQ(buffer->duration(), base::TimeDelta::FromSeconds(30)); + buffer->ReadFrames(10, 0, 0, bus.get()); + VerifyResult(bus->channel(0), 10, 61.0f, 1.0f); + + // Trim off the last 30 frames. + buffer->TrimEnd(30); + EXPECT_EQ(buffer->frame_count(), 0); + EXPECT_EQ(buffer->timestamp(), start_time + base::TimeDelta::FromSeconds(60)); + EXPECT_EQ(buffer->duration(), base::TimeDelta::FromSeconds(0)); } } // namespace media diff --git a/media/base/audio_discard_helper.cc b/media/base/audio_discard_helper.cc index d868382..3088130 100644 --- a/media/base/audio_discard_helper.cc +++ b/media/base/audio_discard_helper.cc @@ -103,8 +103,10 @@ bool AudioDiscardHelper::ProcessBuffers( DCHECK(encoded_buffer->discard_padding() == base::TimeDelta()); } - // Assign timestamp to the buffer. + // Assign timestamp and duration to the buffer. decoded_buffer->set_timestamp(timestamp_helper_.GetTimestamp()); + decoded_buffer->set_duration( + timestamp_helper_.GetFrameDuration(decoded_buffer->frame_count())); timestamp_helper_.AddFrames(decoded_buffer->frame_count()); return true; } diff --git a/media/base/audio_discard_helper_unittest.cc b/media/base/audio_discard_helper_unittest.cc index e3f21c0..7788e7f 100644 --- a/media/base/audio_discard_helper_unittest.cc +++ b/media/base/audio_discard_helper_unittest.cc @@ -33,6 +33,7 @@ static scoped_refptr<AudioBuffer> CreateDecodedBuffer(int frames) { 0.0f, kDataStep, frames, + kNoTimestamp(), kNoTimestamp()); } diff --git a/media/base/audio_splicer.cc b/media/base/audio_splicer.cc index 9fae417..b83765e 100644 --- a/media/base/audio_splicer.cc +++ b/media/base/audio_splicer.cc @@ -35,6 +35,20 @@ static void AccurateTrimStart(int frames_to_trim, const AudioTimestampHelper& timestamp_helper) { buffer->TrimStart(frames_to_trim); buffer->set_timestamp(timestamp_helper.GetTimestamp()); + buffer->set_duration( + timestamp_helper.GetFrameDuration(buffer->frame_count())); +} + +// AudioBuffer::TrimEnd() is not as accurate as the timestamp helper, so +// manually adjust the duration after trimming. +static void AccurateTrimEnd(int frames_to_trim, + const scoped_refptr<AudioBuffer> buffer, + const AudioTimestampHelper& timestamp_helper) { + DCHECK_LT(std::abs(timestamp_helper.GetFramesToTarget(buffer->timestamp())), + kMinGapSize); + buffer->TrimEnd(frames_to_trim); + buffer->set_duration( + timestamp_helper.GetFrameDuration(buffer->frame_count())); } // Returns an AudioBus whose frame buffer is backed by the provided AudioBuffer. @@ -163,12 +177,13 @@ bool AudioStreamSanitizer::AddInput(const scoped_refptr<AudioBuffer>& input) { // Create a buffer with enough silence samples to fill the gap and // add it to the output buffer. - scoped_refptr<AudioBuffer> gap = - AudioBuffer::CreateEmptyBuffer(input->channel_layout(), - input->channel_count(), - input->sample_rate(), - frames_to_fill, - expected_timestamp); + scoped_refptr<AudioBuffer> gap = AudioBuffer::CreateEmptyBuffer( + input->channel_layout(), + input->channel_count(), + input->sample_rate(), + frames_to_fill, + expected_timestamp, + output_timestamp_helper_.GetFrameDuration(frames_to_fill)); AddOutputBuffer(gap); // Add the input buffer now that the gap has been filled. @@ -428,7 +443,9 @@ scoped_ptr<AudioBus> AudioSplicer::ExtractCrossfadeFromPreSplice( // If only part of the buffer was consumed, trim it appropriately and stick // it into the output queue. if (frames_before_splice) { - preroll->TrimEnd(preroll->frame_count() - frames_before_splice); + AccurateTrimEnd(preroll->frame_count() - frames_before_splice, + preroll, + output_ts_helper); CHECK(output_sanitizer_->AddInput(preroll)); frames_before_splice = 0; } @@ -449,6 +466,8 @@ void AudioSplicer::CrossfadePostSplice( const AudioTimestampHelper& output_ts_helper = output_sanitizer_->timestamp_helper(); crossfade_buffer->set_timestamp(output_ts_helper.GetTimestamp()); + crossfade_buffer->set_duration( + output_ts_helper.GetFrameDuration(pre_splice_bus->frames())); // AudioBuffer::ReadFrames() only allows output into an AudioBus, so wrap // our AudioBuffer in one so we can avoid extra data copies. diff --git a/media/base/audio_splicer_unittest.cc b/media/base/audio_splicer_unittest.cc index 2e46b9f..71e1728 100644 --- a/media/base/audio_splicer_unittest.cc +++ b/media/base/audio_splicer_unittest.cc @@ -35,15 +35,16 @@ class AudioSplicerTest : public ::testing::Test { } scoped_refptr<AudioBuffer> GetNextInputBuffer(float value, int frame_size) { - scoped_refptr<AudioBuffer> buffer = - MakeAudioBuffer<float>(kSampleFormat, - kChannelLayout, - kChannels, - kDefaultSampleRate, - value, - 0.0f, - frame_size, - input_timestamp_helper_.GetTimestamp()); + scoped_refptr<AudioBuffer> buffer = MakeAudioBuffer<float>( + kSampleFormat, + kChannelLayout, + kChannels, + kDefaultSampleRate, + value, + 0.0f, + frame_size, + input_timestamp_helper_.GetTimestamp(), + input_timestamp_helper_.GetFrameDuration(frame_size)); input_timestamp_helper_.AddFrames(frame_size); return buffer; } @@ -138,7 +139,8 @@ class AudioSplicerTest : public ::testing::Test { input->sample_rate(), input->frame_count(), &input->channel_data()[0], - input->timestamp()); + input->timestamp(), + input->duration()); return splicer_.AddInput(buffer_copy); } @@ -246,8 +248,7 @@ TEST_F(AudioSplicerTest, GapInsertion) { base::TimeDelta gap_duration = input_2->timestamp() - gap_timestamp; EXPECT_GT(gap_duration, base::TimeDelta()); EXPECT_EQ(gap_timestamp, output_2->timestamp()); - EXPECT_NEAR( - gap_duration.InMicroseconds(), output_2->duration().InMicroseconds(), 1); + EXPECT_EQ(gap_duration, output_2->duration()); EXPECT_EQ(kGapSize, output_2->frame_count()); EXPECT_TRUE(VerifyData(output_2, 0.0f)); @@ -443,7 +444,7 @@ TEST_F(AudioSplicerTest, PartialOverlapCrossfade) { VerifyPreSpliceOutput(overlapped_buffer, overlapping_buffer, 221, - base::TimeDelta::FromMicroseconds(5011)); + base::TimeDelta::FromMicroseconds(5012)); // Due to rounding the crossfade size may vary by up to a frame. const int kExpectedCrossfadeSize = 220; @@ -618,13 +619,11 @@ TEST_F(AudioSplicerTest, IncorrectlyMarkedSplice) { GetNextInputBuffer(1.0f, kBufferSize); // Fuzz the duration slightly so that the buffer overlaps the splice timestamp // by a microsecond, which is not enough to crossfade. - const base::TimeDelta kSpliceTimestamp = - input_timestamp_helper_.GetTimestamp() - - base::TimeDelta::FromMicroseconds(1); - splicer_.SetSpliceTimestamp(kSpliceTimestamp); + first_buffer->set_duration(first_buffer->duration() + + base::TimeDelta::FromMicroseconds(1)); + splicer_.SetSpliceTimestamp(input_timestamp_helper_.GetTimestamp()); scoped_refptr<AudioBuffer> second_buffer = GetNextInputBuffer(0.0f, kBufferSize); - second_buffer->set_timestamp(kSpliceTimestamp); // The splicer should be internally queuing input since |first_buffer| is part // of the supposed splice. diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc index 929b2f3..98d4971 100644 --- a/media/base/test_helpers.cc +++ b/media/base/test_helpers.cc @@ -151,25 +151,29 @@ gfx::Size TestVideoConfig::LargeCodedSize() { template <class T> scoped_refptr<AudioBuffer> MakeAudioBuffer(SampleFormat format, ChannelLayout channel_layout, - size_t channel_count, + int channel_count, int sample_rate, T start, T increment, - size_t frames, - base::TimeDelta timestamp) { - const size_t channels = ChannelLayoutToChannelCount(channel_layout); - scoped_refptr<AudioBuffer> output = - AudioBuffer::CreateBuffer(format, - channel_layout, - static_cast<int>(channel_count), - sample_rate, - static_cast<int>(frames)); + int frames, + base::TimeDelta timestamp, + base::TimeDelta duration) { + int channels = ChannelLayoutToChannelCount(channel_layout); + scoped_refptr<AudioBuffer> output = AudioBuffer::CreateBuffer( + format, channel_layout, channel_count, sample_rate, frames); output->set_timestamp(timestamp); + output->set_duration(duration); - const bool is_planar = - format == kSampleFormatPlanarS16 || format == kSampleFormatPlanarF32; - - // Values in channel 0 will be: + // Create a block of memory with values: + // start + // start + increment + // start + 2 * increment, ... + // For interleaved data, raw data will be: + // start + // start + channels * increment + // start + 2 * channels * increment, ... + // + // For planar data, values in channel 0 will be: // start // start + increment // start + 2 * increment, ... @@ -177,13 +181,13 @@ scoped_refptr<AudioBuffer> MakeAudioBuffer(SampleFormat format, // start + frames * increment // start + (frames + 1) * increment // start + (frames + 2) * increment, ... - for (size_t ch = 0; ch < channels; ++ch) { - T* buffer = - reinterpret_cast<T*>(output->channel_data()[is_planar ? ch : 0]); - const T v = static_cast<T>(start + ch * frames * increment); - for (size_t i = 0; i < frames; ++i) { - buffer[is_planar ? i : ch + i * channels] = - static_cast<T>(v + i * increment); + const size_t output_size = + output->channel_data().size() == 1 ? frames * channels : frames; + for (size_t ch = 0; ch < output->channel_data().size(); ++ch) { + T* buffer = reinterpret_cast<T*>(output->channel_data()[ch]); + const T v = static_cast<T>(start + ch * output_size * increment); + for (size_t i = 0; i < output_size; ++i) { + buffer[i] = static_cast<T>(v + i * increment); } } return output; @@ -195,12 +199,13 @@ scoped_refptr<AudioBuffer> MakeAudioBuffer(SampleFormat format, template scoped_refptr<AudioBuffer> MakeAudioBuffer<type>( \ SampleFormat format, \ ChannelLayout channel_layout, \ - size_t channel_count, \ + int channel_count, \ int sample_rate, \ type start, \ type increment, \ - size_t frames, \ - base::TimeDelta start_time) + int frames, \ + base::TimeDelta start_time, \ + base::TimeDelta duration) DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(uint8); DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int16); DEFINE_MAKE_AUDIO_BUFFER_INSTANCE(int32); diff --git a/media/base/test_helpers.h b/media/base/test_helpers.h index 8dc3895..f342af4 100644 --- a/media/base/test_helpers.h +++ b/media/base/test_helpers.h @@ -86,32 +86,41 @@ class TestVideoConfig { }; // Create an AudioBuffer containing |frames| frames of data, where each sample -// is of type T. |start| and |increment| are used to specify the values for the -// samples, which are created in channel order. The value for frame and channel -// is determined by: +// is of type T. // -// |start| + |channel| * |frames| * |increment| + index * |increment| +// For interleaved formats, each frame will have the data from |channels| +// channels interleaved. |start| and |increment| are used to specify the values +// for the samples. Since this is interleaved data, channel 0 data will be: +// |start| +// |start| + |channels| * |increment| +// |start| + 2 * |channels| * |increment|, and so on. +// Data for subsequent channels is similar. No check is done that |format| +// requires data to be of type T, but it is verified that |format| is an +// interleaved format. // -// E.g., for a stereo buffer the values in channel 0 will be: -// start -// start + increment -// start + 2 * increment, ... +// For planar formats, there will be a block for each of |channel| channels. +// |start| and |increment| are used to specify the values for the samples, which +// are created in channel order. Since this is planar data, channel 0 data will +// be: +// |start| +// |start| + |increment| +// |start| + 2 * |increment|, and so on. +// Data for channel 1 will follow where channel 0 ends. Subsequent channels are +// similar. No check is done that |format| requires data to be of type T, but it +// is verified that |format| is a planar format. // -// While, values in channel 1 will be: -// start + frames * increment -// start + (frames + 1) * increment -// start + (frames + 2) * increment, ... -// -// |start_time| will be used as the start time for the samples. +// |start_time| will be used as the start time for the samples. |duration| is +// the duration. template <class T> scoped_refptr<AudioBuffer> MakeAudioBuffer(SampleFormat format, ChannelLayout channel_layout, - size_t channel_count, + int channel_count, int sample_rate, T start, T increment, - size_t frames, - base::TimeDelta timestamp); + int frames, + base::TimeDelta timestamp, + base::TimeDelta duration); // Create a fake video DecoderBuffer for testing purpose. The buffer contains // part of video decoder config info embedded so that the testing code can do diff --git a/media/filters/audio_renderer_algorithm_unittest.cc b/media/filters/audio_renderer_algorithm_unittest.cc index 596c8cc..ed6b6cc 100644 --- a/media/filters/audio_renderer_algorithm_unittest.cc +++ b/media/filters/audio_renderer_algorithm_unittest.cc @@ -113,6 +113,7 @@ class AudioRendererAlgorithmTest : public testing::Test { 1, 1, kFrameSize, + kNoTimestamp(), kNoTimestamp()); break; case kSampleFormatS16: @@ -124,6 +125,7 @@ class AudioRendererAlgorithmTest : public testing::Test { 1, 1, kFrameSize, + kNoTimestamp(), kNoTimestamp()); break; case kSampleFormatS32: @@ -135,6 +137,7 @@ class AudioRendererAlgorithmTest : public testing::Test { 1, 1, kFrameSize, + kNoTimestamp(), kNoTimestamp()); break; default: diff --git a/media/filters/audio_renderer_impl_unittest.cc b/media/filters/audio_renderer_impl_unittest.cc index 05fb4de..1ae27e3 100644 --- a/media/filters/audio_renderer_impl_unittest.cc +++ b/media/filters/audio_renderer_impl_unittest.cc @@ -288,7 +288,8 @@ class AudioRendererImplTest : public ::testing::Test { kPlayingAudio, 0.0f, size, - next_timestamp_->GetTimestamp()); + next_timestamp_->GetTimestamp(), + next_timestamp_->GetFrameDuration(size)); next_timestamp_->AddFrames(size); DeliverBuffer(AudioDecoder::kOk, buffer); diff --git a/media/filters/decrypting_audio_decoder.cc b/media/filters/decrypting_audio_decoder.cc index d00e3b9..91ee63b 100644 --- a/media/filters/decrypting_audio_decoder.cc +++ b/media/filters/decrypting_audio_decoder.cc @@ -371,6 +371,8 @@ void DecryptingAudioDecoder::EnqueueFrames( } frame->set_timestamp(current_time); + frame->set_duration( + timestamp_helper_->GetFrameDuration(frame->frame_count())); timestamp_helper_->AddFrames(frame->frame_count()); } } diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc index 007a288..d7f1f9d 100644 --- a/media/filters/decrypting_audio_decoder_unittest.cc +++ b/media/filters/decrypting_audio_decoder_unittest.cc @@ -104,6 +104,7 @@ class DecryptingAudioDecoderTest : public testing::Test { channels, kSampleRate, kFakeAudioFrameSize, + kNoTimestamp(), kNoTimestamp()); decoded_frame_list_.push_back(decoded_frame_); @@ -362,12 +363,14 @@ TEST_F(DecryptingAudioDecoderTest, DecryptAndDecode_MultipleFrames) { ChannelLayoutToChannelCount(config_.channel_layout()), kSampleRate, kFakeAudioFrameSize, + kNoTimestamp(), kNoTimestamp()); scoped_refptr<AudioBuffer> frame_b = AudioBuffer::CreateEmptyBuffer( config_.channel_layout(), ChannelLayoutToChannelCount(config_.channel_layout()), kSampleRate, kFakeAudioFrameSize, + kNoTimestamp(), kNoTimestamp()); decoded_frame_list_.push_back(frame_a); decoded_frame_list_.push_back(frame_b); diff --git a/media/filters/ffmpeg_audio_decoder_unittest.cc b/media/filters/ffmpeg_audio_decoder_unittest.cc index 11df377..60d1f40 100644 --- a/media/filters/ffmpeg_audio_decoder_unittest.cc +++ b/media/filters/ffmpeg_audio_decoder_unittest.cc @@ -175,7 +175,7 @@ TEST_F(FFmpegAudioDecoderTest, ProduceAudioSamples) { ASSERT_EQ(3u, decoded_audio_.size()); ExpectDecodedAudio(0, 0, 2902); ExpectDecodedAudio(1, 2902, 13061); - ExpectDecodedAudio(2, 15963, 23219); + ExpectDecodedAudio(2, 15963, 23220); // Call one more time to trigger EOS. Decode(); |