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

Unified Diff: media/base/android/media_codec_loop_unittest.cc

Issue 2132653002: MediaCodecLoop unit tests (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: added some tests Created 4 years, 5 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/android/media_codec_loop.cc ('k') | media/base/android/media_codec_util.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: media/base/android/media_codec_loop_unittest.cc
diff --git a/media/base/android/media_codec_loop_unittest.cc b/media/base/android/media_codec_loop_unittest.cc
index b29d109affd6b5744005da110d0486b50a789738..7451939e952e728463ad2209c6364f7afb92df32 100644
--- a/media/base/android/media_codec_loop_unittest.cc
+++ b/media/base/android/media_codec_loop_unittest.cc
@@ -6,12 +6,26 @@
#include "base/message_loop/message_loop.h"
#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_codec_loop.h"
+#include "media/base/android/mock_media_codec_bridge.h"
+#include "media/base/fake_single_thread_task_runner.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
+using ::testing::_;
+using ::testing::AtLeast;
+using ::testing::Eq;
+using ::testing::Field;
+using ::testing::InSequence;
+using ::testing::Mock;
+using ::testing::Return;
+using ::testing::SetArgPointee;
+using ::testing::StrictMock;
+
namespace media {
-class MockMediaCodecLoopClient : public MediaCodecLoop::Client {
+// The client is a strict mock, since we don't want random calls into it. We
+// want to be sure about the call sequence.
+class MockMediaCodecLoopClient : public StrictMock<MediaCodecLoop::Client> {
public:
MOCK_CONST_METHOD0(IsAnyInputPending, bool());
MOCK_METHOD0(ProvideInputData, MediaCodecLoop::InputData());
@@ -23,11 +37,91 @@ class MockMediaCodecLoopClient : public MediaCodecLoop::Client {
class MediaCodecLoopTest : public testing::Test {
public:
- MediaCodecLoopTest() : client_(new MockMediaCodecLoopClient) {}
+ MediaCodecLoopTest()
+ : client_(new StrictMock<MockMediaCodecLoopClient>()),
+ task_runner_(new FakeSingleThreadTaskRunner(&clock_)) {}
+
+ ~MediaCodecLoopTest() override {}
+
+ protected:
+ enum IdleExpectation {
+ ShouldBeIdle,
+ ShouldNotBeIdle,
+ };
+
+ // Wait until |codec_loop_| is idle.
+ void WaitUntilIdle(IdleExpectation idleExpectation = ShouldBeIdle) {
+ switch (idleExpectation) {
+ case ShouldBeIdle:
+ EXPECT_CALL(*client_, IsAnyInputPending()).Times(0);
+ EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)).Times(0);
+ break;
+ case ShouldNotBeIdle:
+ // Expect at least one call to see if more work is ready. We will
+ // return 'no'.
+ EXPECT_CALL(*client_, IsAnyInputPending())
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(false));
+ EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
+ .Times(AtLeast(1))
+ .WillRepeatedly(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
+ break;
+ }
+
+ // Either way, we expect that MCL should not attempt to dequeue input
+ // buffers, either because it's idle or because we said that no input
+ // is pending.
+ EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(0);
+
+ // TODO(liberato): assume that MCL doesn't retry for 30 seconds. Note
+ // that this doesn't actually wall-clock wait.
+ task_runner_->Sleep(base::TimeDelta::FromSeconds(30));
+ }
+
+ void ConstructCodecLoop() {
+ std::unique_ptr<MediaCodecBridge> codec(new MockMediaCodecBridge());
+ // Since we're providing a codec, we do not expect an error.
+ EXPECT_CALL(*client_, OnCodecLoopError()).Times(0);
+ codec_loop_.reset(
+ new MediaCodecLoop(client_.get(), std::move(codec), task_runner_));
+ codec_loop_->SetTestTickClock(&clock_);
+ Mock::VerifyAndClearExpectations(client_.get());
+ // We might want to WaitUntilIdle here.
+ }
+
+ struct OutputBuffer {
+ int index = 1;
+ size_t offset = 0;
+ size_t size = 1024;
+ base::TimeDelta pts = base::TimeDelta::FromSeconds(1);
+ bool eos = false;
+ bool key_frame = true;
+ };
+
+ struct EosOutputBuffer : public OutputBuffer {
+ EosOutputBuffer() { eos = true; }
+ };
+
+ void QueueOutputBuffer(OutputBuffer buffer) {
+ EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
+ .WillOnce(DoAll(
+ SetArgPointee<1>(buffer.index), SetArgPointee<2>(buffer.offset),
+ SetArgPointee<3>(buffer.size), SetArgPointee<4>(buffer.pts),
+ SetArgPointee<5>(buffer.eos), SetArgPointee<6>(buffer.key_frame),
+ Return(MEDIA_CODEC_OK)));
+ }
+
+ MockMediaCodecBridge& Codec() {
+ return *static_cast<MockMediaCodecBridge*>(codec_loop_->GetCodec());
+ }
public:
std::unique_ptr<MediaCodecLoop> codec_loop_;
std::unique_ptr<MockMediaCodecLoopClient> client_;
+ // TODO: how is the lifecycle of |clock_| handled? |task_runner_| can outlive
+ // us, since it's a refptr.
+ base::SimpleTestTickClock clock_;
+ scoped_refptr<FakeSingleThreadTaskRunner> task_runner_;
DISALLOW_COPY_AND_ASSIGN(MediaCodecLoopTest);
};
@@ -36,8 +130,121 @@ TEST_F(MediaCodecLoopTest, TestConstructionWithNullCodec) {
std::unique_ptr<MediaCodecBridge> codec;
EXPECT_CALL(*client_, OnCodecLoopError()).Times(1);
codec_loop_.reset(new MediaCodecLoop(client_.get(), std::move(codec)));
+ // Do not WaitUntilIdle() here, since that assumes that we have a codec.
ASSERT_FALSE(codec_loop_->GetCodec());
}
+TEST_F(MediaCodecLoopTest, TestConstructionWithCodec) {
+ ConstructCodecLoop();
+ ASSERT_EQ(codec_loop_->GetCodec(), &Codec());
+ WaitUntilIdle(ShouldBeIdle);
+}
+
+TEST_F(MediaCodecLoopTest, TestPendingWorkWithoutInput) {
+ ConstructCodecLoop();
+ // MCL should try ask if there is pending input, and try to dequeue output.
+ EXPECT_CALL(*client_, IsAnyInputPending()).Times(1).WillOnce(Return(false));
+ EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
+ codec_loop_->DoPendingWork();
+ WaitUntilIdle(ShouldNotBeIdle);
+}
+
+TEST_F(MediaCodecLoopTest, TestPendingWorkWithInput) {
+ ConstructCodecLoop();
+ // MCL should try ask if there is pending input, and try to dequeue both an
+ // output and input buffer.
+ EXPECT_CALL(*client_, IsAnyInputPending()).Times(1).WillOnce(Return(true));
+ EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _)).Times(1);
+ EXPECT_CALL(Codec(), DequeueInputBuffer(_, _)).Times(1);
+ codec_loop_->DoPendingWork();
+ WaitUntilIdle(ShouldNotBeIdle);
+}
+
+TEST_F(MediaCodecLoopTest, TestPendingWorkWithOutputBuffer) {
+ ConstructCodecLoop();
+ {
+ InSequence _s;
+
+ // MCL will first request input, then try to dequeue output.
+ EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(false));
+ OutputBuffer buf;
+ QueueOutputBuffer(buf);
+ EXPECT_CALL(*client_,
liberato (no reviews please) 2016/07/08 17:49:46 gmock is really amazing. it lets me set an expect
+ OnDecodedFrame(
+ Field(&MediaCodecLoop::OutputBuffer::index, Eq(buf.index))))
+ .Times(1)
+ .WillOnce(Return(true));
+
+ // MCL will try again for another set of buffers before DoPendingWork()
+ // returns. This is why we don't just leave them for WaitUntilIdle().
+ EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(false));
+ EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
+ }
+ codec_loop_->DoPendingWork();
+ WaitUntilIdle(ShouldNotBeIdle);
+}
+
+TEST_F(MediaCodecLoopTest, TestUnqueuedEos) {
+ // Test sending an unsolicited EOS from MCB to MCL.
+ ConstructCodecLoop();
+ {
+ InSequence _s;
+
+ // MCL will first request input, then try to dequeue output.
+ EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(false));
+ EosOutputBuffer eos;
+ QueueOutputBuffer(eos);
+ EXPECT_CALL(Codec(), ReleaseOutputBuffer(eos.index, false));
+ EXPECT_CALL(*client_, OnDecodedEos(_)).Times(1);
+
+ // MCL should not call back for another input buffer once it receives EOS,
+ // so don't expect a call to IsAnyInputPending. It will try for more
+ // output, however. It's unclear if it should.
+ EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
+ }
+ codec_loop_->DoPendingWork();
+ // Don't WaitUntilIdle() here, since MCL is not requesting buffers. It would
+ // fail the IsAnyInputPending expectation.
+}
+
+TEST_F(MediaCodecLoopTest, TestQueueEos) {
+ // Test sending an unsolicited EOS from MCB to MCL.
+ ConstructCodecLoop();
+ {
+ InSequence _s;
+
+ // MCL will first request input. We will provide an EOS from the client,
+ // and an input buffer to hold it.
+ EXPECT_CALL(*client_, IsAnyInputPending()).WillOnce(Return(true));
+ int input_buffer_index = 123;
+ EXPECT_CALL(Codec(), DequeueInputBuffer(_, _))
+ .WillOnce(DoAll(SetArgPointee<1>(input_buffer_index),
liberato (no reviews please) 2016/07/08 17:49:46 this sets the *index parameter of DequeueInputBuff
+ Return(MEDIA_CODEC_OK)));
+ MediaCodecLoop::InputData data;
+ data.is_eos = true;
+ EXPECT_CALL(*client_, ProvideInputData()).WillOnce(Return(data));
+ EXPECT_CALL(Codec(), QueueEOS(input_buffer_index));
+
+ // Now send the EOS back on the output queue.
+ EosOutputBuffer eos;
+ QueueOutputBuffer(eos);
+ EXPECT_CALL(Codec(), ReleaseOutputBuffer(eos.index, false));
+ EXPECT_CALL(*client_, OnDecodedEos(_)).Times(1);
+
+ // See TestUnqueuedEos.
+ EXPECT_CALL(Codec(), DequeueOutputBuffer(_, _, _, _, _, _, _))
+ .Times(1)
+ .WillOnce(Return(MEDIA_CODEC_DEQUEUE_OUTPUT_AGAIN_LATER));
+ }
+ codec_loop_->DoPendingWork();
+ // Don't WaitUntilIdle() here. See TestUnqueuedEos.
+}
+
} // namespace media
« no previous file with comments | « media/base/android/media_codec_loop.cc ('k') | media/base/android/media_codec_util.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698