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