xref: /aosp_15_r20/external/webrtc/modules/video_coding/timing/timing.cc (revision d9f758449e529ab9291ac668be2861e7a55c2422)
1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker  *  Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
3*d9f75844SAndroid Build Coastguard Worker  *
4*d9f75844SAndroid Build Coastguard Worker  *  Use of this source code is governed by a BSD-style license
5*d9f75844SAndroid Build Coastguard Worker  *  that can be found in the LICENSE file in the root of the source
6*d9f75844SAndroid Build Coastguard Worker  *  tree. An additional intellectual property rights grant can be found
7*d9f75844SAndroid Build Coastguard Worker  *  in the file PATENTS.  All contributing project authors may
8*d9f75844SAndroid Build Coastguard Worker  *  be found in the AUTHORS file in the root of the source tree.
9*d9f75844SAndroid Build Coastguard Worker  */
10*d9f75844SAndroid Build Coastguard Worker 
11*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/timing/timing.h"
12*d9f75844SAndroid Build Coastguard Worker 
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker 
15*d9f75844SAndroid Build Coastguard Worker #include "api/units/time_delta.h"
16*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/timing/timestamp_extrapolator.h"
17*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/experiments/field_trial_parser.h"
18*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
19*d9f75844SAndroid Build Coastguard Worker #include "system_wrappers/include/clock.h"
20*d9f75844SAndroid Build Coastguard Worker 
21*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
22*d9f75844SAndroid Build Coastguard Worker namespace {
23*d9f75844SAndroid Build Coastguard Worker 
24*d9f75844SAndroid Build Coastguard Worker // Default pacing that is used for the low-latency renderer path.
25*d9f75844SAndroid Build Coastguard Worker constexpr TimeDelta kZeroPlayoutDelayDefaultMinPacing = TimeDelta::Millis(8);
26*d9f75844SAndroid Build Coastguard Worker constexpr TimeDelta kLowLatencyStreamMaxPlayoutDelayThreshold =
27*d9f75844SAndroid Build Coastguard Worker     TimeDelta::Millis(500);
28*d9f75844SAndroid Build Coastguard Worker 
CheckDelaysValid(TimeDelta min_delay,TimeDelta max_delay)29*d9f75844SAndroid Build Coastguard Worker void CheckDelaysValid(TimeDelta min_delay, TimeDelta max_delay) {
30*d9f75844SAndroid Build Coastguard Worker   if (min_delay > max_delay) {
31*d9f75844SAndroid Build Coastguard Worker     RTC_LOG(LS_ERROR)
32*d9f75844SAndroid Build Coastguard Worker         << "Playout delays set incorrectly: min playout delay (" << min_delay
33*d9f75844SAndroid Build Coastguard Worker         << ") > max playout delay (" << max_delay
34*d9f75844SAndroid Build Coastguard Worker         << "). This is undefined behaviour. Application writers should "
35*d9f75844SAndroid Build Coastguard Worker            "ensure that the min delay is always less than or equals max "
36*d9f75844SAndroid Build Coastguard Worker            "delay. If trying to use the playout delay header extensions "
37*d9f75844SAndroid Build Coastguard Worker            "described in "
38*d9f75844SAndroid Build Coastguard Worker            "https://webrtc.googlesource.com/src/+/refs/heads/main/docs/"
39*d9f75844SAndroid Build Coastguard Worker            "native-code/rtp-hdrext/playout-delay/, be careful that a playout "
40*d9f75844SAndroid Build Coastguard Worker            "delay hint or A/V sync settings may have caused this conflict.";
41*d9f75844SAndroid Build Coastguard Worker   }
42*d9f75844SAndroid Build Coastguard Worker }
43*d9f75844SAndroid Build Coastguard Worker 
44*d9f75844SAndroid Build Coastguard Worker }  // namespace
45*d9f75844SAndroid Build Coastguard Worker 
VCMTiming(Clock * clock,const FieldTrialsView & field_trials)46*d9f75844SAndroid Build Coastguard Worker VCMTiming::VCMTiming(Clock* clock, const FieldTrialsView& field_trials)
47*d9f75844SAndroid Build Coastguard Worker     : clock_(clock),
48*d9f75844SAndroid Build Coastguard Worker       ts_extrapolator_(
49*d9f75844SAndroid Build Coastguard Worker           std::make_unique<TimestampExtrapolator>(clock_->CurrentTime())),
50*d9f75844SAndroid Build Coastguard Worker       codec_timer_(std::make_unique<CodecTimer>()),
51*d9f75844SAndroid Build Coastguard Worker       render_delay_(kDefaultRenderDelay),
52*d9f75844SAndroid Build Coastguard Worker       min_playout_delay_(TimeDelta::Zero()),
53*d9f75844SAndroid Build Coastguard Worker       max_playout_delay_(TimeDelta::Seconds(10)),
54*d9f75844SAndroid Build Coastguard Worker       jitter_delay_(TimeDelta::Zero()),
55*d9f75844SAndroid Build Coastguard Worker       current_delay_(TimeDelta::Zero()),
56*d9f75844SAndroid Build Coastguard Worker       prev_frame_timestamp_(0),
57*d9f75844SAndroid Build Coastguard Worker       num_decoded_frames_(0),
58*d9f75844SAndroid Build Coastguard Worker       zero_playout_delay_min_pacing_("min_pacing",
59*d9f75844SAndroid Build Coastguard Worker                                      kZeroPlayoutDelayDefaultMinPacing),
60*d9f75844SAndroid Build Coastguard Worker       last_decode_scheduled_(Timestamp::Zero()) {
61*d9f75844SAndroid Build Coastguard Worker   ParseFieldTrial({&zero_playout_delay_min_pacing_},
62*d9f75844SAndroid Build Coastguard Worker                   field_trials.Lookup("WebRTC-ZeroPlayoutDelay"));
63*d9f75844SAndroid Build Coastguard Worker }
64*d9f75844SAndroid Build Coastguard Worker 
Reset()65*d9f75844SAndroid Build Coastguard Worker void VCMTiming::Reset() {
66*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
67*d9f75844SAndroid Build Coastguard Worker   ts_extrapolator_->Reset(clock_->CurrentTime());
68*d9f75844SAndroid Build Coastguard Worker   codec_timer_ = std::make_unique<CodecTimer>();
69*d9f75844SAndroid Build Coastguard Worker   render_delay_ = kDefaultRenderDelay;
70*d9f75844SAndroid Build Coastguard Worker   min_playout_delay_ = TimeDelta::Zero();
71*d9f75844SAndroid Build Coastguard Worker   jitter_delay_ = TimeDelta::Zero();
72*d9f75844SAndroid Build Coastguard Worker   current_delay_ = TimeDelta::Zero();
73*d9f75844SAndroid Build Coastguard Worker   prev_frame_timestamp_ = 0;
74*d9f75844SAndroid Build Coastguard Worker }
75*d9f75844SAndroid Build Coastguard Worker 
set_render_delay(TimeDelta render_delay)76*d9f75844SAndroid Build Coastguard Worker void VCMTiming::set_render_delay(TimeDelta render_delay) {
77*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
78*d9f75844SAndroid Build Coastguard Worker   render_delay_ = render_delay;
79*d9f75844SAndroid Build Coastguard Worker }
80*d9f75844SAndroid Build Coastguard Worker 
min_playout_delay() const81*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::min_playout_delay() const {
82*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
83*d9f75844SAndroid Build Coastguard Worker   return min_playout_delay_;
84*d9f75844SAndroid Build Coastguard Worker }
85*d9f75844SAndroid Build Coastguard Worker 
set_min_playout_delay(TimeDelta min_playout_delay)86*d9f75844SAndroid Build Coastguard Worker void VCMTiming::set_min_playout_delay(TimeDelta min_playout_delay) {
87*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
88*d9f75844SAndroid Build Coastguard Worker   if (min_playout_delay_ != min_playout_delay) {
89*d9f75844SAndroid Build Coastguard Worker     CheckDelaysValid(min_playout_delay, max_playout_delay_);
90*d9f75844SAndroid Build Coastguard Worker     min_playout_delay_ = min_playout_delay;
91*d9f75844SAndroid Build Coastguard Worker   }
92*d9f75844SAndroid Build Coastguard Worker }
93*d9f75844SAndroid Build Coastguard Worker 
set_max_playout_delay(TimeDelta max_playout_delay)94*d9f75844SAndroid Build Coastguard Worker void VCMTiming::set_max_playout_delay(TimeDelta max_playout_delay) {
95*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
96*d9f75844SAndroid Build Coastguard Worker   if (max_playout_delay_ != max_playout_delay) {
97*d9f75844SAndroid Build Coastguard Worker     CheckDelaysValid(min_playout_delay_, max_playout_delay);
98*d9f75844SAndroid Build Coastguard Worker     max_playout_delay_ = max_playout_delay;
99*d9f75844SAndroid Build Coastguard Worker   }
100*d9f75844SAndroid Build Coastguard Worker }
101*d9f75844SAndroid Build Coastguard Worker 
SetJitterDelay(TimeDelta jitter_delay)102*d9f75844SAndroid Build Coastguard Worker void VCMTiming::SetJitterDelay(TimeDelta jitter_delay) {
103*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
104*d9f75844SAndroid Build Coastguard Worker   if (jitter_delay != jitter_delay_) {
105*d9f75844SAndroid Build Coastguard Worker     jitter_delay_ = jitter_delay;
106*d9f75844SAndroid Build Coastguard Worker     // When in initial state, set current delay to minimum delay.
107*d9f75844SAndroid Build Coastguard Worker     if (current_delay_.IsZero()) {
108*d9f75844SAndroid Build Coastguard Worker       current_delay_ = jitter_delay_;
109*d9f75844SAndroid Build Coastguard Worker     }
110*d9f75844SAndroid Build Coastguard Worker   }
111*d9f75844SAndroid Build Coastguard Worker }
112*d9f75844SAndroid Build Coastguard Worker 
UpdateCurrentDelay(uint32_t frame_timestamp)113*d9f75844SAndroid Build Coastguard Worker void VCMTiming::UpdateCurrentDelay(uint32_t frame_timestamp) {
114*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
115*d9f75844SAndroid Build Coastguard Worker   TimeDelta target_delay = TargetDelayInternal();
116*d9f75844SAndroid Build Coastguard Worker 
117*d9f75844SAndroid Build Coastguard Worker   if (current_delay_.IsZero()) {
118*d9f75844SAndroid Build Coastguard Worker     // Not initialized, set current delay to target.
119*d9f75844SAndroid Build Coastguard Worker     current_delay_ = target_delay;
120*d9f75844SAndroid Build Coastguard Worker   } else if (target_delay != current_delay_) {
121*d9f75844SAndroid Build Coastguard Worker     TimeDelta delay_diff = target_delay - current_delay_;
122*d9f75844SAndroid Build Coastguard Worker     // Never change the delay with more than 100 ms every second. If we're
123*d9f75844SAndroid Build Coastguard Worker     // changing the delay in too large steps we will get noticeable freezes. By
124*d9f75844SAndroid Build Coastguard Worker     // limiting the change we can increase the delay in smaller steps, which
125*d9f75844SAndroid Build Coastguard Worker     // will be experienced as the video is played in slow motion. When lowering
126*d9f75844SAndroid Build Coastguard Worker     // the delay the video will be played at a faster pace.
127*d9f75844SAndroid Build Coastguard Worker     TimeDelta max_change = TimeDelta::Zero();
128*d9f75844SAndroid Build Coastguard Worker     if (frame_timestamp < 0x0000ffff && prev_frame_timestamp_ > 0xffff0000) {
129*d9f75844SAndroid Build Coastguard Worker       // wrap
130*d9f75844SAndroid Build Coastguard Worker       max_change =
131*d9f75844SAndroid Build Coastguard Worker           TimeDelta::Millis(kDelayMaxChangeMsPerS *
132*d9f75844SAndroid Build Coastguard Worker                             (frame_timestamp + (static_cast<int64_t>(1) << 32) -
133*d9f75844SAndroid Build Coastguard Worker                              prev_frame_timestamp_) /
134*d9f75844SAndroid Build Coastguard Worker                             90000);
135*d9f75844SAndroid Build Coastguard Worker     } else {
136*d9f75844SAndroid Build Coastguard Worker       max_change =
137*d9f75844SAndroid Build Coastguard Worker           TimeDelta::Millis(kDelayMaxChangeMsPerS *
138*d9f75844SAndroid Build Coastguard Worker                             (frame_timestamp - prev_frame_timestamp_) / 90000);
139*d9f75844SAndroid Build Coastguard Worker     }
140*d9f75844SAndroid Build Coastguard Worker 
141*d9f75844SAndroid Build Coastguard Worker     if (max_change <= TimeDelta::Zero()) {
142*d9f75844SAndroid Build Coastguard Worker       // Any changes less than 1 ms are truncated and will be postponed.
143*d9f75844SAndroid Build Coastguard Worker       // Negative change will be due to reordering and should be ignored.
144*d9f75844SAndroid Build Coastguard Worker       return;
145*d9f75844SAndroid Build Coastguard Worker     }
146*d9f75844SAndroid Build Coastguard Worker     delay_diff = std::max(delay_diff, -max_change);
147*d9f75844SAndroid Build Coastguard Worker     delay_diff = std::min(delay_diff, max_change);
148*d9f75844SAndroid Build Coastguard Worker 
149*d9f75844SAndroid Build Coastguard Worker     current_delay_ = current_delay_ + delay_diff;
150*d9f75844SAndroid Build Coastguard Worker   }
151*d9f75844SAndroid Build Coastguard Worker   prev_frame_timestamp_ = frame_timestamp;
152*d9f75844SAndroid Build Coastguard Worker }
153*d9f75844SAndroid Build Coastguard Worker 
UpdateCurrentDelay(Timestamp render_time,Timestamp actual_decode_time)154*d9f75844SAndroid Build Coastguard Worker void VCMTiming::UpdateCurrentDelay(Timestamp render_time,
155*d9f75844SAndroid Build Coastguard Worker                                    Timestamp actual_decode_time) {
156*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
157*d9f75844SAndroid Build Coastguard Worker   TimeDelta target_delay = TargetDelayInternal();
158*d9f75844SAndroid Build Coastguard Worker   TimeDelta delayed =
159*d9f75844SAndroid Build Coastguard Worker       (actual_decode_time - render_time) + RequiredDecodeTime() + render_delay_;
160*d9f75844SAndroid Build Coastguard Worker 
161*d9f75844SAndroid Build Coastguard Worker   // Only consider `delayed` as negative by more than a few microseconds.
162*d9f75844SAndroid Build Coastguard Worker   if (delayed.ms() < 0) {
163*d9f75844SAndroid Build Coastguard Worker     return;
164*d9f75844SAndroid Build Coastguard Worker   }
165*d9f75844SAndroid Build Coastguard Worker   if (current_delay_ + delayed <= target_delay) {
166*d9f75844SAndroid Build Coastguard Worker     current_delay_ += delayed;
167*d9f75844SAndroid Build Coastguard Worker   } else {
168*d9f75844SAndroid Build Coastguard Worker     current_delay_ = target_delay;
169*d9f75844SAndroid Build Coastguard Worker   }
170*d9f75844SAndroid Build Coastguard Worker }
171*d9f75844SAndroid Build Coastguard Worker 
StopDecodeTimer(TimeDelta decode_time,Timestamp now)172*d9f75844SAndroid Build Coastguard Worker void VCMTiming::StopDecodeTimer(TimeDelta decode_time, Timestamp now) {
173*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
174*d9f75844SAndroid Build Coastguard Worker   codec_timer_->AddTiming(decode_time.ms(), now.ms());
175*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(decode_time, TimeDelta::Zero());
176*d9f75844SAndroid Build Coastguard Worker   ++num_decoded_frames_;
177*d9f75844SAndroid Build Coastguard Worker }
178*d9f75844SAndroid Build Coastguard Worker 
IncomingTimestamp(uint32_t rtp_timestamp,Timestamp now)179*d9f75844SAndroid Build Coastguard Worker void VCMTiming::IncomingTimestamp(uint32_t rtp_timestamp, Timestamp now) {
180*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
181*d9f75844SAndroid Build Coastguard Worker   ts_extrapolator_->Update(now, rtp_timestamp);
182*d9f75844SAndroid Build Coastguard Worker }
183*d9f75844SAndroid Build Coastguard Worker 
RenderTime(uint32_t frame_timestamp,Timestamp now) const184*d9f75844SAndroid Build Coastguard Worker Timestamp VCMTiming::RenderTime(uint32_t frame_timestamp, Timestamp now) const {
185*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
186*d9f75844SAndroid Build Coastguard Worker   return RenderTimeInternal(frame_timestamp, now);
187*d9f75844SAndroid Build Coastguard Worker }
188*d9f75844SAndroid Build Coastguard Worker 
SetLastDecodeScheduledTimestamp(Timestamp last_decode_scheduled)189*d9f75844SAndroid Build Coastguard Worker void VCMTiming::SetLastDecodeScheduledTimestamp(
190*d9f75844SAndroid Build Coastguard Worker     Timestamp last_decode_scheduled) {
191*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
192*d9f75844SAndroid Build Coastguard Worker   last_decode_scheduled_ = last_decode_scheduled;
193*d9f75844SAndroid Build Coastguard Worker }
194*d9f75844SAndroid Build Coastguard Worker 
RenderTimeInternal(uint32_t frame_timestamp,Timestamp now) const195*d9f75844SAndroid Build Coastguard Worker Timestamp VCMTiming::RenderTimeInternal(uint32_t frame_timestamp,
196*d9f75844SAndroid Build Coastguard Worker                                         Timestamp now) const {
197*d9f75844SAndroid Build Coastguard Worker   if (UseLowLatencyRendering()) {
198*d9f75844SAndroid Build Coastguard Worker     // Render as soon as possible or with low-latency renderer algorithm.
199*d9f75844SAndroid Build Coastguard Worker     return Timestamp::Zero();
200*d9f75844SAndroid Build Coastguard Worker   }
201*d9f75844SAndroid Build Coastguard Worker   // Note that TimestampExtrapolator::ExtrapolateLocalTime is not a const
202*d9f75844SAndroid Build Coastguard Worker   // method; it mutates the object's wraparound state.
203*d9f75844SAndroid Build Coastguard Worker   Timestamp estimated_complete_time =
204*d9f75844SAndroid Build Coastguard Worker       ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp).value_or(now);
205*d9f75844SAndroid Build Coastguard Worker 
206*d9f75844SAndroid Build Coastguard Worker   // Make sure the actual delay stays in the range of `min_playout_delay_`
207*d9f75844SAndroid Build Coastguard Worker   // and `max_playout_delay_`.
208*d9f75844SAndroid Build Coastguard Worker   TimeDelta actual_delay =
209*d9f75844SAndroid Build Coastguard Worker       current_delay_.Clamped(min_playout_delay_, max_playout_delay_);
210*d9f75844SAndroid Build Coastguard Worker   return estimated_complete_time + actual_delay;
211*d9f75844SAndroid Build Coastguard Worker }
212*d9f75844SAndroid Build Coastguard Worker 
RequiredDecodeTime() const213*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::RequiredDecodeTime() const {
214*d9f75844SAndroid Build Coastguard Worker   const int decode_time_ms = codec_timer_->RequiredDecodeTimeMs();
215*d9f75844SAndroid Build Coastguard Worker   RTC_DCHECK_GE(decode_time_ms, 0);
216*d9f75844SAndroid Build Coastguard Worker   return TimeDelta::Millis(decode_time_ms);
217*d9f75844SAndroid Build Coastguard Worker }
218*d9f75844SAndroid Build Coastguard Worker 
MaxWaitingTime(Timestamp render_time,Timestamp now,bool too_many_frames_queued) const219*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::MaxWaitingTime(Timestamp render_time,
220*d9f75844SAndroid Build Coastguard Worker                                     Timestamp now,
221*d9f75844SAndroid Build Coastguard Worker                                     bool too_many_frames_queued) const {
222*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
223*d9f75844SAndroid Build Coastguard Worker 
224*d9f75844SAndroid Build Coastguard Worker   if (render_time.IsZero() && zero_playout_delay_min_pacing_->us() > 0 &&
225*d9f75844SAndroid Build Coastguard Worker       min_playout_delay_.IsZero() && max_playout_delay_ > TimeDelta::Zero()) {
226*d9f75844SAndroid Build Coastguard Worker     // `render_time` == 0 indicates that the frame should be decoded and
227*d9f75844SAndroid Build Coastguard Worker     // rendered as soon as possible. However, the decoder can be choked if too
228*d9f75844SAndroid Build Coastguard Worker     // many frames are sent at once. Therefore, limit the interframe delay to
229*d9f75844SAndroid Build Coastguard Worker     // |zero_playout_delay_min_pacing_| unless too many frames are queued in
230*d9f75844SAndroid Build Coastguard Worker     // which case the frames are sent to the decoder at once.
231*d9f75844SAndroid Build Coastguard Worker     if (too_many_frames_queued) {
232*d9f75844SAndroid Build Coastguard Worker       return TimeDelta::Zero();
233*d9f75844SAndroid Build Coastguard Worker     }
234*d9f75844SAndroid Build Coastguard Worker     Timestamp earliest_next_decode_start_time =
235*d9f75844SAndroid Build Coastguard Worker         last_decode_scheduled_ + zero_playout_delay_min_pacing_;
236*d9f75844SAndroid Build Coastguard Worker     TimeDelta max_wait_time = now >= earliest_next_decode_start_time
237*d9f75844SAndroid Build Coastguard Worker                                   ? TimeDelta::Zero()
238*d9f75844SAndroid Build Coastguard Worker                                   : earliest_next_decode_start_time - now;
239*d9f75844SAndroid Build Coastguard Worker     return max_wait_time;
240*d9f75844SAndroid Build Coastguard Worker   }
241*d9f75844SAndroid Build Coastguard Worker   return render_time - now - RequiredDecodeTime() - render_delay_;
242*d9f75844SAndroid Build Coastguard Worker }
243*d9f75844SAndroid Build Coastguard Worker 
TargetVideoDelay() const244*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::TargetVideoDelay() const {
245*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
246*d9f75844SAndroid Build Coastguard Worker   return TargetDelayInternal();
247*d9f75844SAndroid Build Coastguard Worker }
248*d9f75844SAndroid Build Coastguard Worker 
TargetDelayInternal() const249*d9f75844SAndroid Build Coastguard Worker TimeDelta VCMTiming::TargetDelayInternal() const {
250*d9f75844SAndroid Build Coastguard Worker   return std::max(min_playout_delay_,
251*d9f75844SAndroid Build Coastguard Worker                   jitter_delay_ + RequiredDecodeTime() + render_delay_);
252*d9f75844SAndroid Build Coastguard Worker }
253*d9f75844SAndroid Build Coastguard Worker 
RenderParameters() const254*d9f75844SAndroid Build Coastguard Worker VideoFrame::RenderParameters VCMTiming::RenderParameters() const {
255*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
256*d9f75844SAndroid Build Coastguard Worker   return {.use_low_latency_rendering = UseLowLatencyRendering(),
257*d9f75844SAndroid Build Coastguard Worker           .max_composition_delay_in_frames = max_composition_delay_in_frames_};
258*d9f75844SAndroid Build Coastguard Worker }
259*d9f75844SAndroid Build Coastguard Worker 
UseLowLatencyRendering() const260*d9f75844SAndroid Build Coastguard Worker bool VCMTiming::UseLowLatencyRendering() const {
261*d9f75844SAndroid Build Coastguard Worker   // min_playout_delay_==0,
262*d9f75844SAndroid Build Coastguard Worker   // max_playout_delay_<=kLowLatencyStreamMaxPlayoutDelayThreshold indicates
263*d9f75844SAndroid Build Coastguard Worker   // that the low-latency path should be used, which means that frames should be
264*d9f75844SAndroid Build Coastguard Worker   // decoded and rendered as soon as possible.
265*d9f75844SAndroid Build Coastguard Worker   return min_playout_delay_.IsZero() &&
266*d9f75844SAndroid Build Coastguard Worker          max_playout_delay_ <= kLowLatencyStreamMaxPlayoutDelayThreshold;
267*d9f75844SAndroid Build Coastguard Worker }
268*d9f75844SAndroid Build Coastguard Worker 
GetTimings() const269*d9f75844SAndroid Build Coastguard Worker VCMTiming::VideoDelayTimings VCMTiming::GetTimings() const {
270*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
271*d9f75844SAndroid Build Coastguard Worker   return VideoDelayTimings{.max_decode_duration = RequiredDecodeTime(),
272*d9f75844SAndroid Build Coastguard Worker                            .current_delay = current_delay_,
273*d9f75844SAndroid Build Coastguard Worker                            .target_delay = TargetDelayInternal(),
274*d9f75844SAndroid Build Coastguard Worker                            .jitter_buffer_delay = jitter_delay_,
275*d9f75844SAndroid Build Coastguard Worker                            .min_playout_delay = min_playout_delay_,
276*d9f75844SAndroid Build Coastguard Worker                            .max_playout_delay = max_playout_delay_,
277*d9f75844SAndroid Build Coastguard Worker                            .render_delay = render_delay_,
278*d9f75844SAndroid Build Coastguard Worker                            .num_decoded_frames = num_decoded_frames_};
279*d9f75844SAndroid Build Coastguard Worker }
280*d9f75844SAndroid Build Coastguard Worker 
SetTimingFrameInfo(const TimingFrameInfo & info)281*d9f75844SAndroid Build Coastguard Worker void VCMTiming::SetTimingFrameInfo(const TimingFrameInfo& info) {
282*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
283*d9f75844SAndroid Build Coastguard Worker   timing_frame_info_.emplace(info);
284*d9f75844SAndroid Build Coastguard Worker }
285*d9f75844SAndroid Build Coastguard Worker 
GetTimingFrameInfo()286*d9f75844SAndroid Build Coastguard Worker absl::optional<TimingFrameInfo> VCMTiming::GetTimingFrameInfo() {
287*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
288*d9f75844SAndroid Build Coastguard Worker   return timing_frame_info_;
289*d9f75844SAndroid Build Coastguard Worker }
290*d9f75844SAndroid Build Coastguard Worker 
SetMaxCompositionDelayInFrames(absl::optional<int> max_composition_delay_in_frames)291*d9f75844SAndroid Build Coastguard Worker void VCMTiming::SetMaxCompositionDelayInFrames(
292*d9f75844SAndroid Build Coastguard Worker     absl::optional<int> max_composition_delay_in_frames) {
293*d9f75844SAndroid Build Coastguard Worker   MutexLock lock(&mutex_);
294*d9f75844SAndroid Build Coastguard Worker   max_composition_delay_in_frames_ = max_composition_delay_in_frames;
295*d9f75844SAndroid Build Coastguard Worker }
296*d9f75844SAndroid Build Coastguard Worker 
297*d9f75844SAndroid Build Coastguard Worker }  // namespace webrtc
298