2 * Copyright (C) 2017 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "media_omx_hidl_video_test_common"
20 #define OMX_ANDROID_COMPILE_AS_32BIT_ON_64BIT_PLATFORMS
23 #include <android-base/logging.h>
25 #include <android/hardware/media/omx/1.0/IOmx.h>
26 #include <android/hardware/media/omx/1.0/IOmxNode.h>
27 #include <android/hardware/media/omx/1.0/IOmxObserver.h>
28 #include <android/hardware/media/omx/1.0/types.h>
29 #include <android/hidl/allocator/1.0/IAllocator.h>
30 #include <android/hidl/memory/1.0/IMapper.h>
31 #include <android/hidl/memory/1.0/IMemory.h>
33 using ::android::hardware::media::omx::V1_0::IOmx;
34 using ::android::hardware::media::omx::V1_0::IOmxObserver;
35 using ::android::hardware::media::omx::V1_0::IOmxNode;
36 using ::android::hardware::media::omx::V1_0::Message;
37 using ::android::hardware::media::omx::V1_0::CodecBuffer;
38 using ::android::hardware::media::omx::V1_0::PortMode;
39 using ::android::hardware::media::omx::V1_0::Status;
40 using ::android::hidl::allocator::V1_0::IAllocator;
41 using ::android::hidl::memory::V1_0::IMemory;
42 using ::android::hidl::memory::V1_0::IMapper;
43 using ::android::hardware::Return;
44 using ::android::hardware::Void;
45 using ::android::hardware::hidl_vec;
46 using ::android::hardware::hidl_string;
49 #include <VtsHalHidlTargetTestBase.h>
50 #include <hidlmemory/mapping.h>
51 #include <media/hardware/HardwareAPI.h>
52 #include <media_hidl_test_common.h>
56 Return<android::hardware::media::omx::V1_0::Status> setRole(
57 sp<IOmxNode> omxNode, const char* role) {
58 OMX_PARAM_COMPONENTROLETYPE params;
59 strcpy((char*)params.cRole, role);
60 return setParam(omxNode, OMX_IndexParamStandardComponentRole, ¶ms);
63 // get/set video component port format
64 Return<android::hardware::media::omx::V1_0::Status> setVideoPortFormat(
65 sp<IOmxNode> omxNode, OMX_U32 portIndex,
66 OMX_VIDEO_CODINGTYPE eCompressionFormat, OMX_COLOR_FORMATTYPE eColorFormat,
69 OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
70 std::vector<OMX_COLOR_FORMATTYPE> arrColorFormat;
71 std::vector<OMX_VIDEO_CODINGTYPE> arrCompressionFormat;
72 android::hardware::media::omx::V1_0::Status status;
75 portFormat.nIndex = index;
76 status = getPortParam(omxNode, OMX_IndexParamVideoPortFormat, portIndex,
78 if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
79 if (eCompressionFormat == OMX_VIDEO_CodingUnused)
80 arrColorFormat.push_back(portFormat.eColorFormat);
82 arrCompressionFormat.push_back(portFormat.eCompressionFormat);
85 // enumerated way too many formats, highly unusual for this to
87 EXPECT_LE(index, 512U)
88 << "Expecting OMX_ErrorNoMore but not received";
92 if (!index) return status;
93 if (eCompressionFormat == OMX_VIDEO_CodingUnused) {
94 for (index = 0; index < arrColorFormat.size(); index++) {
95 if (arrColorFormat[index] == eColorFormat) {
96 portFormat.eColorFormat = arrColorFormat[index];
100 if (index == arrColorFormat.size()) {
101 ALOGE("setting default color format %x", (int)arrColorFormat[0]);
102 portFormat.eColorFormat = arrColorFormat[0];
104 portFormat.eCompressionFormat = OMX_VIDEO_CodingUnused;
106 for (index = 0; index < arrCompressionFormat.size(); index++) {
107 if (arrCompressionFormat[index] == eCompressionFormat) {
108 portFormat.eCompressionFormat = arrCompressionFormat[index];
112 if (index == arrCompressionFormat.size()) {
113 ALOGE("setting default compression format %x",
114 (int)arrCompressionFormat[0]);
115 portFormat.eCompressionFormat = arrCompressionFormat[0];
117 portFormat.eColorFormat = OMX_COLOR_FormatUnused;
119 // In setParam call nIndex shall be ignored as per omx-il specification.
120 // see how this holds up by corrupting nIndex
121 portFormat.nIndex = RANDOM_INDEX;
122 portFormat.xFramerate = xFramerate;
123 status = setPortParam(omxNode, OMX_IndexParamVideoPortFormat, portIndex,
128 // get/set audio component port format
129 Return<android::hardware::media::omx::V1_0::Status> setAudioPortFormat(
130 sp<IOmxNode> omxNode, OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE eEncoding) {
132 OMX_AUDIO_PARAM_PORTFORMATTYPE portFormat;
133 std::vector<OMX_AUDIO_CODINGTYPE> arrEncoding;
134 android::hardware::media::omx::V1_0::Status status;
137 portFormat.nIndex = index;
138 status = getPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
140 if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
141 arrEncoding.push_back(portFormat.eEncoding);
144 // enumerated way too many formats, highly unusual for this to
146 EXPECT_LE(index, 512U)
147 << "Expecting OMX_ErrorNoMore but not received";
151 if (!index) return status;
152 for (index = 0; index < arrEncoding.size(); index++) {
153 if (arrEncoding[index] == eEncoding) {
154 portFormat.eEncoding = arrEncoding[index];
158 if (index == arrEncoding.size()) {
159 ALOGE("setting default Port format %x", (int)arrEncoding[0]);
160 portFormat.eEncoding = arrEncoding[0];
162 // In setParam call nIndex shall be ignored as per omx-il specification.
163 // see how this holds up by corrupting nIndex
164 portFormat.nIndex = RANDOM_INDEX;
165 status = setPortParam(omxNode, OMX_IndexParamAudioPortFormat, portIndex,
170 // allocate buffers needed on a component port
171 void allocatePortBuffers(sp<IOmxNode> omxNode,
172 android::Vector<BufferInfo>* buffArray,
173 OMX_U32 portIndex, PortMode portMode) {
174 android::hardware::media::omx::V1_0::Status status;
175 OMX_PARAM_PORTDEFINITIONTYPE portDef;
179 status = getPortParam(omxNode, OMX_IndexParamPortDefinition, portIndex,
181 ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
183 if (portMode == PortMode::PRESET_SECURE_BUFFER) {
184 for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
186 buffer.owner = client;
187 buffer.omxBuffer.type = CodecBuffer::Type::NATIVE_HANDLE;
188 omxNode->allocateSecureBuffer(
189 portIndex, portDef.nBufferSize,
191 android::hardware::media::omx::V1_0::Status _s, uint32_t id,
192 ::android::hardware::hidl_handle const& nativeHandle) {
195 buffer.omxBuffer.nativeHandle = nativeHandle;
197 buffArray->push(buffer);
199 ::android::hardware::media::omx::V1_0::Status::OK);
201 } else if (portMode == PortMode::PRESET_BYTE_BUFFER ||
202 portMode == PortMode::DYNAMIC_ANW_BUFFER) {
203 sp<IAllocator> allocator = IAllocator::getService("ashmem");
204 EXPECT_NE(allocator.get(), nullptr);
206 for (size_t i = 0; i < portDef.nBufferCountActual; i++) {
208 buffer.owner = client;
209 buffer.omxBuffer.type = CodecBuffer::Type::SHARED_MEM;
210 buffer.omxBuffer.attr.preset.rangeOffset = 0;
211 buffer.omxBuffer.attr.preset.rangeLength = 0;
212 bool success = false;
213 if (portMode != PortMode::PRESET_BYTE_BUFFER) {
214 portDef.nBufferSize = sizeof(android::VideoNativeMetadata);
219 bool _s, ::android::hardware::hidl_memory const& mem) {
221 buffer.omxBuffer.sharedMemory = mem;
223 ASSERT_EQ(success, true);
224 ASSERT_EQ(buffer.omxBuffer.sharedMemory.size(),
225 portDef.nBufferSize);
226 buffer.mMemory = mapMemory(buffer.omxBuffer.sharedMemory);
227 ASSERT_NE(buffer.mMemory, nullptr);
228 if (portMode == PortMode::DYNAMIC_ANW_BUFFER) {
229 android::VideoNativeMetadata* metaData =
230 static_cast<android::VideoNativeMetadata*>(
231 static_cast<void*>(buffer.mMemory->getPointer()));
232 metaData->nFenceFd = -1;
236 portIndex, buffer.omxBuffer,
238 android::hardware::media::omx::V1_0::Status _s,
243 buffArray->push(buffer);
245 ::android::hardware::media::omx::V1_0::Status::OK);
250 // State Transition : Loaded -> Idle
251 // Note: This function does not make any background checks for this transition.
252 // The callee holds the reponsibility to ensure the legality of the transition.
253 void changeStateLoadedtoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
254 android::Vector<BufferInfo>* iBuffer,
255 android::Vector<BufferInfo>* oBuffer,
256 OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
257 PortMode* portMode) {
258 android::hardware::media::omx::V1_0::Status status;
260 PortMode defaultPortMode[2], *pm;
262 defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER;
263 defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER;
264 pm = portMode ? portMode : defaultPortMode;
267 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
269 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
271 // Dont switch states until the ports are populated
272 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
273 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
275 // allocate buffers on input port
276 allocatePortBuffers(omxNode, iBuffer, kPortIndexInput, pm[0]);
278 // Dont switch states until the ports are populated
279 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
280 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
282 // allocate buffers on output port
283 allocatePortBuffers(omxNode, oBuffer, kPortIndexOutput, pm[1]);
285 // As the ports are populated, check if the state transition is complete
286 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
287 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
288 ASSERT_EQ(msg.type, Message::Type::EVENT);
289 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
290 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
291 ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
296 // State Transition : Idle -> Loaded
297 // Note: This function does not make any background checks for this transition.
298 // The callee holds the reponsibility to ensure the legality of the transition.
299 void changeStateIdletoLoaded(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
300 android::Vector<BufferInfo>* iBuffer,
301 android::Vector<BufferInfo>* oBuffer,
302 OMX_U32 kPortIndexInput,
303 OMX_U32 kPortIndexOutput) {
304 android::hardware::media::omx::V1_0::Status status;
307 // set state to Loaded
308 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
310 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
312 // dont change state until all buffers are freed
313 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
314 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
316 for (size_t i = 0; i < iBuffer->size(); ++i) {
317 status = omxNode->freeBuffer(kPortIndexInput, (*iBuffer)[i].id);
318 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
321 // dont change state until all buffers are freed
322 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
323 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::TIMED_OUT);
325 for (size_t i = 0; i < oBuffer->size(); ++i) {
326 status = omxNode->freeBuffer(kPortIndexOutput, (*oBuffer)[i].id);
327 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
330 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
331 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
332 ASSERT_EQ(msg.type, Message::Type::EVENT);
333 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
334 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
335 ASSERT_EQ(msg.data.eventData.data2, OMX_StateLoaded);
340 // State Transition : Idle -> Execute
341 // Note: This function does not make any background checks for this transition.
342 // The callee holds the reponsibility to ensure the legality of the transition.
343 void changeStateIdletoExecute(sp<IOmxNode> omxNode,
344 sp<CodecObserver> observer) {
345 android::hardware::media::omx::V1_0::Status status;
348 // set state to execute
349 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
351 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
352 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT);
353 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
354 ASSERT_EQ(msg.type, Message::Type::EVENT);
355 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
356 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
357 ASSERT_EQ(msg.data.eventData.data2, OMX_StateExecuting);
362 // State Transition : Execute -> Idle
363 // Note: This function does not make any background checks for this transition.
364 // The callee holds the reponsibility to ensure the legality of the transition.
365 void changeStateExecutetoIdle(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
366 android::Vector<BufferInfo>* iBuffer,
367 android::Vector<BufferInfo>* oBuffer) {
368 android::hardware::media::omx::V1_0::Status status;
372 status = omxNode->sendCommand(toRawCommandType(OMX_CommandStateSet),
374 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
375 status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
376 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
377 ASSERT_EQ(msg.type, Message::Type::EVENT);
378 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
379 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandStateSet);
380 ASSERT_EQ(msg.data.eventData.data2, OMX_StateIdle);
382 // test if client got all its buffers back
383 for (size_t i = 0; i < oBuffer->size(); ++i) {
384 EXPECT_EQ((*oBuffer)[i].owner, client);
386 for (size_t i = 0; i < iBuffer->size(); ++i) {
387 EXPECT_EQ((*iBuffer)[i].owner, client);
391 // get empty buffer index
392 size_t getEmptyBufferID(android::Vector<BufferInfo>* buffArray) {
393 android::Vector<BufferInfo>::iterator it = buffArray->begin();
394 while (it != buffArray->end()) {
395 if (it->owner == client) {
396 // This block of code ensures that all buffers allocated at init
398 BufferInfo backup = *it;
399 buffArray->erase(it);
400 buffArray->push_back(backup);
401 return buffArray->size() - 1;
405 return buffArray->size();
408 // dispatch buffer to output port
409 void dispatchOutputBuffer(sp<IOmxNode> omxNode,
410 android::Vector<BufferInfo>* buffArray,
411 size_t bufferIndex, PortMode portMode) {
412 android::hardware::media::omx::V1_0::Status status;
414 native_handle_t* fenceNh = native_handle_create(0, 0);
415 ASSERT_NE(fenceNh, nullptr);
417 case PortMode::DYNAMIC_ANW_BUFFER:
418 t = (*buffArray)[bufferIndex].omxBuffer;
419 t.type = CodecBuffer::Type::ANW_BUFFER;
421 omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
423 case PortMode::PRESET_SECURE_BUFFER:
424 case PortMode::PRESET_BYTE_BUFFER:
425 t.sharedMemory = android::hardware::hidl_memory();
426 t.nativeHandle = android::hardware::hidl_handle();
427 t.type = CodecBuffer::Type::PRESET;
428 t.attr.preset.rangeOffset = 0;
429 t.attr.preset.rangeLength = 0;
431 omxNode->fillBuffer((*buffArray)[bufferIndex].id, t, fenceNh);
434 status = Status::NAME_NOT_FOUND;
436 native_handle_close(fenceNh);
437 native_handle_delete(fenceNh);
438 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
439 buffArray->editItemAt(bufferIndex).owner = component;
442 // dispatch buffer to input port
443 void dispatchInputBuffer(sp<IOmxNode> omxNode,
444 android::Vector<BufferInfo>* buffArray,
445 size_t bufferIndex, int bytesCount, uint32_t flags,
446 uint64_t timestamp, PortMode portMode) {
447 android::hardware::media::omx::V1_0::Status status;
449 native_handle_t* fenceNh = native_handle_create(0, 0);
450 ASSERT_NE(fenceNh, nullptr);
452 case PortMode::PRESET_SECURE_BUFFER:
453 case PortMode::PRESET_BYTE_BUFFER:
454 t.sharedMemory = android::hardware::hidl_memory();
455 t.nativeHandle = android::hardware::hidl_handle();
456 t.type = CodecBuffer::Type::PRESET;
457 t.attr.preset.rangeOffset = 0;
458 t.attr.preset.rangeLength = bytesCount;
459 status = omxNode->emptyBuffer((*buffArray)[bufferIndex].id, t,
460 flags, timestamp, fenceNh);
463 status = Status::NAME_NOT_FOUND;
465 native_handle_close(fenceNh);
466 native_handle_delete(fenceNh);
467 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
468 buffArray->editItemAt(bufferIndex).owner = component;
471 // Flush input and output ports
472 void flushPorts(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
473 android::Vector<BufferInfo>* iBuffer,
474 android::Vector<BufferInfo>* oBuffer, OMX_U32 kPortIndexInput,
475 OMX_U32 kPortIndexOutput, int64_t timeoutUs) {
476 android::hardware::media::omx::V1_0::Status status;
480 status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
482 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
483 status = observer->dequeueMessage(&msg, timeoutUs, iBuffer, oBuffer);
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_CommandFlush);
488 ASSERT_EQ(msg.data.eventData.data2, kPortIndexInput);
489 // test if client got all its buffers back
490 for (size_t i = 0; i < iBuffer->size(); ++i) {
491 EXPECT_EQ((*iBuffer)[i].owner, client);
495 status = omxNode->sendCommand(toRawCommandType(OMX_CommandFlush),
497 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
498 status = observer->dequeueMessage(&msg, timeoutUs, iBuffer, oBuffer);
499 ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
500 ASSERT_EQ(msg.type, Message::Type::EVENT);
501 ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
502 ASSERT_EQ(msg.data.eventData.data1, OMX_CommandFlush);
503 ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
504 // test if client got all its buffers back
505 for (size_t i = 0; i < oBuffer->size(); ++i) {
506 EXPECT_EQ((*oBuffer)[i].owner, client);
510 // dispatch an empty input buffer with eos flag set if requested.
511 // This call assumes that all input buffers are processed completely.
512 // feed output buffers till we receive a buffer with eos flag set
513 void testEOS(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
514 android::Vector<BufferInfo>* iBuffer,
515 android::Vector<BufferInfo>* oBuffer, bool signalEOS,
516 bool& eosFlag, PortMode* portMode, portreconfig fptr,
517 OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput, void* args) {
518 android::hardware::media::omx::V1_0::Status status;
519 PortMode defaultPortMode[2], *pm;
521 defaultPortMode[0] = PortMode::PRESET_BYTE_BUFFER;
522 defaultPortMode[1] = PortMode::PRESET_BYTE_BUFFER;
523 pm = portMode ? portMode : defaultPortMode;
527 if ((i = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
528 // signal an empty buffer with flag set to EOS
529 dispatchInputBuffer(omxNode, iBuffer, i, 0, OMX_BUFFERFLAG_EOS, 0);
535 int timeOut = TIMEOUT_COUNTER;
537 // Dispatch all client owned output buffers to recover remaining frames
539 if ((i = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
540 dispatchOutputBuffer(omxNode, oBuffer, i, pm[1]);
541 // if dispatch is successful, perhaps there is a latency
542 // in the component. Dont be in a haste to leave. reset timeout
544 timeOut = TIMEOUT_COUNTER;
552 observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer, oBuffer);
553 if (status == android::hardware::media::omx::V1_0::Status::OK) {
554 if (msg.data.eventData.event == OMX_EventPortSettingsChanged) {
556 (*fptr)(omxNode, observer, iBuffer, oBuffer,
557 kPortIndexInput, kPortIndexOutput, msg, pm[1],
560 // something unexpected happened
563 } else if (msg.data.eventData.event == OMX_EventBufferFlag) {
564 // soft omx components donot send this, we will just ignore it
567 // something unexpected happened
571 if (eosFlag == true) break;
574 EXPECT_EQ(eosFlag, true);