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