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_dec_test"
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
32using ::android::hardware::media::omx::V1_0::IOmx;
33using ::android::hardware::media::omx::V1_0::IOmxObserver;
34using ::android::hardware::media::omx::V1_0::IOmxNode;
35using ::android::hardware::media::omx::V1_0::Message;
36using ::android::hardware::media::omx::V1_0::CodecBuffer;
37using ::android::hardware::media::omx::V1_0::PortMode;
38using ::android::hidl::allocator::V1_0::IAllocator;
39using ::android::hidl::memory::V1_0::IMemory;
40using ::android::hidl::memory::V1_0::IMapper;
41using ::android::hardware::Return;
42using ::android::hardware::Void;
43using ::android::hardware::hidl_vec;
44using ::android::hardware::hidl_string;
45using ::android::sp;
46
47#include <VtsHalHidlTargetTestBase.h>
48#include <getopt.h>
49#include <media/hardware/HardwareAPI.h>
50#include <media_hidl_test_common.h>
51#include <media_video_hidl_test_common.h>
52#include <fstream>
53
54// A class for test environment setup
55class ComponentTestEnvironment : public ::testing::Environment {
56   public:
57    virtual void SetUp() {}
58    virtual void TearDown() {}
59
60    ComponentTestEnvironment() : instance("default"), res("/sdcard/media/") {}
61
62    void setInstance(const char* _instance) { instance = _instance; }
63
64    void setComponent(const char* _component) { component = _component; }
65
66    void setRole(const char* _role) { role = _role; }
67
68    void setRes(const char* _res) { res = _res; }
69
70    const hidl_string getInstance() const { return instance; }
71
72    const hidl_string getComponent() const { return component; }
73
74    const hidl_string getRole() const { return role; }
75
76    const hidl_string getRes() const { return res; }
77
78    int initFromOptions(int argc, char** argv) {
79        static struct option options[] = {
80            {"instance", required_argument, 0, 'I'},
81            {"component", required_argument, 0, 'C'},
82            {"role", required_argument, 0, 'R'},
83            {"res", required_argument, 0, 'P'},
84            {0, 0, 0, 0}};
85
86        while (true) {
87            int index = 0;
88            int c = getopt_long(argc, argv, "I:C:R:P:", options, &index);
89            if (c == -1) {
90                break;
91            }
92
93            switch (c) {
94                case 'I':
95                    setInstance(optarg);
96                    break;
97                case 'C':
98                    setComponent(optarg);
99                    break;
100                case 'R':
101                    setRole(optarg);
102                    break;
103                case 'P':
104                    setRes(optarg);
105                    break;
106                case '?':
107                    break;
108            }
109        }
110
111        if (optind < argc) {
112            fprintf(stderr,
113                    "unrecognized option: %s\n\n"
114                    "usage: %s <gtest options> <test options>\n\n"
115                    "test options are:\n\n"
116                    "-I, --instance: HAL instance to test\n"
117                    "-C, --component: OMX component to test\n"
118                    "-R, --role: OMX component Role\n"
119                    "-P, --res: Resource files directory location\n",
120                    argv[optind ?: 1], argv[0]);
121            return 2;
122        }
123        return 0;
124    }
125
126   private:
127    hidl_string instance;
128    hidl_string component;
129    hidl_string role;
130    hidl_string res;
131};
132
133static ComponentTestEnvironment* gEnv = nullptr;
134
135// video decoder test fixture class
136class VideoDecHidlTest : public ::testing::VtsHalHidlTargetTestBase {
137   private:
138    typedef ::testing::VtsHalHidlTargetTestBase Super;
139   public:
140    ::std::string getTestCaseInfo() const override {
141        return ::std::string() +
142                "Component: " + gEnv->getComponent().c_str() + " | " +
143                "Role: " + gEnv->getRole().c_str() + " | " +
144                "Instance: " + gEnv->getInstance().c_str() + " | " +
145                "Res: " + gEnv->getRes().c_str();
146    }
147
148    virtual void SetUp() override {
149        Super::SetUp();
150        disableTest = false;
151        android::hardware::media::omx::V1_0::Status status;
152        omx = Super::getService<IOmx>(gEnv->getInstance());
153        ASSERT_NE(omx, nullptr);
154        observer =
155            new CodecObserver([this](Message msg, const BufferInfo* buffer) {
156                handleMessage(msg, buffer);
157            });
158        ASSERT_NE(observer, nullptr);
159        if (strncmp(gEnv->getComponent().c_str(), "OMX.", 4) != 0)
160            disableTest = true;
161        EXPECT_TRUE(omx->allocateNode(
162                           gEnv->getComponent(), observer,
163                           [&](android::hardware::media::omx::V1_0::Status _s,
164                               sp<IOmxNode> const& _nl) {
165                               status = _s;
166                               this->omxNode = _nl;
167                           })
168                        .isOk());
169        ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
170        ASSERT_NE(omxNode, nullptr);
171        ASSERT_NE(gEnv->getRole().empty(), true) << "Invalid Component Role";
172        struct StringToName {
173            const char* Name;
174            standardComp CompName;
175        };
176        const StringToName kStringToName[] = {
177            {"h263", h263}, {"avc", avc}, {"mpeg2", mpeg2}, {"mpeg4", mpeg4},
178            {"hevc", hevc}, {"vp8", vp8}, {"vp9", vp9},
179        };
180        const size_t kNumStringToName =
181            sizeof(kStringToName) / sizeof(kStringToName[0]);
182        const char* pch;
183        char substring[OMX_MAX_STRINGNAME_SIZE];
184        strcpy(substring, gEnv->getRole().c_str());
185        pch = strchr(substring, '.');
186        ASSERT_NE(pch, nullptr);
187        compName = unknown_comp;
188        for (size_t i = 0; i < kNumStringToName; ++i) {
189            if (!strcasecmp(pch + 1, kStringToName[i].Name)) {
190                compName = kStringToName[i].CompName;
191                break;
192            }
193        }
194        if (compName == unknown_comp) disableTest = true;
195        struct CompToCompression {
196            standardComp CompName;
197            OMX_VIDEO_CODINGTYPE eCompressionFormat;
198        };
199        static const CompToCompression kCompToCompression[] = {
200            {h263, OMX_VIDEO_CodingH263},   {avc, OMX_VIDEO_CodingAVC},
201            {mpeg2, OMX_VIDEO_CodingMPEG2}, {mpeg4, OMX_VIDEO_CodingMPEG4},
202            {hevc, OMX_VIDEO_CodingHEVC},   {vp8, OMX_VIDEO_CodingVP8},
203            {vp9, OMX_VIDEO_CodingVP9},
204        };
205        static const size_t kNumCompToCompression =
206            sizeof(kCompToCompression) / sizeof(kCompToCompression[0]);
207        size_t i;
208        for (i = 0; i < kNumCompToCompression; ++i) {
209            if (kCompToCompression[i].CompName == compName) {
210                eCompressionFormat = kCompToCompression[i].eCompressionFormat;
211                break;
212            }
213        }
214        if (i == kNumCompToCompression) disableTest = true;
215        portMode[0] = portMode[1] = PortMode::PRESET_BYTE_BUFFER;
216        eosFlag = false;
217        framesReceived = 0;
218        timestampUs = 0;
219        timestampDevTest = false;
220        isSecure = false;
221        portSettingsChange = false;
222        size_t suffixLen = strlen(".secure");
223        if (strlen(gEnv->getComponent().c_str()) >= suffixLen) {
224            isSecure =
225                !strcmp(gEnv->getComponent().c_str() +
226                            strlen(gEnv->getComponent().c_str()) - suffixLen,
227                        ".secure");
228        }
229        if (isSecure) disableTest = true;
230        if (disableTest) std::cout << "[   WARN   ] Test Disabled \n";
231    }
232
233    virtual void TearDown() override {
234        if (omxNode != nullptr) {
235            // If you have encountered a fatal failure, it is possible that
236            // freeNode() will not go through. Instead of hanging the app.
237            // let it pass through and report errors
238            if (::testing::Test::HasFatalFailure()) return;
239            EXPECT_TRUE((omxNode->freeNode()).isOk());
240            omxNode = nullptr;
241        }
242        Super::TearDown();
243    }
244
245    // callback function to process messages received by onMessages() from IL
246    // client.
247    void handleMessage(Message msg, const BufferInfo* buffer) {
248        (void)buffer;
249        if (msg.type == Message::Type::FILL_BUFFER_DONE) {
250            if (msg.data.extendedBufferData.flags & OMX_BUFFERFLAG_EOS) {
251                eosFlag = true;
252            }
253            if (msg.data.extendedBufferData.rangeLength != 0) {
254                framesReceived += 1;
255                // For decoder components current timestamp always exceeds
256                // previous timestamp
257                EXPECT_GE(msg.data.extendedBufferData.timestampUs, timestampUs);
258                timestampUs = msg.data.extendedBufferData.timestampUs;
259                // Test if current timestamp is among the list of queued
260                // timestamps
261                if (timestampDevTest) {
262                    bool tsHit = false;
263                    android::List<uint64_t>::iterator it =
264                        timestampUslist.begin();
265                    while (it != timestampUslist.end()) {
266                        if (*it == timestampUs) {
267                            timestampUslist.erase(it);
268                            tsHit = true;
269                            break;
270                        }
271                        it++;
272                    }
273                    if (tsHit == false) {
274                        if (timestampUslist.empty() == false) {
275                            EXPECT_EQ(tsHit, true)
276                                << "TimeStamp not recognized";
277                        } else {
278                            std::cout << "[   INFO   ] Received non-zero "
279                                         "output / TimeStamp not recognized \n";
280                        }
281                    }
282                }
283#define WRITE_OUTPUT 0
284#if WRITE_OUTPUT
285                static int count = 0;
286                FILE* ofp = nullptr;
287                if (count)
288                    ofp = fopen("out.bin", "ab");
289                else
290                    ofp = fopen("out.bin", "wb");
291                if (ofp != nullptr &&
292                    portMode[1] == PortMode::PRESET_BYTE_BUFFER) {
293                    fwrite(static_cast<void*>(buffer->mMemory->getPointer()),
294                           sizeof(char),
295                           msg.data.extendedBufferData.rangeLength, ofp);
296                    fclose(ofp);
297                    count++;
298                }
299#endif
300            }
301        } else if (msg.type == Message::Type::EVENT) {
302            if (msg.data.eventData.event == OMX_EventPortSettingsChanged) {
303                if ((msg.data.eventData.data2 == OMX_IndexParamPortDefinition ||
304                     msg.data.eventData.data2 == 0)) {
305                    portSettingsChange = true;
306                }
307            }
308        }
309    }
310
311    enum standardComp {
312        h263,
313        avc,
314        mpeg2,
315        mpeg4,
316        hevc,
317        vp8,
318        vp9,
319        unknown_comp,
320    };
321
322    sp<IOmx> omx;
323    sp<CodecObserver> observer;
324    sp<IOmxNode> omxNode;
325    standardComp compName;
326    OMX_VIDEO_CODINGTYPE eCompressionFormat;
327    bool disableTest;
328    PortMode portMode[2];
329    bool eosFlag;
330    uint32_t framesReceived;
331    uint64_t timestampUs;
332    ::android::List<uint64_t> timestampUslist;
333    bool timestampDevTest;
334    bool isSecure;
335    bool portSettingsChange;
336
337   protected:
338    static void description(const std::string& description) {
339        RecordProperty("description", description);
340    }
341};
342
343// Set Default port param.
344void setDefaultPortParam(sp<IOmxNode> omxNode, OMX_U32 portIndex,
345                         OMX_VIDEO_CODINGTYPE eCompressionFormat,
346                         OMX_COLOR_FORMATTYPE eColorFormat,
347                         OMX_U32 nFrameWidth = 352, OMX_U32 nFrameHeight = 288,
348                         OMX_U32 nBitrate = 0,
349                         OMX_U32 xFramerate = (24U << 16)) {
350    switch ((int)eCompressionFormat) {
351        case OMX_VIDEO_CodingUnused:
352            setupRAWPort(omxNode, portIndex, nFrameWidth, nFrameHeight,
353                         nBitrate, xFramerate, eColorFormat);
354            break;
355        default:
356            break;
357    }
358}
359
360// In decoder components, often the input port parameters get updated upon
361// parsing the header of elementary stream. Client needs to collect this
362// information to reconfigure other ports that share data with this input
363// port.
364void getInputChannelInfo(sp<IOmxNode> omxNode, OMX_U32 kPortIndexInput,
365                         uint32_t* nFrameWidth, uint32_t* nFrameHeight,
366                         uint32_t* xFramerate) {
367    android::hardware::media::omx::V1_0::Status status;
368    *nFrameWidth = 352;
369    *nFrameHeight = 288;
370    *xFramerate = (24U << 16);
371
372    OMX_PARAM_PORTDEFINITIONTYPE portDef;
373    status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
374                          kPortIndexInput, &portDef);
375    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
376    if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
377        *nFrameWidth = portDef.format.video.nFrameWidth;
378        *nFrameHeight = portDef.format.video.nFrameHeight;
379        *xFramerate = portDef.format.video.xFramerate;
380    }
381}
382
383// number of elementary streams per component
384#define STREAM_COUNT 2
385// LookUpTable of clips and metadata for component testing
386void GetURLForComponent(VideoDecHidlTest::standardComp comp, char* mURL,
387                        char* info, size_t streamIndex = 1) {
388    struct CompToURL {
389        VideoDecHidlTest::standardComp comp;
390        const char mURL[STREAM_COUNT][512];
391        const char info[STREAM_COUNT][512];
392    };
393    ASSERT_TRUE(streamIndex < STREAM_COUNT);
394
395    static const CompToURL kCompToURL[] = {
396        {VideoDecHidlTest::standardComp::avc,
397         {"bbb_avc_176x144_300kbps_60fps.h264",
398          "bbb_avc_1920x1080_5000kbps_30fps.h264"},
399         {"bbb_avc_176x144_300kbps_60fps.info",
400          "bbb_avc_1920x1080_5000kbps_30fps.info"}},
401        {VideoDecHidlTest::standardComp::hevc,
402         {"bbb_hevc_176x144_176kbps_60fps.hevc",
403          "bbb_hevc_640x360_1600kbps_30fps.hevc"},
404         {"bbb_hevc_176x144_176kbps_60fps.info",
405          "bbb_hevc_640x360_1600kbps_30fps.info"}},
406        {VideoDecHidlTest::standardComp::mpeg2,
407         {"bbb_mpeg2_176x144_105kbps_25fps.m2v",
408          "bbb_mpeg2_352x288_1mbps_60fps.m2v"},
409         {"bbb_mpeg2_176x144_105kbps_25fps.info",
410          "bbb_mpeg2_352x288_1mbps_60fps.info"}},
411        {VideoDecHidlTest::standardComp::h263,
412         {"", "bbb_h263_352x288_300kbps_12fps.h263"},
413         {"", "bbb_h263_352x288_300kbps_12fps.info"}},
414        {VideoDecHidlTest::standardComp::mpeg4,
415         {"", "bbb_mpeg4_1280x720_1000kbps_25fps.m4v"},
416         {"", "bbb_mpeg4_1280x720_1000kbps_25fps.info"}},
417        {VideoDecHidlTest::standardComp::vp8,
418         {"bbb_vp8_176x144_240kbps_60fps.vp8",
419          "bbb_vp8_640x360_2mbps_30fps.vp8"},
420         {"bbb_vp8_176x144_240kbps_60fps.info",
421          "bbb_vp8_640x360_2mbps_30fps.info"}},
422        {VideoDecHidlTest::standardComp::vp9,
423         {"bbb_vp9_176x144_285kbps_60fps.vp9",
424          "bbb_vp9_640x360_1600kbps_30fps.vp9"},
425         {"bbb_vp9_176x144_285kbps_60fps.info",
426          "bbb_vp9_640x360_1600kbps_30fps.info"}},
427    };
428
429    for (size_t i = 0; i < sizeof(kCompToURL) / sizeof(kCompToURL[0]); ++i) {
430        if (kCompToURL[i].comp == comp) {
431            strcat(mURL, kCompToURL[i].mURL[streamIndex]);
432            strcat(info, kCompToURL[i].info[streamIndex]);
433            return;
434        }
435    }
436}
437
438// port settings reconfiguration during runtime. reconfigures frame dimensions
439void portReconfiguration(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
440                         android::Vector<BufferInfo>* iBuffer,
441                         android::Vector<BufferInfo>* oBuffer,
442                         OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
443                         Message msg, PortMode oPortMode, void* args) {
444    android::hardware::media::omx::V1_0::Status status;
445    (void)args;
446
447    if (msg.data.eventData.event == OMX_EventPortSettingsChanged) {
448        ASSERT_EQ(msg.data.eventData.data1, kPortIndexOutput);
449        if (msg.data.eventData.data2 == OMX_IndexParamPortDefinition ||
450            msg.data.eventData.data2 == 0) {
451            // Components can send various kinds of port settings changed events
452            // all at once. Before committing to a full port reconfiguration,
453            // defer any events waiting in the queue to be addressed to a later
454            // point.
455            android::List<Message> msgQueueDefer;
456            while (1) {
457                status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
458                                                  iBuffer, oBuffer);
459                if (status !=
460                    android::hardware::media::omx::V1_0::Status::TIMED_OUT) {
461                    msgQueueDefer.push_back(msg);
462                    continue;
463                } else
464                    break;
465            }
466            status = omxNode->sendCommand(
467                toRawCommandType(OMX_CommandPortDisable), kPortIndexOutput);
468            ASSERT_EQ(status, android::hardware::media::omx::V1_0::Status::OK);
469
470            status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT, iBuffer,
471                                              oBuffer);
472            if (status ==
473                android::hardware::media::omx::V1_0::Status::TIMED_OUT) {
474                for (size_t i = 0; i < oBuffer->size(); ++i) {
475                    // test if client got all its buffers back
476                    EXPECT_EQ((*oBuffer)[i].owner, client);
477                    // free the buffers
478                    status =
479                        omxNode->freeBuffer(kPortIndexOutput, (*oBuffer)[i].id);
480                    ASSERT_EQ(status,
481                              android::hardware::media::omx::V1_0::Status::OK);
482                }
483                status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
484                                                  iBuffer, oBuffer);
485                ASSERT_EQ(status,
486                          android::hardware::media::omx::V1_0::Status::OK);
487                ASSERT_EQ(msg.type, Message::Type::EVENT);
488                ASSERT_EQ(msg.data.eventData.event, OMX_EventCmdComplete);
489                ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortDisable);
490                ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
491
492                // set Port Params
493                uint32_t nFrameWidth, nFrameHeight, xFramerate;
494                getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth,
495                                    &nFrameHeight, &xFramerate);
496                // get configured color format
497                OMX_PARAM_PORTDEFINITIONTYPE portDef;
498                status = getPortParam(omxNode, OMX_IndexParamPortDefinition,
499                                      kPortIndexOutput, &portDef);
500                setDefaultPortParam(omxNode, kPortIndexOutput,
501                                    OMX_VIDEO_CodingUnused,
502                                    portDef.format.video.eColorFormat,
503                                    nFrameWidth, nFrameHeight, 0, xFramerate);
504
505                // If you can disable a port, then you should be able to
506                // enable it as well
507                status = omxNode->sendCommand(
508                    toRawCommandType(OMX_CommandPortEnable), kPortIndexOutput);
509                ASSERT_EQ(status,
510                          android::hardware::media::omx::V1_0::Status::OK);
511
512                // do not enable the port until all the buffers are supplied
513                status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
514                                                  iBuffer, oBuffer);
515                ASSERT_EQ(
516                    status,
517                    android::hardware::media::omx::V1_0::Status::TIMED_OUT);
518
519                ASSERT_NO_FATAL_FAILURE(allocatePortBuffers(
520                    omxNode, oBuffer, kPortIndexOutput, oPortMode, true));
521                status = observer->dequeueMessage(&msg, DEFAULT_TIMEOUT,
522                                                  iBuffer, oBuffer);
523                ASSERT_EQ(status,
524                          android::hardware::media::omx::V1_0::Status::OK);
525                ASSERT_EQ(msg.type, Message::Type::EVENT);
526                ASSERT_EQ(msg.data.eventData.data1, OMX_CommandPortEnable);
527                ASSERT_EQ(msg.data.eventData.data2, kPortIndexOutput);
528
529                // Push back deferred messages to the list
530                android::List<Message>::iterator it = msgQueueDefer.begin();
531                while (it != msgQueueDefer.end()) {
532                    status = omxNode->dispatchMessage(*it);
533                    ASSERT_EQ(
534                        status,
535                        ::android::hardware::media::omx::V1_0::Status::OK);
536                    it++;
537                }
538
539                // dispatch output buffers
540                for (size_t i = 0; i < oBuffer->size(); i++) {
541                    ASSERT_NO_FATAL_FAILURE(
542                        dispatchOutputBuffer(omxNode, oBuffer, i, oPortMode));
543                }
544            } else {
545                ASSERT_TRUE(false);
546            }
547        } else if (msg.data.eventData.data2 ==
548                   OMX_IndexConfigCommonOutputCrop) {
549            std::cout << "[   INFO   ] OMX_EventPortSettingsChanged/ "
550                         "OMX_IndexConfigCommonOutputCrop not handled \n";
551        } else if (msg.data.eventData.data2 == OMX_IndexVendorStartUnused + 3) {
552            std::cout << "[   INFO   ] OMX_EventPortSettingsChanged/ "
553                         "kDescribeColorAspectsIndex not handled \n";
554        }
555    } else if (msg.data.eventData.event == OMX_EventError) {
556        std::cerr << "[   ERROR   ] OMX_EventError/ "
557                     "Decode Frame Call might be failed \n";
558        ASSERT_TRUE(false);
559    } else {
560        // something unexpected happened
561        ASSERT_TRUE(false);
562    }
563}
564
565// blocking call to ensures application to Wait till all the inputs are consumed
566void waitOnInputConsumption(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
567                            android::Vector<BufferInfo>* iBuffer,
568                            android::Vector<BufferInfo>* oBuffer,
569                            OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
570                            PortMode oPortMode) {
571    android::hardware::media::omx::V1_0::Status status;
572    Message msg;
573    int timeOut = TIMEOUT_COUNTER_Q;
574
575    while (timeOut--) {
576        size_t i = 0;
577        status =
578            observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
579        if (status == android::hardware::media::omx::V1_0::Status::OK) {
580            ASSERT_EQ(msg.type, Message::Type::EVENT);
581            ASSERT_NO_FATAL_FAILURE(portReconfiguration(
582                omxNode, observer, iBuffer, oBuffer, kPortIndexInput,
583                kPortIndexOutput, msg, oPortMode, nullptr));
584        }
585        // status == TIMED_OUT, it could be due to process time being large
586        // than DEFAULT_TIMEOUT or component needs output buffers to start
587        // processing.
588        for (; i < iBuffer->size(); i++) {
589            if ((*iBuffer)[i].owner != client) break;
590        }
591        if (i == iBuffer->size()) break;
592
593        // Dispatch an output buffer assuming outQueue.empty() is true
594        size_t index;
595        if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
596            ASSERT_NO_FATAL_FAILURE(
597                dispatchOutputBuffer(omxNode, oBuffer, index, oPortMode));
598            timeOut = TIMEOUT_COUNTER_Q;
599        }
600    }
601}
602
603// Decode N Frames
604void decodeNFrames(sp<IOmxNode> omxNode, sp<CodecObserver> observer,
605                   android::Vector<BufferInfo>* iBuffer,
606                   android::Vector<BufferInfo>* oBuffer,
607                   OMX_U32 kPortIndexInput, OMX_U32 kPortIndexOutput,
608                   std::ifstream& eleStream, android::Vector<FrameData>* Info,
609                   int offset, int range, PortMode oPortMode,
610                   bool signalEOS = true) {
611    android::hardware::media::omx::V1_0::Status status;
612    Message msg;
613    size_t index;
614    uint32_t flags = 0;
615    int frameID = offset;
616    int timeOut = TIMEOUT_COUNTER_Q;
617    bool iQueued, oQueued;
618
619    while (1) {
620        iQueued = oQueued = false;
621        status =
622            observer->dequeueMessage(&msg, DEFAULT_TIMEOUT_Q, iBuffer, oBuffer);
623        // Port Reconfiguration
624        if (status == android::hardware::media::omx::V1_0::Status::OK &&
625            msg.type == Message::Type::EVENT) {
626            ASSERT_NO_FATAL_FAILURE(portReconfiguration(
627                omxNode, observer, iBuffer, oBuffer, kPortIndexInput,
628                kPortIndexOutput, msg, oPortMode, nullptr));
629        }
630
631        if (frameID == (int)Info->size() || frameID == (offset + range)) break;
632
633        // Dispatch input buffer
634        if ((index = getEmptyBufferID(iBuffer)) < iBuffer->size()) {
635            char* ipBuffer = static_cast<char*>(
636                static_cast<void*>((*iBuffer)[index].mMemory->getPointer()));
637            ASSERT_LE((*Info)[frameID].bytesCount,
638                      static_cast<int>((*iBuffer)[index].mMemory->getSize()));
639            eleStream.read(ipBuffer, (*Info)[frameID].bytesCount);
640            ASSERT_EQ(eleStream.gcount(), (*Info)[frameID].bytesCount);
641            flags = (*Info)[frameID].flags;
642            // Indicate to omx core that the buffer contains a full frame worth
643            // of data
644            flags |= OMX_BUFFERFLAG_ENDOFFRAME;
645            // Indicate the omx core that this is the last buffer it needs to
646            // process
647            if (signalEOS && ((frameID == (int)Info->size() - 1) ||
648                              (frameID == (offset + range - 1))))
649                flags |= OMX_BUFFERFLAG_EOS;
650            ASSERT_NO_FATAL_FAILURE(dispatchInputBuffer(
651                omxNode, iBuffer, index, (*Info)[frameID].bytesCount, flags,
652                (*Info)[frameID].timestamp));
653            frameID++;
654            iQueued = true;
655        }
656        // Dispatch output buffer
657        if ((index = getEmptyBufferID(oBuffer)) < oBuffer->size()) {
658            ASSERT_NO_FATAL_FAILURE(
659                dispatchOutputBuffer(omxNode, oBuffer, index, oPortMode));
660            oQueued = true;
661        }
662        // Reset Counters when either input or output buffer is dispatched
663        if (iQueued || oQueued)
664            timeOut = TIMEOUT_COUNTER_Q;
665        else
666            timeOut--;
667        if (timeOut == 0) {
668            ASSERT_TRUE(false) << "Wait on Input/Output is found indefinite";
669        }
670    }
671}
672
673// DescribeColorFormatParams Copy Constructor (Borrowed from OMXUtils.cpp)
674android::DescribeColorFormatParams::DescribeColorFormatParams(
675    const android::DescribeColorFormat2Params& params) {
676    eColorFormat = params.eColorFormat;
677    nFrameWidth = params.nFrameWidth;
678    nFrameHeight = params.nFrameHeight;
679    nStride = params.nStride;
680    nSliceHeight = params.nSliceHeight;
681    bUsingNativeBuffers = params.bUsingNativeBuffers;
682};
683
684bool isColorFormatFlexibleYUV(sp<IOmxNode> omxNode,
685                              OMX_COLOR_FORMATTYPE eColorFormat) {
686    android::hardware::media::omx::V1_0::Status status;
687    unsigned int index = OMX_IndexMax, index2 = OMX_IndexMax;
688    omxNode->getExtensionIndex(
689        "OMX.google.android.index.describeColorFormat",
690        [&index](android::hardware::media::omx::V1_0::Status _s,
691                          unsigned int _nl) {
692            if (_s == ::android::hardware::media::omx::V1_0::Status::OK)
693                index = _nl;
694        });
695    omxNode->getExtensionIndex(
696        "OMX.google.android.index.describeColorFormat2",
697        [&index2](android::hardware::media::omx::V1_0::Status _s,
698                           unsigned int _nl) {
699            if (_s == ::android::hardware::media::omx::V1_0::Status::OK)
700                index2 = _nl;
701        });
702
703    android::DescribeColorFormat2Params describeParams;
704    describeParams.eColorFormat = eColorFormat;
705    describeParams.nFrameWidth = 128;
706    describeParams.nFrameHeight = 128;
707    describeParams.nStride = 128;
708    describeParams.nSliceHeight = 128;
709    describeParams.bUsingNativeBuffers = OMX_FALSE;
710    if (index != OMX_IndexMax) {
711        android::DescribeColorFormatParams describeParamsV1(describeParams);
712        status = getParam(omxNode, static_cast<OMX_INDEXTYPE>(index),
713                          &describeParamsV1);
714        if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
715            android::MediaImage& img = describeParamsV1.sMediaImage;
716            if (img.mType == android::MediaImage::MEDIA_IMAGE_TYPE_YUV) {
717                if (img.mNumPlanes == 3 &&
718                    img.mPlane[img.Y].mHorizSubsampling == 1 &&
719                    img.mPlane[img.Y].mVertSubsampling == 1) {
720                    if (img.mPlane[img.U].mHorizSubsampling == 2 &&
721                        img.mPlane[img.U].mVertSubsampling == 2 &&
722                        img.mPlane[img.V].mHorizSubsampling == 2 &&
723                        img.mPlane[img.V].mVertSubsampling == 2) {
724                        if (img.mBitDepth <= 8) {
725                            return true;
726                        }
727                    }
728                }
729            }
730        }
731    } else if (index2 != OMX_IndexMax) {
732        status = getParam(omxNode, static_cast<OMX_INDEXTYPE>(index2),
733                          &describeParams);
734        android::MediaImage2& img = describeParams.sMediaImage;
735        if (img.mType == android::MediaImage2::MEDIA_IMAGE_TYPE_YUV) {
736            if (img.mNumPlanes == 3 &&
737                img.mPlane[img.Y].mHorizSubsampling == 1 &&
738                img.mPlane[img.Y].mVertSubsampling == 1) {
739                if (img.mPlane[img.U].mHorizSubsampling == 2 &&
740                    img.mPlane[img.U].mVertSubsampling == 2 &&
741                    img.mPlane[img.V].mHorizSubsampling == 2 &&
742                    img.mPlane[img.V].mVertSubsampling == 2) {
743                    if (img.mBitDepth <= 8) {
744                        return true;
745                    }
746                }
747            }
748        }
749    }
750    return false;
751}
752
753// get default color format for output port
754void getDefaultColorFormat(sp<IOmxNode> omxNode, OMX_U32 kPortIndexOutput,
755                           PortMode oPortMode,
756                           OMX_COLOR_FORMATTYPE* eColorFormat) {
757    android::hardware::media::omx::V1_0::Status status;
758    OMX_VIDEO_PARAM_PORTFORMATTYPE portFormat;
759    *eColorFormat = OMX_COLOR_FormatUnused;
760    portFormat.nIndex = 0;
761    while (portFormat.nIndex < 512) {
762        status = getPortParam(omxNode, OMX_IndexParamVideoPortFormat,
763                              kPortIndexOutput, &portFormat);
764        if (status != ::android::hardware::media::omx::V1_0::Status::OK) break;
765        EXPECT_EQ(portFormat.eCompressionFormat, OMX_VIDEO_CodingUnused);
766        if (oPortMode != PortMode::PRESET_BYTE_BUFFER) {
767            *eColorFormat = portFormat.eColorFormat;
768            break;
769        }
770        if (isColorFormatFlexibleYUV(omxNode, portFormat.eColorFormat)) {
771            *eColorFormat = portFormat.eColorFormat;
772            break;
773        }
774        if (OMX_COLOR_FormatYUV420SemiPlanar == portFormat.eColorFormat ||
775            OMX_COLOR_FormatYUV420Planar == portFormat.eColorFormat ||
776            OMX_COLOR_FormatYUV420PackedPlanar == portFormat.eColorFormat ||
777            OMX_COLOR_FormatYUV420PackedSemiPlanar == portFormat.eColorFormat) {
778            *eColorFormat = portFormat.eColorFormat;
779            break;
780        }
781        portFormat.nIndex++;
782    }
783}
784
785// set component role
786TEST_F(VideoDecHidlTest, SetRole) {
787    description("Test Set Component Role");
788    if (disableTest) return;
789    android::hardware::media::omx::V1_0::Status status;
790    status = setRole(omxNode, gEnv->getRole().c_str());
791    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
792}
793
794// port format enumeration
795TEST_F(VideoDecHidlTest, EnumeratePortFormat) {
796    description("Test Component on Mandatory Port Parameters (Port Format)");
797    if (disableTest) return;
798    android::hardware::media::omx::V1_0::Status status;
799    uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
800    OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatYUV420Planar;
801    OMX_U32 xFramerate = (24U << 16);
802    status = setRole(omxNode, gEnv->getRole().c_str());
803    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
804    OMX_PORT_PARAM_TYPE params;
805    status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
806    if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
807        ASSERT_EQ(params.nPorts, 2U);
808        kPortIndexInput = params.nStartPortNumber;
809        kPortIndexOutput = kPortIndexInput + 1;
810    }
811    status = setVideoPortFormat(omxNode, kPortIndexInput, eCompressionFormat,
812                                OMX_COLOR_FormatUnused, 0U);
813    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
814    status =
815        setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
816                           eColorFormat, xFramerate);
817    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
818}
819
820// test port settings reconfiguration, elementary stream decode and timestamp
821// deviation
822TEST_F(VideoDecHidlTest, DecodeTest) {
823    description("Tests Port Reconfiguration, Decode and timestamp deviation");
824    if (disableTest) return;
825    android::hardware::media::omx::V1_0::Status status;
826    uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
827    status = setRole(omxNode, gEnv->getRole().c_str());
828    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
829    OMX_PORT_PARAM_TYPE params;
830    status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
831    if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
832        ASSERT_EQ(params.nPorts, 2U);
833        kPortIndexInput = params.nStartPortNumber;
834        kPortIndexOutput = kPortIndexInput + 1;
835    }
836    char mURL[512], info[512];
837    strcpy(mURL, gEnv->getRes().c_str());
838    strcpy(info, gEnv->getRes().c_str());
839    GetURLForComponent(compName, mURL, info);
840
841    std::ifstream eleStream, eleInfo;
842
843    eleInfo.open(info);
844    ASSERT_EQ(eleInfo.is_open(), true);
845    android::Vector<FrameData> Info;
846    int bytesCount = 0, maxBytesCount = 0;
847    uint32_t flags = 0;
848    uint32_t timestamp = 0;
849    timestampDevTest = true;
850    while (1) {
851        if (!(eleInfo >> bytesCount)) break;
852        eleInfo >> flags;
853        eleInfo >> timestamp;
854        Info.push_back({bytesCount, flags, timestamp});
855        if (timestampDevTest && (flags != OMX_BUFFERFLAG_CODECCONFIG))
856            timestampUslist.push_back(timestamp);
857        if (maxBytesCount < bytesCount) maxBytesCount = bytesCount;
858    }
859    eleInfo.close();
860
861    // As the frame sizes are known ahead, use it to configure i/p buffer size
862    maxBytesCount = ALIGN_POWER_OF_TWO(maxBytesCount, 10);
863    status = setPortBufferSize(omxNode, kPortIndexInput, maxBytesCount);
864    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
865
866    // set port mode
867    portMode[0] = PortMode::PRESET_BYTE_BUFFER;
868    portMode[1] = PortMode::DYNAMIC_ANW_BUFFER;
869    status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
870    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
871    status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
872    if (status != ::android::hardware::media::omx::V1_0::Status::OK) {
873        portMode[1] = PortMode::PRESET_BYTE_BUFFER;
874        status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
875        ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
876    }
877
878    // set Port Params
879    uint32_t nFrameWidth, nFrameHeight, xFramerate;
880    getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight,
881                        &xFramerate);
882    // get default color format
883    OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
884    getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1],
885                          &eColorFormat);
886    ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused);
887    status =
888        setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
889                           eColorFormat, xFramerate);
890    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
891    setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
892                        eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate);
893
894    android::Vector<BufferInfo> iBuffer, oBuffer;
895
896    // set state to idle
897    ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(
898        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
899        kPortIndexOutput, portMode, true));
900    // set state to executing
901    ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
902
903    // Port Reconfiguration
904    eleStream.open(mURL, std::ifstream::binary);
905    ASSERT_EQ(eleStream.is_open(), true);
906    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
907        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
908        kPortIndexOutput, eleStream, &Info, 0, (int)Info.size(), portMode[1]));
909    eleStream.close();
910    ASSERT_NO_FATAL_FAILURE(
911        waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer,
912                               kPortIndexInput, kPortIndexOutput, portMode[1]));
913    ASSERT_NO_FATAL_FAILURE(testEOS(
914        omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode,
915        portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr));
916    if (timestampDevTest) EXPECT_EQ(timestampUslist.empty(), true);
917    // set state to idle
918    ASSERT_NO_FATAL_FAILURE(
919        changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
920    // set state to executing
921    ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer,
922                                                    &oBuffer, kPortIndexInput,
923                                                    kPortIndexOutput));
924}
925
926// Test for adaptive playback support
927TEST_F(VideoDecHidlTest, AdaptivePlaybackTest) {
928    description("Tests for Adaptive Playback support");
929    if (disableTest) return;
930    if (!(compName == avc || compName == hevc || compName == vp8 ||
931          compName == vp9 || compName == mpeg2))
932        return;
933    android::hardware::media::omx::V1_0::Status status;
934    uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
935    status = setRole(omxNode, gEnv->getRole().c_str());
936    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
937    OMX_PORT_PARAM_TYPE params;
938    status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
939    if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
940        ASSERT_EQ(params.nPorts, 2U);
941        kPortIndexInput = params.nStartPortNumber;
942        kPortIndexOutput = kPortIndexInput + 1;
943    }
944
945    // set port mode
946    portMode[0] = PortMode::PRESET_BYTE_BUFFER;
947    portMode[1] = PortMode::DYNAMIC_ANW_BUFFER;
948    status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
949    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
950    status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
951    if (status != ::android::hardware::media::omx::V1_0::Status::OK) {
952        portMode[1] = PortMode::PRESET_BYTE_BUFFER;
953        status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
954        ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
955    }
956
957    // prepare for adaptive playback
958    uint32_t adaptiveMaxWidth = 320;
959    uint32_t adaptiveMaxHeight = 240;
960    status = omxNode->prepareForAdaptivePlayback(
961        kPortIndexOutput, true, adaptiveMaxWidth, adaptiveMaxHeight);
962    if (strncmp(gEnv->getComponent().c_str(), "OMX.google.", 11) == 0) {
963        // SoftOMX Decoders donot support graphic buffer modes. So for them
964        // support for adaptive play back is mandatory in Byte Buffer mode
965        ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
966    } else {
967        // for vendor codecs, support for adaptive play back is optional
968        // in byte buffer mode.
969        if (portMode[1] == PortMode::PRESET_BYTE_BUFFER) return;
970        if (status != ::android::hardware::media::omx::V1_0::Status::OK) return;
971    }
972
973    // TODO: Handle this better !!!
974    // Without the knowledge of the maximum resolution of the frame to be
975    // decoded it is not possible to choose the size of the input buffer.
976    // The value below is based on the info. files of clips in res folder.
977    status = setPortBufferSize(omxNode, kPortIndexInput, 482304);
978    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
979
980    // set Port Params
981    uint32_t nFrameWidth, nFrameHeight, xFramerate;
982    getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight,
983                        &xFramerate);
984    // get default color format
985    OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
986    getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1],
987                          &eColorFormat);
988    ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused);
989    status =
990        setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
991                           eColorFormat, xFramerate);
992    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
993    setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
994                        eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate);
995
996    android::Vector<BufferInfo> iBuffer, oBuffer;
997
998    // set state to idle
999    ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(
1000        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
1001        kPortIndexOutput, portMode, true));
1002    // set state to executing
1003    ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1004
1005    timestampDevTest = true;
1006    uint32_t timestampOffset = 0;
1007    for (uint32_t i = 0; i < STREAM_COUNT * 2; i++) {
1008        std::ifstream eleStream, eleInfo;
1009        char mURL[512], info[512];
1010        android::Vector<FrameData> Info;
1011        strcpy(mURL, gEnv->getRes().c_str());
1012        strcpy(info, gEnv->getRes().c_str());
1013        GetURLForComponent(compName, mURL, info, i % STREAM_COUNT);
1014        eleInfo.open(info);
1015        ASSERT_EQ(eleInfo.is_open(), true);
1016        int bytesCount = 0;
1017        uint32_t flags = 0;
1018        uint32_t timestamp = 0;
1019        uint32_t timestampMax = 0;
1020        while (1) {
1021            if (!(eleInfo >> bytesCount)) break;
1022            eleInfo >> flags;
1023            eleInfo >> timestamp;
1024            timestamp += timestampOffset;
1025            Info.push_back({bytesCount, flags, timestamp});
1026            if (timestampDevTest && (flags != OMX_BUFFERFLAG_CODECCONFIG))
1027                timestampUslist.push_back(timestamp);
1028            if (timestampMax < timestamp) timestampMax = timestamp;
1029        }
1030        timestampOffset = timestampMax;
1031        eleInfo.close();
1032
1033        // Port Reconfiguration
1034        eleStream.open(mURL, std::ifstream::binary);
1035        ASSERT_EQ(eleStream.is_open(), true);
1036        ASSERT_NO_FATAL_FAILURE(
1037            decodeNFrames(omxNode, observer, &iBuffer, &oBuffer,
1038                          kPortIndexInput, kPortIndexOutput, eleStream, &Info,
1039                          0, (int)Info.size(), portMode[1], false));
1040        eleStream.close();
1041
1042        getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth,
1043                            &nFrameHeight, &xFramerate);
1044        if ((nFrameWidth > adaptiveMaxWidth) ||
1045            (nFrameHeight > adaptiveMaxHeight)) {
1046            if (nFrameWidth > adaptiveMaxWidth) adaptiveMaxWidth = nFrameWidth;
1047            if (nFrameHeight > adaptiveMaxHeight)
1048                adaptiveMaxHeight = nFrameHeight;
1049            EXPECT_TRUE(portSettingsChange);
1050        } else {
1051            // In DynamicANW Buffer mode, its ok to do a complete
1052            // reconfiguration even if a partial reconfiguration is sufficient.
1053            if (portMode[1] != PortMode::DYNAMIC_ANW_BUFFER)
1054                EXPECT_FALSE(portSettingsChange);
1055        }
1056        portSettingsChange = false;
1057    }
1058    ASSERT_NO_FATAL_FAILURE(
1059        waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer,
1060                               kPortIndexInput, kPortIndexOutput, portMode[1]));
1061    ASSERT_NO_FATAL_FAILURE(testEOS(
1062        omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode,
1063        portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr));
1064    if (timestampDevTest) EXPECT_EQ(timestampUslist.empty(), true);
1065    // set state to idle
1066    ASSERT_NO_FATAL_FAILURE(
1067        changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1068    // set state to executing
1069    ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer,
1070                                                    &oBuffer, kPortIndexInput,
1071                                                    kPortIndexOutput));
1072}
1073
1074// end of sequence test
1075TEST_F(VideoDecHidlTest, EOSTest_M) {
1076    description("Test End of stream monkeying");
1077    if (disableTest) return;
1078    android::hardware::media::omx::V1_0::Status status;
1079    uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1080    status = setRole(omxNode, gEnv->getRole().c_str());
1081    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1082    OMX_PORT_PARAM_TYPE params;
1083    status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
1084    if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1085        ASSERT_EQ(params.nPorts, 2U);
1086        kPortIndexInput = params.nStartPortNumber;
1087        kPortIndexOutput = kPortIndexInput + 1;
1088    }
1089
1090    // set port mode
1091    status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1092    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1093    status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1094    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1095
1096    // set Port Params
1097    uint32_t nFrameWidth, nFrameHeight, xFramerate;
1098    getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight,
1099                        &xFramerate);
1100    // get default color format
1101    OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
1102    getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1],
1103                          &eColorFormat);
1104    ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused);
1105    status =
1106        setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
1107                           eColorFormat, xFramerate);
1108    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1109    setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
1110                        eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate);
1111
1112    android::Vector<BufferInfo> iBuffer, oBuffer;
1113
1114    // set state to idle
1115    ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(
1116        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
1117        kPortIndexOutput, portMode, true));
1118    // set state to executing
1119    ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1120
1121    // request EOS at the start
1122    ASSERT_NO_FATAL_FAILURE(testEOS(
1123        omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode,
1124        portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr));
1125    ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer,
1126                                       kPortIndexInput, kPortIndexOutput));
1127    EXPECT_GE(framesReceived, 0U);
1128    framesReceived = 0;
1129    timestampUs = 0;
1130
1131    // set state to idle
1132    ASSERT_NO_FATAL_FAILURE(
1133        changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1134    // set state to executing
1135    ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer,
1136                                                    &oBuffer, kPortIndexInput,
1137                                                    kPortIndexOutput));
1138}
1139
1140// end of sequence test
1141TEST_F(VideoDecHidlTest, ThumbnailTest) {
1142    description("Test Request for thumbnail");
1143    if (disableTest) return;
1144    android::hardware::media::omx::V1_0::Status status;
1145    uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1146    status = setRole(omxNode, gEnv->getRole().c_str());
1147    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1148    OMX_PORT_PARAM_TYPE params;
1149    status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
1150    if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1151        ASSERT_EQ(params.nPorts, 2U);
1152        kPortIndexInput = params.nStartPortNumber;
1153        kPortIndexOutput = kPortIndexInput + 1;
1154    }
1155    char mURL[512], info[512];
1156    strcpy(mURL, gEnv->getRes().c_str());
1157    strcpy(info, gEnv->getRes().c_str());
1158    GetURLForComponent(compName, mURL, info);
1159
1160    std::ifstream eleStream, eleInfo;
1161
1162    eleInfo.open(info);
1163    ASSERT_EQ(eleInfo.is_open(), true);
1164    android::Vector<FrameData> Info;
1165    int bytesCount = 0, maxBytesCount = 0;
1166    uint32_t flags = 0;
1167    uint32_t timestamp = 0;
1168    while (1) {
1169        if (!(eleInfo >> bytesCount)) break;
1170        eleInfo >> flags;
1171        eleInfo >> timestamp;
1172        Info.push_back({bytesCount, flags, timestamp});
1173        if (maxBytesCount < bytesCount) maxBytesCount = bytesCount;
1174    }
1175    eleInfo.close();
1176
1177    // As the frame sizes are known ahead, use it to configure i/p buffer size
1178    maxBytesCount = ALIGN_POWER_OF_TWO(maxBytesCount, 10);
1179    status = setPortBufferSize(omxNode, kPortIndexInput, maxBytesCount);
1180    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1181
1182    // set port mode
1183    status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1184    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1185    status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1186    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1187
1188    // set Port Params
1189    uint32_t nFrameWidth, nFrameHeight, xFramerate;
1190    getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight,
1191                        &xFramerate);
1192    // get default color format
1193    OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
1194    getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1],
1195                          &eColorFormat);
1196    ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused);
1197    status =
1198        setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
1199                           eColorFormat, xFramerate);
1200    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1201    setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
1202                        eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate);
1203
1204    android::Vector<BufferInfo> iBuffer, oBuffer;
1205
1206    // set state to idle
1207    ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(
1208        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
1209        kPortIndexOutput, portMode, true));
1210    // set state to executing
1211    ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1212
1213    // request EOS for thumbnail
1214    size_t i = 0;
1215    while (!(Info[i].flags & OMX_BUFFERFLAG_SYNCFRAME)) i++;
1216    eleStream.open(mURL, std::ifstream::binary);
1217    ASSERT_EQ(eleStream.is_open(), true);
1218    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
1219        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
1220        kPortIndexOutput, eleStream, &Info, 0, i + 1, portMode[1]));
1221    eleStream.close();
1222    ASSERT_NO_FATAL_FAILURE(
1223        waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer,
1224                               kPortIndexInput, kPortIndexOutput, portMode[1]));
1225    ASSERT_NO_FATAL_FAILURE(testEOS(
1226        omxNode, observer, &iBuffer, &oBuffer, false, eosFlag, portMode,
1227        portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr));
1228    ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer,
1229                                       kPortIndexInput, kPortIndexOutput));
1230    EXPECT_GE(framesReceived, 1U);
1231    framesReceived = 0;
1232    timestampUs = 0;
1233
1234    eleStream.open(mURL, std::ifstream::binary);
1235    ASSERT_EQ(eleStream.is_open(), true);
1236    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
1237        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
1238        kPortIndexOutput, eleStream, &Info, 0, i + 1, portMode[1], false));
1239    eleStream.close();
1240    ASSERT_NO_FATAL_FAILURE(
1241        waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer,
1242                               kPortIndexInput, kPortIndexOutput, portMode[1]));
1243    ASSERT_NO_FATAL_FAILURE(testEOS(
1244        omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode,
1245        portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr));
1246    ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer,
1247                                       kPortIndexInput, kPortIndexOutput));
1248    EXPECT_GE(framesReceived, 1U);
1249    framesReceived = 0;
1250    timestampUs = 0;
1251
1252    // set state to idle
1253    ASSERT_NO_FATAL_FAILURE(
1254        changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1255    // set state to executing
1256    ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer,
1257                                                    &oBuffer, kPortIndexInput,
1258                                                    kPortIndexOutput));
1259}
1260
1261// end of sequence test
1262TEST_F(VideoDecHidlTest, SimpleEOSTest) {
1263    description("Test End of stream");
1264    if (disableTest) return;
1265    android::hardware::media::omx::V1_0::Status status;
1266    uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1267    status = setRole(omxNode, gEnv->getRole().c_str());
1268    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1269    OMX_PORT_PARAM_TYPE params;
1270    status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
1271    if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1272        ASSERT_EQ(params.nPorts, 2U);
1273        kPortIndexInput = params.nStartPortNumber;
1274        kPortIndexOutput = kPortIndexInput + 1;
1275    }
1276    char mURL[512], info[512];
1277    strcpy(mURL, gEnv->getRes().c_str());
1278    strcpy(info, gEnv->getRes().c_str());
1279    GetURLForComponent(compName, mURL, info);
1280
1281    std::ifstream eleStream, eleInfo;
1282
1283    eleInfo.open(info);
1284    ASSERT_EQ(eleInfo.is_open(), true);
1285    android::Vector<FrameData> Info;
1286    int bytesCount = 0, maxBytesCount = 0;
1287    uint32_t flags = 0;
1288    uint32_t timestamp = 0;
1289    while (1) {
1290        if (!(eleInfo >> bytesCount)) break;
1291        eleInfo >> flags;
1292        eleInfo >> timestamp;
1293        Info.push_back({bytesCount, flags, timestamp});
1294        if (maxBytesCount < bytesCount) maxBytesCount = bytesCount;
1295    }
1296    eleInfo.close();
1297
1298    // As the frame sizes are known ahead, use it to configure i/p buffer size
1299    maxBytesCount = ALIGN_POWER_OF_TWO(maxBytesCount, 10);
1300    status = setPortBufferSize(omxNode, kPortIndexInput, maxBytesCount);
1301    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1302
1303    // set port mode
1304    portMode[0] = PortMode::PRESET_BYTE_BUFFER;
1305    portMode[1] = PortMode::PRESET_ANW_BUFFER;
1306    status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1307    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1308    status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1309    if (status != ::android::hardware::media::omx::V1_0::Status::OK) {
1310        portMode[1] = PortMode::PRESET_BYTE_BUFFER;
1311        status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1312        ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1313    }
1314
1315    // set Port Params
1316    uint32_t nFrameWidth, nFrameHeight, xFramerate;
1317    getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight,
1318                        &xFramerate);
1319    // get default color format
1320    OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
1321    getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1],
1322                          &eColorFormat);
1323    ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused);
1324    status =
1325        setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
1326                           eColorFormat, xFramerate);
1327    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1328    setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
1329                        eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate);
1330
1331    android::Vector<BufferInfo> iBuffer, oBuffer;
1332
1333    // set state to idle
1334    ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(
1335        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
1336        kPortIndexOutput, portMode, true));
1337    // set state to executing
1338    ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1339
1340    // request EOS at the end
1341    eleStream.open(mURL, std::ifstream::binary);
1342    ASSERT_EQ(eleStream.is_open(), true);
1343    ASSERT_NO_FATAL_FAILURE(decodeNFrames(omxNode, observer, &iBuffer, &oBuffer,
1344                                          kPortIndexInput, kPortIndexOutput,
1345                                          eleStream, &Info, 0, (int)Info.size(),
1346                                          portMode[1], false));
1347    eleStream.close();
1348    ASSERT_NO_FATAL_FAILURE(
1349        waitOnInputConsumption(omxNode, observer, &iBuffer, &oBuffer,
1350                               kPortIndexInput, kPortIndexOutput, portMode[1]));
1351    ASSERT_NO_FATAL_FAILURE(testEOS(
1352        omxNode, observer, &iBuffer, &oBuffer, true, eosFlag, portMode,
1353        portReconfiguration, kPortIndexInput, kPortIndexOutput, nullptr));
1354    ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer,
1355                                       kPortIndexInput, kPortIndexOutput));
1356    framesReceived = 0;
1357    timestampUs = 0;
1358
1359    // set state to idle
1360    ASSERT_NO_FATAL_FAILURE(
1361        changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1362    // set state to executing
1363    ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer,
1364                                                    &oBuffer, kPortIndexInput,
1365                                                    kPortIndexOutput));
1366}
1367
1368// test input/output port flush
1369TEST_F(VideoDecHidlTest, FlushTest) {
1370    description("Test Flush");
1371    if (disableTest) return;
1372    android::hardware::media::omx::V1_0::Status status;
1373    uint32_t kPortIndexInput = 0, kPortIndexOutput = 1;
1374    status = setRole(omxNode, gEnv->getRole().c_str());
1375    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1376    OMX_PORT_PARAM_TYPE params;
1377    status = getParam(omxNode, OMX_IndexParamVideoInit, &params);
1378    if (status == ::android::hardware::media::omx::V1_0::Status::OK) {
1379        ASSERT_EQ(params.nPorts, 2U);
1380        kPortIndexInput = params.nStartPortNumber;
1381        kPortIndexOutput = kPortIndexInput + 1;
1382    }
1383    char mURL[512], info[512];
1384    strcpy(mURL, gEnv->getRes().c_str());
1385    strcpy(info, gEnv->getRes().c_str());
1386    GetURLForComponent(compName, mURL, info);
1387
1388    std::ifstream eleStream, eleInfo;
1389
1390    eleInfo.open(info);
1391    ASSERT_EQ(eleInfo.is_open(), true);
1392    android::Vector<FrameData> Info;
1393    int bytesCount = 0, maxBytesCount = 0;
1394    uint32_t flags = 0;
1395    uint32_t timestamp = 0;
1396    while (1) {
1397        if (!(eleInfo >> bytesCount)) break;
1398        eleInfo >> flags;
1399        eleInfo >> timestamp;
1400        Info.push_back({bytesCount, flags, timestamp});
1401        if (maxBytesCount < bytesCount) maxBytesCount = bytesCount;
1402    }
1403    eleInfo.close();
1404
1405    // As the frame sizes are known ahead, use it to configure i/p buffer size
1406    maxBytesCount = ALIGN_POWER_OF_TWO(maxBytesCount, 10);
1407    status = setPortBufferSize(omxNode, kPortIndexInput, maxBytesCount);
1408    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1409
1410    // set port mode
1411    status = omxNode->setPortMode(kPortIndexInput, portMode[0]);
1412    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1413    status = omxNode->setPortMode(kPortIndexOutput, portMode[1]);
1414    ASSERT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1415
1416    // set Port Params
1417    uint32_t nFrameWidth, nFrameHeight, xFramerate;
1418    getInputChannelInfo(omxNode, kPortIndexInput, &nFrameWidth, &nFrameHeight,
1419                        &xFramerate);
1420    // get default color format
1421    OMX_COLOR_FORMATTYPE eColorFormat = OMX_COLOR_FormatUnused;
1422    getDefaultColorFormat(omxNode, kPortIndexOutput, portMode[1],
1423                          &eColorFormat);
1424    ASSERT_NE(eColorFormat, OMX_COLOR_FormatUnused);
1425    status =
1426        setVideoPortFormat(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
1427                           eColorFormat, xFramerate);
1428    EXPECT_EQ(status, ::android::hardware::media::omx::V1_0::Status::OK);
1429    setDefaultPortParam(omxNode, kPortIndexOutput, OMX_VIDEO_CodingUnused,
1430                        eColorFormat, nFrameWidth, nFrameHeight, 0, xFramerate);
1431
1432    android::Vector<BufferInfo> iBuffer, oBuffer;
1433
1434    // set state to idle
1435    ASSERT_NO_FATAL_FAILURE(changeStateLoadedtoIdle(
1436        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
1437        kPortIndexOutput, portMode, true));
1438    // set state to executing
1439    ASSERT_NO_FATAL_FAILURE(changeStateIdletoExecute(omxNode, observer));
1440
1441    // Decode 128 frames and flush. here 128 is chosen to ensure there is a key
1442    // frame after this so that the below section can be convered for all
1443    // components
1444    int nFrames = 128;
1445    eleStream.open(mURL, std::ifstream::binary);
1446    ASSERT_EQ(eleStream.is_open(), true);
1447    ASSERT_NO_FATAL_FAILURE(decodeNFrames(
1448        omxNode, observer, &iBuffer, &oBuffer, kPortIndexInput,
1449        kPortIndexOutput, eleStream, &Info, 0, nFrames, portMode[1], false));
1450    ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer,
1451                                       kPortIndexInput, kPortIndexOutput));
1452    framesReceived = 0;
1453
1454    // Seek to next key frame and start decoding till the end
1455    int index = nFrames;
1456    bool keyFrame = false;
1457    while (index < (int)Info.size()) {
1458        if ((Info[index].flags & OMX_BUFFERFLAG_SYNCFRAME) ==
1459            OMX_BUFFERFLAG_SYNCFRAME) {
1460            timestampUs = Info[index - 1].timestamp;
1461            keyFrame = true;
1462            break;
1463        }
1464        eleStream.ignore(Info[index].bytesCount);
1465        index++;
1466    }
1467    if (keyFrame) {
1468        ASSERT_NO_FATAL_FAILURE(
1469            decodeNFrames(omxNode, observer, &iBuffer, &oBuffer,
1470                          kPortIndexInput, kPortIndexOutput, eleStream, &Info,
1471                          index, Info.size() - index, portMode[1], false));
1472    }
1473    eleStream.close();
1474    ASSERT_NO_FATAL_FAILURE(flushPorts(omxNode, observer, &iBuffer, &oBuffer,
1475                                       kPortIndexInput, kPortIndexOutput));
1476    framesReceived = 0;
1477
1478    // set state to idle
1479    ASSERT_NO_FATAL_FAILURE(
1480        changeStateExecutetoIdle(omxNode, observer, &iBuffer, &oBuffer));
1481    // set state to executing
1482    ASSERT_NO_FATAL_FAILURE(changeStateIdletoLoaded(omxNode, observer, &iBuffer,
1483                                                    &oBuffer, kPortIndexInput,
1484                                                    kPortIndexOutput));
1485}
1486
1487int main(int argc, char** argv) {
1488    gEnv = new ComponentTestEnvironment();
1489    ::testing::AddGlobalTestEnvironment(gEnv);
1490    ::testing::InitGoogleTest(&argc, argv);
1491    int status = gEnv->initFromOptions(argc, argv);
1492    if (status == 0) {
1493        status = RUN_ALL_TESTS();
1494        ALOGI("Test result = %d", status);
1495    }
1496    return status;
1497}
1498