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