• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 }