1*d9f75844SAndroid Build Coastguard Worker /*
2*d9f75844SAndroid Build Coastguard Worker * Copyright (c) 2022 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 "video/video_stream_buffer_controller.h"
12*d9f75844SAndroid Build Coastguard Worker
13*d9f75844SAndroid Build Coastguard Worker #include <algorithm>
14*d9f75844SAndroid Build Coastguard Worker #include <memory>
15*d9f75844SAndroid Build Coastguard Worker #include <utility>
16*d9f75844SAndroid Build Coastguard Worker
17*d9f75844SAndroid Build Coastguard Worker #include "absl/base/attributes.h"
18*d9f75844SAndroid Build Coastguard Worker #include "absl/functional/bind_front.h"
19*d9f75844SAndroid Build Coastguard Worker #include "api/sequence_checker.h"
20*d9f75844SAndroid Build Coastguard Worker #include "api/task_queue/task_queue_base.h"
21*d9f75844SAndroid Build Coastguard Worker #include "api/units/data_size.h"
22*d9f75844SAndroid Build Coastguard Worker #include "api/video/encoded_frame.h"
23*d9f75844SAndroid Build Coastguard Worker #include "api/video/frame_buffer.h"
24*d9f75844SAndroid Build Coastguard Worker #include "api/video/video_content_type.h"
25*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/frame_helpers.h"
26*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/timing/inter_frame_delay.h"
27*d9f75844SAndroid Build Coastguard Worker #include "modules/video_coding/timing/jitter_estimator.h"
28*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/checks.h"
29*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/logging.h"
30*d9f75844SAndroid Build Coastguard Worker #include "rtc_base/thread_annotations.h"
31*d9f75844SAndroid Build Coastguard Worker #include "video/frame_decode_scheduler.h"
32*d9f75844SAndroid Build Coastguard Worker #include "video/frame_decode_timing.h"
33*d9f75844SAndroid Build Coastguard Worker #include "video/task_queue_frame_decode_scheduler.h"
34*d9f75844SAndroid Build Coastguard Worker #include "video/video_receive_stream_timeout_tracker.h"
35*d9f75844SAndroid Build Coastguard Worker
36*d9f75844SAndroid Build Coastguard Worker namespace webrtc {
37*d9f75844SAndroid Build Coastguard Worker
38*d9f75844SAndroid Build Coastguard Worker namespace {
39*d9f75844SAndroid Build Coastguard Worker
40*d9f75844SAndroid Build Coastguard Worker // Max number of frames the buffer will hold.
41*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kMaxFramesBuffered = 800;
42*d9f75844SAndroid Build Coastguard Worker // Max number of decoded frame info that will be saved.
43*d9f75844SAndroid Build Coastguard Worker static constexpr int kMaxFramesHistory = 1 << 13;
44*d9f75844SAndroid Build Coastguard Worker
45*d9f75844SAndroid Build Coastguard Worker // Default value for the maximum decode queue size that is used when the
46*d9f75844SAndroid Build Coastguard Worker // low-latency renderer is used.
47*d9f75844SAndroid Build Coastguard Worker static constexpr size_t kZeroPlayoutDelayDefaultMaxDecodeQueueSize = 8;
48*d9f75844SAndroid Build Coastguard Worker
49*d9f75844SAndroid Build Coastguard Worker struct FrameMetadata {
FrameMetadatawebrtc::__anon550731d50111::FrameMetadata50*d9f75844SAndroid Build Coastguard Worker explicit FrameMetadata(const EncodedFrame& frame)
51*d9f75844SAndroid Build Coastguard Worker : is_last_spatial_layer(frame.is_last_spatial_layer),
52*d9f75844SAndroid Build Coastguard Worker is_keyframe(frame.is_keyframe()),
53*d9f75844SAndroid Build Coastguard Worker size(frame.size()),
54*d9f75844SAndroid Build Coastguard Worker contentType(frame.contentType()),
55*d9f75844SAndroid Build Coastguard Worker delayed_by_retransmission(frame.delayed_by_retransmission()),
56*d9f75844SAndroid Build Coastguard Worker rtp_timestamp(frame.Timestamp()),
57*d9f75844SAndroid Build Coastguard Worker receive_time(frame.ReceivedTimestamp()) {}
58*d9f75844SAndroid Build Coastguard Worker
59*d9f75844SAndroid Build Coastguard Worker const bool is_last_spatial_layer;
60*d9f75844SAndroid Build Coastguard Worker const bool is_keyframe;
61*d9f75844SAndroid Build Coastguard Worker const size_t size;
62*d9f75844SAndroid Build Coastguard Worker const VideoContentType contentType;
63*d9f75844SAndroid Build Coastguard Worker const bool delayed_by_retransmission;
64*d9f75844SAndroid Build Coastguard Worker const uint32_t rtp_timestamp;
65*d9f75844SAndroid Build Coastguard Worker const absl::optional<Timestamp> receive_time;
66*d9f75844SAndroid Build Coastguard Worker };
67*d9f75844SAndroid Build Coastguard Worker
ReceiveTime(const EncodedFrame & frame)68*d9f75844SAndroid Build Coastguard Worker Timestamp ReceiveTime(const EncodedFrame& frame) {
69*d9f75844SAndroid Build Coastguard Worker absl::optional<Timestamp> ts = frame.ReceivedTimestamp();
70*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(ts.has_value()) << "Received frame must have a timestamp set!";
71*d9f75844SAndroid Build Coastguard Worker return *ts;
72*d9f75844SAndroid Build Coastguard Worker }
73*d9f75844SAndroid Build Coastguard Worker
74*d9f75844SAndroid Build Coastguard Worker } // namespace
75*d9f75844SAndroid Build Coastguard Worker
VideoStreamBufferController(Clock * clock,TaskQueueBase * worker_queue,VCMTiming * timing,VCMReceiveStatisticsCallback * stats_proxy,FrameSchedulingReceiver * receiver,TimeDelta max_wait_for_keyframe,TimeDelta max_wait_for_frame,std::unique_ptr<FrameDecodeScheduler> frame_decode_scheduler,const FieldTrialsView & field_trials)76*d9f75844SAndroid Build Coastguard Worker VideoStreamBufferController::VideoStreamBufferController(
77*d9f75844SAndroid Build Coastguard Worker Clock* clock,
78*d9f75844SAndroid Build Coastguard Worker TaskQueueBase* worker_queue,
79*d9f75844SAndroid Build Coastguard Worker VCMTiming* timing,
80*d9f75844SAndroid Build Coastguard Worker VCMReceiveStatisticsCallback* stats_proxy,
81*d9f75844SAndroid Build Coastguard Worker FrameSchedulingReceiver* receiver,
82*d9f75844SAndroid Build Coastguard Worker TimeDelta max_wait_for_keyframe,
83*d9f75844SAndroid Build Coastguard Worker TimeDelta max_wait_for_frame,
84*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<FrameDecodeScheduler> frame_decode_scheduler,
85*d9f75844SAndroid Build Coastguard Worker const FieldTrialsView& field_trials)
86*d9f75844SAndroid Build Coastguard Worker : field_trials_(field_trials),
87*d9f75844SAndroid Build Coastguard Worker clock_(clock),
88*d9f75844SAndroid Build Coastguard Worker stats_proxy_(stats_proxy),
89*d9f75844SAndroid Build Coastguard Worker receiver_(receiver),
90*d9f75844SAndroid Build Coastguard Worker timing_(timing),
91*d9f75844SAndroid Build Coastguard Worker frame_decode_scheduler_(std::move(frame_decode_scheduler)),
92*d9f75844SAndroid Build Coastguard Worker jitter_estimator_(clock_, field_trials),
93*d9f75844SAndroid Build Coastguard Worker buffer_(std::make_unique<FrameBuffer>(kMaxFramesBuffered,
94*d9f75844SAndroid Build Coastguard Worker kMaxFramesHistory,
95*d9f75844SAndroid Build Coastguard Worker field_trials)),
96*d9f75844SAndroid Build Coastguard Worker decode_timing_(clock_, timing_),
97*d9f75844SAndroid Build Coastguard Worker timeout_tracker_(
98*d9f75844SAndroid Build Coastguard Worker clock_,
99*d9f75844SAndroid Build Coastguard Worker worker_queue,
100*d9f75844SAndroid Build Coastguard Worker VideoReceiveStreamTimeoutTracker::Timeouts{
101*d9f75844SAndroid Build Coastguard Worker .max_wait_for_keyframe = max_wait_for_keyframe,
102*d9f75844SAndroid Build Coastguard Worker .max_wait_for_frame = max_wait_for_frame},
103*d9f75844SAndroid Build Coastguard Worker absl::bind_front(&VideoStreamBufferController::OnTimeout, this)),
104*d9f75844SAndroid Build Coastguard Worker zero_playout_delay_max_decode_queue_size_(
105*d9f75844SAndroid Build Coastguard Worker "max_decode_queue_size",
106*d9f75844SAndroid Build Coastguard Worker kZeroPlayoutDelayDefaultMaxDecodeQueueSize) {
107*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(stats_proxy_);
108*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(receiver_);
109*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(timing_);
110*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(clock_);
111*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(frame_decode_scheduler_);
112*d9f75844SAndroid Build Coastguard Worker
113*d9f75844SAndroid Build Coastguard Worker ParseFieldTrial({&zero_playout_delay_max_decode_queue_size_},
114*d9f75844SAndroid Build Coastguard Worker field_trials.Lookup("WebRTC-ZeroPlayoutDelay"));
115*d9f75844SAndroid Build Coastguard Worker }
116*d9f75844SAndroid Build Coastguard Worker
Stop()117*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::Stop() {
118*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
119*d9f75844SAndroid Build Coastguard Worker frame_decode_scheduler_->Stop();
120*d9f75844SAndroid Build Coastguard Worker timeout_tracker_.Stop();
121*d9f75844SAndroid Build Coastguard Worker decoder_ready_for_new_frame_ = false;
122*d9f75844SAndroid Build Coastguard Worker }
123*d9f75844SAndroid Build Coastguard Worker
SetProtectionMode(VCMVideoProtection protection_mode)124*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::SetProtectionMode(
125*d9f75844SAndroid Build Coastguard Worker VCMVideoProtection protection_mode) {
126*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
127*d9f75844SAndroid Build Coastguard Worker protection_mode_ = protection_mode;
128*d9f75844SAndroid Build Coastguard Worker }
129*d9f75844SAndroid Build Coastguard Worker
Clear()130*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::Clear() {
131*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
132*d9f75844SAndroid Build Coastguard Worker stats_proxy_->OnDroppedFrames(buffer_->CurrentSize());
133*d9f75844SAndroid Build Coastguard Worker buffer_ = std::make_unique<FrameBuffer>(kMaxFramesBuffered, kMaxFramesHistory,
134*d9f75844SAndroid Build Coastguard Worker field_trials_);
135*d9f75844SAndroid Build Coastguard Worker frame_decode_scheduler_->CancelOutstanding();
136*d9f75844SAndroid Build Coastguard Worker }
137*d9f75844SAndroid Build Coastguard Worker
InsertFrame(std::unique_ptr<EncodedFrame> frame)138*d9f75844SAndroid Build Coastguard Worker absl::optional<int64_t> VideoStreamBufferController::InsertFrame(
139*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<EncodedFrame> frame) {
140*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
141*d9f75844SAndroid Build Coastguard Worker FrameMetadata metadata(*frame);
142*d9f75844SAndroid Build Coastguard Worker int complete_units = buffer_->GetTotalNumberOfContinuousTemporalUnits();
143*d9f75844SAndroid Build Coastguard Worker if (buffer_->InsertFrame(std::move(frame))) {
144*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(metadata.receive_time) << "Frame receive time must be set!";
145*d9f75844SAndroid Build Coastguard Worker if (!metadata.delayed_by_retransmission && metadata.receive_time &&
146*d9f75844SAndroid Build Coastguard Worker (field_trials_.IsDisabled("WebRTC-IncomingTimestampOnMarkerBitOnly") ||
147*d9f75844SAndroid Build Coastguard Worker metadata.is_last_spatial_layer)) {
148*d9f75844SAndroid Build Coastguard Worker timing_->IncomingTimestamp(metadata.rtp_timestamp,
149*d9f75844SAndroid Build Coastguard Worker *metadata.receive_time);
150*d9f75844SAndroid Build Coastguard Worker }
151*d9f75844SAndroid Build Coastguard Worker if (complete_units < buffer_->GetTotalNumberOfContinuousTemporalUnits()) {
152*d9f75844SAndroid Build Coastguard Worker stats_proxy_->OnCompleteFrame(metadata.is_keyframe, metadata.size,
153*d9f75844SAndroid Build Coastguard Worker metadata.contentType);
154*d9f75844SAndroid Build Coastguard Worker MaybeScheduleFrameForRelease();
155*d9f75844SAndroid Build Coastguard Worker }
156*d9f75844SAndroid Build Coastguard Worker }
157*d9f75844SAndroid Build Coastguard Worker
158*d9f75844SAndroid Build Coastguard Worker return buffer_->LastContinuousFrameId();
159*d9f75844SAndroid Build Coastguard Worker }
160*d9f75844SAndroid Build Coastguard Worker
UpdateRtt(int64_t max_rtt_ms)161*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::UpdateRtt(int64_t max_rtt_ms) {
162*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
163*d9f75844SAndroid Build Coastguard Worker jitter_estimator_.UpdateRtt(TimeDelta::Millis(max_rtt_ms));
164*d9f75844SAndroid Build Coastguard Worker }
165*d9f75844SAndroid Build Coastguard Worker
SetMaxWaits(TimeDelta max_wait_for_keyframe,TimeDelta max_wait_for_frame)166*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::SetMaxWaits(TimeDelta max_wait_for_keyframe,
167*d9f75844SAndroid Build Coastguard Worker TimeDelta max_wait_for_frame) {
168*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
169*d9f75844SAndroid Build Coastguard Worker timeout_tracker_.SetTimeouts({.max_wait_for_keyframe = max_wait_for_keyframe,
170*d9f75844SAndroid Build Coastguard Worker .max_wait_for_frame = max_wait_for_frame});
171*d9f75844SAndroid Build Coastguard Worker }
172*d9f75844SAndroid Build Coastguard Worker
StartNextDecode(bool keyframe_required)173*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::StartNextDecode(bool keyframe_required) {
174*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
175*d9f75844SAndroid Build Coastguard Worker if (!timeout_tracker_.Running())
176*d9f75844SAndroid Build Coastguard Worker timeout_tracker_.Start(keyframe_required);
177*d9f75844SAndroid Build Coastguard Worker keyframe_required_ = keyframe_required;
178*d9f75844SAndroid Build Coastguard Worker if (keyframe_required_) {
179*d9f75844SAndroid Build Coastguard Worker timeout_tracker_.SetWaitingForKeyframe();
180*d9f75844SAndroid Build Coastguard Worker }
181*d9f75844SAndroid Build Coastguard Worker decoder_ready_for_new_frame_ = true;
182*d9f75844SAndroid Build Coastguard Worker MaybeScheduleFrameForRelease();
183*d9f75844SAndroid Build Coastguard Worker }
184*d9f75844SAndroid Build Coastguard Worker
Size()185*d9f75844SAndroid Build Coastguard Worker int VideoStreamBufferController::Size() {
186*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
187*d9f75844SAndroid Build Coastguard Worker return buffer_->CurrentSize();
188*d9f75844SAndroid Build Coastguard Worker }
189*d9f75844SAndroid Build Coastguard Worker
OnFrameReady(absl::InlinedVector<std::unique_ptr<EncodedFrame>,4> frames,Timestamp render_time)190*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::OnFrameReady(
191*d9f75844SAndroid Build Coastguard Worker absl::InlinedVector<std::unique_ptr<EncodedFrame>, 4> frames,
192*d9f75844SAndroid Build Coastguard Worker Timestamp render_time) {
193*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
194*d9f75844SAndroid Build Coastguard Worker RTC_CHECK(!frames.empty())
195*d9f75844SAndroid Build Coastguard Worker << "Callers must ensure there is at least one frame to decode.";
196*d9f75844SAndroid Build Coastguard Worker
197*d9f75844SAndroid Build Coastguard Worker timeout_tracker_.OnEncodedFrameReleased();
198*d9f75844SAndroid Build Coastguard Worker
199*d9f75844SAndroid Build Coastguard Worker Timestamp now = clock_->CurrentTime();
200*d9f75844SAndroid Build Coastguard Worker bool superframe_delayed_by_retransmission = false;
201*d9f75844SAndroid Build Coastguard Worker DataSize superframe_size = DataSize::Zero();
202*d9f75844SAndroid Build Coastguard Worker const EncodedFrame& first_frame = *frames.front();
203*d9f75844SAndroid Build Coastguard Worker Timestamp receive_time = ReceiveTime(first_frame);
204*d9f75844SAndroid Build Coastguard Worker
205*d9f75844SAndroid Build Coastguard Worker if (first_frame.is_keyframe())
206*d9f75844SAndroid Build Coastguard Worker keyframe_required_ = false;
207*d9f75844SAndroid Build Coastguard Worker
208*d9f75844SAndroid Build Coastguard Worker // Gracefully handle bad RTP timestamps and render time issues.
209*d9f75844SAndroid Build Coastguard Worker if (FrameHasBadRenderTiming(render_time, now) ||
210*d9f75844SAndroid Build Coastguard Worker TargetVideoDelayIsTooLarge(timing_->TargetVideoDelay())) {
211*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_WARNING) << "Resetting jitter estimator and timing module due "
212*d9f75844SAndroid Build Coastguard Worker "to bad render timing for rtp_timestamp="
213*d9f75844SAndroid Build Coastguard Worker << first_frame.Timestamp();
214*d9f75844SAndroid Build Coastguard Worker jitter_estimator_.Reset();
215*d9f75844SAndroid Build Coastguard Worker timing_->Reset();
216*d9f75844SAndroid Build Coastguard Worker render_time = timing_->RenderTime(first_frame.Timestamp(), now);
217*d9f75844SAndroid Build Coastguard Worker }
218*d9f75844SAndroid Build Coastguard Worker
219*d9f75844SAndroid Build Coastguard Worker for (std::unique_ptr<EncodedFrame>& frame : frames) {
220*d9f75844SAndroid Build Coastguard Worker frame->SetRenderTime(render_time.ms());
221*d9f75844SAndroid Build Coastguard Worker
222*d9f75844SAndroid Build Coastguard Worker superframe_delayed_by_retransmission |= frame->delayed_by_retransmission();
223*d9f75844SAndroid Build Coastguard Worker receive_time = std::max(receive_time, ReceiveTime(*frame));
224*d9f75844SAndroid Build Coastguard Worker superframe_size += DataSize::Bytes(frame->size());
225*d9f75844SAndroid Build Coastguard Worker }
226*d9f75844SAndroid Build Coastguard Worker
227*d9f75844SAndroid Build Coastguard Worker if (!superframe_delayed_by_retransmission) {
228*d9f75844SAndroid Build Coastguard Worker auto frame_delay = inter_frame_delay_.CalculateDelay(
229*d9f75844SAndroid Build Coastguard Worker first_frame.Timestamp(), receive_time);
230*d9f75844SAndroid Build Coastguard Worker if (frame_delay) {
231*d9f75844SAndroid Build Coastguard Worker jitter_estimator_.UpdateEstimate(*frame_delay, superframe_size);
232*d9f75844SAndroid Build Coastguard Worker }
233*d9f75844SAndroid Build Coastguard Worker
234*d9f75844SAndroid Build Coastguard Worker float rtt_mult = protection_mode_ == kProtectionNackFEC ? 0.0 : 1.0;
235*d9f75844SAndroid Build Coastguard Worker absl::optional<TimeDelta> rtt_mult_add_cap_ms = absl::nullopt;
236*d9f75844SAndroid Build Coastguard Worker if (rtt_mult_settings_.has_value()) {
237*d9f75844SAndroid Build Coastguard Worker rtt_mult = rtt_mult_settings_->rtt_mult_setting;
238*d9f75844SAndroid Build Coastguard Worker rtt_mult_add_cap_ms =
239*d9f75844SAndroid Build Coastguard Worker TimeDelta::Millis(rtt_mult_settings_->rtt_mult_add_cap_ms);
240*d9f75844SAndroid Build Coastguard Worker }
241*d9f75844SAndroid Build Coastguard Worker timing_->SetJitterDelay(
242*d9f75844SAndroid Build Coastguard Worker jitter_estimator_.GetJitterEstimate(rtt_mult, rtt_mult_add_cap_ms));
243*d9f75844SAndroid Build Coastguard Worker timing_->UpdateCurrentDelay(render_time, now);
244*d9f75844SAndroid Build Coastguard Worker } else if (RttMultExperiment::RttMultEnabled()) {
245*d9f75844SAndroid Build Coastguard Worker jitter_estimator_.FrameNacked();
246*d9f75844SAndroid Build Coastguard Worker }
247*d9f75844SAndroid Build Coastguard Worker
248*d9f75844SAndroid Build Coastguard Worker // Update stats.
249*d9f75844SAndroid Build Coastguard Worker UpdateDroppedFrames();
250*d9f75844SAndroid Build Coastguard Worker UpdateJitterDelay();
251*d9f75844SAndroid Build Coastguard Worker UpdateTimingFrameInfo();
252*d9f75844SAndroid Build Coastguard Worker
253*d9f75844SAndroid Build Coastguard Worker std::unique_ptr<EncodedFrame> frame =
254*d9f75844SAndroid Build Coastguard Worker CombineAndDeleteFrames(std::move(frames));
255*d9f75844SAndroid Build Coastguard Worker
256*d9f75844SAndroid Build Coastguard Worker timing_->SetLastDecodeScheduledTimestamp(now);
257*d9f75844SAndroid Build Coastguard Worker
258*d9f75844SAndroid Build Coastguard Worker decoder_ready_for_new_frame_ = false;
259*d9f75844SAndroid Build Coastguard Worker receiver_->OnEncodedFrame(std::move(frame));
260*d9f75844SAndroid Build Coastguard Worker }
261*d9f75844SAndroid Build Coastguard Worker
OnTimeout(TimeDelta delay)262*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::OnTimeout(TimeDelta delay) {
263*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
264*d9f75844SAndroid Build Coastguard Worker
265*d9f75844SAndroid Build Coastguard Worker // Stop sending timeouts until receiver starts waiting for a new frame.
266*d9f75844SAndroid Build Coastguard Worker timeout_tracker_.Stop();
267*d9f75844SAndroid Build Coastguard Worker
268*d9f75844SAndroid Build Coastguard Worker // If the stream is paused then ignore the timeout.
269*d9f75844SAndroid Build Coastguard Worker if (!decoder_ready_for_new_frame_) {
270*d9f75844SAndroid Build Coastguard Worker return;
271*d9f75844SAndroid Build Coastguard Worker }
272*d9f75844SAndroid Build Coastguard Worker decoder_ready_for_new_frame_ = false;
273*d9f75844SAndroid Build Coastguard Worker receiver_->OnDecodableFrameTimeout(delay);
274*d9f75844SAndroid Build Coastguard Worker }
275*d9f75844SAndroid Build Coastguard Worker
FrameReadyForDecode(uint32_t rtp_timestamp,Timestamp render_time)276*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::FrameReadyForDecode(uint32_t rtp_timestamp,
277*d9f75844SAndroid Build Coastguard Worker Timestamp render_time) {
278*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
279*d9f75844SAndroid Build Coastguard Worker // Check that the frame to decode is still valid before passing the frame for
280*d9f75844SAndroid Build Coastguard Worker // decoding.
281*d9f75844SAndroid Build Coastguard Worker auto decodable_tu_info = buffer_->DecodableTemporalUnitsInfo();
282*d9f75844SAndroid Build Coastguard Worker if (!decodable_tu_info) {
283*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR)
284*d9f75844SAndroid Build Coastguard Worker << "The frame buffer became undecodable during the wait "
285*d9f75844SAndroid Build Coastguard Worker "to decode frame with rtp-timestamp "
286*d9f75844SAndroid Build Coastguard Worker << rtp_timestamp
287*d9f75844SAndroid Build Coastguard Worker << ". Cancelling the decode of this frame, decoding "
288*d9f75844SAndroid Build Coastguard Worker "will resume when the frame buffers become decodable again.";
289*d9f75844SAndroid Build Coastguard Worker return;
290*d9f75844SAndroid Build Coastguard Worker }
291*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_EQ(rtp_timestamp, decodable_tu_info->next_rtp_timestamp)
292*d9f75844SAndroid Build Coastguard Worker << "Frame buffer's next decodable frame was not the one sent for "
293*d9f75844SAndroid Build Coastguard Worker "extraction.";
294*d9f75844SAndroid Build Coastguard Worker auto frames = buffer_->ExtractNextDecodableTemporalUnit();
295*d9f75844SAndroid Build Coastguard Worker if (frames.empty()) {
296*d9f75844SAndroid Build Coastguard Worker RTC_LOG(LS_ERROR)
297*d9f75844SAndroid Build Coastguard Worker << "The frame buffer should never return an empty temporal until list "
298*d9f75844SAndroid Build Coastguard Worker "when there is a decodable temporal unit.";
299*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_NOTREACHED();
300*d9f75844SAndroid Build Coastguard Worker return;
301*d9f75844SAndroid Build Coastguard Worker }
302*d9f75844SAndroid Build Coastguard Worker OnFrameReady(std::move(frames), render_time);
303*d9f75844SAndroid Build Coastguard Worker }
304*d9f75844SAndroid Build Coastguard Worker
UpdateDroppedFrames()305*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::UpdateDroppedFrames()
306*d9f75844SAndroid Build Coastguard Worker RTC_RUN_ON(&worker_sequence_checker_) {
307*d9f75844SAndroid Build Coastguard Worker const int dropped_frames = buffer_->GetTotalNumberOfDroppedFrames() -
308*d9f75844SAndroid Build Coastguard Worker frames_dropped_before_last_new_frame_;
309*d9f75844SAndroid Build Coastguard Worker if (dropped_frames > 0)
310*d9f75844SAndroid Build Coastguard Worker stats_proxy_->OnDroppedFrames(dropped_frames);
311*d9f75844SAndroid Build Coastguard Worker frames_dropped_before_last_new_frame_ =
312*d9f75844SAndroid Build Coastguard Worker buffer_->GetTotalNumberOfDroppedFrames();
313*d9f75844SAndroid Build Coastguard Worker }
314*d9f75844SAndroid Build Coastguard Worker
UpdateJitterDelay()315*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::UpdateJitterDelay() {
316*d9f75844SAndroid Build Coastguard Worker auto timings = timing_->GetTimings();
317*d9f75844SAndroid Build Coastguard Worker if (timings.num_decoded_frames) {
318*d9f75844SAndroid Build Coastguard Worker stats_proxy_->OnFrameBufferTimingsUpdated(
319*d9f75844SAndroid Build Coastguard Worker timings.max_decode_duration.ms(), timings.current_delay.ms(),
320*d9f75844SAndroid Build Coastguard Worker timings.target_delay.ms(), timings.jitter_buffer_delay.ms(),
321*d9f75844SAndroid Build Coastguard Worker timings.min_playout_delay.ms(), timings.render_delay.ms());
322*d9f75844SAndroid Build Coastguard Worker }
323*d9f75844SAndroid Build Coastguard Worker }
324*d9f75844SAndroid Build Coastguard Worker
UpdateTimingFrameInfo()325*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::UpdateTimingFrameInfo() {
326*d9f75844SAndroid Build Coastguard Worker absl::optional<TimingFrameInfo> info = timing_->GetTimingFrameInfo();
327*d9f75844SAndroid Build Coastguard Worker if (info)
328*d9f75844SAndroid Build Coastguard Worker stats_proxy_->OnTimingFrameInfoUpdated(*info);
329*d9f75844SAndroid Build Coastguard Worker }
330*d9f75844SAndroid Build Coastguard Worker
IsTooManyFramesQueued() const331*d9f75844SAndroid Build Coastguard Worker bool VideoStreamBufferController::IsTooManyFramesQueued() const
332*d9f75844SAndroid Build Coastguard Worker RTC_RUN_ON(&worker_sequence_checker_) {
333*d9f75844SAndroid Build Coastguard Worker return buffer_->CurrentSize() > zero_playout_delay_max_decode_queue_size_;
334*d9f75844SAndroid Build Coastguard Worker }
335*d9f75844SAndroid Build Coastguard Worker
ForceKeyFrameReleaseImmediately()336*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::ForceKeyFrameReleaseImmediately()
337*d9f75844SAndroid Build Coastguard Worker RTC_RUN_ON(&worker_sequence_checker_) {
338*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK(keyframe_required_);
339*d9f75844SAndroid Build Coastguard Worker // Iterate through the frame buffer until there is a complete keyframe and
340*d9f75844SAndroid Build Coastguard Worker // release this right away.
341*d9f75844SAndroid Build Coastguard Worker while (buffer_->DecodableTemporalUnitsInfo()) {
342*d9f75844SAndroid Build Coastguard Worker auto next_frame = buffer_->ExtractNextDecodableTemporalUnit();
343*d9f75844SAndroid Build Coastguard Worker if (next_frame.empty()) {
344*d9f75844SAndroid Build Coastguard Worker RTC_DCHECK_NOTREACHED()
345*d9f75844SAndroid Build Coastguard Worker << "Frame buffer should always return at least 1 frame.";
346*d9f75844SAndroid Build Coastguard Worker continue;
347*d9f75844SAndroid Build Coastguard Worker }
348*d9f75844SAndroid Build Coastguard Worker // Found keyframe - decode right away.
349*d9f75844SAndroid Build Coastguard Worker if (next_frame.front()->is_keyframe()) {
350*d9f75844SAndroid Build Coastguard Worker auto render_time = timing_->RenderTime(next_frame.front()->Timestamp(),
351*d9f75844SAndroid Build Coastguard Worker clock_->CurrentTime());
352*d9f75844SAndroid Build Coastguard Worker OnFrameReady(std::move(next_frame), render_time);
353*d9f75844SAndroid Build Coastguard Worker return;
354*d9f75844SAndroid Build Coastguard Worker }
355*d9f75844SAndroid Build Coastguard Worker }
356*d9f75844SAndroid Build Coastguard Worker }
357*d9f75844SAndroid Build Coastguard Worker
MaybeScheduleFrameForRelease()358*d9f75844SAndroid Build Coastguard Worker void VideoStreamBufferController::MaybeScheduleFrameForRelease()
359*d9f75844SAndroid Build Coastguard Worker RTC_RUN_ON(&worker_sequence_checker_) {
360*d9f75844SAndroid Build Coastguard Worker auto decodable_tu_info = buffer_->DecodableTemporalUnitsInfo();
361*d9f75844SAndroid Build Coastguard Worker if (!decoder_ready_for_new_frame_ || !decodable_tu_info) {
362*d9f75844SAndroid Build Coastguard Worker return;
363*d9f75844SAndroid Build Coastguard Worker }
364*d9f75844SAndroid Build Coastguard Worker
365*d9f75844SAndroid Build Coastguard Worker if (keyframe_required_) {
366*d9f75844SAndroid Build Coastguard Worker return ForceKeyFrameReleaseImmediately();
367*d9f75844SAndroid Build Coastguard Worker }
368*d9f75844SAndroid Build Coastguard Worker
369*d9f75844SAndroid Build Coastguard Worker // If already scheduled then abort.
370*d9f75844SAndroid Build Coastguard Worker if (frame_decode_scheduler_->ScheduledRtpTimestamp() ==
371*d9f75844SAndroid Build Coastguard Worker decodable_tu_info->next_rtp_timestamp) {
372*d9f75844SAndroid Build Coastguard Worker return;
373*d9f75844SAndroid Build Coastguard Worker }
374*d9f75844SAndroid Build Coastguard Worker
375*d9f75844SAndroid Build Coastguard Worker TimeDelta max_wait = timeout_tracker_.TimeUntilTimeout();
376*d9f75844SAndroid Build Coastguard Worker // Ensures the frame is scheduled for decode before the stream times out.
377*d9f75844SAndroid Build Coastguard Worker // This is otherwise a race condition.
378*d9f75844SAndroid Build Coastguard Worker max_wait = std::max(max_wait - TimeDelta::Millis(1), TimeDelta::Zero());
379*d9f75844SAndroid Build Coastguard Worker absl::optional<FrameDecodeTiming::FrameSchedule> schedule;
380*d9f75844SAndroid Build Coastguard Worker while (decodable_tu_info) {
381*d9f75844SAndroid Build Coastguard Worker schedule = decode_timing_.OnFrameBufferUpdated(
382*d9f75844SAndroid Build Coastguard Worker decodable_tu_info->next_rtp_timestamp,
383*d9f75844SAndroid Build Coastguard Worker decodable_tu_info->last_rtp_timestamp, max_wait,
384*d9f75844SAndroid Build Coastguard Worker IsTooManyFramesQueued());
385*d9f75844SAndroid Build Coastguard Worker if (schedule) {
386*d9f75844SAndroid Build Coastguard Worker // Don't schedule if already waiting for the same frame.
387*d9f75844SAndroid Build Coastguard Worker if (frame_decode_scheduler_->ScheduledRtpTimestamp() !=
388*d9f75844SAndroid Build Coastguard Worker decodable_tu_info->next_rtp_timestamp) {
389*d9f75844SAndroid Build Coastguard Worker frame_decode_scheduler_->CancelOutstanding();
390*d9f75844SAndroid Build Coastguard Worker frame_decode_scheduler_->ScheduleFrame(
391*d9f75844SAndroid Build Coastguard Worker decodable_tu_info->next_rtp_timestamp, *schedule,
392*d9f75844SAndroid Build Coastguard Worker absl::bind_front(&VideoStreamBufferController::FrameReadyForDecode,
393*d9f75844SAndroid Build Coastguard Worker this));
394*d9f75844SAndroid Build Coastguard Worker }
395*d9f75844SAndroid Build Coastguard Worker return;
396*d9f75844SAndroid Build Coastguard Worker }
397*d9f75844SAndroid Build Coastguard Worker // If no schedule for current rtp, drop and try again.
398*d9f75844SAndroid Build Coastguard Worker buffer_->DropNextDecodableTemporalUnit();
399*d9f75844SAndroid Build Coastguard Worker decodable_tu_info = buffer_->DecodableTemporalUnitsInfo();
400*d9f75844SAndroid Build Coastguard Worker }
401*d9f75844SAndroid Build Coastguard Worker }
402*d9f75844SAndroid Build Coastguard Worker
403*d9f75844SAndroid Build Coastguard Worker } // namespace webrtc
404