OLD | NEW |
| (Empty) |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "base/message_loop.h" | |
6 #include "chrome/renderer/gpu_video_decoder_host.h" | |
7 #include "content/common/message_router.h" | |
8 #include "content/common/gpu_messages.h" | |
9 #include "media/base/pipeline.h" | |
10 #include "media/video/video_mock_objects.h" | |
11 #include "testing/gmock/include/gmock/gmock.h" | |
12 #include "testing/gtest/include/gtest/gtest.h" | |
13 | |
14 using testing::_; | |
15 using testing::DoAll; | |
16 using testing::NotNull; | |
17 using testing::Return; | |
18 using testing::SetArgumentPointee; | |
19 | |
20 static const int kContextRouteId = 50; | |
21 static const int kDecoderHostId = 51; | |
22 static const int kDecoderId = 51; | |
23 static const int kVideoFrames = 3; | |
24 static const int kWidth = 320; | |
25 static const int kHeight = 240; | |
26 static const int kFrameRateNumerator = 25; | |
27 static const int kFrameRateDenominator = 1; | |
28 static const int kTransportBufferSize = 1024; | |
29 | |
30 ACTION_P(SimulateAllocateVideoFrames, frames) { | |
31 // Fake some texture IDs here. | |
32 media::VideoFrame::GlTexture textures[] = {4, 5, 6}; | |
33 for (int i = 0; i < kVideoFrames; ++i) { | |
34 scoped_refptr<media::VideoFrame> frame; | |
35 media::VideoFrame::CreateFrameGlTexture(media::VideoFrame::YV12, | |
36 kWidth, kHeight, textures, | |
37 &frame); | |
38 frames->push_back(frame); | |
39 arg4->push_back(frame); | |
40 } | |
41 | |
42 // Execute the callback to complete the task. | |
43 arg5->Run(); | |
44 delete arg5; | |
45 } | |
46 | |
47 ACTION_P2(SendMessage, handler, msg) { | |
48 handler->OnMessageReceived(msg); | |
49 } | |
50 | |
51 class GpuVideoDecoderHostTest : public testing::Test, | |
52 public IPC::Message::Sender, | |
53 public media::VideoDecodeEngine::EventHandler { | |
54 public: | |
55 // This method is used to dispatch IPC messages to mock methods. | |
56 virtual bool Send(IPC::Message* msg) { | |
57 EXPECT_TRUE(msg); | |
58 if (!msg) | |
59 return false; | |
60 | |
61 bool handled = true; | |
62 IPC_BEGIN_MESSAGE_MAP(GpuVideoDecoderHostTest, *msg) | |
63 IPC_MESSAGE_HANDLER(GpuChannelMsg_CreateVideoDecoder, | |
64 OnCreateVideoDecoder) | |
65 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Initialize, | |
66 OnInitialize) | |
67 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Destroy, | |
68 OnDestroy) | |
69 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_Flush, | |
70 OnFlush) | |
71 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_EmptyThisBuffer, | |
72 OnEmptyThisBuffer) | |
73 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_VideoFrameAllocated, | |
74 OnVideoFrameAllocated) | |
75 IPC_MESSAGE_HANDLER(GpuVideoDecoderMsg_ProduceVideoFrame, | |
76 OnProduceVideoFrame) | |
77 IPC_MESSAGE_UNHANDLED_ERROR() | |
78 IPC_END_MESSAGE_MAP() | |
79 EXPECT_TRUE(handled); | |
80 delete msg; | |
81 return true; | |
82 } | |
83 | |
84 // Mock methods for outgoing messages. | |
85 MOCK_METHOD1(OnInitialize, void(GpuVideoDecoderInitParam param)); | |
86 MOCK_METHOD0(OnDestroy, void()); | |
87 MOCK_METHOD0(OnFlush, void()); | |
88 MOCK_METHOD1(OnEmptyThisBuffer, | |
89 void(GpuVideoDecoderInputBufferParam param)); | |
90 MOCK_METHOD1(OnProduceVideoFrame, void(int32 frame_id)); | |
91 MOCK_METHOD2(OnVideoFrameAllocated, | |
92 void(int32 frame_id, std::vector<uint32> textures)); | |
93 MOCK_METHOD2(OnCreateVideoDecoder, | |
94 void(int32 context_route_id, int32 decoder_host_id)); | |
95 | |
96 // Mock methods for VideoDecodeEngine::EventHandler. | |
97 MOCK_METHOD1(ProduceVideoSample, | |
98 void(scoped_refptr<media::Buffer> buffer)); | |
99 MOCK_METHOD2(ConsumeVideoFrame, | |
100 void(scoped_refptr<media::VideoFrame> frame, | |
101 const media::PipelineStatistics& statistics)); | |
102 MOCK_METHOD1(OnInitializeComplete, | |
103 void(const media::VideoCodecInfo& info)); | |
104 MOCK_METHOD0(OnUninitializeComplete, void()); | |
105 MOCK_METHOD0(OnFlushComplete, void()); | |
106 MOCK_METHOD0(OnSeekComplete, void()); | |
107 MOCK_METHOD0(OnError, void()); | |
108 MOCK_METHOD1(OnFormatChange, | |
109 void(media::VideoStreamInfo stream_info)); | |
110 | |
111 void Initialize() { | |
112 decoder_host_.reset( | |
113 new GpuVideoDecoderHost(&router_, this, kContextRouteId, | |
114 kDecoderHostId)); | |
115 shared_memory_.reset(new base::SharedMemory()); | |
116 shared_memory_->CreateAnonymous(kTransportBufferSize); | |
117 | |
118 GpuVideoDecoderHostMsg_CreateVideoDecoderDone msg1(kDecoderHostId, | |
119 kDecoderId); | |
120 EXPECT_CALL(*this, OnCreateVideoDecoder(kContextRouteId, kDecoderHostId)) | |
121 .WillOnce(SendMessage(decoder_host_.get(), msg1)); | |
122 | |
123 GpuVideoDecoderInitDoneParam param; | |
124 param.success = true; | |
125 param.input_buffer_size = kTransportBufferSize; | |
126 param.input_buffer_handle = shared_memory_->handle(); | |
127 | |
128 GpuVideoDecoderHostMsg_InitializeACK msg2(kDecoderHostId, param); | |
129 EXPECT_CALL(*this, OnInitialize(_)) | |
130 .WillOnce(SendMessage(decoder_host_.get(), msg2)); | |
131 EXPECT_CALL(*this, OnInitializeComplete(_)); | |
132 | |
133 media::VideoCodecConfig config( | |
134 media::kCodecH264, | |
135 kWidth, | |
136 kHeight, | |
137 kFrameRateNumerator, | |
138 kFrameRateDenominator, | |
139 NULL, | |
140 0); | |
141 decoder_host_->Initialize(&message_loop_, this, &context_, config); | |
142 message_loop_.RunAllPending(); | |
143 } | |
144 | |
145 void Uninitialize() { | |
146 // A message is sent to GPU process to destroy the decoder. | |
147 GpuVideoDecoderHostMsg_DestroyACK msg(kDecoderHostId); | |
148 EXPECT_CALL(*this, OnDestroy()) | |
149 .WillOnce(SendMessage(decoder_host_.get(), msg)); | |
150 EXPECT_CALL(context_, ReleaseAllVideoFrames()); | |
151 EXPECT_CALL(*this, OnUninitializeComplete()); | |
152 decoder_host_->Uninitialize(); | |
153 } | |
154 | |
155 void AllocateVideoFrames() { | |
156 // Expect context is called to allocate video frames. | |
157 EXPECT_CALL(context_, | |
158 AllocateVideoFrames(kVideoFrames, kWidth, kHeight, | |
159 media::VideoFrame::YV12, | |
160 NotNull(), NotNull())) | |
161 .WillOnce(SimulateAllocateVideoFrames(&frames_)) | |
162 .RetiresOnSaturation(); | |
163 | |
164 // Expect that we send the video frames to the GPU process. | |
165 EXPECT_CALL(*this, OnVideoFrameAllocated(_, _)) | |
166 .Times(kVideoFrames) | |
167 .RetiresOnSaturation(); | |
168 | |
169 // Pretend that a message is sent to GpuVideoDecoderHost to allocate | |
170 // video frames. | |
171 GpuVideoDecoderHostMsg_AllocateVideoFrames msg( | |
172 kDecoderHostId, kVideoFrames, kWidth, kHeight, | |
173 static_cast<int32>(media::VideoFrame::YV12)); | |
174 decoder_host_->OnMessageReceived(msg); | |
175 } | |
176 | |
177 void ReleaseVideoFrames() { | |
178 // Expect that context is called to release all video frames. | |
179 EXPECT_CALL(context_, ReleaseAllVideoFrames()) | |
180 .RetiresOnSaturation(); | |
181 | |
182 // Pretend a message is sent to release all video frames. | |
183 GpuVideoDecoderHostMsg_ReleaseAllVideoFrames msg(kDecoderHostId); | |
184 decoder_host_->OnMessageReceived(msg); | |
185 | |
186 // Clear the list of video frames allocated. | |
187 frames_.clear(); | |
188 } | |
189 | |
190 void ProduceVideoFrame(int first_frame_id) { | |
191 for (int i = 0; i < kVideoFrames; ++i) { | |
192 // Expect that a request is received to produce a video frame. | |
193 GpuVideoDecoderHostMsg_ConsumeVideoFrame msg( | |
194 kDecoderHostId, first_frame_id + i, 0, 0, 0); | |
195 EXPECT_CALL(*this, OnProduceVideoFrame(first_frame_id + i)) | |
196 .WillOnce(SendMessage(decoder_host_.get(), msg)) | |
197 .RetiresOnSaturation(); | |
198 | |
199 // Expect that a reply is made when a video frame is ready. | |
200 EXPECT_CALL(*this, ConsumeVideoFrame(frames_[i], _)) | |
201 .RetiresOnSaturation(); | |
202 | |
203 // Use the allocated video frames to make a request. | |
204 decoder_host_->ProduceVideoFrame(frames_[i]); | |
205 } | |
206 } | |
207 | |
208 private: | |
209 MessageLoop message_loop_; | |
210 MessageRouter router_; | |
211 media::MockVideoDecodeContext context_; | |
212 | |
213 scoped_ptr<GpuVideoDecoderHost> decoder_host_; | |
214 scoped_ptr<base::SharedMemory> shared_memory_; | |
215 | |
216 // Keeps the video frames allocated. | |
217 std::vector<scoped_refptr<media::VideoFrame> > frames_; | |
218 }; | |
219 | |
220 // Test that when we initialize GpuVideoDecoderHost the corresponding | |
221 // IPC messages are sent and at the end OnInitializeComplete() is | |
222 // called with the right parameters. | |
223 TEST_F(GpuVideoDecoderHostTest, Initialize) { | |
224 Initialize(); | |
225 } | |
226 | |
227 // Test that the sequence of method calls and IPC messages is correct. | |
228 // And at the end OnUninitializeComplete() is called. | |
229 TEST_F(GpuVideoDecoderHostTest, Uninitialize) { | |
230 Initialize(); | |
231 Uninitialize(); | |
232 } | |
233 | |
234 // Test that IPC messages are sent to GpuVideoDecoderHost and it | |
235 // calls VideoDecodeContext to allocate textures and send these | |
236 // textures back to the GPU process by IPC messages. | |
237 TEST_F(GpuVideoDecoderHostTest, AllocateVideoFrames) { | |
238 Initialize(); | |
239 AllocateVideoFrames(); | |
240 Uninitialize(); | |
241 } | |
242 | |
243 // Test that IPC messages are sent to GpuVideoDecoderHost to | |
244 // release textures and VideoDecodeContext is called correctly. | |
245 TEST_F(GpuVideoDecoderHostTest, ReleaseVideoFrames) { | |
246 Initialize(); | |
247 AllocateVideoFrames(); | |
248 ReleaseVideoFrames(); | |
249 AllocateVideoFrames(); | |
250 ReleaseVideoFrames(); | |
251 Uninitialize(); | |
252 } | |
253 | |
254 // Test the sequence of IPC messages and methods calls for a decode | |
255 // routine. This tests the output port only. | |
256 TEST_F(GpuVideoDecoderHostTest, ProduceVideoFrame) { | |
257 Initialize(); | |
258 AllocateVideoFrames(); | |
259 ProduceVideoFrame(0); | |
260 ReleaseVideoFrames(); | |
261 AllocateVideoFrames(); | |
262 ProduceVideoFrame(kVideoFrames); | |
263 ReleaseVideoFrames(); | |
264 Uninitialize(); | |
265 } | |
OLD | NEW |