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/command_line.h" | |
6 #include "base/logging.h" | |
7 #include "base/synchronization/waitable_event.h" | |
8 #include "testing/gtest/include/gtest/gtest.h" | |
9 #include "third_party/openmax/il/OMX_Component.h" | |
10 #include "third_party/openmax/il/OMX_Core.h" | |
11 | |
12 namespace media { | |
13 | |
14 // Defines the maximum number of buffers created for I/O ports. | |
15 static const int kMaxBufferNum = 256; | |
16 | |
17 template <typename T> | |
18 static void ResetHeader(T* param) { | |
19 memset(param, 0, sizeof(T)); | |
20 // TODO(hclam): Make this version number configurable. | |
21 param->nVersion.nVersion = 0x00000101; | |
22 param->nSize = sizeof(T); | |
23 } | |
24 | |
25 class OmxTest : public testing::Test { | |
26 public: | |
27 OmxTest() | |
28 : handle_(NULL), | |
29 event_(false, false), | |
30 empty_buffer_(false, false), | |
31 fill_buffer_(false, false), | |
32 last_event_type_(OMX_EventMax), | |
33 last_event_data1_(0), | |
34 last_event_data2_(0) { | |
35 memset(input_buffers_, 0, sizeof(input_buffers_)); | |
36 memset(output_buffers_, 0, sizeof(output_buffers_)); | |
37 } | |
38 | |
39 protected: | |
40 virtual void SetUp() { | |
41 // Initialize OpenMAX. | |
42 EXPECT_EQ(OMX_ErrorNone, OMX_Init()); | |
43 } | |
44 | |
45 virtual void TearDown() { | |
46 EXPECT_EQ(OMX_ErrorNone, OMX_Deinit()); | |
47 } | |
48 | |
49 void InitComponent(std::string component_name) { | |
50 // TODO(hclam): Remove static when bug in driver is fixed. | |
51 static OMX_CALLBACKTYPE callback = { &EventHandler, | |
52 &EmptyBufferCallback, | |
53 &FillBufferCallback }; | |
54 | |
55 OMX_ERRORTYPE omxresult = OMX_GetHandle( | |
56 (void**)&handle_, | |
57 const_cast<OMX_STRING>(component_name.c_str()), | |
58 this, &callback); | |
59 EXPECT_EQ(OMX_ErrorNone, omxresult); | |
60 CHECK(handle_); | |
61 } | |
62 | |
63 void DeinitComponent() { | |
64 if (handle_) | |
65 OMX_FreeHandle(handle_); | |
66 } | |
67 | |
68 void AllocateBuffers(int port) { | |
69 int count = 0; | |
70 int size = 0; | |
71 OMX_BUFFERHEADERTYPE** buffers = NULL; | |
72 if (port == input_port_) { | |
73 count = input_buffer_count_; | |
74 size = input_buffer_size_; | |
75 buffers = input_buffers_; | |
76 } else if (port == output_port_) { | |
77 count = output_buffer_count_; | |
78 size = output_buffer_size_; | |
79 buffers = output_buffers_; | |
80 } else { | |
81 NOTREACHED() << "Not a valid port"; | |
82 } | |
83 for (int i = 0; i < count; ++i) { | |
84 EXPECT_EQ(OMX_ErrorNone, | |
85 OMX_AllocateBuffer(handle_, buffers + i, | |
86 port, NULL, size)); | |
87 } | |
88 } | |
89 | |
90 void ReleaseBuffers(int port) { | |
91 int count = 0; | |
92 OMX_BUFFERHEADERTYPE** buffers = NULL; | |
93 if (port == input_port_) { | |
94 count = input_buffer_count_; | |
95 buffers = input_buffers_; | |
96 } else if (port == output_port_) { | |
97 count = output_buffer_count_; | |
98 buffers = output_buffers_; | |
99 } else { | |
100 NOTREACHED() << "Not a valid port"; | |
101 } | |
102 for (int i = 0; i < count; ++i) { | |
103 CHECK(buffers[i]); | |
104 EXPECT_EQ(OMX_ErrorNone, | |
105 OMX_FreeBuffer(handle_, port, buffers[i])); | |
106 buffers[i] = NULL; | |
107 } | |
108 } | |
109 | |
110 void TransitionLoadedToIdle() { | |
111 EXPECT_EQ(OMX_ErrorNone, | |
112 OMX_SendCommand(handle_, OMX_CommandStateSet, | |
113 OMX_StateIdle, 0)); | |
114 AllocateBuffers(input_port_); | |
115 AllocateBuffers(output_port_); | |
116 event_.Wait(); | |
117 EXPECT_EQ(OMX_EventCmdComplete, last_event_type_); | |
118 EXPECT_EQ(OMX_CommandStateSet, last_event_data1_); | |
119 EXPECT_EQ(OMX_StateIdle, last_event_data2_); | |
120 } | |
121 | |
122 void TransitionIdleToLoaded() { | |
123 EXPECT_EQ(OMX_ErrorNone, | |
124 OMX_SendCommand(handle_, OMX_CommandStateSet, | |
125 OMX_StateLoaded, 0)); | |
126 ReleaseBuffers(input_port_); | |
127 ReleaseBuffers(output_port_); | |
128 event_.Wait(); | |
129 EXPECT_EQ(OMX_EventCmdComplete, last_event_type_); | |
130 EXPECT_EQ(OMX_CommandStateSet, last_event_data1_); | |
131 EXPECT_EQ(OMX_StateLoaded, last_event_data2_); | |
132 } | |
133 | |
134 void TransitionIdleToExecuting() { | |
135 EXPECT_EQ(OMX_ErrorNone, | |
136 OMX_SendCommand(handle_, OMX_CommandStateSet, | |
137 OMX_StateExecuting, 0)); | |
138 event_.Wait(); | |
139 EXPECT_EQ(OMX_EventCmdComplete, last_event_type_); | |
140 EXPECT_EQ(OMX_CommandStateSet, last_event_data1_); | |
141 EXPECT_EQ(OMX_StateExecuting, last_event_data2_); | |
142 } | |
143 | |
144 void TransitionExecutingToIdle() { | |
145 EXPECT_EQ(OMX_ErrorNone, | |
146 OMX_SendCommand(handle_, OMX_CommandStateSet, | |
147 OMX_StateIdle, 0)); | |
148 event_.Wait(); | |
149 EXPECT_EQ(OMX_EventCmdComplete, last_event_type_); | |
150 EXPECT_EQ(OMX_CommandStateSet, last_event_data1_); | |
151 EXPECT_EQ(OMX_StateIdle, last_event_data2_); | |
152 } | |
153 | |
154 void GetComponentsOfRole(std::string role) { | |
155 OMX_U32 roles = 0; | |
156 OMX_U8** component_names = NULL; | |
157 const int kSize = 256; | |
158 | |
159 LOG(INFO) << "GetComponentsOfRole: " << role; | |
160 EXPECT_EQ(OMX_ErrorNone, OMX_GetComponentsOfRole( | |
161 const_cast<OMX_STRING>(role.c_str()), &roles, 0)); | |
162 | |
163 // TODO(hclam): Should assert the component number. | |
164 LOG(INFO) << "Components: " << roles; | |
165 | |
166 if (roles) { | |
167 component_names = new OMX_U8*[roles]; | |
168 for (size_t i = 0; i < roles; ++i) | |
169 component_names[i] = new OMX_U8[kSize]; | |
170 | |
171 OMX_U32 roles_backup = roles; | |
172 EXPECT_EQ(OMX_ErrorNone, | |
173 OMX_GetComponentsOfRole( | |
174 const_cast<OMX_STRING>(role.c_str()), | |
175 &roles, component_names)); | |
176 ASSERT_EQ(roles_backup, roles); | |
177 | |
178 for (size_t i = 0; i < roles; ++i) { | |
179 LOG(INFO) << "Component name: " << component_names[i]; | |
180 delete [] component_names[i]; | |
181 } | |
182 delete [] component_names; | |
183 } | |
184 } | |
185 | |
186 OMX_ERRORTYPE EventHandlerInternal( | |
187 OMX_HANDLETYPE component, OMX_EVENTTYPE event, | |
188 OMX_U32 data1, OMX_U32 data2, OMX_PTR event_data) { | |
189 last_event_type_ = event; | |
190 last_event_data1_ = static_cast<int>(data1); | |
191 last_event_data2_ = static_cast<int>(data2); | |
192 // TODO(hclam): Save |event_data|. | |
193 event_.Signal(); | |
194 return OMX_ErrorNone; | |
195 } | |
196 | |
197 OMX_ERRORTYPE EmptyBufferCallbackInternal( | |
198 OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE* buffer) { | |
199 // TODO(hclam): Add code here. | |
200 empty_buffer_.Signal(); | |
201 return OMX_ErrorNone; | |
202 } | |
203 | |
204 OMX_ERRORTYPE FillBufferCallbackInternal( | |
205 OMX_HANDLETYPE component, OMX_BUFFERHEADERTYPE* buffer) { | |
206 // TODO(hclam): Add code here. | |
207 fill_buffer_.Signal(); | |
208 return OMX_ErrorNone; | |
209 } | |
210 | |
211 // Static callback methods. | |
212 static OMX_ERRORTYPE EventHandler( | |
213 OMX_HANDLETYPE component, OMX_PTR priv_data, | |
214 OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2, | |
215 OMX_PTR event_data) { | |
216 return static_cast<OmxTest*>(priv_data) | |
217 ->EventHandlerInternal(component, | |
218 event, data1, data2, event_data); | |
219 } | |
220 | |
221 static OMX_ERRORTYPE EmptyBufferCallback( | |
222 OMX_HANDLETYPE component, OMX_PTR priv_data, | |
223 OMX_BUFFERHEADERTYPE* buffer) { | |
224 return static_cast<OmxTest*>(priv_data) | |
225 ->EmptyBufferCallbackInternal(component, buffer); | |
226 } | |
227 | |
228 static OMX_ERRORTYPE FillBufferCallback( | |
229 OMX_HANDLETYPE component, OMX_PTR priv_data, | |
230 OMX_BUFFERHEADERTYPE* buffer) { | |
231 return static_cast<OmxTest*>(priv_data) | |
232 ->FillBufferCallbackInternal(component, buffer); | |
233 } | |
234 | |
235 OMX_COMPONENTTYPE* handle_; | |
236 int input_port_; | |
237 int output_port_; | |
238 int input_buffer_count_; | |
239 int input_buffer_size_; | |
240 int output_buffer_count_; | |
241 int output_buffer_size_; | |
242 OMX_BUFFERHEADERTYPE* input_buffers_[kMaxBufferNum]; | |
243 OMX_BUFFERHEADERTYPE* output_buffers_[kMaxBufferNum]; | |
244 | |
245 base::WaitableEvent event_; | |
246 base::WaitableEvent empty_buffer_; | |
247 base::WaitableEvent fill_buffer_; | |
248 | |
249 OMX_EVENTTYPE last_event_type_; | |
250 int last_event_data1_; | |
251 int last_event_data2_; | |
252 }; | |
253 | |
254 class OmxVideoDecoderTest : public OmxTest { | |
255 protected: | |
256 void Configure(OMX_VIDEO_CODINGTYPE codec, | |
257 int width, int height) { | |
258 // Obtain port IDs. | |
259 OMX_PORT_PARAM_TYPE port_param; | |
260 ResetHeader(&port_param); | |
261 EXPECT_EQ(OMX_ErrorNone, | |
262 OMX_GetParameter(handle_, | |
263 OMX_IndexParamVideoInit, | |
264 &port_param)); | |
265 | |
266 input_port_ = port_param.nStartPortNumber; | |
267 output_port_ = port_param.nStartPortNumber + 1; | |
268 LOG(INFO) << "Input port number: " << input_port_; | |
269 LOG(INFO) << "Output port number: " << output_port_; | |
270 | |
271 // Get and set parameters for input port. | |
272 LOG(INFO) << "Input port width: " << width; | |
273 LOG(INFO) << "Input port height: " << height; | |
274 LOG(INFO) << "Input port codec: " << codec; | |
275 OMX_PARAM_PORTDEFINITIONTYPE port_format; | |
276 ResetHeader(&port_format); | |
277 port_format.nPortIndex = input_port_; | |
278 EXPECT_EQ(OMX_ErrorNone, | |
279 OMX_GetParameter(handle_, | |
280 OMX_IndexParamPortDefinition, | |
281 &port_format)); | |
282 EXPECT_EQ(OMX_DirInput, port_format.eDir); | |
283 port_format.format.video.eCompressionFormat = codec; | |
284 port_format.format.video.nFrameWidth = width; | |
285 port_format.format.video.nFrameHeight = height; | |
286 EXPECT_EQ(OMX_ErrorNone, | |
287 OMX_SetParameter(handle_, | |
288 OMX_IndexParamPortDefinition, | |
289 &port_format)); | |
290 | |
291 // TODO(hclam): Add configurations to output port. | |
292 | |
293 // Get Parameters for input port. | |
294 ResetHeader(&port_format); | |
295 port_format.nPortIndex = input_port_; | |
296 EXPECT_EQ(OMX_ErrorNone, | |
297 OMX_GetParameter(handle_, | |
298 OMX_IndexParamPortDefinition, | |
299 &port_format)); | |
300 EXPECT_EQ(OMX_DirInput, port_format.eDir); | |
301 input_buffer_count_ = port_format.nBufferCountMin; | |
302 input_buffer_size_ = port_format.nBufferSize; | |
303 CHECK(input_buffer_count_ < kMaxBufferNum); | |
304 | |
305 // Get parameters for output port. | |
306 ResetHeader(&port_format); | |
307 port_format.nPortIndex = output_port_; | |
308 EXPECT_EQ(OMX_ErrorNone, | |
309 OMX_GetParameter(handle_, | |
310 OMX_IndexParamPortDefinition, | |
311 &port_format)); | |
312 EXPECT_EQ(OMX_DirOutput, port_format.eDir); | |
313 output_buffer_count_ = port_format.nBufferCountMin; | |
314 output_buffer_size_ = port_format.nBufferSize; | |
315 CHECK(output_buffer_count_ < kMaxBufferNum); | |
316 | |
317 LOG(INFO) << "Input buffer count: " << input_buffer_count_; | |
318 LOG(INFO) << "Input buffer size: " << input_buffer_size_; | |
319 LOG(INFO) << "Output buffer count: " << output_buffer_count_; | |
320 LOG(INFO) << "Output buffer size: " << output_buffer_size_; | |
321 } | |
322 | |
323 std::string component() { | |
324 return CommandLine::ForCurrentProcess() | |
325 ->GetSwitchValueASCII("video-decoder-component"); | |
326 } | |
327 | |
328 OMX_VIDEO_CODINGTYPE codec() { | |
329 std::string codec = CommandLine::ForCurrentProcess() | |
330 ->GetSwitchValueASCII("video-decoder-codec"); | |
331 if (codec == "h264") | |
332 return OMX_VIDEO_CodingAVC; | |
333 return OMX_VIDEO_CodingAutoDetect; | |
334 } | |
335 }; | |
336 | |
337 TEST_F(OmxTest, SimpleInit) { | |
338 // A empty test case will test basic init/deinit of OpenMAX library. | |
339 } | |
340 | |
341 TEST_F(OmxTest, GetComponentsOfRole) { | |
342 // Roles video decoders. | |
343 GetComponentsOfRole("video_decoder.avc"); | |
344 GetComponentsOfRole("video_decoder.mpeg4"); | |
345 GetComponentsOfRole("video_decoder.vc1"); | |
346 | |
347 // TODO(hclam): Add roles of encoders. | |
348 } | |
349 | |
350 TEST_F(OmxVideoDecoderTest, GetHandle) { | |
351 // TODO(hclam): Should use GetComponentsOfRole instead. | |
352 InitComponent(component()); | |
353 DeinitComponent(); | |
354 } | |
355 | |
356 TEST_F(OmxVideoDecoderTest, Configuration) { | |
357 InitComponent(component()); | |
358 // TODO(hclam): Make resolution configurable. | |
359 Configure(codec(), 1024, 768); | |
360 DeinitComponent(); | |
361 } | |
362 | |
363 TEST_F(OmxVideoDecoderTest, TransitionToIdle) { | |
364 InitComponent(component()); | |
365 Configure(codec(), 1024, 768); | |
366 TransitionLoadedToIdle(); | |
367 TransitionIdleToLoaded(); | |
368 DeinitComponent(); | |
369 } | |
370 | |
371 TEST_F(OmxVideoDecoderTest, FreeHandleWhenIdle) { | |
372 InitComponent(component()); | |
373 Configure(codec(), 1024, 768); | |
374 TransitionLoadedToIdle(); | |
375 DeinitComponent(); | |
376 } | |
377 | |
378 TEST_F(OmxVideoDecoderTest, TransitionToExecuting) { | |
379 InitComponent(component()); | |
380 Configure(codec(), 1024, 768); | |
381 TransitionLoadedToIdle(); | |
382 TransitionIdleToExecuting(); | |
383 TransitionExecutingToIdle(); | |
384 TransitionIdleToLoaded(); | |
385 DeinitComponent(); | |
386 } | |
387 | |
388 TEST_F(OmxVideoDecoderTest, FreeHandleWhenExecuting) { | |
389 InitComponent(component()); | |
390 Configure(codec(), 1024, 768); | |
391 TransitionLoadedToIdle(); | |
392 TransitionIdleToExecuting(); | |
393 DeinitComponent(); | |
394 } | |
395 | |
396 TEST_F(OmxVideoDecoderTest, CallbacksAreCopied) { | |
397 // Allocate a callback struct on stack and clear it with zero. | |
398 // This make sure OpenMAX library will copy the content of the | |
399 // struct. | |
400 OMX_CALLBACKTYPE callback = { &EventHandler, | |
401 &EmptyBufferCallback, | |
402 &FillBufferCallback }; | |
403 | |
404 OMX_ERRORTYPE omxresult = OMX_GetHandle( | |
405 (void**)&handle_, | |
406 const_cast<OMX_STRING>(component().c_str()), | |
407 this, &callback); | |
408 EXPECT_EQ(OMX_ErrorNone, omxresult); | |
409 CHECK(handle_); | |
410 memset(&callback, 0, sizeof(callback)); | |
411 | |
412 // Then configure the component as usual. | |
413 Configure(codec(), 1024, 768); | |
414 TransitionLoadedToIdle(); | |
415 TransitionIdleToExecuting(); | |
416 TransitionExecutingToIdle(); | |
417 TransitionIdleToLoaded(); | |
418 DeinitComponent(); | |
419 } | |
420 | |
421 } // namespace media | |
OLD | NEW |