d3c25fb9444facd2f7161e9fd62d9d8ce507d9fc
[platform/framework/web/crosswalk.git] / src / third_party / webrtc / modules / video_coding / utility / frame_dropper.cc
1 /*
2  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3  *
4  *  Use of this source code is governed by a BSD-style license
5  *  that can be found in the LICENSE file in the root of the source
6  *  tree. An additional intellectual property rights grant can be found
7  *  in the file PATENTS.  All contributing project authors may
8  *  be found in the AUTHORS file in the root of the source tree.
9  */
10
11 #include "webrtc/modules/video_coding/utility/include/frame_dropper.h"
12
13 #include "webrtc/system_wrappers/interface/trace.h"
14
15 namespace webrtc
16 {
17
18 const float kDefaultKeyFrameSizeAvgKBits = 0.9f;
19 const float kDefaultKeyFrameRatio = 0.99f;
20 const float kDefaultDropRatioAlpha = 0.9f;
21 const float kDefaultDropRatioMax = 0.96f;
22 const float kDefaultMaxTimeToDropFrames = 4.0f;  // In seconds.
23
24 FrameDropper::FrameDropper()
25 :
26 _keyFrameSizeAvgKbits(kDefaultKeyFrameSizeAvgKBits),
27 _keyFrameRatio(kDefaultKeyFrameRatio),
28 _dropRatio(kDefaultDropRatioAlpha, kDefaultDropRatioMax),
29 _enabled(true),
30 _max_time_drops(kDefaultMaxTimeToDropFrames)
31 {
32     Reset();
33 }
34
35 FrameDropper::FrameDropper(float max_time_drops)
36 :
37 _keyFrameSizeAvgKbits(kDefaultKeyFrameSizeAvgKBits),
38 _keyFrameRatio(kDefaultKeyFrameRatio),
39 _dropRatio(kDefaultDropRatioAlpha, kDefaultDropRatioMax),
40 _enabled(true),
41 _max_time_drops(max_time_drops)
42 {
43     Reset();
44 }
45
46 void
47 FrameDropper::Reset()
48 {
49     _keyFrameRatio.Reset(0.99f);
50     _keyFrameRatio.Apply(1.0f, 1.0f/300.0f); // 1 key frame every 10th second in 30 fps
51     _keyFrameSizeAvgKbits.Reset(0.9f);
52     _keyFrameCount = 0;
53     _accumulator = 0.0f;
54     _accumulatorMax = 150.0f; // assume 300 kb/s and 0.5 s window
55     _targetBitRate = 300.0f;
56     _incoming_frame_rate = 30;
57     _keyFrameSpreadFrames = 0.5f * _incoming_frame_rate;
58     _dropNext = false;
59     _dropRatio.Reset(0.9f);
60     _dropRatio.Apply(0.0f, 0.0f); // Initialize to 0
61     _dropCount = 0;
62     _windowSize = 0.5f;
63     _wasBelowMax = true;
64     _fastMode = false; // start with normal (non-aggressive) mode
65     // Cap for the encoder buffer level/accumulator, in secs.
66     _cap_buffer_size = 3.0f;
67     // Cap on maximum amount of dropped frames between kept frames, in secs.
68     _max_time_drops = 4.0f;
69 }
70
71 void
72 FrameDropper::Enable(bool enable)
73 {
74     _enabled = enable;
75 }
76
77 void
78 FrameDropper::Fill(uint32_t frameSizeBytes, bool deltaFrame)
79 {
80     if (!_enabled)
81     {
82         return;
83     }
84     float frameSizeKbits = 8.0f * static_cast<float>(frameSizeBytes) / 1000.0f;
85     if (!deltaFrame && !_fastMode) // fast mode does not treat key-frames any different
86     {
87         _keyFrameSizeAvgKbits.Apply(1, frameSizeKbits);
88         _keyFrameRatio.Apply(1.0, 1.0);
89         if (frameSizeKbits > _keyFrameSizeAvgKbits.Value())
90         {
91             // Remove the average key frame size since we
92             // compensate for key frames when adding delta
93             // frames.
94             frameSizeKbits -= _keyFrameSizeAvgKbits.Value();
95         }
96         else
97         {
98             // Shouldn't be negative, so zero is the lower bound.
99             frameSizeKbits = 0;
100         }
101         if (_keyFrameRatio.Value() > 1e-5 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
102         {
103             // We are sending key frames more often than our upper bound for
104             // how much we allow the key frame compensation to be spread
105             // out in time. Therefor we must use the key frame ratio rather
106             // than keyFrameSpreadFrames.
107             _keyFrameCount = static_cast<int32_t>(1 / _keyFrameRatio.Value() + 0.5);
108         }
109         else
110         {
111             // Compensate for the key frame the following frames
112             _keyFrameCount = static_cast<int32_t>(_keyFrameSpreadFrames + 0.5);
113         }
114     }
115     else
116     {
117         // Decrease the keyFrameRatio
118         _keyFrameRatio.Apply(1.0, 0.0);
119     }
120     // Change the level of the accumulator (bucket)
121     _accumulator += frameSizeKbits;
122     CapAccumulator();
123 }
124
125 void
126 FrameDropper::Leak(uint32_t inputFrameRate)
127 {
128     if (!_enabled)
129     {
130         return;
131     }
132     if (inputFrameRate < 1)
133     {
134         return;
135     }
136     if (_targetBitRate < 0.0f)
137     {
138         return;
139     }
140     _keyFrameSpreadFrames = 0.5f * inputFrameRate;
141     // T is the expected bits per frame (target). If all frames were the same size,
142     // we would get T bits per frame. Notice that T is also weighted to be able to
143     // force a lower frame rate if wanted.
144     float T = _targetBitRate / inputFrameRate;
145     if (_keyFrameCount > 0)
146     {
147         // Perform the key frame compensation
148         if (_keyFrameRatio.Value() > 0 && 1 / _keyFrameRatio.Value() < _keyFrameSpreadFrames)
149         {
150             T -= _keyFrameSizeAvgKbits.Value() * _keyFrameRatio.Value();
151         }
152         else
153         {
154             T -= _keyFrameSizeAvgKbits.Value() / _keyFrameSpreadFrames;
155         }
156         _keyFrameCount--;
157     }
158     _accumulator -= T;
159     if (_accumulator < 0.0f)
160     {
161         _accumulator = 0.0f;
162     }
163     UpdateRatio();
164 }
165
166 void
167 FrameDropper::UpdateNack(uint32_t nackBytes)
168 {
169     if (!_enabled)
170     {
171         return;
172     }
173     _accumulator += static_cast<float>(nackBytes) * 8.0f / 1000.0f;
174 }
175
176 void
177 FrameDropper::FillBucket(float inKbits, float outKbits)
178 {
179     _accumulator += (inKbits - outKbits);
180 }
181
182 void
183 FrameDropper::UpdateRatio()
184 {
185     if (_accumulator > 1.3f * _accumulatorMax)
186     {
187         // Too far above accumulator max, react faster
188         _dropRatio.UpdateBase(0.8f);
189     }
190     else
191     {
192         // Go back to normal reaction
193         _dropRatio.UpdateBase(0.9f);
194     }
195     if (_accumulator > _accumulatorMax)
196     {
197         // We are above accumulator max, and should ideally
198         // drop a frame. Increase the dropRatio and drop
199         // the frame later.
200         if (_wasBelowMax)
201         {
202             _dropNext = true;
203         }
204         if (_fastMode)
205         {
206             // always drop in aggressive mode
207             _dropNext = true;
208         }
209
210         _dropRatio.Apply(1.0f, 1.0f);
211         _dropRatio.UpdateBase(0.9f);
212     }
213     else
214     {
215         _dropRatio.Apply(1.0f, 0.0f);
216     }
217     _wasBelowMax = _accumulator < _accumulatorMax;
218 }
219
220 // This function signals when to drop frames to the caller. It makes use of the dropRatio
221 // to smooth out the drops over time.
222 bool
223 FrameDropper::DropFrame()
224 {
225     if (!_enabled)
226     {
227         return false;
228     }
229     if (_dropNext)
230     {
231         _dropNext = false;
232         _dropCount = 0;
233     }
234
235     if (_dropRatio.Value() >= 0.5f) // Drops per keep
236     {
237         // limit is the number of frames we should drop between each kept frame
238         // to keep our drop ratio. limit is positive in this case.
239         float denom = 1.0f - _dropRatio.Value();
240         if (denom < 1e-5)
241         {
242             denom = (float)1e-5;
243         }
244         int32_t limit = static_cast<int32_t>(1.0f / denom - 1.0f + 0.5f);
245         // Put a bound on the max amount of dropped frames between each kept
246         // frame, in terms of frame rate and window size (secs).
247         int max_limit = static_cast<int>(_incoming_frame_rate *
248                                          _max_time_drops);
249         if (limit > max_limit) {
250           limit = max_limit;
251         }
252         if (_dropCount < 0)
253         {
254             // Reset the _dropCount since it was negative and should be positive.
255             if (_dropRatio.Value() > 0.4f)
256             {
257                 _dropCount = -_dropCount;
258             }
259             else
260             {
261                 _dropCount = 0;
262             }
263         }
264         if (_dropCount < limit)
265         {
266             // As long we are below the limit we should drop frames.
267             _dropCount++;
268             return true;
269         }
270         else
271         {
272             // Only when we reset _dropCount a frame should be kept.
273             _dropCount = 0;
274             return false;
275         }
276     }
277     else if (_dropRatio.Value() > 0.0f && _dropRatio.Value() < 0.5f) // Keeps per drop
278     {
279         // limit is the number of frames we should keep between each drop
280         // in order to keep the drop ratio. limit is negative in this case,
281         // and the _dropCount is also negative.
282         float denom = _dropRatio.Value();
283         if (denom < 1e-5)
284         {
285             denom = (float)1e-5;
286         }
287         int32_t limit = -static_cast<int32_t>(1.0f / denom - 1.0f + 0.5f);
288         if (_dropCount > 0)
289         {
290             // Reset the _dropCount since we have a positive
291             // _dropCount, and it should be negative.
292             if (_dropRatio.Value() < 0.6f)
293             {
294                 _dropCount = -_dropCount;
295             }
296             else
297             {
298                 _dropCount = 0;
299             }
300         }
301         if (_dropCount > limit)
302         {
303             if (_dropCount == 0)
304             {
305                 // Drop frames when we reset _dropCount.
306                 _dropCount--;
307                 return true;
308             }
309             else
310             {
311                 // Keep frames as long as we haven't reached limit.
312                 _dropCount--;
313                 return false;
314             }
315         }
316         else
317         {
318             _dropCount = 0;
319             return false;
320         }
321     }
322     _dropCount = 0;
323     return false;
324
325     // A simpler version, unfiltered and quicker
326     //bool dropNext = _dropNext;
327     //_dropNext = false;
328     //return dropNext;
329 }
330
331 void
332 FrameDropper::SetRates(float bitRate, float incoming_frame_rate)
333 {
334     // Bit rate of -1 means infinite bandwidth.
335     _accumulatorMax = bitRate * _windowSize; // bitRate * windowSize (in seconds)
336     if (_targetBitRate > 0.0f && bitRate < _targetBitRate && _accumulator > _accumulatorMax)
337     {
338         // Rescale the accumulator level if the accumulator max decreases
339         _accumulator = bitRate / _targetBitRate * _accumulator;
340     }
341     _targetBitRate = bitRate;
342     CapAccumulator();
343     _incoming_frame_rate = incoming_frame_rate;
344 }
345
346 float
347 FrameDropper::ActualFrameRate(uint32_t inputFrameRate) const
348 {
349     if (!_enabled)
350     {
351         return static_cast<float>(inputFrameRate);
352     }
353     return inputFrameRate * (1.0f - _dropRatio.Value());
354 }
355
356 // Put a cap on the accumulator, i.e., don't let it grow beyond some level.
357 // This is a temporary fix for screencasting where very large frames from
358 // encoder will cause very slow response (too many frame drops).
359 void FrameDropper::CapAccumulator() {
360   float max_accumulator = _targetBitRate * _cap_buffer_size;
361   if (_accumulator > max_accumulator) {
362     _accumulator = max_accumulator;
363   }
364 }
365
366 }