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 #define _CRT_SECURE_NO_WARNINGS | |
6 | |
7 #if 0 | |
8 #include <deque> | |
9 | |
10 #include "base/callback.h" | |
11 #include "base/message_loop.h" | |
12 #include "base/task.h" | |
13 #include "media/base/buffers.h" | |
14 #include "media/base/mock_filters.h" | |
15 #include "media/base/mock_task.h" | |
16 #include "media/ffmpeg/ffmpeg_common.h" | |
17 #include "media/video/omx_video_decode_engine.h" | |
18 #include "media/video/video_decode_engine.h" | |
19 #include "media/omx/mock_omx.h" | |
20 #include "testing/gtest/include/gtest/gtest.h" | |
21 | |
22 using ::testing::_; | |
23 using ::testing::DoAll; | |
24 using ::testing::InSequence; | |
25 using ::testing::IsNull; | |
26 using ::testing::NotNull; | |
27 using ::testing::Return; | |
28 using ::testing::SaveArg; | |
29 using ::testing::SetArgumentPointee; | |
30 using ::testing::StrEq; | |
31 using ::testing::StrictMock; | |
32 | |
33 namespace media { | |
34 | |
35 static const int kBufferCount = 3; | |
36 static const int kBufferSize = 4096; | |
37 static const char* kComponentName = "OMX.google.video_decoder.avc"; | |
38 | |
39 ACTION(ReturnComponentName) { | |
40 strcpy(((char**)arg2)[0], kComponentName); | |
41 } | |
42 | |
43 ACTION(GetHandle) { | |
44 *arg0 = MockOmx::get()->component(); | |
45 MockOmx::get()->component()->pApplicationPrivate = arg2; | |
46 memcpy(MockOmx::get()->callbacks(), arg3, sizeof(OMX_CALLBACKTYPE)); | |
47 } | |
48 | |
49 ACTION(GetParameterVideoInit) { | |
50 ((OMX_PORT_PARAM_TYPE*)arg1)->nStartPortNumber = 0; | |
51 } | |
52 | |
53 ACTION(GetParameterPortDefinition) { | |
54 OMX_PARAM_PORTDEFINITIONTYPE* port_format = | |
55 (OMX_PARAM_PORTDEFINITIONTYPE*)arg1; | |
56 CHECK(port_format->nPortIndex == 0 || port_format->nPortIndex == 1); | |
57 if (port_format->nPortIndex == 0) | |
58 port_format->eDir = OMX_DirInput; | |
59 else | |
60 port_format->eDir = OMX_DirOutput; | |
61 port_format->nBufferCountMin = kBufferCount; | |
62 port_format->nBufferCountActual = kBufferCount; | |
63 port_format->nBufferSize = kBufferSize; | |
64 } | |
65 | |
66 ACTION(AllocateBuffer) { | |
67 *arg0 = new OMX_BUFFERHEADERTYPE(); | |
68 memset(*arg0, 0, sizeof(OMX_BUFFERHEADERTYPE)); | |
69 (*arg0)->nAllocLen = arg3; | |
70 (*arg0)->pBuffer = new uint8[arg3]; | |
71 (*arg0)->nOutputPortIndex = 1; | |
72 (*arg0)->nInputPortIndex = OMX_ALL; | |
73 } | |
74 | |
75 ACTION(UseBuffer) { | |
76 *arg0 = new OMX_BUFFERHEADERTYPE(); | |
77 memset(*arg0, 0, sizeof(OMX_BUFFERHEADERTYPE)); | |
78 (*arg0)->nOutputPortIndex = OMX_ALL; | |
79 (*arg0)->nInputPortIndex = 0; | |
80 } | |
81 | |
82 ACTION(FreeBuffer) { | |
83 if (1 == arg1->nOutputPortIndex) | |
84 delete [] arg1->pBuffer; | |
85 delete arg1; | |
86 } | |
87 | |
88 ACTION_P3(SendEvent, event, data1, data2) { | |
89 (*MockOmx::get()->callbacks()->EventHandler)( | |
90 MockOmx::get()->component(), | |
91 MockOmx::get()->component()->pApplicationPrivate, | |
92 event, static_cast<OMX_U32>(data1), static_cast<OMX_U32>(data2), NULL); | |
93 } | |
94 | |
95 ACTION_P(EmptyBufferDone, output_pool_ptr) { | |
96 (*MockOmx::get()->callbacks()->EmptyBufferDone)( | |
97 MockOmx::get()->component(), | |
98 MockOmx::get()->component()->pApplicationPrivate, | |
99 arg0); | |
100 OMX_BUFFERHEADERTYPE* out_buffer = output_pool_ptr->front(); | |
101 output_pool_ptr->pop_front(); | |
102 if (arg0->nFlags & OMX_BUFFERFLAG_EOS) | |
103 out_buffer->nFlags |= OMX_BUFFERFLAG_EOS; | |
104 out_buffer->nFilledLen = kBufferSize; | |
105 (*MockOmx::get()->callbacks()->FillBufferDone)( | |
106 MockOmx::get()->component(), | |
107 MockOmx::get()->component()->pApplicationPrivate, | |
108 out_buffer); | |
109 } | |
110 | |
111 ACTION_P(EnqueueOutputBuffer, output_pool_ptr) { | |
112 output_pool_ptr->push_back(arg0); | |
113 } | |
114 | |
115 ACTION(FillEosBuffer) { | |
116 arg0->nFlags = OMX_BUFFERFLAG_EOS; | |
117 arg0->nFilledLen = 0; | |
118 (*MockOmx::get()->callbacks()->FillBufferDone)( | |
119 MockOmx::get()->component(), | |
120 MockOmx::get()->component()->pApplicationPrivate, | |
121 arg0); | |
122 } | |
123 | |
124 class TestBuffer : public media::Buffer { | |
125 public: | |
126 TestBuffer() : size_(0), data_(NULL) { } | |
127 explicit TestBuffer(int size) : size_(size) { | |
128 if (size) | |
129 data_.reset(new uint8[size]); | |
130 else | |
131 data_.reset(NULL); | |
132 } | |
133 virtual const uint8* GetData() const { | |
134 return data_.get(); | |
135 } | |
136 virtual size_t GetDataSize() const { | |
137 return size_; | |
138 } | |
139 private: | |
140 virtual ~TestBuffer() { } | |
141 | |
142 int size_; | |
143 scoped_array<uint8> data_; | |
144 DISALLOW_COPY_AND_ASSIGN(TestBuffer); | |
145 }; | |
146 | |
147 class OmxCodecTest : public testing::Test { | |
148 public: | |
149 OmxCodecTest () | |
150 : input_buffer_count_(0), | |
151 got_eos_(false), | |
152 omx_engine_(new OmxVideoDecodeEngine()) { | |
153 av_stream_.codec = &av_codec_context_; | |
154 av_codec_context_.width = 16; | |
155 av_codec_context_.height = 16; | |
156 feed_done_cb_ = | |
157 NewCallback(this, &OmxCodecTest::EmptyBufferDoneCallback); | |
158 decode_done_cb_ = | |
159 NewCallback(this, &OmxCodecTest::FillBufferDoneCallback); | |
160 } | |
161 | |
162 ~OmxCodecTest() { | |
163 } | |
164 | |
165 protected: | |
166 void ExpectSettings() { | |
167 // Return the component name. | |
168 EXPECT_CALL(*MockOmx::get(), GetComponentsOfRole(_, _, IsNull())) | |
169 .WillOnce(DoAll(SetArgumentPointee<1>(1), | |
170 Return(OMX_ErrorNone))); | |
171 EXPECT_CALL(*MockOmx::get(), GetComponentsOfRole(_, _, NotNull())) | |
172 .WillOnce(DoAll(SetArgumentPointee<1>(1), | |
173 ReturnComponentName(), | |
174 Return(OMX_ErrorNone))); | |
175 | |
176 // Handle get parameter calls. | |
177 EXPECT_CALL(*MockOmx::get(), | |
178 GetParameter(OMX_IndexParamVideoInit, NotNull())) | |
179 .WillRepeatedly(DoAll(GetParameterVideoInit(), Return(OMX_ErrorNone))); | |
180 EXPECT_CALL(*MockOmx::get(), | |
181 GetParameter(OMX_IndexParamPortDefinition, NotNull())) | |
182 .WillRepeatedly(DoAll(GetParameterPortDefinition(), | |
183 Return(OMX_ErrorNone))); | |
184 | |
185 // Ignore all set parameter calls. | |
186 EXPECT_CALL(*MockOmx::get(), SetParameter(_, _)) | |
187 .WillRepeatedly(Return(OMX_ErrorNone)); | |
188 } | |
189 | |
190 void ExpectToLoaded() { | |
191 InSequence s; | |
192 | |
193 // Expect initialization. | |
194 EXPECT_CALL(*MockOmx::get(), Init()) | |
195 .WillOnce(Return(OMX_ErrorNone)); | |
196 | |
197 // Return the handle. | |
198 EXPECT_CALL(*MockOmx::get(), | |
199 GetHandle(NotNull(), StrEq(kComponentName), | |
200 NotNull(), NotNull())) | |
201 .WillOnce(DoAll(GetHandle(), | |
202 Return(OMX_ErrorNone))); | |
203 } | |
204 | |
205 void ExpectLoadedToIdle() { | |
206 InSequence s; | |
207 | |
208 // Expect transition to idle. | |
209 EXPECT_CALL(*MockOmx::get(), | |
210 SendCommand(OMX_CommandStateSet, OMX_StateIdle, _)) | |
211 .WillOnce( | |
212 DoAll( | |
213 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet, | |
214 OMX_StateIdle), | |
215 Return(OMX_ErrorNone))); | |
216 | |
217 // Expect allocation of buffers. | |
218 EXPECT_CALL(*MockOmx::get(), | |
219 UseBuffer(NotNull(), 0, NotNull(), kBufferSize, _)) | |
220 .Times(kBufferCount) | |
221 .WillRepeatedly(DoAll(UseBuffer(), Return(OMX_ErrorNone))); | |
222 | |
223 // Expect allocation of output buffers and send command complete. | |
224 EXPECT_CALL(*MockOmx::get(), | |
225 AllocateBuffer(NotNull(), 1, IsNull(), kBufferSize)) | |
226 .Times(kBufferCount) | |
227 .WillRepeatedly(DoAll(AllocateBuffer(), Return(OMX_ErrorNone))); | |
228 } | |
229 | |
230 void ExpectToExecuting() { | |
231 InSequence s; | |
232 | |
233 // Expect transition to executing. | |
234 EXPECT_CALL(*MockOmx::get(), | |
235 SendCommand(OMX_CommandStateSet, OMX_StateExecuting, _)) | |
236 .WillOnce(DoAll( | |
237 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet, | |
238 OMX_StateExecuting), | |
239 Return(OMX_ErrorNone))); | |
240 | |
241 // Expect initial FillThisBuffer() calls. | |
242 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) | |
243 .Times(kBufferCount) | |
244 .WillRepeatedly(DoAll(EnqueueOutputBuffer(&output_pool_), | |
245 Return(OMX_ErrorNone))); | |
246 } | |
247 | |
248 void ExpectToIdle() { | |
249 // Expect going to idle | |
250 EXPECT_CALL(*MockOmx::get(), | |
251 SendCommand(OMX_CommandStateSet, OMX_StateIdle, _)) | |
252 .WillOnce(DoAll( | |
253 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet, OMX_StateIdle), | |
254 Return(OMX_ErrorNone))); | |
255 } | |
256 | |
257 void ExpectIdleToLoaded() { | |
258 InSequence s; | |
259 | |
260 // Expect transition to loaded. | |
261 EXPECT_CALL(*MockOmx::get(), | |
262 SendCommand(OMX_CommandStateSet, OMX_StateLoaded, _)) | |
263 .WillOnce(DoAll( | |
264 SendEvent(OMX_EventCmdComplete, OMX_CommandStateSet, | |
265 OMX_StateLoaded), | |
266 Return(OMX_ErrorNone))); | |
267 | |
268 // Expect free buffer for input port. | |
269 EXPECT_CALL(*MockOmx::get(), FreeBuffer(0, NotNull())) | |
270 .Times(kBufferCount) | |
271 .WillRepeatedly(DoAll(FreeBuffer(), Return(OMX_ErrorNone))); | |
272 | |
273 EXPECT_CALL(*MockOmx::get(), FreeBuffer(1, NotNull())) | |
274 .Times(kBufferCount) | |
275 .WillRepeatedly(DoAll(FreeBuffer(), Return(OMX_ErrorNone))); | |
276 } | |
277 | |
278 void ExpectToEmpty() { | |
279 InSequence s; | |
280 | |
281 EXPECT_CALL(*MockOmx::get(), FreeHandle(MockOmx::get()->component())) | |
282 .WillOnce(Return(OMX_ErrorNone)); | |
283 EXPECT_CALL(*MockOmx::get(), Deinit()) | |
284 .WillOnce(Return(OMX_ErrorNone)); | |
285 } | |
286 | |
287 // TODO(hclam): Make a more generic about when to stop. | |
288 void ExpectStart() { | |
289 ExpectToLoaded(); | |
290 ExpectLoadedToIdle(); | |
291 ExpectToExecuting(); | |
292 EXPECT_CALL(init_done_cb_task_, Run()); | |
293 } | |
294 | |
295 void ExpectStop() { | |
296 EXPECT_CALL(stop_task_, Run()); | |
297 ExpectToIdle(); | |
298 ExpectIdleToLoaded(); | |
299 ExpectToEmpty(); | |
300 } | |
301 | |
302 void EmptyBufferDoneCallback(scoped_refptr<Buffer> buffer) { | |
303 if (buffer.get()) { | |
304 input_units_.push_back(buffer); | |
305 } else { | |
306 input_buffer_count_++; | |
307 scoped_refptr<Buffer> buffer_ref = new TestBuffer(input_buffer_count_); | |
308 input_units_.push_back(buffer_ref); | |
309 } | |
310 } | |
311 | |
312 void FillBufferDoneCallback(scoped_refptr<VideoFrame> frame) { | |
313 output_units_.push_back(frame); | |
314 if (frame->IsEndOfStream()) | |
315 got_eos_ = true; | |
316 } | |
317 | |
318 void MakeEmptyBufferRequest() { | |
319 scoped_refptr<Buffer> buffer = input_units_.front(); | |
320 input_units_.pop_front(); | |
321 omx_engine_->EmptyThisBuffer(buffer); | |
322 } | |
323 | |
324 void SendEOSInputBuffer() { | |
325 input_units_.pop_front(); | |
326 scoped_refptr<Buffer> buffer_ref = new TestBuffer(); | |
327 input_units_.push_front(buffer_ref); | |
328 EXPECT_CALL(*MockOmx::get(), EmptyThisBuffer(NotNull())) | |
329 .WillOnce(DoAll(EmptyBufferDone(&output_pool_), Return(OMX_ErrorNone))) | |
330 .RetiresOnSaturation(); | |
331 MakeEmptyBufferRequest(); | |
332 message_loop_.RunAllPending(); | |
333 } | |
334 | |
335 int input_buffer_count_; | |
336 | |
337 std::deque<scoped_refptr<Buffer> > input_units_; | |
338 std::deque<scoped_refptr<VideoFrame> > output_units_; | |
339 std::deque<OMX_BUFFERHEADERTYPE*> fill_this_buffer_received_; | |
340 std::deque<OMX_BUFFERHEADERTYPE*> output_pool_; | |
341 | |
342 MockOmx mock_omx_; | |
343 | |
344 bool got_eos_; | |
345 MessageLoop message_loop_; | |
346 scoped_refptr<OmxVideoDecodeEngine> omx_engine_; | |
347 | |
348 AVStream av_stream_; | |
349 AVCodecContext av_codec_context_; | |
350 | |
351 VideoDecodeEngine::ProduceVideoSampleCallback* feed_done_cb_; | |
352 VideoDecodeEngine::ConsumeVideoFrameCallback* decode_done_cb_; | |
353 TaskMocker init_done_cb_task_; | |
354 | |
355 TaskMocker stop_task_; | |
356 | |
357 private: | |
358 DISALLOW_COPY_AND_ASSIGN(OmxCodecTest); | |
359 }; | |
360 | |
361 TEST_F(OmxCodecTest, SimpleStartAndStop) { | |
362 ExpectSettings(); | |
363 ExpectStart(); | |
364 omx_engine_->Initialize(&message_loop_, | |
365 &av_stream_, | |
366 feed_done_cb_, | |
367 decode_done_cb_, | |
368 init_done_cb_task_.CreateTask()); | |
369 message_loop_.RunAllPending(); | |
370 | |
371 EXPECT_EQ(kBufferCount, input_buffer_count_); | |
372 EXPECT_EQ(VideoDecodeEngine::kNormal, omx_engine_->state()); | |
373 | |
374 ExpectStop(); | |
375 omx_engine_->Stop(stop_task_.CreateTask()); | |
376 message_loop_.RunAllPending(); | |
377 } | |
378 | |
379 TEST_F(OmxCodecTest, NormalFlow) { | |
380 ExpectSettings(); | |
381 ExpectStart(); | |
382 omx_engine_->Initialize(&message_loop_, | |
383 &av_stream_, | |
384 feed_done_cb_, | |
385 decode_done_cb_, | |
386 init_done_cb_task_.CreateTask()); | |
387 message_loop_.RunAllPending(); | |
388 | |
389 EXPECT_EQ(kBufferCount, input_buffer_count_); | |
390 EXPECT_EQ(VideoDecodeEngine::kNormal, omx_engine_->state()); | |
391 | |
392 // Make emptybuffer requests. | |
393 EXPECT_EQ(0u, output_units_.size()); | |
394 int count = output_pool_.size(); | |
395 for (int i = 0; i < kBufferCount; ++i) { | |
396 // Give input buffers to OmxVideoDecodeEngine. OmxVideoDecodeEngine will | |
397 // make a new FillThisBuffer() call for each read. | |
398 EXPECT_CALL(*MockOmx::get(), EmptyThisBuffer(NotNull())) | |
399 .WillOnce(DoAll(EmptyBufferDone(&output_pool_), Return(OMX_ErrorNone))) | |
400 .RetiresOnSaturation(); | |
401 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) | |
402 .WillOnce(DoAll(EnqueueOutputBuffer(&output_pool_), | |
403 Return(OMX_ErrorNone))) | |
404 .RetiresOnSaturation(); | |
405 MakeEmptyBufferRequest(); | |
406 } | |
407 message_loop_.RunAllPending(); | |
408 EXPECT_EQ(kBufferCount, static_cast<int>(input_units_.size())); | |
409 EXPECT_EQ(kBufferCount, static_cast<int>(output_units_.size())); | |
410 EXPECT_EQ(count, static_cast<int>(output_pool_.size())); | |
411 output_units_.clear(); | |
412 | |
413 // Send EndOfStream, expect eos flag. | |
414 SendEOSInputBuffer(); | |
415 EXPECT_EQ(kBufferCount - 1, static_cast<int>(input_units_.size())); | |
416 EXPECT_EQ(1, static_cast<int>(output_units_.size())); | |
417 EXPECT_EQ(count - 1, static_cast<int>(output_pool_.size())); | |
418 EXPECT_TRUE(got_eos_); | |
419 | |
420 // Shutdown. | |
421 ExpectStop(); | |
422 omx_engine_->Stop(stop_task_.CreateTask()); | |
423 message_loop_.RunAllPending(); | |
424 } | |
425 | |
426 TEST_F(OmxCodecTest, RecycleInputBuffers) { | |
427 ExpectSettings(); | |
428 ExpectStart(); | |
429 omx_engine_->Initialize(&message_loop_, | |
430 &av_stream_, | |
431 feed_done_cb_, | |
432 decode_done_cb_, | |
433 init_done_cb_task_.CreateTask()); | |
434 message_loop_.RunAllPending(); | |
435 | |
436 EXPECT_EQ(kBufferCount, input_buffer_count_); | |
437 EXPECT_EQ(VideoDecodeEngine::kNormal, omx_engine_->state()); | |
438 | |
439 // Make emptybuffer requests, also recycle input buffers | |
440 EXPECT_EQ(0u, output_units_.size()); | |
441 int count = output_pool_.size(); | |
442 int repeat_count = kBufferCount * 2; | |
443 for (int i = 0; i < repeat_count; ++i) { | |
444 // Give input buffers to OmxVideoDecodeEngine. OmxVideoDecodeEngine will | |
445 // make a new FillThisBuffer() call for each read. | |
446 EXPECT_CALL(*MockOmx::get(), EmptyThisBuffer(NotNull())) | |
447 .WillOnce(DoAll(EmptyBufferDone(&output_pool_), Return(OMX_ErrorNone))) | |
448 .RetiresOnSaturation(); | |
449 EXPECT_CALL(*MockOmx::get(), FillThisBuffer(NotNull())) | |
450 .WillOnce(DoAll(EnqueueOutputBuffer(&output_pool_), | |
451 Return(OMX_ErrorNone))) | |
452 .RetiresOnSaturation(); | |
453 MakeEmptyBufferRequest(); | |
454 message_loop_.RunAllPending(); | |
455 CHECK(kBufferCount == static_cast<int>(input_units_.size())); | |
456 CHECK(((i % kBufferCount) + 1) == | |
457 static_cast<int>(input_units_.back()->GetDataSize())); | |
458 } | |
459 message_loop_.RunAllPending(); | |
460 EXPECT_EQ(kBufferCount, static_cast<int>(input_units_.size())); | |
461 EXPECT_EQ(repeat_count, static_cast<int>(output_units_.size())); | |
462 EXPECT_EQ(count, static_cast<int>(output_pool_.size())); | |
463 output_units_.clear(); | |
464 | |
465 // Send EndOfStream, expect eos flag. | |
466 SendEOSInputBuffer(); | |
467 EXPECT_EQ(kBufferCount - 1, static_cast<int>(input_units_.size())); | |
468 EXPECT_EQ(1, static_cast<int>(output_units_.size())); | |
469 EXPECT_EQ(count - 1, static_cast<int>(output_pool_.size())); | |
470 EXPECT_TRUE(got_eos_); | |
471 | |
472 // Shutdown. | |
473 ExpectStop(); | |
474 omx_engine_->Stop(stop_task_.CreateTask()); | |
475 message_loop_.RunAllPending(); | |
476 } | |
477 | |
478 // TODO(hclam): Add test case for dynamic port config. | |
479 // TODO(hclam): Create a more complicated test case so that read | |
480 // requests and reply from FillThisBuffer() arrives out of order. | |
481 | |
482 } // namespace media | |
483 #endif | |
OLD | NEW |