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