blob: f88f30c22224c33631e390de85b68788f7f5c8ba [file] [log] [blame]
// 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 "base/process.h"
#include "chrome/common/gpu_messages.h"
#include "chrome/gpu/gpu_video_decoder.h"
#include "gpu/command_buffer/service/gles2_cmd_decoder_mock.h"
#include "ipc/ipc_message_utils.h"
#include "media/base/pipeline.h"
#include "media/video/video_mock_objects.h"
#include "testing/gtest/include/gtest/gtest.h"
using testing::_;
using testing::DoAll;
using testing::NotNull;
using testing::Return;
using testing::SetArgumentPointee;
static const int32 kFrameId = 10;
static const int32 kDecoderHostId = 50;
static const media::VideoFrame::GlTexture kClientTexture = 101;
static const media::VideoFrame::GlTexture kServiceTexture = 102;
static const size_t kWidth = 320;
static const size_t kHeight = 240;
class MockGpuVideoDevice : public GpuVideoDevice {
public:
MockGpuVideoDevice() {}
virtual ~MockGpuVideoDevice() {}
MOCK_METHOD0(GetDevice, void*());
MOCK_METHOD5(CreateVideoFrameFromGlTextures,
bool(size_t, size_t, media::VideoFrame::Format,
const std::vector<media::VideoFrame::GlTexture>&,
scoped_refptr<media::VideoFrame>*));
MOCK_METHOD1(ReleaseVideoFrame,
void(const scoped_refptr<media::VideoFrame>& frame));
MOCK_METHOD2(ConvertToVideoFrame,
bool(void* buffer, scoped_refptr<media::VideoFrame> frame));
private:
DISALLOW_COPY_AND_ASSIGN(MockGpuVideoDevice);
};
ACTION_P(InitializationDone, handler) {
media::VideoCodecInfo info;
info.success = true;
info.provides_buffers = false;
info.stream_info.surface_format = media::VideoFrame::RGBA;
info.stream_info.surface_type = media::VideoFrame::TYPE_SYSTEM_MEMORY;
info.stream_info.surface_width = kWidth;
info.stream_info.surface_height = kHeight;
handler->OnInitializeComplete(info);
}
ACTION_P(SendVideoFrameAllocated, handler) {
std::vector<media::VideoFrame::GlTexture> textures;
textures.push_back(kClientTexture);
GpuVideoDecoderMsg_VideoFrameAllocated msg(0, kFrameId, textures);
handler->OnMessageReceived(msg);
}
ACTION_P2(SendConsumeVideoFrame, handler, frame) {
media::PipelineStatistics statistics;
handler->ConsumeVideoFrame(frame, statistics);
}
class GpuVideoDecoderTest : public testing::Test,
public IPC::Message::Sender {
public:
GpuVideoDecoderTest() {
// Create the mock objects.
gles2_decoder_.reset(new gpu::gles2::MockGLES2Decoder());
gpu_video_decoder_ = new GpuVideoDecoder(
&message_loop_, kDecoderHostId, this, base::kNullProcessHandle,
gles2_decoder_.get());
// Create the mock objects.
mock_engine_ = new media::MockVideoDecodeEngine();
mock_device_ = new MockGpuVideoDevice();
// Inject the mock objects.
gpu_video_decoder_->SetVideoDecodeEngine(mock_engine_);
gpu_video_decoder_->SetGpuVideoDevice(mock_device_);
// VideoFrame for GpuVideoDevice.
media::VideoFrame::GlTexture textures[] = { kServiceTexture, 0, 0 };
media::VideoFrame::CreateFrameGlTexture(media::VideoFrame::RGBA,
kWidth, kHeight, textures,
&device_frame_);
}
virtual ~GpuVideoDecoderTest() {
gpu_video_decoder_->SetVideoDecodeEngine(NULL);
gpu_video_decoder_->SetGpuVideoDevice(NULL);
}
// 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(GpuVideoDecoderTest, *msg)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_InitializeACK,
OnInitializeDone)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_DestroyACK,
OnUninitializeDone)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_FlushACK,
OnFlushDone)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_EmptyThisBufferACK,
OnEmptyThisBufferACK)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_EmptyThisBufferDone,
OnEmptyThisBufferDone)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_AllocateVideoFrames,
OnAllocateVideoFrames)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_ReleaseAllVideoFrames,
OnReleaseAllVideoFrames)
IPC_MESSAGE_HANDLER(GpuVideoDecoderHostMsg_ConsumeVideoFrame,
OnConsumeVideoFrame)
IPC_MESSAGE_UNHANDLED_ERROR()
IPC_END_MESSAGE_MAP()
EXPECT_TRUE(handled);
delete msg;
return true;
}
// Mock methods for handling output IPC messages.
MOCK_METHOD1(OnInitializeDone,
void(const GpuVideoDecoderInitDoneParam& param));
MOCK_METHOD0(OnUninitializeDone, void());
MOCK_METHOD0(OnFlushDone, void());
MOCK_METHOD0(OnEmptyThisBufferDone, void());
MOCK_METHOD4(OnConsumeVideoFrame, void(int32 device_frame_id, int64 timestamp,
int64 duration, int32 flags));
MOCK_METHOD0(OnEmptyThisBufferACK, void());
MOCK_METHOD4(OnAllocateVideoFrames, void(int32 n, uint32 width,
uint32 height, int32 format));
MOCK_METHOD0(OnReleaseAllVideoFrames, void());
// Receive events from GpuVideoDecoder.
MOCK_METHOD0(VideoFramesAllocated, void());
void Initialize() {
// VideoDecodeEngine is called.
EXPECT_CALL(*mock_engine_, Initialize(_, _, _, _))
.WillOnce(InitializationDone(gpu_video_decoder_));
// Expect that initialization is completed.
EXPECT_CALL(*this, OnInitializeDone(_));
// Send an initialiaze message to GpuVideoDecoder.
GpuVideoDecoderInitParam param;
param.width = kWidth;
param.height = kHeight;
GpuVideoDecoderMsg_Initialize msg(0, param);
gpu_video_decoder_->OnMessageReceived(msg);
}
void AllocateVideoFrames() {
// Expect that IPC messages are sent. We'll reply with some GL textures.
EXPECT_CALL(*this, OnAllocateVideoFrames(
1, kWidth, kHeight, static_cast<int32>(media::VideoFrame::RGBA)))
.WillOnce(SendVideoFrameAllocated(gpu_video_decoder_));
// Expect that MakeCurrent() is called.
EXPECT_CALL(*gles2_decoder_.get(), MakeCurrent())
.WillOnce(Return(true))
.RetiresOnSaturation();
// Expect that translate method is called.
EXPECT_CALL(*gles2_decoder_.get(),
GetServiceTextureId(kClientTexture, NotNull()))
.WillOnce(DoAll(SetArgumentPointee<1>(kServiceTexture), Return(true)));
// And then GpuVideoDevice is called to create VideoFrame from GL textures.
EXPECT_CALL(*mock_device_,
CreateVideoFrameFromGlTextures(kWidth, kHeight,
media::VideoFrame::RGBA, _,
NotNull()))
.WillOnce(DoAll(SetArgumentPointee<4>(device_frame_), Return(true)));
// Finally the task is called.
EXPECT_CALL(*this, VideoFramesAllocated());
// Pretend calling GpuVideoDecoder for allocating frames.
gpu_video_decoder_->AllocateVideoFrames(
1, kWidth, kHeight, media::VideoFrame::RGBA, &decoder_frames_,
NewRunnableMethod(this, &GpuVideoDecoderTest::VideoFramesAllocated));
}
void ReleaseVideoFrames() {
// Expect that MakeCurrent() is called.
EXPECT_CALL(*gles2_decoder_.get(), MakeCurrent())
.WillOnce(Return(true))
.RetiresOnSaturation();
// Expect that video frame is released.
EXPECT_CALL(*mock_device_, ReleaseVideoFrame(device_frame_));
// Expect that IPC message is send to release video frame.
EXPECT_CALL(*this, OnReleaseAllVideoFrames());
// Call to GpuVideoDecoder to release all video frames.
gpu_video_decoder_->ReleaseAllVideoFrames();
}
void BufferExchange() {
// Expect that we call to produce video frame.
EXPECT_CALL(*mock_engine_, ProduceVideoFrame(device_frame_))
.WillOnce(SendConsumeVideoFrame(gpu_video_decoder_, device_frame_))
.RetiresOnSaturation();
// Expect that consume video frame is called.
EXPECT_CALL(*this, OnConsumeVideoFrame(kFrameId, 0, 0, 0))
.RetiresOnSaturation();
// Ask the GpuVideoDecoder to produce a video frame.
GpuVideoDecoderMsg_ProduceVideoFrame msg(0, kFrameId);
gpu_video_decoder_->OnMessageReceived(msg);
}
private:
scoped_refptr<GpuVideoDecoder> gpu_video_decoder_;
MockGpuVideoDevice* mock_device_;
media::MockVideoDecodeEngine* mock_engine_;
scoped_ptr<gpu::gles2::MockGLES2Decoder> gles2_decoder_;
std::vector<scoped_refptr<media::VideoFrame> > decoder_frames_;
scoped_refptr<media::VideoFrame> device_frame_;
MessageLoop message_loop_;
DISALLOW_COPY_AND_ASSIGN(GpuVideoDecoderTest);
};
TEST_F(GpuVideoDecoderTest, Initialize) {
Initialize();
}
TEST_F(GpuVideoDecoderTest, AllocateVideoFrames) {
Initialize();
AllocateVideoFrames();
}
TEST_F(GpuVideoDecoderTest, ReleaseVideoFrames) {
Initialize();
AllocateVideoFrames();
ReleaseVideoFrames();
}
TEST_F(GpuVideoDecoderTest, BufferExchange) {
Initialize();
AllocateVideoFrames();
BufferExchange();
BufferExchange();
ReleaseVideoFrames();
}
DISABLE_RUNNABLE_METHOD_REFCOUNT(GpuVideoDecoderTest);