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