diff options
author | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-07 18:59:36 +0000 |
---|---|---|
committer | hclam@chromium.org <hclam@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-10-07 18:59:36 +0000 |
commit | 3b098bbef42fa93a2c17c96c888a65564191f767 (patch) | |
tree | 0509385a390e0ff9b348e96382c10074127319f6 /chrome/renderer/gpu_video_decoder_host_unittest.cc | |
parent | c7b7800afbf7aadb5c9f99c95209237cdf869678 (diff) | |
download | chromium_src-3b098bbef42fa93a2c17c96c888a65564191f767.zip chromium_src-3b098bbef42fa93a2c17c96c888a65564191f767.tar.gz chromium_src-3b098bbef42fa93a2c17c96c888a65564191f767.tar.bz2 |
Implement GpuVideoDecoderHost and unit tests
Add the following feature to GpuVideoDecoderHost:
1. Video frame allocation / release.
2. ProduceVideoFrame / ConsumeVideoFrame using frames allocated.
3. Change GpuVideoDecoder creation to asynchronous.
BUG=53714
TEST=unit_tests --gtest_filter=GpuVideoDecoder*
Review URL: http://codereview.chromium.org/3397027
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@61824 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/gpu_video_decoder_host_unittest.cc')
-rw-r--r-- | chrome/renderer/gpu_video_decoder_host_unittest.cc | 259 |
1 files changed, 259 insertions, 0 deletions
diff --git a/chrome/renderer/gpu_video_decoder_host_unittest.cc b/chrome/renderer/gpu_video_decoder_host_unittest.cc new file mode 100644 index 0000000..c0a10be --- /dev/null +++ b/chrome/renderer/gpu_video_decoder_host_unittest.cc @@ -0,0 +1,259 @@ +// Copyright (c) 2010 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/message_loop.h" +#include "chrome/common/gpu_messages.h" +#include "chrome/common/message_router.h" +#include "chrome/renderer/gpu_video_decoder_host.h" +#include "media/video/mock_objects.h" +#include "testing/gmock/include/gmock/gmock.h" +#include "testing/gtest/include/gtest/gtest.h" + +using testing::_; +using testing::DoAll; +using testing::NotNull; +using testing::Return; +using testing::SetArgumentPointee; + +static const int kContextRouteId = 50; +static const int kDecoderHostId = 51; +static const int kDecoderId = 51; +static const int kVideoFrames = 3; +static const int kWidth = 320; +static const int kHeight = 240; +static const int kTransportBufferSize = 1024; + +ACTION_P(SimulateAllocateVideoFrames, frames) { + // Fake some texture IDs here. + media::VideoFrame::GlTexture textures[] = {4, 5, 6}; + for (int i = 0; i < kVideoFrames; ++i) { + scoped_refptr<media::VideoFrame> frame; + media::VideoFrame::CreateFrameGlTexture(media::VideoFrame::YV12, + kWidth, kHeight, textures, + base::TimeDelta(), + base::TimeDelta(), + &frame); + frames->push_back(frame); + arg4->push_back(frame); + } + + // Execute the callback to complete the task. + arg5->Run(); + delete arg5; +} + +ACTION_P2(SendMessage, handler, msg) { + handler->OnMessageReceived(msg); +} + +class GpuVideoDecoderHostTest : public testing::Test, + public IPC::Message::Sender, + public media::VideoDecodeEngine::EventHandler { + public: + // This method is used to dispatch IPC messages to mock methods. + virtual bool Send(IPC::Message* msg) { + EXPECT_TRUE(msg); + if (!msg) + return false; + + bool handled = true; + IPC_BEGIN_MESSAGE_MAP(GpuVideoDecoderHostTest, *msg) + IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoDecoder, + OnCreateVideoDecoder) + IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Initialize, + OnInitialize) + IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Destroy, + OnDestroy) + IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Flush, + OnFlush) + IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_EmptyThisBuffer, + OnEmptyThisBuffer) + IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_VideoFrameAllocated, + OnVideoFrameAllocated) + IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_ProduceVideoFrame, + OnProduceVideoFrame) + IPC_MESSAGE_UNHANDLED_ERROR() + IPC_END_MESSAGE_MAP() + EXPECT_TRUE(handled); + delete msg; + return true; + } + + // Mock methods for outgoing messages. + MOCK_METHOD1(OnInitialize, void(GpuVideoDecoderInitParam param)); + MOCK_METHOD0(OnDestroy, void()); + MOCK_METHOD0(OnFlush, void()); + MOCK_METHOD1(OnEmptyThisBuffer, + void(GpuVideoDecoderInputBufferParam param)); + MOCK_METHOD1(OnProduceVideoFrame, void(int32 frame_id)); + MOCK_METHOD2(OnVideoFrameAllocated, + void(int32 frame_id, std::vector<uint32> textures)); + MOCK_METHOD2(OnCreateVideoDecoder, + void(int32 context_route_id, int32 decoder_host_id)); + + // Mock methods for VideoDecodeEngine::EventHandler. + MOCK_METHOD1(ProduceVideoSample, + void(scoped_refptr<media::Buffer> buffer)); + MOCK_METHOD1(ConsumeVideoFrame, + void(scoped_refptr<media::VideoFrame> frame)); + MOCK_METHOD1(OnInitializeComplete, + void(const media::VideoCodecInfo& info)); + MOCK_METHOD0(OnUninitializeComplete, void()); + MOCK_METHOD0(OnFlushComplete, void()); + MOCK_METHOD0(OnSeekComplete, void()); + MOCK_METHOD0(OnError, void()); + MOCK_METHOD1(OnFormatChange, + void(media::VideoStreamInfo stream_info)); + + void Initialize() { + decoder_host_.reset( + new GpuVideoDecoderHost(&router_, this, kContextRouteId, + kDecoderHostId)); + shared_memory_.reset(new base::SharedMemory()); + shared_memory_->Create("", false, false, kTransportBufferSize); + + GpuVideoDecoderHostMsg_CreateVideoDecoderDone msg1(kDecoderHostId, + kDecoderId); + EXPECT_CALL(*this, OnCreateVideoDecoder(kContextRouteId, kDecoderHostId)) + .WillOnce(SendMessage(decoder_host_.get(), msg1)); + + GpuVideoDecoderInitDoneParam param; + param.success = true; + param.input_buffer_size = kTransportBufferSize; + param.input_buffer_handle = shared_memory_->handle(); + + GpuVideoDecoderHostMsg_InitializeACK msg2(kDecoderHostId, param); + EXPECT_CALL(*this, OnInitialize(_)) + .WillOnce(SendMessage(decoder_host_.get(), msg2)); + EXPECT_CALL(*this, OnInitializeComplete(_)); + + media::VideoCodecConfig config; + config.codec = media::kCodecH264; + config.width = kWidth; + config.height = kHeight; + decoder_host_->Initialize(&message_loop_, this, &context_, config); + message_loop_.RunAllPending(); + } + + void Uninitialize() { + // A message is sent to GPU process to destroy the decoder. + GpuVideoDecoderHostMsg_DestroyACK msg(kDecoderHostId); + EXPECT_CALL(*this, OnDestroy()) + .WillOnce(SendMessage(decoder_host_.get(), msg)); + EXPECT_CALL(context_, ReleaseAllVideoFrames()); + EXPECT_CALL(*this, OnUninitializeComplete()); + decoder_host_->Uninitialize(); + } + + void AllocateVideoFrames() { + // Expect context is called to allocate video frames. + EXPECT_CALL(context_, + AllocateVideoFrames(kVideoFrames, kWidth, kHeight, + media::VideoFrame::YV12, + NotNull(), NotNull())) + .WillOnce(SimulateAllocateVideoFrames(&frames_)) + .RetiresOnSaturation(); + + // Expect that we send the video frames to the GPU process. + EXPECT_CALL(*this, OnVideoFrameAllocated(_, _)) + .Times(kVideoFrames) + .RetiresOnSaturation(); + + // Pretend that a message is sent to GpuVideoDecoderHost to allocate + // video frames. + GpuVideoDecoderHostMsg_AllocateVideoFrames msg( + kDecoderHostId, kVideoFrames, kWidth, kHeight, + static_cast<int32>(media::VideoFrame::YV12)); + decoder_host_->OnMessageReceived(msg); + } + + void ReleaseVideoFrames() { + // Expect that context is called to release all video frames. + EXPECT_CALL(context_, ReleaseAllVideoFrames()) + .RetiresOnSaturation(); + + // Pretend a message is sent to release all video frames. + GpuVideoDecoderHostMsg_ReleaseAllVideoFrames msg(kDecoderHostId); + decoder_host_->OnMessageReceived(msg); + + // Clear the list of video frames allocated. + frames_.clear(); + } + + void ProduceVideoFrame(int first_frame_id) { + for (int i = 0; i < kVideoFrames; ++i) { + // Expect that a request is received to produce a video frame. + GpuVideoDecoderHostMsg_ConsumeVideoFrame msg( + kDecoderHostId, first_frame_id + i, 0, 0, 0); + EXPECT_CALL(*this, OnProduceVideoFrame(first_frame_id + i)) + .WillOnce(SendMessage(decoder_host_.get(), msg)) + .RetiresOnSaturation(); + + // Expect that a reply is made when a video frame is ready. + EXPECT_CALL(*this, ConsumeVideoFrame(frames_[i])) + .RetiresOnSaturation(); + + // Use the allocated video frames to make a request. + decoder_host_->ProduceVideoFrame(frames_[i]); + } + } + + private: + MessageLoop message_loop_; + MessageRouter router_; + media::MockVideoDecodeContext context_; + + scoped_ptr<GpuVideoDecoderHost> decoder_host_; + scoped_ptr<base::SharedMemory> shared_memory_; + + // Keeps the video frames allocated. + std::vector<scoped_refptr<media::VideoFrame> > frames_; +}; + +// Test that when we initialize GpuVideoDecoderHost the corresponding +// IPC messages are sent and at the end OnInitializeComplete() is +// called with the right parameters. +TEST_F(GpuVideoDecoderHostTest, Initialize) { + Initialize(); +} + +// Test that the sequence of method calls and IPC messages is correct. +// And at the end OnUninitializeComplete() is called. +TEST_F(GpuVideoDecoderHostTest, Uninitialize) { + Initialize(); + Uninitialize(); +} + +// Test that IPC messages are sent to GpuVideoDecoderHost and it +// calls VideoDecodeContext to allocate textures and send these +// textures back to the GPU process by IPC messages. +TEST_F(GpuVideoDecoderHostTest, AllocateVideoFrames) { + Initialize(); + AllocateVideoFrames(); + Uninitialize(); +} + +// Test that IPC messages are sent to GpuVideoDecoderHost to +// release textures and VideoDecodeContext is called correctly. +TEST_F(GpuVideoDecoderHostTest, ReleaseVideoFrames) { + Initialize(); + AllocateVideoFrames(); + ReleaseVideoFrames(); + AllocateVideoFrames(); + ReleaseVideoFrames(); + Uninitialize(); +} + +// Test the sequence of IPC messages and methods calls for a decode +// routine. This tests the output port only. +TEST_F(GpuVideoDecoderHostTest, ProduceVideoFrame) { + Initialize(); + AllocateVideoFrames(); + ProduceVideoFrame(0); + ReleaseVideoFrames(); + AllocateVideoFrames(); + ProduceVideoFrame(kVideoFrames); + ReleaseVideoFrames(); + Uninitialize(); +} |