blob: 7a559ba1f2074a3794e5a6715e9aa0074874e1df [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
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020011#include "modules/video_coding/timing.h"
stefan@webrtc.orga678a3b2013-01-21 07:42:11 +000012
philipel5908c712015-12-21 08:23:20 -080013#include <algorithm>
14
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010015#include "api/units/time_delta.h"
Johannes Kron111e9812020-10-26 13:54:40 +010016#include "rtc_base/experiments/field_trial_parser.h"
Evan Shrubsoleeabaf8d2022-05-23 17:45:58 +020017#include "rtc_base/logging.h"
Karl Wiberg76b7f512018-03-22 15:29:03 +010018#include "rtc_base/time/timestamp_extrapolator.h"
Mirko Bonadei92ea95e2017-09-15 06:47:31 +020019#include "system_wrappers/include/clock.h"
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000020
niklase@google.com470e71d2011-07-07 08:21:25 +000021namespace webrtc {
Johannes Kron23bfff32021-09-28 21:31:46 +020022namespace {
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010023
Johannes Kron23bfff32021-09-28 21:31:46 +020024// Default pacing that is used for the low-latency renderer path.
25constexpr TimeDelta kZeroPlayoutDelayDefaultMinPacing = TimeDelta::Millis(8);
Evan Shrubsolef6adc642022-04-26 11:10:21 +020026constexpr TimeDelta kLowLatencyRendererMaxPlayoutDelay = TimeDelta::Millis(500);
27
Evan Shrubsolecc52f072022-05-24 15:00:00 +020028void CheckDelaysValid(TimeDelta min_delay, TimeDelta max_delay) {
29 if (min_delay > max_delay) {
30 RTC_LOG(LS_ERROR)
31 << "Playout delays set incorrectly: min playout delay (" << min_delay
32 << ") > max playout delay (" << max_delay
33 << "). This is undefined behaviour. Application writers should "
34 "ensure that the min delay is always less than or equals max "
35 "delay. If trying to use the playout delay header extensions "
36 "described in "
37 "https://webrtc.googlesource.com/src/+/refs/heads/main/docs/"
38 "native-code/rtp-hdrext/playout-delay/, be careful that a playout "
39 "delay hint or A/V sync settings may have caused this conflict.";
40 }
41}
42
Johannes Kron23bfff32021-09-28 21:31:46 +020043} // namespace
niklase@google.com470e71d2011-07-07 08:21:25 +000044
Jonas Orelande62c2f22022-03-29 11:04:48 +020045VCMTiming::VCMTiming(Clock* clock, const FieldTrialsView& field_trials)
ilnik2edc6842017-07-06 03:06:50 -070046 : clock_(clock),
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010047 ts_extrapolator_(
48 std::make_unique<TimestampExtrapolator>(clock_->CurrentTime())),
Rasmus Brandt23772262022-05-23 09:53:15 +020049 codec_timer_(std::make_unique<CodecTimer>()),
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010050 render_delay_(kDefaultRenderDelay),
51 min_playout_delay_(TimeDelta::Zero()),
52 max_playout_delay_(TimeDelta::Seconds(10)),
53 jitter_delay_(TimeDelta::Zero()),
54 current_delay_(TimeDelta::Zero()),
ilnik2edc6842017-07-06 03:06:50 -070055 prev_frame_timestamp_(0),
Johannes Kron111e9812020-10-26 13:54:40 +010056 num_decoded_frames_(0),
Johannes Kron23bfff32021-09-28 21:31:46 +020057 zero_playout_delay_min_pacing_("min_pacing",
58 kZeroPlayoutDelayDefaultMinPacing),
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010059 last_decode_scheduled_(Timestamp::Zero()) {
Johannes Kron985905d2021-06-29 11:37:06 +020060 ParseFieldTrial({&zero_playout_delay_min_pacing_},
Jonas Orelande02f9ee2022-03-25 12:43:14 +010061 field_trials.Lookup("WebRTC-ZeroPlayoutDelay"));
niklase@google.com470e71d2011-07-07 08:21:25 +000062}
63
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000064void VCMTiming::Reset() {
Markus Handell6deec382020-07-07 12:17:12 +020065 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010066 ts_extrapolator_->Reset(clock_->CurrentTime());
Rasmus Brandt23772262022-05-23 09:53:15 +020067 codec_timer_ = std::make_unique<CodecTimer>();
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010068 render_delay_ = kDefaultRenderDelay;
69 min_playout_delay_ = TimeDelta::Zero();
70 jitter_delay_ = TimeDelta::Zero();
71 current_delay_ = TimeDelta::Zero();
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +000072 prev_frame_timestamp_ = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000073}
74
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010075void VCMTiming::set_render_delay(TimeDelta render_delay) {
Markus Handell6deec382020-07-07 12:17:12 +020076 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010077 render_delay_ = render_delay;
niklase@google.com470e71d2011-07-07 08:21:25 +000078}
79
Evan Shrubsoleeabaf8d2022-05-23 17:45:58 +020080TimeDelta VCMTiming::min_playout_delay() const {
81 MutexLock lock(&mutex_);
82 return min_playout_delay_;
83}
84
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010085void VCMTiming::set_min_playout_delay(TimeDelta min_playout_delay) {
Markus Handell6deec382020-07-07 12:17:12 +020086 MutexLock lock(&mutex_);
Evan Shrubsolecc52f072022-05-24 15:00:00 +020087 if (min_playout_delay_ != min_playout_delay) {
88 CheckDelaysValid(min_playout_delay, max_playout_delay_);
89 min_playout_delay_ = min_playout_delay;
90 }
niklase@google.com470e71d2011-07-07 08:21:25 +000091}
92
Evan Shrubsoled6cdf802022-03-02 15:13:55 +010093void VCMTiming::set_max_playout_delay(TimeDelta max_playout_delay) {
Markus Handell6deec382020-07-07 12:17:12 +020094 MutexLock lock(&mutex_);
Evan Shrubsoleeabaf8d2022-05-23 17:45:58 +020095 if (max_playout_delay_ != max_playout_delay) {
Evan Shrubsolecc52f072022-05-24 15:00:00 +020096 CheckDelaysValid(min_playout_delay_, max_playout_delay);
Evan Shrubsoleeabaf8d2022-05-23 17:45:58 +020097 max_playout_delay_ = max_playout_delay;
98 }
isheriff6b4b5f32016-06-08 00:24:21 -070099}
100
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100101void VCMTiming::SetJitterDelay(TimeDelta jitter_delay) {
Markus Handell6deec382020-07-07 12:17:12 +0200102 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100103 if (jitter_delay != jitter_delay_) {
104 jitter_delay_ = jitter_delay;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000105 // When in initial state, set current delay to minimum delay.
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100106 if (current_delay_.IsZero()) {
107 current_delay_ = jitter_delay_;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000108 }
109 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000110}
111
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000112void VCMTiming::UpdateCurrentDelay(uint32_t frame_timestamp) {
Markus Handell6deec382020-07-07 12:17:12 +0200113 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100114 TimeDelta target_delay = TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000115
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100116 if (current_delay_.IsZero()) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000117 // Not initialized, set current delay to target.
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100118 current_delay_ = target_delay;
119 } else if (target_delay != current_delay_) {
120 TimeDelta delay_diff = target_delay - current_delay_;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000121 // Never change the delay with more than 100 ms every second. If we're
122 // changing the delay in too large steps we will get noticeable freezes. By
123 // limiting the change we can increase the delay in smaller steps, which
124 // will be experienced as the video is played in slow motion. When lowering
125 // the delay the video will be played at a faster pace.
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100126 TimeDelta max_change = TimeDelta::Zero();
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000127 if (frame_timestamp < 0x0000ffff && prev_frame_timestamp_ > 0xffff0000) {
128 // wrap
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100129 max_change =
130 TimeDelta::Millis(kDelayMaxChangeMsPerS *
131 (frame_timestamp + (static_cast<int64_t>(1) << 32) -
132 prev_frame_timestamp_) /
133 90000);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000134 } else {
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100135 max_change =
136 TimeDelta::Millis(kDelayMaxChangeMsPerS *
137 (frame_timestamp - prev_frame_timestamp_) / 90000);
niklase@google.com470e71d2011-07-07 08:21:25 +0000138 }
philipelfd5a20f2016-11-15 00:57:57 -0800139
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100140 if (max_change <= TimeDelta::Zero()) {
Ã…sa Persson8368d1a2018-01-05 12:44:45 +0100141 // Any changes less than 1 ms are truncated and will be postponed.
142 // Negative change will be due to reordering and should be ignored.
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000143 return;
144 }
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100145 delay_diff = std::max(delay_diff, -max_change);
146 delay_diff = std::min(delay_diff, max_change);
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000147
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100148 current_delay_ = current_delay_ + delay_diff;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000149 }
150 prev_frame_timestamp_ = frame_timestamp;
niklase@google.com470e71d2011-07-07 08:21:25 +0000151}
152
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100153void VCMTiming::UpdateCurrentDelay(Timestamp render_time,
154 Timestamp actual_decode_time) {
Markus Handell6deec382020-07-07 12:17:12 +0200155 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100156 TimeDelta target_delay = TargetDelayInternal();
157 TimeDelta delayed =
158 (actual_decode_time - render_time) + RequiredDecodeTime() + render_delay_;
159 if (delayed < TimeDelta::Zero()) {
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000160 return;
161 }
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100162 if (current_delay_ + delayed <= target_delay) {
163 current_delay_ += delayed;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000164 } else {
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100165 current_delay_ = target_delay;
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000166 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000167}
168
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100169void VCMTiming::StopDecodeTimer(TimeDelta decode_time, Timestamp now) {
Markus Handell6deec382020-07-07 12:17:12 +0200170 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100171 codec_timer_->AddTiming(decode_time.ms(), now.ms());
172 RTC_DCHECK_GE(decode_time, TimeDelta::Zero());
asapersson@webrtc.orgf2447602014-12-09 14:13:26 +0000173 ++num_decoded_frames_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000174}
175
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100176void VCMTiming::IncomingTimestamp(uint32_t rtp_timestamp, Timestamp now) {
Markus Handell6deec382020-07-07 12:17:12 +0200177 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100178 ts_extrapolator_->Update(now, rtp_timestamp);
niklase@google.com470e71d2011-07-07 08:21:25 +0000179}
180
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100181Timestamp VCMTiming::RenderTime(uint32_t frame_timestamp, Timestamp now) const {
Markus Handell6deec382020-07-07 12:17:12 +0200182 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100183 return RenderTimeInternal(frame_timestamp, now);
niklase@google.com470e71d2011-07-07 08:21:25 +0000184}
185
Rezaul Barbhuiya82c22482021-08-05 17:54:11 -0700186void VCMTiming::SetLastDecodeScheduledTimestamp(
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100187 Timestamp last_decode_scheduled) {
Rezaul Barbhuiya82c22482021-08-05 17:54:11 -0700188 MutexLock lock(&mutex_);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100189 last_decode_scheduled_ = last_decode_scheduled;
Rezaul Barbhuiya82c22482021-08-05 17:54:11 -0700190}
191
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100192Timestamp VCMTiming::RenderTimeInternal(uint32_t frame_timestamp,
193 Timestamp now) const {
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100194 if (min_playout_delay_.IsZero() &&
195 (max_playout_delay_.IsZero() ||
Evan Shrubsolef6adc642022-04-26 11:10:21 +0200196 max_playout_delay_ <= kLowLatencyRendererMaxPlayoutDelay)) {
Johannes Kron111e9812020-10-26 13:54:40 +0100197 // Render as soon as possible or with low-latency renderer algorithm.
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100198 return Timestamp::Zero();
Stefan Holmer812ceaf2018-05-15 13:00:10 +0200199 }
Niels Möller043725f2020-10-30 10:44:52 +0100200 // Note that TimestampExtrapolator::ExtrapolateLocalTime is not a const
201 // method; it mutates the object's wraparound state.
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100202 Timestamp estimated_complete_time =
203 ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp).value_or(now);
mikhal@webrtc.org6faba6e2013-04-30 15:39:34 +0000204
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100205 // Make sure the actual delay stays in the range of `min_playout_delay_`
206 // and `max_playout_delay_`.
207 TimeDelta actual_delay =
208 current_delay_.Clamped(min_playout_delay_, max_playout_delay_);
209 return estimated_complete_time + actual_delay;
niklase@google.com470e71d2011-07-07 08:21:25 +0000210}
211
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100212TimeDelta VCMTiming::RequiredDecodeTime() const {
isheriff6b4b5f32016-06-08 00:24:21 -0700213 const int decode_time_ms = codec_timer_->RequiredDecodeTimeMs();
Mirko Bonadei25ab3222021-07-08 20:08:20 +0200214 RTC_DCHECK_GE(decode_time_ms, 0);
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100215 return TimeDelta::Millis(decode_time_ms);
niklase@google.com470e71d2011-07-07 08:21:25 +0000216}
217
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100218TimeDelta VCMTiming::MaxWaitingTime(Timestamp render_time,
219 Timestamp now,
220 bool too_many_frames_queued) const {
Markus Handell6deec382020-07-07 12:17:12 +0200221 MutexLock lock(&mutex_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000222
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100223 if (render_time.IsZero() && zero_playout_delay_min_pacing_->us() > 0 &&
224 min_playout_delay_.IsZero() && max_playout_delay_ > TimeDelta::Zero()) {
225 // `render_time` == 0 indicates that the frame should be decoded and
Johannes Kron985905d2021-06-29 11:37:06 +0200226 // rendered as soon as possible. However, the decoder can be choked if too
Johannes Kron2ddc39e2021-08-10 16:56:12 +0200227 // many frames are sent at once. Therefore, limit the interframe delay to
228 // |zero_playout_delay_min_pacing_| unless too many frames are queued in
229 // which case the frames are sent to the decoder at once.
230 if (too_many_frames_queued) {
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100231 return TimeDelta::Zero();
Johannes Kron2ddc39e2021-08-10 16:56:12 +0200232 }
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100233 Timestamp earliest_next_decode_start_time =
234 last_decode_scheduled_ + zero_playout_delay_min_pacing_;
235 TimeDelta max_wait_time = now >= earliest_next_decode_start_time
236 ? TimeDelta::Zero()
237 : earliest_next_decode_start_time - now;
238 return max_wait_time;
Johannes Kron985905d2021-06-29 11:37:06 +0200239 }
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100240 return render_time - now - RequiredDecodeTime() - render_delay_;
niklase@google.com470e71d2011-07-07 08:21:25 +0000241}
242
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100243TimeDelta VCMTiming::TargetVideoDelay() const {
Markus Handell6deec382020-07-07 12:17:12 +0200244 MutexLock lock(&mutex_);
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000245 return TargetDelayInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000246}
247
Evan Shrubsoled6cdf802022-03-02 15:13:55 +0100248TimeDelta VCMTiming::TargetDelayInternal() const {
249 return std::max(min_playout_delay_,
250 jitter_delay_ + RequiredDecodeTime() + render_delay_);
niklase@google.com470e71d2011-07-07 08:21:25 +0000251}
252
Evan Shrubsole92e89d72022-03-22 10:55:15 +0100253VCMTiming::VideoDelayTimings VCMTiming::GetTimings() const {
Markus Handell6deec382020-07-07 12:17:12 +0200254 MutexLock lock(&mutex_);
Evan Shrubsole92e89d72022-03-22 10:55:15 +0100255 return VideoDelayTimings{.max_decode_duration = RequiredDecodeTime(),
256 .current_delay = current_delay_,
257 .target_delay = TargetDelayInternal(),
258 .jitter_buffer_delay = jitter_delay_,
259 .min_playout_delay = min_playout_delay_,
Evan Shrubsole8f1159b2022-03-22 12:12:17 +0100260 .max_playout_delay = max_playout_delay_,
Evan Shrubsole92e89d72022-03-22 10:55:15 +0100261 .render_delay = render_delay_,
262 .num_decoded_frames = num_decoded_frames_};
fischman@webrtc.org37bb4972013-10-23 23:59:45 +0000263}
264
ilnik2edc6842017-07-06 03:06:50 -0700265void VCMTiming::SetTimingFrameInfo(const TimingFrameInfo& info) {
Markus Handell6deec382020-07-07 12:17:12 +0200266 MutexLock lock(&mutex_);
ilnik2edc6842017-07-06 03:06:50 -0700267 timing_frame_info_.emplace(info);
268}
269
Danil Chapovalov0040b662018-06-18 10:48:16 +0200270absl::optional<TimingFrameInfo> VCMTiming::GetTimingFrameInfo() {
Markus Handell6deec382020-07-07 12:17:12 +0200271 MutexLock lock(&mutex_);
ilnik2edc6842017-07-06 03:06:50 -0700272 return timing_frame_info_;
273}
274
Johannes Kron111e9812020-10-26 13:54:40 +0100275void VCMTiming::SetMaxCompositionDelayInFrames(
276 absl::optional<int> max_composition_delay_in_frames) {
277 MutexLock lock(&mutex_);
278 max_composition_delay_in_frames_ = max_composition_delay_in_frames;
279}
280
281absl::optional<int> VCMTiming::MaxCompositionDelayInFrames() const {
282 MutexLock lock(&mutex_);
283 return max_composition_delay_in_frames_;
284}
285
mikhal@webrtc.org2eaf98b2013-05-21 17:58:43 +0000286} // namespace webrtc