summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authordalecurtis@google.com <dalecurtis@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-21 18:27:55 +0000
committerdalecurtis@google.com <dalecurtis@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2014-05-21 18:27:55 +0000
commit1d717e832233f4b00050531c10b54b3187b53bc7 (patch)
tree072feb770b81aaf00ccea4599611f56a60be85f3 /media
parentb8ddfce1801d9016e08c0859a5e17a4df8735600 (diff)
downloadchromium_src-1d717e832233f4b00050531c10b54b3187b53bc7.zip
chromium_src-1d717e832233f4b00050531c10b54b3187b53bc7.tar.gz
chromium_src-1d717e832233f4b00050531c10b54b3187b53bc7.tar.bz2
Add support for complete buffer discards.
Per discussion, allows kInfiniteDuration() for the front DiscardPadding value. When there's no decoder delay, this ensures accuracy when discarding. If decoder delay is present, the code falls back to using the duration as an estimation. BUG=371633 TEST=new unittests NOTRY=true R=wolenetz@chromium.org Review URL: https://codereview.chromium.org/293053005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271928 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/audio_discard_helper.cc18
-rw-r--r--media/base/audio_discard_helper_unittest.cc113
-rw-r--r--media/base/decoder_buffer.h4
3 files changed, 124 insertions, 11 deletions
diff --git a/media/base/audio_discard_helper.cc b/media/base/audio_discard_helper.cc
index f7279d7..303ee79 100644
--- a/media/base/audio_discard_helper.cc
+++ b/media/base/audio_discard_helper.cc
@@ -86,8 +86,13 @@ bool AudioDiscardHelper::ProcessBuffers(
// buffer's discard padding for processing with the current decoded buffer.
DecoderBuffer::DiscardPadding current_discard_padding =
encoded_buffer->discard_padding();
- if (delayed_discard_)
+ if (delayed_discard_) {
+ // For simplicity disallow cases where decoder delay is present with delayed
+ // discard (no codecs at present). Doing so allows us to avoid complexity
+ // around endpoint tracking when handling complete buffer discards.
+ DCHECK_EQ(decoder_delay_, 0u);
std::swap(current_discard_padding, delayed_discard_padding_);
+ }
if (discard_frames_ > 0) {
const size_t decoded_frames = decoded_buffer->frame_count();
@@ -110,8 +115,17 @@ bool AudioDiscardHelper::ProcessBuffers(
// Handle front discard padding.
if (current_discard_padding.first > base::TimeDelta()) {
const size_t decoded_frames = decoded_buffer->frame_count();
+
+ // If a complete buffer discard is requested and there's no decoder delay,
+ // just discard all remaining frames from this buffer. With decoder delay
+ // we have to estimate the correct number of frames to discard based on the
+ // duration of the encoded buffer.
const size_t start_frames_to_discard =
- TimeDeltaToFrames(current_discard_padding.first);
+ current_discard_padding.first == kInfiniteDuration()
+ ? (decoder_delay_ > 0
+ ? TimeDeltaToFrames(encoded_buffer->duration())
+ : decoded_frames)
+ : TimeDeltaToFrames(current_discard_padding.first);
// Regardless of the timestamp on the encoded buffer, the corresponding
// decoded output will appear |decoder_delay_| frames later.
diff --git a/media/base/audio_discard_helper_unittest.cc b/media/base/audio_discard_helper_unittest.cc
index 55d2b61..1ea0cc6 100644
--- a/media/base/audio_discard_helper_unittest.cc
+++ b/media/base/audio_discard_helper_unittest.cc
@@ -306,12 +306,12 @@ TEST(AudioDiscardHelperTest, InitialDiscardAndDiscardPadding) {
decoded_buffer->frame_count());
}
-TEST(AudioDiscardHelperTest, InitialDiscardAndDiscardPaddingAndCodecDelay) {
- // Use a codec delay of 5ms.
- const int kCodecDelay = kSampleRate / 100 / 2;
- AudioDiscardHelper discard_helper(kSampleRate, kCodecDelay);
+TEST(AudioDiscardHelperTest, InitialDiscardAndDiscardPaddingAndDecoderDelay) {
+ // Use a decoder delay of 5ms.
+ const int kDecoderDelay = kSampleRate / 100 / 2;
+ AudioDiscardHelper discard_helper(kSampleRate, kDecoderDelay);
ASSERT_FALSE(discard_helper.initialized());
- discard_helper.Reset(kCodecDelay);
+ discard_helper.Reset(kDecoderDelay);
const base::TimeDelta kTimestamp = base::TimeDelta();
const base::TimeDelta kDuration = base::TimeDelta::FromMilliseconds(10);
@@ -330,12 +330,12 @@ TEST(AudioDiscardHelperTest, InitialDiscardAndDiscardPaddingAndCodecDelay) {
ASSERT_TRUE(discard_helper.initialized());
// Processing another buffer (with the same discard padding) should discard
- // the back half of the buffer since kCodecDelay is half a buffer.
+ // the back half of the buffer since kDecoderDelay is half a buffer.
encoded_buffer->set_timestamp(kTimestamp + kDuration);
decoded_buffer = CreateDecodedBuffer(kTestFrames);
ASSERT_FLOAT_EQ(0.0f, ExtractDecodedData(decoded_buffer, 0));
- ASSERT_NEAR(kCodecDelay * kDataStep,
- ExtractDecodedData(decoded_buffer, kCodecDelay),
+ ASSERT_NEAR(kDecoderDelay * kDataStep,
+ ExtractDecodedData(decoded_buffer, kDecoderDelay),
kDataStep * 1000);
ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
@@ -381,4 +381,101 @@ TEST(AudioDiscardHelperTest, DelayedDiscardInitialDiscardAndDiscardPadding) {
decoded_buffer->frame_count());
}
+TEST(AudioDiscardHelperTest, CompleteDiscard) {
+ AudioDiscardHelper discard_helper(kSampleRate, 0);
+ 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);
+ discard_helper.Reset(0);
+
+ scoped_refptr<DecoderBuffer> encoded_buffer =
+ CreateEncodedBuffer(kTimestamp, kDuration);
+ encoded_buffer->set_discard_padding(
+ std::make_pair(kInfiniteDuration(), base::TimeDelta()));
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
+
+ // Verify all of the first buffer is discarded.
+ ASSERT_FALSE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
+ ASSERT_TRUE(discard_helper.initialized());
+ encoded_buffer->set_timestamp(kTimestamp + kDuration);
+ encoded_buffer->set_discard_padding(DecoderBuffer::DiscardPadding());
+
+ // Verify a second buffer goes through untouched.
+ decoded_buffer = CreateDecodedBuffer(kTestFrames / 2);
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
+ 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.0f, ExtractDecodedData(decoded_buffer, 0));
+}
+
+TEST(AudioDiscardHelperTest, CompleteDiscardWithDelayedDiscard) {
+ AudioDiscardHelper discard_helper(kSampleRate, 0);
+ 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);
+ discard_helper.Reset(0);
+
+ scoped_refptr<DecoderBuffer> encoded_buffer =
+ CreateEncodedBuffer(kTimestamp, kDuration);
+ encoded_buffer->set_discard_padding(
+ std::make_pair(kInfiniteDuration(), base::TimeDelta()));
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
+
+ // Setup a delayed discard.
+ ASSERT_FALSE(discard_helper.ProcessBuffers(encoded_buffer, NULL));
+ ASSERT_TRUE(discard_helper.initialized());
+
+ // Verify the first output buffer is dropped.
+ encoded_buffer->set_timestamp(kTimestamp + kDuration);
+ encoded_buffer->set_discard_padding(DecoderBuffer::DiscardPadding());
+ ASSERT_FALSE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
+
+ // Verify the second buffer goes through untouched.
+ encoded_buffer->set_timestamp(kTimestamp + 2 * kDuration);
+ decoded_buffer = CreateDecodedBuffer(kTestFrames / 2);
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
+ 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.0f, ExtractDecodedData(decoded_buffer, 0));
+}
+
+TEST(AudioDiscardHelperTest, CompleteDiscardWithInitialDiscardDecoderDelay) {
+ // Use a decoder delay of 5ms.
+ const int kDecoderDelay = kSampleRate / 100 / 2;
+ AudioDiscardHelper discard_helper(kSampleRate, kDecoderDelay);
+ ASSERT_FALSE(discard_helper.initialized());
+ discard_helper.Reset(kDecoderDelay);
+
+ 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);
+ encoded_buffer->set_discard_padding(
+ std::make_pair(kInfiniteDuration(), base::TimeDelta()));
+ scoped_refptr<AudioBuffer> decoded_buffer = CreateDecodedBuffer(kTestFrames);
+
+ // Verify all of the first buffer is discarded.
+ ASSERT_FALSE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
+ ASSERT_TRUE(discard_helper.initialized());
+ encoded_buffer->set_timestamp(kTimestamp + kDuration);
+ encoded_buffer->set_discard_padding(DecoderBuffer::DiscardPadding());
+
+ // Verify 5ms off the front of the second buffer is discarded.
+ decoded_buffer = CreateDecodedBuffer(kTestFrames * 2);
+ ASSERT_TRUE(discard_helper.ProcessBuffers(encoded_buffer, decoded_buffer));
+ EXPECT_EQ(kTimestamp, decoded_buffer->timestamp());
+ EXPECT_EQ(kDuration * 2 - kDuration / 2, decoded_buffer->duration());
+ EXPECT_EQ(kTestFrames * 2 - kDecoderDelay, decoded_buffer->frame_count());
+ ASSERT_FLOAT_EQ(kDecoderDelay * kDataStep,
+ ExtractDecodedData(decoded_buffer, 0));
+}
+
} // namespace media
diff --git a/media/base/decoder_buffer.h b/media/base/decoder_buffer.h
index 4ff836d..a3e6aa0 100644
--- a/media/base/decoder_buffer.h
+++ b/media/base/decoder_buffer.h
@@ -108,7 +108,9 @@ class MEDIA_EXPORT DecoderBuffer
// A discard window indicates the amount of data which should be discard from
// this buffer after decoding. The first value is the amount of the front and
- // the second the amount off the back.
+ // the second the amount off the back. A value of kInfiniteDuration() for the
+ // first value indicates the entire buffer should be discarded; the second
+ // value must be base::TimeDelta() in this case.
typedef std::pair<base::TimeDelta, base::TimeDelta> DiscardPadding;
const DiscardPadding& discard_padding() const {
DCHECK(!end_of_stream());