1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "fps_controller_process.h"
17
18 #include "dcamera_utils_tools.h"
19 #include "distributed_camera_errno.h"
20 #include "distributed_hardware_log.h"
21
22 namespace OHOS {
23 namespace DistributedHardware {
~FpsControllerProcess()24 FpsControllerProcess::~FpsControllerProcess()
25 {
26 if (isFpsControllerProcess_) {
27 DHLOGD("~DecodeDataProcess : ReleaseProcessNode.");
28 ReleaseProcessNode();
29 }
30 }
31
InitNode()32 int32_t FpsControllerProcess::InitNode()
33 {
34 if (targetConfig_.GetFrameRate() > MAX_TARGET_FRAME_RATE) {
35 DHLOGE("The target framerate : %d is greater than the max framerate : %d.",
36 targetConfig_.GetFrameRate(), MAX_TARGET_FRAME_RATE);
37 return DCAMERA_BAD_TYPE;
38 }
39 targetFrameRate_ = targetConfig_.GetFrameRate();
40 isFpsControllerProcess_ = true;
41 return DCAMERA_OK;
42 }
43
ReleaseProcessNode()44 void FpsControllerProcess::ReleaseProcessNode()
45 {
46 DHLOGD("Start release [%d] node : FPS controller.", nodeRank_);
47 if (nextDataProcess_ != nullptr) {
48 nextDataProcess_->ReleaseProcessNode();
49 }
50
51 isFpsControllerProcess_ = false;
52 isFirstFrame_ = false;
53 targetFrameRate_ = 0;
54 lastFrameIncomeTimeMs_ = 0;
55 recentFrameTimeSpanMs_ = -1;
56 keepCorrectionCount_ = 0;
57 keepLessThanDoubleCount_ = 0;
58 keepMoreThanDoubleCount_ = 0;
59 frameRateCorrectionFactor_ = 0.0;
60 frameRateOvershootMdf_ = 0;
61 for (int i = 0; i < INCOME_FRAME_TIME_HISTORY_WINDOWS_SIZE; i++) {
62 incomingFrameTimesMs_[i] = 0;
63 }
64 }
65
ProcessData(std::vector<std::shared_ptr<DataBuffer>> & inputBuffers)66 int32_t FpsControllerProcess::ProcessData(std::vector<std::shared_ptr<DataBuffer>>& inputBuffers)
67 {
68 if (inputBuffers.empty()) {
69 DHLOGE("Data buffers is null.");
70 return DCAMERA_BAD_TYPE;
71 }
72 if (!isFpsControllerProcess_) {
73 DHLOGE("Decoder node occurred error.");
74 return DCAMERA_DISABLE_PROCESS;
75 }
76 int64_t timeStampUs = 0;
77 if (!inputBuffers[0]->FindInt64("timeUs", timeStampUs)) {
78 DHLOGE("Find decoder output timestamp fail.");
79 return DCAMERA_BAD_TYPE;
80 }
81
82 std::lock_guard<std::mutex> lck (mtx);
83 int64_t nowTimeMs = GetNowTimeStampMs();
84 UpdateFPSControllerInfo(nowTimeMs);
85
86 float curFrameRate = CalculateFrameRate(nowTimeMs);
87 if (IsDropFrame(curFrameRate)) {
88 DHLOGD("frame control, currect frameRate %u, targetRate %u, drop it", curFrameRate, targetFrameRate_);
89 return DCAMERA_OK;
90 }
91
92 DHLOGD("frame control render PushVideoFrame, frame info width %d height %d, timeStampUs %lld, fps %d",
93 sourceConfig_.GetWidth(), sourceConfig_.GetHeight(), (long long)timeStampUs, curFrameRate);
94 return FpsControllerDone(inputBuffers);
95 }
96
UpdateFPSControllerInfo(int64_t nowMs)97 void FpsControllerProcess::UpdateFPSControllerInfo(int64_t nowMs)
98 {
99 DHLOGD("Frame control, update control info.");
100 if (targetFrameRate_ <= 0) {
101 DHLOGD("Frame control, targetFrameRate_ : %d", targetFrameRate_);
102 return;
103 }
104
105 isFirstFrame_ = false;
106 if (lastFrameIncomeTimeMs_ == 0) {
107 DHLOGD("Frame control, income fisrt frame.");
108 isFirstFrame_ = true;
109 }
110 lastFrameIncomeTimeMs_ = nowMs;
111 recentFrameTimeSpanMs_ = nowMs - lastFrameIncomeTimeMs_;
112 DHLOGD("Frame control, lastFrameIncomeTimeMs_ %lld, receive Frame after last frame(ms): %lld",
113 (long long)lastFrameIncomeTimeMs_, (long long)recentFrameTimeSpanMs_);
114 UpdateIncomingFrameTimes(nowMs);
115 UpdateFrameRateCorrectionFactor(nowMs);
116 return;
117 }
118
UpdateFrameRateCorrectionFactor(int64_t nowMs)119 void FpsControllerProcess::UpdateFrameRateCorrectionFactor(int64_t nowMs)
120 {
121 DHLOGD("Frame control, update FPS correction factor.");
122 if (targetFrameRate_ <= 0) {
123 DHLOGD("Frame control, targetFrameRate_ : %d", targetFrameRate_);
124 return;
125 }
126 if (isFirstFrame_) {
127 DHLOGD("No frame rate correction factor when the first frame.");
128 return;
129 }
130
131 const float minDropFrmValue = 0.5;
132 const float maxDropFrmValue = 1.0;
133 const float msPerSecond = 1000;
134 const float maxInstantaneousFrameRateCoefficient = 1.1;
135 float maxInstantaneousFrameRateThreshold = targetFrameRate_ * maxInstantaneousFrameRateCoefficient;
136 float instantaneousFrameRate = msPerSecond / recentFrameTimeSpanMs_;
137 if (instantaneousFrameRate < 0) {
138 instantaneousFrameRate = -instantaneousFrameRate;
139 }
140 if (instantaneousFrameRate <= maxInstantaneousFrameRateThreshold) {
141 frameRateCorrectionFactor_ = minDropFrmValue;
142 } else {
143 if (keepCorrectionCount_ >= VIDEO_FRAME_DROP_INTERVAL) {
144 frameRateCorrectionFactor_ = maxDropFrmValue;
145 keepCorrectionCount_ = 0;
146 } else {
147 frameRateCorrectionFactor_ = 0;
148 keepCorrectionCount_++;
149 }
150 DHLOGD("Frame control, instantaneousFrameRate %.3f is more than maxInstantaneousFrameRateThreshold %.3f, " +
151 "keepCorrectionCount %d", instantaneousFrameRate, maxInstantaneousFrameRateThreshold,
152 keepCorrectionCount_);
153 }
154
155 DHLOGD("Frame control, targetFramerate %d, maxInstantaneousFrameRateThreshold %.3f," +
156 "instantaneousFrameRate %.3f, frameRateCorrectionFactor %.3f", targetFrameRate_,
157 maxInstantaneousFrameRateThreshold, instantaneousFrameRate, frameRateCorrectionFactor_);
158 return;
159 }
160
UpdateIncomingFrameTimes(int64_t nowMs)161 void FpsControllerProcess::UpdateIncomingFrameTimes(int64_t nowMs)
162 {
163 DHLOGD("Frame control, update incoming frame times array.");
164 if (targetFrameRate_ <= 0) {
165 DHLOGD("Frame control, targetFrameRate_ : %d", targetFrameRate_);
166 return;
167 }
168 if (isFirstFrame_) {
169 incomingFrameTimesMs_[0] = nowMs;
170 return;
171 }
172
173 int64_t intervalNewAndFirst = nowMs - incomingFrameTimesMs_[0];
174 if (intervalNewAndFirst < 0) {
175 intervalNewAndFirst = -intervalNewAndFirst;
176 }
177 if (intervalNewAndFirst > FRMAE_MAX_INTERVAL_TIME_WINDOW_MS) {
178 DHLOGD("frame control, nowMs: %lld mIncomingFrameT[0]: %lld intervalNewAndFirst: %lld",
179 (long long)nowMs, (long long)incomingFrameTimesMs_[0], (long long)intervalNewAndFirst);
180 for (int i = 0; i < INCOME_FRAME_TIME_HISTORY_WINDOWS_SIZE; i++) {
181 incomingFrameTimesMs_[i] = 0;
182 }
183 } else {
184 DHLOGD("frame control shift, nowMs: %lld mIncomingFrameT[0]: %lld intervalNewAndFirst: %lld",
185 (long long)nowMs, (long long)incomingFrameTimesMs_[0], (long long)intervalNewAndFirst);
186 const int32_t windowLeftNum = 2;
187 for (int i = (INCOME_FRAME_TIME_HISTORY_WINDOWS_SIZE - windowLeftNum); i >= 0; --i) {
188 incomingFrameTimesMs_[i + 1] = incomingFrameTimesMs_[i];
189 }
190 }
191 incomingFrameTimesMs_[0] = nowMs;
192 return;
193 }
194
CalculateFrameRate(int64_t nowMs)195 float FpsControllerProcess::CalculateFrameRate(int64_t nowMs)
196 {
197 DHLOGD("Frame control, calculate frame rate.");
198 if (targetFrameRate_ <= 0) {
199 DHLOGE("Frame control, targetFrameRate_ : %d", targetFrameRate_);
200 return 0.0;
201 }
202
203 int32_t num = 0;
204 int32_t validFramesNumber = 0;
205 if (nowMs < 0) {
206 nowMs = -nowMs;
207 }
208 for (; num < INCOME_FRAME_TIME_HISTORY_WINDOWS_SIZE; num++) {
209 if (incomingFrameTimesMs_[num] <= 0 || nowMs - incomingFrameTimesMs_[num] > FRAME_HISTORY_TIME_WINDOWS_MS) {
210 break;
211 } else {
212 validFramesNumber++;
213 }
214 }
215
216 const float msPerSecond = 1000;
217 const int32_t minValidCalculatedFrameRatesNum = 2;
218 int32_t minIncomingFrameNum = static_cast<int32_t>(targetFrameRate_) / MIN_INCOME_FRAME_NUM_COEFFICIENT;
219 if (validFramesNumber > minIncomingFrameNum && validFramesNumber > minValidCalculatedFrameRatesNum) {
220 int64_t validTotalTimeDifference = (nowMs - incomingFrameTimesMs_[num - 1]);
221 if (validTotalTimeDifference < 0) {
222 validTotalTimeDifference = -validTotalTimeDifference;
223 }
224 if (validTotalTimeDifference > 0) {
225 return validFramesNumber * msPerSecond / validTotalTimeDifference + frameRateCorrectionFactor_;
226 }
227 }
228 return static_cast<float>(validFramesNumber);
229 }
230
IsDropFrame(float incomingFps)231 bool FpsControllerProcess::IsDropFrame(float incomingFps)
232 {
233 DHLOGD("Frame control, IsDropFrame");
234 if (targetFrameRate_ == 0) {
235 DHLOGD("target fps is 0, drop all frame.");
236 return true;
237 }
238 if (incomingFps <= 0) {
239 DHLOGD("incoming fps not more than 0, not drop");
240 return false;
241 }
242 const int32_t incomingFrmRate = static_cast<int32_t>(incomingFps);
243 if (incomingFrmRate > static_cast<int32_t>(targetFrameRate_)) {
244 DHLOGD("incoming fps not more than targetFrameRate_, not drop");
245 return false;
246 }
247 bool isDrop = ReduceFrameRateByUniformStrategy(incomingFrmRate);
248 DHLOGD("drop frame result: %s", isDrop ? "drop" : "no drop");
249 return isDrop;
250 }
251
ReduceFrameRateByUniformStrategy(int32_t incomingFrmRate)252 bool FpsControllerProcess::ReduceFrameRateByUniformStrategy(int32_t incomingFrmRate)
253 {
254 DHLOGD("Frame control, reduce frame rate by uniform rate strategy");
255 if (incomingFrmRate > static_cast<int32_t>(targetFrameRate_)) {
256 DHLOGD("incoming fps not more than targetFrameRate_, not drop");
257 return false;
258 }
259
260 /*
261 * When the actual incoming frame rate correction value is greater than the target frame
262 * rate, the incoming frames are reduced uniformly.
263 */
264 bool isDrop = false;
265 int32_t overshoot = frameRateOvershootMdf_ + (incomingFrmRate - targetFrameRate_);
266 if (overshoot < 0) {
267 overshoot = 0;
268 frameRateOvershootMdf_ = 0;
269 }
270 if (overshoot && DOUBLE_MULTIPLE * overshoot < incomingFrmRate) {
271 /*
272 * When the actual input frame rate is less than or equal to twice the target frame rate,
273 * one frame is droped every (incomingFrmRate / overshoot) frames.
274 */
275 if (keepMoreThanDoubleCount_) {
276 keepMoreThanDoubleCount_ = 0;
277 return true;
278 }
279 const int32_t dropVar = incomingFrmRate / overshoot;
280 if (keepLessThanDoubleCount_ >= dropVar) {
281 isDrop = true;
282 frameRateOvershootMdf_ = -(incomingFrmRate % overshoot) / OVERSHOOT_MODIFY_COEFFICIENT;
283 keepLessThanDoubleCount_ = 1;
284 } else {
285 keepLessThanDoubleCount_++;
286 }
287 } else {
288 /*
289 * When the actual frame rate is more than twice the target frame rate or the overshoot is
290 * equal to 0, one frame is reserved every (overshoot / targetFrameRate_) frames.
291 */
292 keepLessThanDoubleCount_ = 0;
293 const int32_t dropVar = overshoot / targetFrameRate_;
294 if (keepMoreThanDoubleCount_ < dropVar) {
295 isDrop = true;
296 keepMoreThanDoubleCount_++;
297 } else {
298 frameRateOvershootMdf_ = overshoot % static_cast<int32_t>(targetFrameRate_);
299 isDrop = false;
300 keepMoreThanDoubleCount_ = 0;
301 }
302 }
303 return isDrop;
304 }
305
FpsControllerDone(std::vector<std::shared_ptr<DataBuffer>> outputBuffers)306 int32_t FpsControllerProcess::FpsControllerDone(std::vector<std::shared_ptr<DataBuffer>> outputBuffers)
307 {
308 if (outputBuffers.empty()) {
309 DHLOGE("The received data buffers is empty.");
310 return DCAMERA_BAD_VALUE;
311 }
312
313 if (nextDataProcess_ != nullptr) {
314 DHLOGD("Send to the next node of the FpsController for processing.");
315 int32_t err = nextDataProcess_->ProcessData(outputBuffers);
316 if (err != DCAMERA_OK) {
317 DHLOGE("Someone node after the FpsController processes fail.");
318 }
319 return err;
320 }
321 DHLOGD("The current node is the last node, and Output the processed video buffer");
322 std::shared_ptr<DCameraPipelineSource> targetPipelineSource = callbackPipelineSource_.lock();
323 if (targetPipelineSource == nullptr) {
324 DHLOGE("callbackPipelineSource_ is nullptr.");
325 return DCAMERA_BAD_VALUE;
326 }
327 targetPipelineSource->OnProcessedVideoBuffer(outputBuffers[0]);
328 return DCAMERA_OK;
329 }
330 }
331 }