blob: d41e53008c5fce87ffbf0a3438e0640e665c8574 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
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
Henrik Kjellander2557b862015-11-18 22:00:21 +010011#include "webrtc/modules/video_coding/timing.h"
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000012
philipel5908c712015-12-21 08:23:20 -080013#include <algorithm>
14
Henrik Kjellander2557b862015-11-18 22:00:21 +010015#include "webrtc/modules/video_coding/internal_defines.h"
16#include "webrtc/modules/video_coding/jitter_buffer_common.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010017#include "webrtc/system_wrappers/include/clock.h"
18#include "webrtc/system_wrappers/include/metrics.h"
19#include "webrtc/system_wrappers/include/timestamp_extrapolator.h"
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000020
niklase@google.com470e71d2011-07-07 08:21:25 +000021namespace webrtc {
22
philipel5908c712015-12-21 08:23:20 -080023VCMTiming::VCMTiming(Clock* clock, VCMTiming* master_timing)
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000024 : crit_sect_(CriticalSectionWrapper::CreateCriticalSection()),
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000025 clock_(clock),
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000026 master_(false),
27 ts_extrapolator_(),
magjed2943f012016-03-22 05:12:09 -070028 codec_timer_(new VCMCodecTimer()),
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000029 render_delay_ms_(kDefaultRenderDelayMs),
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000030 min_playout_delay_ms_(0),
isheriff6b4b5f32016-06-08 00:24:21 -070031 max_playout_delay_ms_(10000),
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000032 jitter_delay_ms_(0),
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000033 current_delay_ms_(0),
fischman@webrtc.org37bb4972013-10-23 23:59:45 +000034 last_decode_ms_(0),
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +000035 prev_frame_timestamp_(0),
36 num_decoded_frames_(0),
37 num_delayed_decoded_frames_(0),
38 first_decoded_frame_ms_(-1),
39 sum_missed_render_deadline_ms_(0) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000040 if (master_timing == NULL) {
41 master_ = true;
wu@webrtc.org66773a02014-05-07 17:09:44 +000042 ts_extrapolator_ = new TimestampExtrapolator(clock_->TimeInMilliseconds());
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000043 } else {
44 ts_extrapolator_ = master_timing->ts_extrapolator_;
45 }
niklase@google.com470e71d2011-07-07 08:21:25 +000046}
47
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000048VCMTiming::~VCMTiming() {
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +000049 UpdateHistograms();
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000050 if (master_) {
51 delete ts_extrapolator_;
52 }
53 delete crit_sect_;
niklase@google.com470e71d2011-07-07 08:21:25 +000054}
55
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +000056void VCMTiming::UpdateHistograms() const {
57 CriticalSectionScoped cs(crit_sect_);
58 if (num_decoded_frames_ == 0) {
59 return;
60 }
61 int64_t elapsed_sec =
62 (clock_->TimeInMilliseconds() - first_decoded_frame_ms_) / 1000;
63 if (elapsed_sec < metrics::kMinRunTimeInSeconds) {
64 return;
65 }
asapersson1d02d3e2016-09-09 22:40:25 -070066 RTC_HISTOGRAM_COUNTS_100(
asapersson53805322015-12-21 01:46:20 -080067 "WebRTC.Video.DecodedFramesPerSecond",
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +000068 static_cast<int>((num_decoded_frames_ / elapsed_sec) + 0.5f));
asapersson1d02d3e2016-09-09 22:40:25 -070069 RTC_HISTOGRAM_PERCENTAGE(
asapersson53805322015-12-21 01:46:20 -080070 "WebRTC.Video.DelayedFramesToRenderer",
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +000071 num_delayed_decoded_frames_ * 100 / num_decoded_frames_);
72 if (num_delayed_decoded_frames_ > 0) {
asapersson1d02d3e2016-09-09 22:40:25 -070073 RTC_HISTOGRAM_COUNTS_1000(
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +000074 "WebRTC.Video.DelayedFramesToRenderer_AvgDelayInMs",
asapersson53805322015-12-21 01:46:20 -080075 sum_missed_render_deadline_ms_ / num_delayed_decoded_frames_);
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +000076 }
77}
78
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000079void VCMTiming::Reset() {
80 CriticalSectionScoped cs(crit_sect_);
wu@webrtc.orged4cb562014-05-06 04:50:49 +000081 ts_extrapolator_->Reset(clock_->TimeInMilliseconds());
magjed2943f012016-03-22 05:12:09 -070082 codec_timer_.reset(new VCMCodecTimer());
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000083 render_delay_ms_ = kDefaultRenderDelayMs;
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +000084 min_playout_delay_ms_ = 0;
85 jitter_delay_ms_ = 0;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000086 current_delay_ms_ = 0;
87 prev_frame_timestamp_ = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000088}
89
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000090void VCMTiming::ResetDecodeTime() {
pbos@webrtc.org04221002014-07-10 15:25:37 +000091 CriticalSectionScoped lock(crit_sect_);
magjed2943f012016-03-22 05:12:09 -070092 codec_timer_.reset(new VCMCodecTimer());
niklase@google.com470e71d2011-07-07 08:21:25 +000093}
94
isheriff6b4b5f32016-06-08 00:24:21 -070095void VCMTiming::set_render_delay(int render_delay_ms) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000096 CriticalSectionScoped cs(crit_sect_);
97 render_delay_ms_ = render_delay_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +000098}
99
isheriff6b4b5f32016-06-08 00:24:21 -0700100void VCMTiming::set_min_playout_delay(int min_playout_delay_ms) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000101 CriticalSectionScoped cs(crit_sect_);
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000102 min_playout_delay_ms_ = min_playout_delay_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +0000103}
104
isheriff6b4b5f32016-06-08 00:24:21 -0700105int VCMTiming::min_playout_delay() {
106 CriticalSectionScoped cs(crit_sect_);
107 return min_playout_delay_ms_;
108}
109
110void VCMTiming::set_max_playout_delay(int max_playout_delay_ms) {
111 CriticalSectionScoped cs(crit_sect_);
112 max_playout_delay_ms_ = max_playout_delay_ms;
113}
114
115int VCMTiming::max_playout_delay() {
116 CriticalSectionScoped cs(crit_sect_);
117 return max_playout_delay_ms_;
118}
119
120void VCMTiming::SetJitterDelay(int jitter_delay_ms) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000121 CriticalSectionScoped cs(crit_sect_);
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000122 if (jitter_delay_ms != jitter_delay_ms_) {
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000123 jitter_delay_ms_ = jitter_delay_ms;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000124 // When in initial state, set current delay to minimum delay.
125 if (current_delay_ms_ == 0) {
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000126 current_delay_ms_ = jitter_delay_ms_;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000127 }
128 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000129}
130
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000131void VCMTiming::UpdateCurrentDelay(uint32_t frame_timestamp) {
132 CriticalSectionScoped cs(crit_sect_);
isheriff6b4b5f32016-06-08 00:24:21 -0700133 int target_delay_ms = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000134
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000135 if (current_delay_ms_ == 0) {
136 // Not initialized, set current delay to target.
137 current_delay_ms_ = target_delay_ms;
138 } else if (target_delay_ms != current_delay_ms_) {
philipel5908c712015-12-21 08:23:20 -0800139 int64_t delay_diff_ms =
140 static_cast<int64_t>(target_delay_ms) - current_delay_ms_;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000141 // Never change the delay with more than 100 ms every second. If we're
142 // changing the delay in too large steps we will get noticeable freezes. By
143 // limiting the change we can increase the delay in smaller steps, which
144 // will be experienced as the video is played in slow motion. When lowering
145 // the delay the video will be played at a faster pace.
146 int64_t max_change_ms = 0;
147 if (frame_timestamp < 0x0000ffff && prev_frame_timestamp_ > 0xffff0000) {
148 // wrap
philipel5908c712015-12-21 08:23:20 -0800149 max_change_ms = kDelayMaxChangeMsPerS *
150 (frame_timestamp + (static_cast<int64_t>(1) << 32) -
151 prev_frame_timestamp_) /
152 90000;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000153 } else {
154 max_change_ms = kDelayMaxChangeMsPerS *
philipel5908c712015-12-21 08:23:20 -0800155 (frame_timestamp - prev_frame_timestamp_) / 90000;
niklase@google.com470e71d2011-07-07 08:21:25 +0000156 }
philipelfd5a20f2016-11-15 00:57:57 -0800157
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000158 if (max_change_ms <= 0) {
159 // Any changes less than 1 ms are truncated and
160 // will be postponed. Negative change will be due
161 // to reordering and should be ignored.
162 return;
163 }
164 delay_diff_ms = std::max(delay_diff_ms, -max_change_ms);
165 delay_diff_ms = std::min(delay_diff_ms, max_change_ms);
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000166
isheriff6b4b5f32016-06-08 00:24:21 -0700167 current_delay_ms_ = current_delay_ms_ + delay_diff_ms;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000168 }
169 prev_frame_timestamp_ = frame_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000170}
171
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000172void VCMTiming::UpdateCurrentDelay(int64_t render_time_ms,
173 int64_t actual_decode_time_ms) {
174 CriticalSectionScoped cs(crit_sect_);
175 uint32_t target_delay_ms = TargetDelayInternal();
magjed2943f012016-03-22 05:12:09 -0700176 int64_t delayed_ms =
177 actual_decode_time_ms -
178 (render_time_ms - RequiredDecodeTimeMs() - render_delay_ms_);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000179 if (delayed_ms < 0) {
180 return;
181 }
182 if (current_delay_ms_ + delayed_ms <= target_delay_ms) {
isheriff6b4b5f32016-06-08 00:24:21 -0700183 current_delay_ms_ += delayed_ms;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000184 } else {
185 current_delay_ms_ = target_delay_ms;
186 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000187}
188
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000189int32_t VCMTiming::StopDecodeTimer(uint32_t time_stamp,
Per327d8ba2015-11-10 14:00:27 +0100190 int32_t decode_time_ms,
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +0000191 int64_t now_ms,
192 int64_t render_time_ms) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000193 CriticalSectionScoped cs(crit_sect_);
magjed2943f012016-03-22 05:12:09 -0700194 codec_timer_->AddTiming(decode_time_ms, now_ms);
Per327d8ba2015-11-10 14:00:27 +0100195 assert(decode_time_ms >= 0);
196 last_decode_ms_ = decode_time_ms;
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +0000197
198 // Update stats.
199 ++num_decoded_frames_;
200 if (num_decoded_frames_ == 1) {
201 first_decoded_frame_ms_ = now_ms;
202 }
203 int time_until_rendering_ms = render_time_ms - render_delay_ms_ - now_ms;
204 if (time_until_rendering_ms < 0) {
205 sum_missed_render_deadline_ms_ += -time_until_rendering_ms;
206 ++num_delayed_decoded_frames_;
207 }
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000208 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000209}
210
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000211void VCMTiming::IncomingTimestamp(uint32_t time_stamp, int64_t now_ms) {
212 CriticalSectionScoped cs(crit_sect_);
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000213 ts_extrapolator_->Update(now_ms, time_stamp);
niklase@google.com470e71d2011-07-07 08:21:25 +0000214}
215
philipel5908c712015-12-21 08:23:20 -0800216int64_t VCMTiming::RenderTimeMs(uint32_t frame_timestamp,
217 int64_t now_ms) const {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000218 CriticalSectionScoped cs(crit_sect_);
219 const int64_t render_time_ms = RenderTimeMsInternal(frame_timestamp, now_ms);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000220 return render_time_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +0000221}
222
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000223int64_t VCMTiming::RenderTimeMsInternal(uint32_t frame_timestamp,
224 int64_t now_ms) const {
225 int64_t estimated_complete_time_ms =
philipel5908c712015-12-21 08:23:20 -0800226 ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000227 if (estimated_complete_time_ms == -1) {
228 estimated_complete_time_ms = now_ms;
229 }
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000230
isheriff6b4b5f32016-06-08 00:24:21 -0700231 if (min_playout_delay_ms_ == 0 && max_playout_delay_ms_ == 0) {
232 // Render as soon as possible
233 return now_ms;
234 }
235
236 // Make sure the actual delay stays in the range of |min_playout_delay_ms_|
237 // and |max_playout_delay_ms_|.
238 int actual_delay = std::max(current_delay_ms_, min_playout_delay_ms_);
239 actual_delay = std::min(actual_delay, max_playout_delay_ms_);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000240 return estimated_complete_time_ms + actual_delay;
niklase@google.com470e71d2011-07-07 08:21:25 +0000241}
242
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000243// Must be called from inside a critical section.
isheriff6b4b5f32016-06-08 00:24:21 -0700244int VCMTiming::RequiredDecodeTimeMs() const {
245 const int decode_time_ms = codec_timer_->RequiredDecodeTimeMs();
stefan@webrtc.org34c5da62014-04-11 14:08:35 +0000246 assert(decode_time_ms >= 0);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000247 return decode_time_ms;
niklase@google.com470e71d2011-07-07 08:21:25 +0000248}
249
philipel5908c712015-12-21 08:23:20 -0800250uint32_t VCMTiming::MaxWaitingTime(int64_t render_time_ms,
251 int64_t now_ms) const {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000252 CriticalSectionScoped cs(crit_sect_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
philipel5908c712015-12-21 08:23:20 -0800254 const int64_t max_wait_time_ms =
magjed2943f012016-03-22 05:12:09 -0700255 render_time_ms - now_ms - RequiredDecodeTimeMs() - render_delay_ms_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000256
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000257 if (max_wait_time_ms < 0) {
258 return 0;
259 }
260 return static_cast<uint32_t>(max_wait_time_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000261}
262
philipel5908c712015-12-21 08:23:20 -0800263bool VCMTiming::EnoughTimeToDecode(
264 uint32_t available_processing_time_ms) const {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000265 CriticalSectionScoped cs(crit_sect_);
magjed2943f012016-03-22 05:12:09 -0700266 int64_t required_decode_time_ms = RequiredDecodeTimeMs();
267 if (required_decode_time_ms < 0) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000268 // Haven't decoded any frames yet, try decoding one to get an estimate
269 // of the decode time.
270 return true;
magjed2943f012016-03-22 05:12:09 -0700271 } else if (required_decode_time_ms == 0) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000272 // Decode time is less than 1, set to 1 for now since
273 // we don't have any better precision. Count ticks later?
magjed2943f012016-03-22 05:12:09 -0700274 required_decode_time_ms = 1;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000275 }
magjed2943f012016-03-22 05:12:09 -0700276 return static_cast<int64_t>(available_processing_time_ms) -
277 required_decode_time_ms >
philipel5908c712015-12-21 08:23:20 -0800278 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000279}
280
isheriff6b4b5f32016-06-08 00:24:21 -0700281int VCMTiming::TargetVideoDelay() const {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000282 CriticalSectionScoped cs(crit_sect_);
283 return TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000284}
285
isheriff6b4b5f32016-06-08 00:24:21 -0700286int VCMTiming::TargetDelayInternal() const {
mikhal@webrtc.orgadc64a72013-05-30 16:20:18 +0000287 return std::max(min_playout_delay_ms_,
isheriff6b4b5f32016-06-08 00:24:21 -0700288 jitter_delay_ms_ + RequiredDecodeTimeMs() + render_delay_ms_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000289}
290
fischman@webrtc.org37bb4972013-10-23 23:59:45 +0000291void VCMTiming::GetTimings(int* decode_ms,
292 int* max_decode_ms,
293 int* current_delay_ms,
294 int* target_delay_ms,
295 int* jitter_buffer_ms,
296 int* min_playout_delay_ms,
297 int* render_delay_ms) const {
298 CriticalSectionScoped cs(crit_sect_);
299 *decode_ms = last_decode_ms_;
isheriff6b4b5f32016-06-08 00:24:21 -0700300 *max_decode_ms = RequiredDecodeTimeMs();
fischman@webrtc.org37bb4972013-10-23 23:59:45 +0000301 *current_delay_ms = current_delay_ms_;
302 *target_delay_ms = TargetDelayInternal();
303 *jitter_buffer_ms = jitter_delay_ms_;
304 *min_playout_delay_ms = min_playout_delay_ms_;
305 *render_delay_ms = render_delay_ms_;
306}
307
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000308} // namespace webrtc