Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1441)

Unified Diff: media/base/audio_discard_helper_unittest.cc

Issue 259453003: Introduce AudioDiscardHelper. Refactor audio decoders to use it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix x64 type. Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/base/audio_discard_helper.cc ('k') | media/base/test_helpers.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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..7788e7f6c49e4824726430c2cd71c709cf1c626b
--- /dev/null
+++ b/media/base/audio_discard_helper_unittest.cc
@@ -0,0 +1,261 @@
+// 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_bus.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 float kDataStep = 0.01f;
+static const size_t 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,
+ kDataStep,
+ frames,
+ kNoTimestamp(),
+ kNoTimestamp());
+}
+
+static float ExtractDecodedData(const scoped_refptr<AudioBuffer>& buffer,
+ int index) {
+ // This is really inefficient, but we can't access the raw AudioBuffer if any
+ // start trimming has been applied.
+ scoped_ptr<AudioBus> temp_bus = AudioBus::Create(buffer->channel_count(), 1);
+ buffer->ReadFrames(1, index, 0, temp_bus.get());
+ return temp_bus->channel(0)[0];
+}
+
+TEST(AudioDiscardHelperTest, TimeDeltaToFrames) {
+ AudioDiscardHelper discard_helper(kSampleRate);
+
+ EXPECT_EQ(0u, discard_helper.TimeDeltaToFrames(base::TimeDelta()));
+ EXPECT_EQ(
+ kSampleRate / 100,
+ discard_helper.TimeDeltaToFrames(base::TimeDelta::FromMilliseconds(10)));
+
+ // Ensure partial frames are rounded down correctly. 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 - 1,
+ discard_helper.TimeDeltaToFrames(
+ base::TimeDelta::FromMicroseconds(small_remainder)));
+
+ // Ditto, but rounded up using a fractional part > 0.5.
+ const int large_remainder =
+ base::Time::kMicrosecondsPerSecond * (kSampleRate - 0.4) / kSampleRate;
+ EXPECT_EQ(kSampleRate,
+ discard_helper.TimeDeltaToFrames(
+ base::TimeDelta::FromMicroseconds(large_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, NegativeTimestampClampsToZero) {
+ AudioDiscardHelper discard_helper(kSampleRate);
+ ASSERT_FALSE(discard_helper.initialized());
+
+ const base::TimeDelta kTimestamp = -base::TimeDelta::FromSeconds(1);
+ 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);
+
+ // Verify the basic case where nothing is discarded.
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
+ ASSERT_TRUE(discard_helper.initialized());
+ EXPECT_EQ(base::TimeDelta(), decoded_buffer->timestamp());
+ EXPECT_EQ(kDuration, decoded_buffer->duration());
+ EXPECT_EQ(kTestFrames, decoded_buffer->frame_count());
+}
+
+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.
+ const int kDiscardFrames = kTestFrames / 2;
+ discard_helper.Reset(kDiscardFrames);
+
+ 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(kDiscardFrames, decoded_buffer->frame_count());
+ ASSERT_FLOAT_EQ(kDiscardFrames * kDataStep,
+ ExtractDecodedData(decoded_buffer, 0));
+}
+
+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.
+ const int kDiscardFrames = kTestFrames / 2;
+ EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
+ EXPECT_EQ(kDuration / 2, decoded_buffer->duration());
+ EXPECT_EQ(kDiscardFrames, decoded_buffer->frame_count());
+ ASSERT_FLOAT_EQ(kDiscardFrames * kDataStep,
+ ExtractDecodedData(decoded_buffer, 0));
+}
+
+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
+ // 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) {
+ 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());
+ ASSERT_FLOAT_EQ(0, ExtractDecodedData(decoded_buffer, 0));
+}
+
+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.
+ const int kDiscardFrames = kTestFrames / 4;
+ discard_helper.Reset(kDiscardFrames);
+
+ 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());
+ ASSERT_FLOAT_EQ(kDiscardFrames * kDataStep,
+ ExtractDecodedData(decoded_buffer, 0));
+}
+
+} // namespace media
« no previous file with comments | « media/base/audio_discard_helper.cc ('k') | media/base/test_helpers.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698