1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "media_omx_hidl_video_test_common"
18 #ifdef __LP64__
19 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
20 #endif
21
22 #include <android-base/logging.h>
23
24 #include <android/hardware/media/omx/1.0/IOmx.h>
25 #include <android/hardware/media/omx/1.0/IOmxNode.h>
26 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
27 #include <android/hardware/media/omx/1.0/types.h>
28 #include <android/hidl/allocator/1.0/IAllocator.h>
29 #include <android/hidl/memory/1.0/IMapper.h>
30 #include <android/hidl/memory/1.0/IMemory.h>
31
32 #include <atomic>
33 #include <variant>
34
35 using ::android::hardware::graphics::common::V1_0::BufferUsage;
36 using ::android::hardware::graphics::common::V1_0::PixelFormat;
37 using ::android::hardware::media::omx::V1_0::IOmx;
38 using ::android::hardware::media::omx::V1_0::IOmxObserver;
39 using ::android::hardware::media::omx::V1_0::IOmxNode;
40 using ::android::hardware::media::omx::V1_0::Message;
41 using ::android::hardware::media::omx::V1_0::CodecBuffer;
42 using ::android::hardware::media::omx::V1_0::PortMode;
43 using ::android::hardware::media::omx::V1_0::Status;
44 using ::android::hidl::allocator::V1_0::IAllocator;
45 using ::android::hidl::memory::V1_0::IMemory;
46 using ::android::hidl::memory::V1_0::IMapper;
47 using ::android::hardware::Return;
48 using ::android::hardware::Void;
49 using ::android::hardware::hidl_vec;
50 using ::android::hardware::hidl_string;
51 using ::android::sp;
52
53 #include <hidlmemory/mapping.h>
54 #include <media/hardware/HardwareAPI.h>
55 #include <media_hidl_test_common.h>
56 #include <memory>
57
58 // set component role
setRole(sp<IOmxNode> omxNode,const std::string & role)59 Return<android::hardware::media::omx::V1_0::Status> setRole(sp<IOmxNode> omxNode,
60 const std::string& role) {
61 OMX_PARAM_COMPONENTROLETYPE params;
62 strcpy((char*)params.cRole, role.c_str());
63 return setParam(omxNode, OMX_IndexParamStandardComponentRole, ¶ms);
64 }
65
setPortBufferSize(sp<IOmxNode> omxNode,OMX_U32 portIndex,OMX_U32 size)66 Return<android::hardware::media::omx::V1_0::Status> setPortBufferSize(
67 sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_U32 size) {
68 android::hardware::media::omx::V1_0::Status status;
69 OMX_PARAM_PORTDEFINITIONTYPE portDef;
70
71 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
72 &portDef);
73 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
74 return status;
75 if (portDef.nBufferSize < size) {
76 portDef.nBufferSize = size;
77 status = setPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
78 &portDef);
79 if (status != ::android::hardware::media::omx::V1_0::Status::OK)
80 return status;
81 }
82 return status;
83 }
84
85 // get/set video component port format
setVideoPortFormat(sp<IOmxNode> omxNode,OMX_U32 portIndex,OMX_VIDEO_CODINGTYPE eCompressionFormat,OMX_COLOR_FORMATTYPE eColorFormat,OMX_U32 xFramerate)86 Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
87 sp<IOmxNode> omxNode, OMX_U32 portIndex,
88 OMX_VIDEO_CODINGTYPE eCompressionFormat, OMX_COLOR_FORMATTYPE eColorFormat,
89 OMX_U32 xFramerate) {
90 OMX_U32 index = 0;
91 OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
92 std::vector<OMX_COLOR_FORMATTYPE> arrColorFormat;
93 std::vector<OMX_VIDEO_CODINGTYPE> arrCompressionFormat;
94 android::hardware::media::omx::V1_0::Status status;
95
96 while (1) {
97 portFormat.nIndex = index;
98 status = getPortParam(omxNode, OMX_IndexParamVideoPortFormat, portIndex,
99 &portFormat);
100 if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
101 if (eCompressionFormat == OMX_VIDEO_CodingUnused)
102 arrColorFormat.push_back(portFormat.eColorFormat);
103 else
104 arrCompressionFormat.push_back(portFormat.eCompressionFormat);
105 index++;
106 if (index == 512) {
107 // enumerated way too many formats, highly unusual for this to
108 // happen.
109 EXPECT_LE(index, 512U)
110 << "Expecting OMX_ErrorNoMore but not received";
111 break;
112 }
113 }
114 if (!index) return status;
115 if (eCompressionFormat == OMX_VIDEO_CodingUnused) {
116 for (index = 0; index < arrColorFormat.size(); index++) {
117 if (arrColorFormat[index] == eColorFormat) {
118 portFormat.eColorFormat = arrColorFormat[index];
119 break;
120 }
121 }
122 if (index == arrColorFormat.size()) {
123 ALOGE("setting default color format %x", (int)arrColorFormat[0]);
124 portFormat.eColorFormat = arrColorFormat[0];
125 }
126 portFormat.eCompressionFormat = OMX_VIDEO_CodingUnused;
127 } else {
128 for (index = 0; index < arrCompressionFormat.size(); index++) {
129 if (arrCompressionFormat[index] == eCompressionFormat) {
130 portFormat.eCompressionFormat = arrCompressionFormat[index];
131 break;
132 }
133 }
134 if (index == arrCompressionFormat.size()) {
135 ALOGE("setting default compression format %x",
136 (int)arrCompressionFormat[0]);
137 portFormat.eCompressionFormat = arrCompressionFormat[0];
138 }
139 portFormat.eColorFormat = OMX_COLOR_FormatUnused;
140 }
141 // In setParam call nIndex shall be ignored as per omx-il specification.
142 // see how this holds up by corrupting nIndex
143 portFormat.nIndex = RANDOM_INDEX;
144 portFormat.xFramerate = xFramerate;
145 status = setPortParam(omxNode, OMX_IndexParamVideoPortFormat, portIndex,
146 &portFormat);
147 return status;
148 }
149
150 // get/set audio component port format
setAudioPortFormat(sp<IOmxNode> omxNode,OMX_U32 portIndex,OMX_AUDIO_CODINGTYPE eEncoding)151 Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
152 sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding) {
153 OMX_U32 index = 0;
154 OMX_AUDIO_PARAM_PORTFORMATTYPE portFormat;
155 std::vector<OMX_AUDIO_CODINGTYPE> arrEncoding;
156 android::hardware::media::omx::V1_0::Status status;
157
158 while (1) {
159 portFormat.nIndex = index;
160 status = getPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
161 &portFormat);
162 if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
163 arrEncoding.push_back(portFormat.eEncoding);
164 index++;
165 if (index == 512) {
166 // enumerated way too many formats, highly unusual for this to
167 // happen.
168 EXPECT_LE(index, 512U)
169 << "Expecting OMX_ErrorNoMore but not received";
170 break;
171 }
172 }
173 if (!index) return status;
174 for (index = 0; index < arrEncoding.size(); index++) {
175 if (arrEncoding[index] == eEncoding) {
176 portFormat.eEncoding = arrEncoding[index];
177 break;
178 }
179 }
180 if (index == arrEncoding.size()) {
181 ALOGE("setting default Port format %x", (int)arrEncoding[0]);
182 portFormat.eEncoding = arrEncoding[0];
183 }
184 // In setParam call nIndex shall be ignored as per omx-il specification.
185 // see how this holds up by corrupting nIndex
186 portFormat.nIndex = RANDOM_INDEX;
187 status = setPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
188 &portFormat);
189 return status;
190 }
191
allocateGraphicBuffers(sp<IOmxNode> omxNode,OMX_U32 portIndex,BufferInfo * buffer,uint32_t nFrameWidth,uint32_t nFrameHeight,int32_t * nStride,int format)192 void allocateGraphicBuffers(sp<IOmxNode> omxNode, OMX_U32 portIndex,
193 BufferInfo* buffer, uint32_t nFrameWidth,
194 uint32_t nFrameHeight, int32_t* nStride,
195 int format) {
196 android::hardware::media::omx::V1_0::Status status{};
197 uint64_t usage{};
198 ASSERT_TRUE(omxNode->getGraphicBufferUsage(
199 portIndex,
200 [&status, &usage](android::hardware::media::omx::V1_0::Status _s,
201 uint32_t _n1) {
202 status = _s;
203 usage = _n1;
204 }).isOk());
205 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
206
207 uint32_t stride;
208 buffer_handle_t handle = nullptr;
209 android::GraphicBufferAllocator& allocator = android::GraphicBufferAllocator::get();
210 android::status_t error = allocator.allocate(
211 nFrameWidth, nFrameHeight, static_cast<android::PixelFormat>(format), 1,
212 usage | BufferUsage::CPU_READ_OFTEN, &handle, &stride, "omx_vts_common");
213
214 ASSERT_EQ(error, android::NO_ERROR);
215 ASSERT_NE(handle, nullptr);
216
217 *nStride = static_cast<int32_t>(stride);
218 buffer->handle = handle;
219 buffer->omxBuffer.nativeHandle = handle;
220 buffer->omxBuffer.attr.anwBuffer.width = nFrameWidth;
221 buffer->omxBuffer.attr.anwBuffer.height = nFrameHeight;
222 buffer->omxBuffer.attr.anwBuffer.stride = stride;
223 buffer->omxBuffer.attr.anwBuffer.format = static_cast<PixelFormat>(format);
224 buffer->omxBuffer.attr.anwBuffer.usage = usage | BufferUsage::CPU_READ_OFTEN;
225 buffer->omxBuffer.attr.anwBuffer.layerCount = 1;
226 static std::atomic_int32_t bufferIdCounter{0};
227 buffer->omxBuffer.attr.anwBuffer.id = (static_cast<uint64_t>(getpid()) << 32) |
228 bufferIdCounter.fetch_add(1, std::memory_order_relaxed);
229 }
230
231 // allocate buffers needed on a component port
allocateBuffer(sp<IOmxNode> omxNode,BufferInfo * buffer,OMX_U32 portIndex,OMX_U32 nBufferSize,PortMode portMode)232 void allocateBuffer(sp<IOmxNode> omxNode, BufferInfo* buffer, OMX_U32 portIndex,
233 OMX_U32 nBufferSize, PortMode portMode) {
234 android::hardware::media::omx::V1_0::Status status;
235
236 if (portMode == PortMode::PRESET_SECURE_BUFFER) {
237 buffer->owner = client;
238 buffer->omxBuffer.type = CodecBuffer::Type::NATIVE_HANDLE;
239 omxNode->allocateSecureBuffer(
240 portIndex, nBufferSize,
241 [&status, &buffer](
242 android::hardware::media::omx::V1_0::Status _s, uint32_t id,
243 ::android::hardware::hidl_handle const& nativeHandle) {
244 status = _s;
245 buffer->id = id;
246 buffer->omxBuffer.nativeHandle = nativeHandle;
247 });
248 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
249 } else if (portMode == PortMode::PRESET_BYTE_BUFFER ||
250 portMode == PortMode::DYNAMIC_ANW_BUFFER) {
251 sp<IAllocator> allocator = IAllocator::getService("ashmem");
252 ASSERT_NE(allocator.get(), nullptr);
253
254 buffer->owner = client;
255 buffer->omxBuffer.type = CodecBuffer::Type::SHARED_MEM;
256 buffer->omxBuffer.attr.preset.rangeOffset = 0;
257 buffer->omxBuffer.attr.preset.rangeLength = 0;
258 bool success = false;
259 if (portMode != PortMode::PRESET_BYTE_BUFFER) {
260 nBufferSize = sizeof(android::VideoNativeMetadata);
261 }
262 allocator->allocate(
263 nBufferSize,
264 [&success, &buffer](bool _s,
265 ::android::hardware::hidl_memory const& mem) {
266 success = _s;
267 buffer->omxBuffer.sharedMemory = mem;
268 });
269 ASSERT_EQ(success, true);
270 ASSERT_EQ(buffer->omxBuffer.sharedMemory.size(), nBufferSize);
271 buffer->mMemory = mapMemory(buffer->omxBuffer.sharedMemory);
272 ASSERT_NE(buffer->mMemory, nullptr);
273 if (portMode == PortMode::DYNAMIC_ANW_BUFFER) {
274 android::VideoNativeMetadata* metaData =
275 static_cast<android::VideoNativeMetadata*>(
276 static_cast<void*>(buffer->mMemory->getPointer()));
277 metaData->nFenceFd = -1;
278 buffer->slot = -1;
279 }
280 omxNode->useBuffer(
281 portIndex, buffer->omxBuffer,
282 [&status, &buffer](android::hardware::media::omx::V1_0::Status _s,
283 uint32_t id) {
284 status = _s;
285 buffer->id = id;
286 });
287 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
288 } else if (portMode == PortMode::PRESET_ANW_BUFFER) {
289 OMX_PARAM_PORTDEFINITIONTYPE portDef;
290 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
291 &portDef);
292 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
293 int32_t nStride;
294 buffer->owner = client;
295 buffer->omxBuffer.type = CodecBuffer::Type::ANW_BUFFER;
296 ASSERT_NO_FATAL_FAILURE(allocateGraphicBuffers(
297 omxNode, portIndex, buffer, portDef.format.video.nFrameWidth,
298 portDef.format.video.nFrameHeight, &nStride,
299 portDef.format.video.eColorFormat));
300 omxNode->useBuffer(
301 portIndex, buffer->omxBuffer,
302 [&status, &buffer](android::hardware::media::omx::V1_0::Status _s,
303 uint32_t id) {
304 status = _s;
305 buffer->id = id;
306 });
307 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
308 }
309 }
310
311 // allocate buffers needed on a component port
allocatePortBuffers(sp<IOmxNode> omxNode,android::Vector<BufferInfo> * buffArray,OMX_U32 portIndex,PortMode portMode,bool allocGrap)312 void allocatePortBuffers(sp<IOmxNode> omxNode,
313 android::Vector<BufferInfo>* buffArray,
314 OMX_U32 portIndex, PortMode portMode, bool allocGrap) {
315 android::hardware::media::omx::V1_0::Status status;
316 OMX_PARAM_PORTDEFINITIONTYPE portDef;
317
318 buffArray->clear();
319
320 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
321 &portDef);
322 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
323
324 for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
325 BufferInfo buffer;
326 ASSERT_NO_FATAL_FAILURE(allocateBuffer(omxNode, &buffer, portIndex,
327 portDef.nBufferSize, portMode));
328 if (allocGrap && portMode == PortMode::DYNAMIC_ANW_BUFFER) {
329 int32_t nStride;
330 ASSERT_NO_FATAL_FAILURE(allocateGraphicBuffers(
331 omxNode, portIndex, &buffer, portDef.format.video.nFrameWidth,
332 portDef.format.video.nFrameHeight, &nStride,
333 portDef.format.video.eColorFormat));
334 }
335 buffArray->push(buffer);
336 }
337 }
338
339 // free buffers needed on a component port
freePortBuffers(android::Vector<BufferInfo> * buffArray,PortMode portMode,bool allocGrap)340 void freePortBuffers(android::Vector<BufferInfo>* buffArray, PortMode portMode, bool allocGrap) {
341 for (size_t i = 0; i < buffArray->size(); i++) {
342 if (portMode == PortMode::PRESET_ANW_BUFFER ||
343 (allocGrap && portMode == PortMode::DYNAMIC_ANW_BUFFER)) {
344 android::GraphicBufferAllocator& allocator = android::GraphicBufferAllocator::get();
345 android::status_t error = allocator.free((*buffArray)[i].handle);
346 ASSERT_EQ(error, android::NO_ERROR);
347 }
348 }
349 }
350
351 // State Transition : Loaded -> Idle
352 // Note: This function does not make any background checks for this transition.
353 // The callee holds the reponsibility to ensure the legality of the transition.
changeStateLoadedtoIdle(sp<IOmxNode> omxNode,sp<CodecObserver> observer,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer,OMX_U32 kPortIndexInput,OMX_U32 kPortIndexOutput,PortMode * portMode,bool allocGrap)354 void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
355 android::Vector<BufferInfo>* iBuffer,
356 android::Vector<BufferInfo>* oBuffer,
357 OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
358 PortMode* portMode, bool allocGrap) {
359 android::hardware::media::omx::V1_0::Status status;
360 Message msg;
361 PortMode defaultPortMode[2], *pm;
362
363 defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER;
364 defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER;
365 pm = portMode ? portMode : defaultPortMode;
366
367 // set state to idle
368 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
369 OMX_StateIdle);
370 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
371
372 OMX_PARAM_PORTDEFINITIONTYPE portDefInput;
373 OMX_PARAM_PORTDEFINITIONTYPE portDefOutput;
374 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, kPortIndexInput, &portDefInput);
375 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
376 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, kPortIndexOutput, &portDefOutput);
377 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
378
379 // Dont switch states until the ports are populated
380 if (portDefInput.nBufferCountActual || portDefOutput.nBufferCountActual) {
381 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
382 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
383 }
384
385 // allocate buffers on input port
386 ASSERT_NO_FATAL_FAILURE(allocatePortBuffers(
387 omxNode, iBuffer, kPortIndexInput, pm[0], allocGrap));
388
389 // Dont switch states until the ports are populated
390 if (portDefOutput.nBufferCountActual) {
391 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
392 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
393 }
394
395 // allocate buffers on output port
396 ASSERT_NO_FATAL_FAILURE(allocatePortBuffers(
397 omxNode, oBuffer, kPortIndexOutput, pm[1], allocGrap));
398
399 // As the ports are populated, check if the state transition is complete
400 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
401 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
402 ASSERT_EQ(msg.type, Message::Type::EVENT);
403 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
404 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
405 ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
406
407 return;
408 }
409
410 // State Transition : Idle -> Loaded
411 // Note: This function does not make any background checks for this transition.
412 // The callee holds the reponsibility to ensure the legality of the transition.
changeStateIdletoLoaded(sp<IOmxNode> omxNode,sp<CodecObserver> observer,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer,OMX_U32 kPortIndexInput,OMX_U32 kPortIndexOutput,PortMode * portMode,bool allocGrap)413 void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
414 android::Vector<BufferInfo>* iBuffer,
415 android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
416 OMX_U32 kPortIndexOutput, PortMode* portMode, bool allocGrap) {
417 android::hardware::media::omx::V1_0::Status status;
418 Message msg;
419 PortMode defaultPortMode[2], *pm;
420
421 defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER;
422 defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER;
423 pm = portMode ? portMode : defaultPortMode;
424
425 // set state to Loaded
426 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
427 OMX_StateLoaded);
428 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
429
430 OMX_PARAM_PORTDEFINITIONTYPE portDefInput;
431 OMX_PARAM_PORTDEFINITIONTYPE portDefOutput;
432 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, kPortIndexInput, &portDefInput);
433 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
434 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, kPortIndexOutput, &portDefOutput);
435 EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
436
437 // dont change state until all buffers are freed
438 if (portDefInput.nBufferCountActual || portDefOutput.nBufferCountActual) {
439 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
440 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
441 }
442
443 for (size_t i = 0; i < iBuffer->size(); ++i) {
444 status = omxNode->freeBuffer(kPortIndexInput, (*iBuffer)[i].id);
445 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
446 }
447
448 // dont change state until all buffers are freed
449 if (portDefOutput.nBufferCountActual) {
450 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
451 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
452 }
453
454 for (size_t i = 0; i < oBuffer->size(); ++i) {
455 status = omxNode->freeBuffer(kPortIndexOutput, (*oBuffer)[i].id);
456 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
457 }
458
459 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
460 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
461 ASSERT_EQ(msg.type, Message::Type::EVENT);
462 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
463 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
464 ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
465
466 ASSERT_NO_FATAL_FAILURE(freePortBuffers(iBuffer, pm[0], allocGrap));
467 ASSERT_NO_FATAL_FAILURE(freePortBuffers(oBuffer, pm[1], allocGrap));
468 return;
469 }
470
471 // State Transition : Idle -> Execute
472 // Note: This function does not make any background checks for this transition.
473 // The callee holds the reponsibility to ensure the legality of the transition.
changeStateIdletoExecute(sp<IOmxNode> omxNode,sp<CodecObserver> observer)474 void changeStateIdletoExecute(sp<IOmxNode> omxNode,
475 sp<CodecObserver> observer) {
476 android::hardware::media::omx::V1_0::Status status;
477 Message msg;
478
479 // set state to execute
480 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
481 OMX_StateExecuting);
482 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
483 status = observer->dequeueMessage(&msg, RELAXED_TIMEOUT);
484 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
485 ASSERT_EQ(msg.type, Message::Type::EVENT);
486 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
487 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
488 ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
489
490 return;
491 }
492
493 // State Transition : Execute -> Idle
494 // Note: This function does not make any background checks for this transition.
495 // The callee holds the reponsibility to ensure the legality of the transition.
changeStateExecutetoIdle(sp<IOmxNode> omxNode,sp<CodecObserver> observer,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer)496 void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
497 android::Vector<BufferInfo>* iBuffer,
498 android::Vector<BufferInfo>* oBuffer) {
499 android::hardware::media::omx::V1_0::Status status;
500 Message msg;
501
502 // set state to Idle
503 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
504 OMX_StateIdle);
505 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
506 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
507 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
508 ASSERT_EQ(msg.type, Message::Type::EVENT);
509 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
510 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
511 ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
512
513 // test if client got all its buffers back
514 for (size_t i = 0; i < oBuffer->size(); ++i) {
515 EXPECT_EQ((*oBuffer)[i].owner, client);
516 }
517 for (size_t i = 0; i < iBuffer->size(); ++i) {
518 EXPECT_EQ((*iBuffer)[i].owner, client);
519 }
520 }
521
522 // get empty buffer index
getEmptyBufferID(android::Vector<BufferInfo> * buffArray)523 size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray) {
524 android::Vector<BufferInfo>::iterator it = buffArray->begin();
525 while (it != buffArray->end()) {
526 if (it->owner == client) {
527 // This block of code ensures that all buffers allocated at init
528 // time are utilized
529 BufferInfo backup = *it;
530 buffArray->erase(it);
531 buffArray->push_back(backup);
532 return buffArray->size() - 1;
533 }
534 it++;
535 }
536 return buffArray->size();
537 }
538
539 // dispatch buffer to output port
dispatchOutputBuffer(sp<IOmxNode> omxNode,android::Vector<BufferInfo> * buffArray,size_t bufferIndex,PortMode portMode)540 void dispatchOutputBuffer(sp<IOmxNode> omxNode,
541 android::Vector<BufferInfo>* buffArray,
542 size_t bufferIndex, PortMode portMode) {
543 android::hardware::media::omx::V1_0::Status status;
544 CodecBuffer t;
545 native_handle_t* fenceNh = native_handle_create(0, 0);
546 ASSERT_NE(fenceNh, nullptr);
547 switch (portMode) {
548 case PortMode::DYNAMIC_ANW_BUFFER:
549 t = (*buffArray)[bufferIndex].omxBuffer;
550 t.type = CodecBuffer::Type::ANW_BUFFER;
551 status =
552 omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
553 break;
554 case PortMode::PRESET_ANW_BUFFER:
555 case PortMode::PRESET_SECURE_BUFFER:
556 case PortMode::PRESET_BYTE_BUFFER:
557 t.sharedMemory = android::hardware::hidl_memory();
558 t.nativeHandle = android::hardware::hidl_handle();
559 t.type = CodecBuffer::Type::PRESET;
560 t.attr.preset.rangeOffset = 0;
561 t.attr.preset.rangeLength = 0;
562 status =
563 omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
564 break;
565 default:
566 status = Status::NAME_NOT_FOUND;
567 }
568 native_handle_close(fenceNh);
569 native_handle_delete(fenceNh);
570 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
571 buffArray->editItemAt(bufferIndex).owner = component;
572 }
573
574 // dispatch buffer to input port
dispatchInputBuffer(sp<IOmxNode> omxNode,android::Vector<BufferInfo> * buffArray,size_t bufferIndex,int bytesCount,uint32_t flags,uint64_t timestamp,PortMode portMode)575 void dispatchInputBuffer(sp<IOmxNode> omxNode,
576 android::Vector<BufferInfo>* buffArray,
577 size_t bufferIndex, int bytesCount, uint32_t flags,
578 uint64_t timestamp, PortMode portMode) {
579 android::hardware::media::omx::V1_0::Status status;
580 CodecBuffer t;
581 native_handle_t* fenceNh = native_handle_create(0, 0);
582 ASSERT_NE(fenceNh, nullptr);
583 switch (portMode) {
584 case PortMode::PRESET_SECURE_BUFFER:
585 case PortMode::PRESET_BYTE_BUFFER:
586 t.sharedMemory = android::hardware::hidl_memory();
587 t.nativeHandle = android::hardware::hidl_handle();
588 t.type = CodecBuffer::Type::PRESET;
589 t.attr.preset.rangeOffset = 0;
590 t.attr.preset.rangeLength = bytesCount;
591 status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t,
592 flags, timestamp, fenceNh);
593 break;
594 default:
595 status = Status::NAME_NOT_FOUND;
596 }
597 native_handle_close(fenceNh);
598 native_handle_delete(fenceNh);
599 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
600 buffArray->editItemAt(bufferIndex).owner = component;
601 }
602
603 // Flush input and output ports
flushPorts(sp<IOmxNode> omxNode,sp<CodecObserver> observer,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer,OMX_U32 kPortIndexInput,OMX_U32 kPortIndexOutput,int64_t timeoutUs)604 void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
605 android::Vector<BufferInfo>* iBuffer,
606 android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
607 OMX_U32 kPortIndexOutput, int64_t timeoutUs) {
608 android::hardware::media::omx::V1_0::Status status;
609 Message msg;
610
611 // Flush input port
612 status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
613 kPortIndexInput);
614 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
615 status = observer->dequeueMessage(&msg, timeoutUs, iBuffer, oBuffer);
616 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
617 ASSERT_EQ(msg.type, Message::Type::EVENT);
618 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
619 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
620 ASSERT_EQ(msg.data.eventData.data2, kPortIndexInput);
621 // test if client got all its buffers back
622 for (size_t i = 0; i < iBuffer->size(); ++i) {
623 EXPECT_EQ((*iBuffer)[i].owner, client);
624 }
625
626 // Flush output port
627 status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
628 kPortIndexOutput);
629 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
630 status = observer->dequeueMessage(&msg, timeoutUs, iBuffer, oBuffer);
631 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
632 ASSERT_EQ(msg.type, Message::Type::EVENT);
633 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
634 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
635 ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
636 // test if client got all its buffers back
637 for (size_t i = 0; i < oBuffer->size(); ++i) {
638 EXPECT_EQ((*oBuffer)[i].owner, client);
639 }
640 }
641
642 // dispatch an empty input buffer with eos flag set if requested.
643 // This call assumes that all input buffers are processed completely.
644 // feed output buffers till we receive a buffer with eos flag set
testEOS(sp<IOmxNode> omxNode,sp<CodecObserver> observer,android::Vector<BufferInfo> * iBuffer,android::Vector<BufferInfo> * oBuffer,bool signalEOS,bool & eosFlag,PortMode * portMode,portreconfig fptr,OMX_U32 kPortIndexInput,OMX_U32 kPortIndexOutput,void * args)645 void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
646 android::Vector<BufferInfo>* iBuffer,
647 android::Vector<BufferInfo>* oBuffer, bool signalEOS,
648 bool& eosFlag, PortMode* portMode, portreconfig fptr,
649 OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, void* args) {
650 android::hardware::media::omx::V1_0::Status status;
651 PortMode defaultPortMode[2], *pm;
652
653 defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER;
654 defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER;
655 pm = portMode ? portMode : defaultPortMode;
656
657 size_t i = 0;
658 if (signalEOS) {
659 if ((i = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
660 // signal an empty buffer with flag set to EOS
661 ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer(omxNode, iBuffer, i, 0,
662 OMX_BUFFERFLAG_EOS, 0));
663 } else {
664 ASSERT_TRUE(false);
665 }
666 }
667
668 int timeOut = TIMEOUT_COUNTER_PE;
669 while (timeOut--) {
670 // Dispatch all client owned output buffers to recover remaining frames
671 while (1) {
672 if ((i = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
673 ASSERT_NO_FATAL_FAILURE(
674 dispatchOutputBuffer(omxNode, oBuffer, i, pm[1]));
675 // if dispatch is successful, perhaps there is a latency
676 // in the component. Dont be in a haste to leave. reset timeout
677 // counter
678 timeOut = TIMEOUT_COUNTER_PE;
679 } else {
680 break;
681 }
682 }
683
684 Message msg;
685 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_PE, iBuffer,
686 oBuffer);
687 if (status == android::hardware::media::omx::V1_0::Status::OK) {
688 if (msg.data.eventData.event == OMX_EventPortSettingsChanged) {
689 if (fptr) {
690 ASSERT_NO_FATAL_FAILURE((*fptr)(
691 omxNode, observer, iBuffer, oBuffer, kPortIndexInput,
692 kPortIndexOutput, msg, pm[1], args));
693 } else {
694 // something unexpected happened
695 ASSERT_TRUE(false);
696 }
697 } else {
698 // something unexpected happened
699 ASSERT_TRUE(false);
700 }
701 }
702 if (eosFlag == true) break;
703 }
704 // test for flag
705 EXPECT_EQ(eosFlag, true);
706 eosFlag = false;
707 }
708
getComponentInfoList(sp<IOmx> omx)709 hidl_vec<IOmx::ComponentInfo> getComponentInfoList(sp<IOmx> omx) {
710 android::hardware::media::omx::V1_0::Status status;
711 hidl_vec<IOmx::ComponentInfo> nodeList;
712 omx->listNodes([&status, &nodeList](android::hardware::media::omx::V1_0::Status _s,
713 hidl_vec<IOmx::ComponentInfo> const& _nl) {
714 status = _s;
715 nodeList = _nl;
716 });
717 if (status != android::hardware::media::omx::V1_0::Status::OK) {
718 ALOGE("Failed to get ComponentInfo list for IOmx.");
719 }
720 return nodeList;
721 }
722
723 // Return all test parameters, a list of tuple of <instance, component, role>
getTestParameters(const std::string & filter)724 const std::vector<std::tuple<std::string, std::string, std::string>>& getTestParameters(
725 const std::string& filter) {
726 static std::vector<std::tuple<std::string, std::string, std::string>> parameters;
727
728 auto instances = android::hardware::getAllHalInstanceNames(IOmx::descriptor);
729 for (std::string instance : instances) {
730 sp<IOmx> omx = IOmx::getService(instance);
731 hidl_vec<IOmx::ComponentInfo> componentInfos = getComponentInfoList(omx);
732 for (IOmx::ComponentInfo info : componentInfos) {
733 for (std::string role : info.mRoles) {
734 if (filter.empty()) {
735 if (kKnownRoles.find(role.c_str()) == kKnownRoles.end()) {
736 // This is for component test and the role is not supported.
737 continue;
738 }
739 } else if (role.find(filter) == std::string::npos) {
740 // The role doesn't match the given filter, e.g., video_decoder_vp8 role doesn't
741 // need to run for audio_decoder tests.
742 continue;
743 }
744 parameters.push_back(std::make_tuple(instance, info.mName.c_str(), role.c_str()));
745 }
746 }
747 }
748
749 return parameters;
750 }