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