1 /*
2  * Copyright (C) 2018 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_NDEBUG 0
18 #define LOG_TAG "media_c2_hidl_test_common"
19 #include <stdio.h>
20 
21 #include "media_c2_hidl_test_common.h"
22 
23 // Test the codecs for NullBuffer, Empty Input Buffer with(out) flags set
testInputBuffer(const std::shared_ptr<android::Codec2Client::Component> & component,std::mutex & queueLock,std::list<std::unique_ptr<C2Work>> & workQueue,uint32_t flags,bool isNullBuffer)24 void testInputBuffer(
25     const std::shared_ptr<android::Codec2Client::Component>& component,
26     std::mutex& queueLock, std::list<std::unique_ptr<C2Work>>& workQueue,
27     uint32_t flags, bool isNullBuffer) {
28     std::unique_ptr<C2Work> work;
29     {
30         typedef std::unique_lock<std::mutex> ULock;
31         ULock l(queueLock);
32         if (!workQueue.empty()) {
33             work.swap(workQueue.front());
34             workQueue.pop_front();
35         } else {
36             ASSERT_TRUE(false) << "workQueue Empty at the start of test";
37         }
38     }
39     ASSERT_NE(work, nullptr);
40 
41     work->input.flags = (C2FrameData::flags_t)flags;
42     work->input.ordinal.timestamp = 0;
43     work->input.ordinal.frameIndex = 0;
44     work->input.buffers.clear();
45     if (isNullBuffer) {
46         work->input.buffers.emplace_back(nullptr);
47     }
48     work->worklets.clear();
49     work->worklets.emplace_back(new C2Worklet);
50 
51     std::list<std::unique_ptr<C2Work>> items;
52     items.push_back(std::move(work));
53     ASSERT_EQ(component->queue(&items), C2_OK);
54 }
55 
56 // Wait for all the inputs to be consumed by the plugin.
waitOnInputConsumption(std::mutex & queueLock,std::condition_variable & queueCondition,std::list<std::unique_ptr<C2Work>> & workQueue,size_t bufferCount)57 void waitOnInputConsumption(std::mutex& queueLock,
58                             std::condition_variable& queueCondition,
59                             std::list<std::unique_ptr<C2Work>>& workQueue,
60                             size_t bufferCount) {
61     typedef std::unique_lock<std::mutex> ULock;
62     uint32_t queueSize;
63     uint32_t maxRetry = 0;
64     {
65         ULock l(queueLock);
66         queueSize = workQueue.size();
67     }
68     while ((maxRetry < MAX_RETRY) && (queueSize < bufferCount)) {
69         ULock l(queueLock);
70         if (queueSize != workQueue.size()) {
71             queueSize = workQueue.size();
72             maxRetry = 0;
73         } else {
74             queueCondition.wait_for(l, TIME_OUT);
75             maxRetry++;
76         }
77     }
78 }
79 
80 // process onWorkDone received by Listener
workDone(const std::shared_ptr<android::Codec2Client::Component> & component,std::unique_ptr<C2Work> & work,std::list<uint64_t> & flushedIndices,std::mutex & queueLock,std::condition_variable & queueCondition,std::list<std::unique_ptr<C2Work>> & workQueue,bool & eos,bool & csd,uint32_t & framesReceived)81 void workDone(
82     const std::shared_ptr<android::Codec2Client::Component>& component,
83     std::unique_ptr<C2Work>& work, std::list<uint64_t>& flushedIndices,
84     std::mutex& queueLock, std::condition_variable& queueCondition,
85     std::list<std::unique_ptr<C2Work>>& workQueue, bool& eos, bool& csd,
86     uint32_t& framesReceived) {
87     // handle configuration changes in work done
88     if (work->worklets.front()->output.configUpdate.size() != 0) {
89         ALOGV("Config Update");
90         std::vector<std::unique_ptr<C2Param>> updates =
91             std::move(work->worklets.front()->output.configUpdate);
92         std::vector<C2Param*> configParam;
93         std::vector<std::unique_ptr<C2SettingResult>> failures;
94         for (size_t i = 0; i < updates.size(); ++i) {
95             C2Param* param = updates[i].get();
96             if (param->index() == C2StreamInitDataInfo::output::PARAM_TYPE) {
97                 csd = true;
98             } else if ((param->index() ==
99                         C2StreamSampleRateInfo::output::PARAM_TYPE) ||
100                        (param->index() ==
101                         C2StreamChannelCountInfo::output::PARAM_TYPE) ||
102                        (param->index() ==
103                         C2StreamPictureSizeInfo::output::PARAM_TYPE)) {
104                 configParam.push_back(param);
105             }
106         }
107         component->config(configParam, C2_DONT_BLOCK, &failures);
108         ASSERT_EQ(failures.size(), 0u);
109     }
110     if (work->worklets.front()->output.flags != C2FrameData::FLAG_INCOMPLETE) {
111         framesReceived++;
112         eos = (work->worklets.front()->output.flags &
113                C2FrameData::FLAG_END_OF_STREAM) != 0;
114         auto frameIndexIt = std::find(flushedIndices.begin(), flushedIndices.end(),
115                                       work->input.ordinal.frameIndex.peeku());
116         ALOGV("WorkDone: frameID received %d",
117               (int)work->worklets.front()->output.ordinal.frameIndex.peeku());
118         work->input.buffers.clear();
119         work->worklets.clear();
120         {
121             typedef std::unique_lock<std::mutex> ULock;
122             ULock l(queueLock);
123             workQueue.push_back(std::move(work));
124             if (!flushedIndices.empty()) {
125                 flushedIndices.erase(frameIndexIt);
126             }
127             queueCondition.notify_all();
128         }
129     }
130 }
131 
132 // Return current time in micro seconds
getNowUs()133 int64_t getNowUs() {
134     struct timeval tv;
135     gettimeofday(&tv, NULL);
136 
137     return (int64_t)tv.tv_usec + tv.tv_sec * 1000000ll;
138 }
139