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