Index: media/base/audio_discard_helper_unittest.cc |
diff --git a/media/base/audio_discard_helper_unittest.cc b/media/base/audio_discard_helper_unittest.cc |
new file mode 100644 |
index 0000000000000000000000000000000000000000..1a6b592120da4b8425361e606a89b28cb334c1b9 |
--- /dev/null |
+++ b/media/base/audio_discard_helper_unittest.cc |
@@ -0,0 +1,214 @@ |
+// Copyright 2014 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/memory/scoped_ptr.h" |
+#include "media/base/audio_buffer.h" |
+#include "media/base/audio_discard_helper.h" |
+#include "media/base/buffers.h" |
+#include "media/base/decoder_buffer.h" |
+#include "media/base/test_helpers.h" |
+#include "testing/gtest/include/gtest/gtest.h" |
+ |
+namespace media { |
+ |
+static const int kSampleRate = 48000; |
+ |
+static scoped_refptr<DecoderBuffer> CreateEncodedBuffer( |
+ base::TimeDelta timestamp, |
+ base::TimeDelta duration) { |
+ scoped_refptr<DecoderBuffer> result(new DecoderBuffer(1)); |
+ result->set_timestamp(timestamp); |
+ result->set_duration(duration); |
+ return result; |
+} |
+ |
+static scoped_refptr<AudioBuffer> CreateDecodedBuffer(int frames) { |
+ return MakeAudioBuffer(kSampleFormatPlanarF32, |
+ CHANNEL_LAYOUT_MONO, |
+ 1, |
+ kSampleRate, |
+ 0.0f, |
+ 0.01f, |
+ frames, |
+ kNoTimestamp(), |
+ kNoTimestamp()); |
+} |
+ |
+TEST(AudioDiscardHelperTest, TimeDeltaToFrames) { |
+ AudioDiscardHelper discard_helper(kSampleRate); |
+ |
+ EXPECT_EQ(0, discard_helper.TimeDeltaToFrames(base::TimeDelta())); |
+ EXPECT_EQ( |
+ kSampleRate / 100, |
+ discard_helper.TimeDeltaToFrames(base::TimeDelta::FromMilliseconds(10))); |
+ |
+ // Ensure partial frames are always rounded up. The equation below calculates |
+ // a frame count with a fractional part < 0.5. |
+ const int small_remainder = |
+ base::Time::kMicrosecondsPerSecond * (kSampleRate - 0.9) / kSampleRate; |
+ EXPECT_EQ(kSampleRate, |
+ discard_helper.TimeDeltaToFrames( |
+ base::TimeDelta::FromMicroseconds(small_remainder))); |
+} |
+ |
+TEST(AudioDiscardHelperTest, BasicProcessBuffers) { |
+ AudioDiscardHelper discard_helper(kSampleRate); |
+ ASSERT_FALSE(discard_helper.initialized()); |
+ |
+ const base::TimeDelta kTimestamp = base::TimeDelta(); |
+ |
+ // Use an estimated duration which doesn't match the number of decoded frames |
+ // to ensure the helper is correctly setting durations based on output frames. |
+ const base::TimeDelta kEstimatedDuration = |
+ base::TimeDelta::FromMilliseconds(9); |
+ const base::TimeDelta kActualDuration = base::TimeDelta::FromMilliseconds(10); |
+ const int kTestFrames = discard_helper.TimeDeltaToFrames(kActualDuration); |
+ |
+ scoped_refptr<DecoderBuffer> encoded_buffer = |
+ CreateEncodedBuffer(kTimestamp, kEstimatedDuration); |
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames); |
+ |
+ // Verify the basic case where nothing is discarded. |
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer)); |
+ ASSERT_TRUE(discard_helper.initialized()); |
+ EXPECT_EQ(kTimestamp, decoded_buffer->timestamp()); |
+ EXPECT_EQ(kActualDuration, decoded_buffer->duration()); |
+ EXPECT_EQ(kTestFrames, decoded_buffer->frame_count()); |
+ |
+ // Verify a Reset() takes us back to an uninitialized state. |
+ discard_helper.Reset(0); |
+ ASSERT_FALSE(discard_helper.initialized()); |
+ |
+ // Verify a NULL output buffer returns false. |
+ ASSERT_FALSE(discard_helper.ProcessBuffers(encoded_buffer, NULL)); |
+} |
+ |
+TEST(AudioDiscardHelperTest, ProcessBuffersWithInitialDiscard) { |
+ AudioDiscardHelper discard_helper(kSampleRate); |
+ ASSERT_FALSE(discard_helper.initialized()); |
+ |
+ const base::TimeDelta kTimestamp = base::TimeDelta(); |
+ const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10); |
+ const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration); |
+ |
+ // Tell the helper we want to discard half of the initial frames. |
+ discard_helper.Reset(kTestFrames / 2); |
+ |
+ scoped_refptr<DecoderBuffer> encoded_buffer = |
+ CreateEncodedBuffer(kTimestamp, kDuration); |
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames); |
+ |
+ // Verify half the frames end up discarded. |
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer)); |
+ ASSERT_TRUE(discard_helper.initialized()); |
+ EXPECT_EQ(kTimestamp, decoded_buffer->timestamp()); |
+ EXPECT_EQ(kDuration / 2, decoded_buffer->duration()); |
+ EXPECT_EQ(kTestFrames / 2, decoded_buffer->frame_count()); |
+} |
+ |
+TEST(AudioDiscardHelperTest, ProcessBuffersWithLargeInitialDiscard) { |
+ AudioDiscardHelper discard_helper(kSampleRate); |
+ ASSERT_FALSE(discard_helper.initialized()); |
+ |
+ const base::TimeDelta kTimestamp = base::TimeDelta(); |
+ const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10); |
+ const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration); |
+ |
+ // Tell the helper we want to discard 1.5 buffers worth of frames. |
+ discard_helper.Reset(kTestFrames * 1.5); |
+ |
+ scoped_refptr<DecoderBuffer> encoded_buffer = |
+ CreateEncodedBuffer(kTimestamp, kDuration); |
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames); |
+ |
+ // The first call should fail since no output buffer remains. |
+ ASSERT_FALSE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer)); |
+ ASSERT_TRUE(discard_helper.initialized()); |
+ |
+ // Generate another set of buffers and expect half the output frames. |
+ encoded_buffer = CreateEncodedBuffer(kTimestamp + kDuration, kDuration); |
+ decoded_buffer = CreateDecodedBuffer(kTestFrames); |
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer)); |
+ |
+ // The timestamp should match that of the initial buffer. |
+ EXPECT_EQ(kTimestamp, decoded_buffer->timestamp()); |
+ EXPECT_EQ(kDuration / 2, decoded_buffer->duration()); |
+ EXPECT_EQ(kTestFrames / 2, decoded_buffer->frame_count()); |
+} |
+ |
+TEST(AudioDiscardHelperTest, AllowNonMonotonicTimestamps) { |
+ AudioDiscardHelper discard_helper(kSampleRate); |
+ ASSERT_FALSE(discard_helper.initialized()); |
+ |
+ const base::TimeDelta kTimestamp = base::TimeDelta(); |
+ const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10); |
+ const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration); |
+ |
+ scoped_refptr<DecoderBuffer> encoded_buffer = |
+ CreateEncodedBuffer(kTimestamp, kDuration); |
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames); |
+ |
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer)); |
+ ASSERT_TRUE(discard_helper.initialized()); |
+ EXPECT_EQ(kTimestamp, decoded_buffer->timestamp()); |
+ EXPECT_EQ(kDuration, decoded_buffer->duration()); |
+ EXPECT_EQ(kTestFrames, decoded_buffer->frame_count()); |
+ |
+ // Process the same input buffer again to ensure input timestamps which go |
wolenetz
2014/04/28 21:52:07
nit: timestamp really isn't going backwards in tim
DaleCurtis
2014/04/28 23:09:03
kTimestamp on buffer 2 is now behind kTimestamp+kD
|
+ // backwards in time are not errors. |
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer)); |
+ EXPECT_EQ(kTimestamp + kDuration, decoded_buffer->timestamp()); |
+ EXPECT_EQ(kDuration, decoded_buffer->duration()); |
+ EXPECT_EQ(kTestFrames, decoded_buffer->frame_count()); |
+} |
+ |
+TEST(AudioDiscardHelperTest, DiscardPadding) { |
wolenetz
2014/04/28 21:52:07
Versus ProcessBuffersWithInitialDiscard and Initia
DaleCurtis
2014/04/28 23:09:03
Done. Doing so required improving the accuracy of
|
+ AudioDiscardHelper discard_helper(kSampleRate); |
+ ASSERT_FALSE(discard_helper.initialized()); |
+ |
+ const base::TimeDelta kTimestamp = base::TimeDelta(); |
+ const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10); |
+ const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration); |
+ |
+ scoped_refptr<DecoderBuffer> encoded_buffer = |
+ CreateEncodedBuffer(kTimestamp, kDuration); |
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames); |
+ |
+ // Set a discard padding equivalent to half the buffer. |
+ encoded_buffer->set_discard_padding(kDuration / 2); |
+ |
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer)); |
+ ASSERT_TRUE(discard_helper.initialized()); |
+ EXPECT_EQ(kTimestamp, decoded_buffer->timestamp()); |
+ EXPECT_EQ(kDuration / 2, decoded_buffer->duration()); |
+ EXPECT_EQ(kTestFrames / 2, decoded_buffer->frame_count()); |
+} |
+ |
+TEST(AudioDiscardHelperTest, InitialDiscardAndDiscardPadding) { |
+ AudioDiscardHelper discard_helper(kSampleRate); |
+ ASSERT_FALSE(discard_helper.initialized()); |
+ |
+ const base::TimeDelta kTimestamp = base::TimeDelta(); |
+ const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10); |
+ const int kTestFrames = discard_helper.TimeDeltaToFrames(kDuration); |
+ |
+ scoped_refptr<DecoderBuffer> encoded_buffer = |
+ CreateEncodedBuffer(kTimestamp, kDuration); |
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames); |
+ |
+ // Set a discard padding equivalent to a quarter of the buffer. |
+ encoded_buffer->set_discard_padding(kDuration / 4); |
+ |
+ // Set an initial discard of a quarter of the buffer. |
+ discard_helper.Reset(kTestFrames / 4); |
+ |
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer)); |
+ ASSERT_TRUE(discard_helper.initialized()); |
+ EXPECT_EQ(kTimestamp, decoded_buffer->timestamp()); |
+ EXPECT_EQ(kDuration / 2, decoded_buffer->duration()); |
+ EXPECT_EQ(kTestFrames / 2, decoded_buffer->frame_count()); |
+} |
+ |
wolenetz
2014/04/28 21:52:07
nit: remove extra line.
DaleCurtis
2014/04/28 23:09:03
Done.
|
+ |
+} // namespace media |