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, &params);
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 }