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