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

Unified Diff: media/filters/audio_timestamp_validator_unittest.cc

Issue 1954633002: MEDIA_LOG for large encoded timestamp gaps in decoder stream. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase Created 4 years, 6 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/filters/audio_timestamp_validator.cc ('k') | media/filters/decoder_selector.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/filters/audio_timestamp_validator_unittest.cc
diff --git a/media/filters/audio_timestamp_validator_unittest.cc b/media/filters/audio_timestamp_validator_unittest.cc
new file mode 100644
index 0000000000000000000000000000000000000000..de2f47449f88e64900b4f6fc3062afb88e97139a
--- /dev/null
+++ b/media/filters/audio_timestamp_validator_unittest.cc
@@ -0,0 +1,252 @@
+// 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 "media/filters/audio_timestamp_validator.h"
+
+#include <tuple>
+
+#include "base/time/time.h"
+#include "media/base/audio_decoder_config.h"
+#include "media/base/media_util.h"
+#include "media/base/mock_media_log.h"
+#include "media/base/test_helpers.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using ::testing::HasSubstr;
+
+namespace media {
+
+// Constants to specify the type of audio data used.
+static const AudioCodec kCodec = kCodecVorbis;
+static const SampleFormat kSampleFormat = kSampleFormatPlanarF32;
+static const base::TimeDelta kSeekPreroll;
+static const int kSamplesPerSecond = 10000;
+static const base::TimeDelta kBufferDuration =
+ base::TimeDelta::FromMilliseconds(20);
+static const ChannelLayout kChannelLayout = CHANNEL_LAYOUT_STEREO;
+static const int kChannelCount = 2;
+static const int kChannels = ChannelLayoutToChannelCount(kChannelLayout);
+static const int kFramesPerBuffer = kBufferDuration.InMicroseconds() *
+ kSamplesPerSecond /
+ base::Time::kMicrosecondsPerSecond;
+
+// Params are:
+// 1. Output delay: number of encoded buffers before first decoded output
+// 2. Codec delay: number of frames of codec delay in decoder config
+// 3. Front discard: front discard for the first buffer
+using ValidatorTestParams = testing::tuple<int, int, base::TimeDelta>;
+
+class AudioTimestampValidatorTest
+ : public testing::Test,
+ public ::testing::WithParamInterface<ValidatorTestParams> {
+ public:
+ AudioTimestampValidatorTest()
+ : media_log_(new testing::StrictMock<MockMediaLog>()) {}
+
+ protected:
+ void SetUp() override {
+ output_delay_ = testing::get<0>(GetParam());
+ codec_delay_ = testing::get<1>(GetParam());
+ front_discard_ = testing::get<2>(GetParam());
+ }
+
+ int output_delay_;
+
+ int codec_delay_;
+
+ base::TimeDelta front_discard_;
+
+ scoped_refptr<testing::StrictMock<MockMediaLog>> media_log_;
+};
+
+TEST_P(AudioTimestampValidatorTest, WarnForEraticTimes) {
+ AudioDecoderConfig decoder_config;
+ decoder_config.Initialize(kCodec, kSampleFormat, kChannelLayout,
+ kSamplesPerSecond, EmptyExtraData(), Unencrypted(),
+ kSeekPreroll, codec_delay_);
+
+ // Validator should fail to stabilize pattern for timestamp expectations.
+ EXPECT_MEDIA_LOG(
+ HasSubstr("Failed to reconcile encoded audio times "
+ "with decoded output."));
+
+ // No gap warnings should be emitted because the timestamps expectations never
+ // stabilized.
+ EXPECT_MEDIA_LOG(HasSubstr("timestamp gap detected")).Times(0);
+
+ AudioTimestampValidator validator(decoder_config, media_log_);
+
+ const base::TimeDelta kRandomOffsets[] = {
+ base::TimeDelta::FromMilliseconds(100),
+ base::TimeDelta::FromMilliseconds(350)};
+
+ for (int i = 0; i < 100; ++i) {
+ // Each buffer's timestamp is kBufferDuration from the previous buffer.
+ scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
+
+ // Ping-pong between two random offsets to prevent validator from
+ // stabilizing timestamp pattern.
+ base::TimeDelta randomOffset =
+ kRandomOffsets[i % arraysize(kRandomOffsets)];
+ encoded_buffer->set_timestamp(i * kBufferDuration + randomOffset);
+
+ if (i == 0) {
+ encoded_buffer->set_discard_padding(
+ std::make_pair(front_discard_, base::TimeDelta()));
+ }
+
+ validator.CheckForTimestampGap(encoded_buffer);
+
+ if (i >= output_delay_) {
+ // kFramesPerBuffer is derived to perfectly match kBufferDuration, so
+ // no gaps exists as long as timestamps are exactly kBufferDuration apart.
+ scoped_refptr<AudioBuffer> decoded_buffer = MakeAudioBuffer<float>(
+ kSampleFormat, kChannelLayout, kChannelCount, kSamplesPerSecond, 1.0f,
+ 0.0f, kFramesPerBuffer, i * kBufferDuration);
+ validator.RecordOutputDuration(decoded_buffer.get());
+ }
+ }
+}
+
+TEST_P(AudioTimestampValidatorTest, NoWarningForValidTimes) {
+ AudioDecoderConfig decoder_config;
+ decoder_config.Initialize(kCodec, kSampleFormat, kChannelLayout,
+ kSamplesPerSecond, EmptyExtraData(), Unencrypted(),
+ kSeekPreroll, codec_delay_);
+
+ // Validator should quickly stabilize pattern for timestamp expectations.
+ EXPECT_MEDIA_LOG(HasSubstr("Failed to reconcile encoded audio times "
+ "with decoded output."))
+ .Times(0);
+
+ // Expect no gap warnings for series of buffers with valid timestamps.
+ EXPECT_MEDIA_LOG(HasSubstr("timestamp gap detected")).Times(0);
+
+ AudioTimestampValidator validator(decoder_config, media_log_);
+
+ for (int i = 0; i < 100; ++i) {
+ // Each buffer's timestamp is kBufferDuration from the previous buffer.
+ scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
+ encoded_buffer->set_timestamp(i * kBufferDuration);
+
+ if (i == 0) {
+ encoded_buffer->set_discard_padding(
+ std::make_pair(front_discard_, base::TimeDelta()));
+ }
+
+ validator.CheckForTimestampGap(encoded_buffer);
+
+ if (i >= output_delay_) {
+ // kFramesPerBuffer is derived to perfectly match kBufferDuration, so
+ // no gaps exists as long as timestamps are exactly kBufferDuration apart.
+ scoped_refptr<AudioBuffer> decoded_buffer = MakeAudioBuffer<float>(
+ kSampleFormat, kChannelLayout, kChannelCount, kSamplesPerSecond, 1.0f,
+ 0.0f, kFramesPerBuffer, i * kBufferDuration);
+ validator.RecordOutputDuration(decoded_buffer.get());
+ }
+ }
+}
+
+TEST_P(AudioTimestampValidatorTest, SingleWarnForSingleLargeGap) {
+ AudioDecoderConfig decoder_config;
+ decoder_config.Initialize(kCodec, kSampleFormat, kChannelLayout,
+ kSamplesPerSecond, EmptyExtraData(), Unencrypted(),
+ kSeekPreroll, codec_delay_);
+
+ AudioTimestampValidator validator(decoder_config, media_log_);
+
+ // Validator should quickly stabilize pattern for timestamp expectations.
+ EXPECT_MEDIA_LOG(HasSubstr("Failed to reconcile encoded audio times "
+ "with decoded output."))
+ .Times(0);
+
+ for (int i = 0; i < 100; ++i) {
+ // Halfway through the stream, introduce sudden gap of 50 milliseconds.
+ base::TimeDelta offset;
+ if (i >= 50)
+ offset = base::TimeDelta::FromMilliseconds(100);
+
+ // This gap never widens, so expect only a single warning when its first
+ // introduced.
+ if (i == 50)
+ EXPECT_MEDIA_LOG(HasSubstr("timestamp gap detected"));
+
+ scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
+ encoded_buffer->set_timestamp(i * kBufferDuration + offset);
+
+ if (i == 0) {
+ encoded_buffer->set_discard_padding(
+ std::make_pair(front_discard_, base::TimeDelta()));
+ }
+
+ validator.CheckForTimestampGap(encoded_buffer);
+
+ if (i >= output_delay_) {
+ // kFramesPerBuffer is derived to perfectly match kBufferDuration, so
+ // no gaps exists as long as timestamps are exactly kBufferDuration apart.
+ scoped_refptr<AudioBuffer> decoded_buffer = MakeAudioBuffer<float>(
+ kSampleFormat, kChannelLayout, kChannelCount, kSamplesPerSecond, 1.0f,
+ 0.0f, kFramesPerBuffer, i * kBufferDuration);
+ validator.RecordOutputDuration(decoded_buffer.get());
+ }
+ }
+}
+
+TEST_P(AudioTimestampValidatorTest, RepeatedWarnForSlowAccumulatingDrift) {
+ AudioDecoderConfig decoder_config;
+ decoder_config.Initialize(kCodec, kSampleFormat, kChannelLayout,
+ kSamplesPerSecond, EmptyExtraData(), Unencrypted(),
+ kSeekPreroll, codec_delay_);
+
+ AudioTimestampValidator validator(decoder_config, media_log_);
+
+ EXPECT_MEDIA_LOG(HasSubstr("Failed to reconcile encoded audio times "
+ "with decoded output."))
+ .Times(0);
+
+ for (int i = 0; i < 100; ++i) {
+ // Wait for delayed output to begin plus an additional two iterations to
+ // start using drift offset. The the two iterations without offset will
+ // allow the validator to stabilize the pattern of timestamps and begin
+ // checking for gaps. Once stable, increase offset by 1 millisecond for each
+ // iteration.
+ base::TimeDelta offset;
+ if (i >= output_delay_ + 2)
+ offset = i * base::TimeDelta::FromMilliseconds(1);
+
+ scoped_refptr<DecoderBuffer> encoded_buffer = new DecoderBuffer(0);
+ encoded_buffer->set_timestamp((i * kBufferDuration) + offset);
+
+ // Expect gap warnings to start when drift hits 50 milliseconds. Warnings
+ // should continue as the gap widens.
+ if (offset > base::TimeDelta::FromMilliseconds(50)) {
+ EXPECT_MEDIA_LOG(HasSubstr("timestamp gap detected"));
+ }
+
+ validator.CheckForTimestampGap(encoded_buffer);
+
+ if (i >= output_delay_) {
+ // kFramesPerBuffer is derived to perfectly match kBufferDuration, so
+ // no gaps exists as long as timestamps are exactly kBufferDuration apart.
+ scoped_refptr<AudioBuffer> decoded_buffer = MakeAudioBuffer<float>(
+ kSampleFormat, kChannelLayout, kChannelCount, kSamplesPerSecond, 1.0f,
+ 0.0f, kFramesPerBuffer, i * kBufferDuration);
+ validator.RecordOutputDuration(decoded_buffer.get());
+ }
+ }
+}
+
+// Test with cartesian product of various output delay, codec delay, and front
+// discard values. These simulate configurations for different containers/codecs
+// which present different challenges when building timestamp expectations.
+INSTANTIATE_TEST_CASE_P(
+ ,
+ AudioTimestampValidatorTest,
+ ::testing::Combine(
+ ::testing::Values(0, 10), // output delay
+ ::testing::Values(0, 512), // codec delay
+ ::testing::Values(base::TimeDelta(), // front discard
+ base::TimeDelta::FromMilliseconds(65))));
+
+} // namespace media
« no previous file with comments | « media/filters/audio_timestamp_validator.cc ('k') | media/filters/decoder_selector.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698