blob: 93bb147802c5ebb78f2c175531179f27697c28e8 [file] [log] [blame]
Evan Shrubsole476f18d22022-08-15 15:21:161/*
2 * Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11#include "video/video_stream_buffer_controller.h"
12
13#include <algorithm>
Philipp Hancke94db4c42025-05-06 20:55:1314#include <cstddef>
15#include <cstdint>
Evan Shrubsole476f18d22022-08-15 15:21:1616#include <memory>
Florent Castelli8037fc62024-08-29 13:00:4017#include <optional>
Evan Shrubsole476f18d22022-08-15 15:21:1618#include <utility>
19
Philipp Hancke94db4c42025-05-06 20:55:1320#include "absl/container/inlined_vector.h"
Evan Shrubsole476f18d22022-08-15 15:21:1621#include "absl/functional/bind_front.h"
Philipp Hancke94db4c42025-05-06 20:55:1322#include "api/field_trials_view.h"
Evan Shrubsole476f18d22022-08-15 15:21:1623#include "api/sequence_checker.h"
24#include "api/task_queue/task_queue_base.h"
25#include "api/units/data_size.h"
Rasmus Brandt65a6eca2023-03-03 08:22:1826#include "api/units/time_delta.h"
Rasmus Brandt621cb292023-05-24 11:29:1427#include "api/units/timestamp.h"
Evan Shrubsole476f18d22022-08-15 15:21:1628#include "api/video/encoded_frame.h"
29#include "api/video/frame_buffer.h"
30#include "api/video/video_content_type.h"
Philipp Hancke94db4c42025-05-06 20:55:1331#include "api/video/video_timing.h"
Evan Shrubsole476f18d22022-08-15 15:21:1632#include "modules/video_coding/frame_helpers.h"
Philipp Hancke94db4c42025-05-06 20:55:1333#include "modules/video_coding/include/video_coding_defines.h"
Rasmus Brandt65a6eca2023-03-03 08:22:1834#include "modules/video_coding/timing/inter_frame_delay_variation_calculator.h"
Evan Shrubsole476f18d22022-08-15 15:21:1635#include "modules/video_coding/timing/jitter_estimator.h"
Philipp Hancke94db4c42025-05-06 20:55:1336#include "modules/video_coding/timing/timing.h"
Evan Shrubsole476f18d22022-08-15 15:21:1637#include "rtc_base/checks.h"
Philipp Hancke94db4c42025-05-06 20:55:1338#include "rtc_base/experiments/field_trial_parser.h"
Evan Shrubsole476f18d22022-08-15 15:21:1639#include "rtc_base/logging.h"
Evan Shrubsolea006ba12022-09-05 10:09:0840#include "video/frame_decode_scheduler.h"
Evan Shrubsole476f18d22022-08-15 15:21:1641#include "video/frame_decode_timing.h"
Evan Shrubsole476f18d22022-08-15 15:21:1642#include "video/video_receive_stream_timeout_tracker.h"
43
44namespace webrtc {
45
46namespace {
47
48// Max number of frames the buffer will hold.
49static constexpr size_t kMaxFramesBuffered = 800;
50// Max number of decoded frame info that will be saved.
51static constexpr int kMaxFramesHistory = 1 << 13;
52
53// Default value for the maximum decode queue size that is used when the
54// low-latency renderer is used.
55static constexpr size_t kZeroPlayoutDelayDefaultMaxDecodeQueueSize = 8;
56
57struct FrameMetadata {
58 explicit FrameMetadata(const EncodedFrame& frame)
59 : is_last_spatial_layer(frame.is_last_spatial_layer),
60 is_keyframe(frame.is_keyframe()),
61 size(frame.size()),
62 contentType(frame.contentType()),
63 delayed_by_retransmission(frame.delayed_by_retransmission()),
Danil Chapovalov9c584832023-09-18 13:48:4964 rtp_timestamp(frame.RtpTimestamp()),
Evan Shrubsole476f18d22022-08-15 15:21:1665 receive_time(frame.ReceivedTimestamp()) {}
66
67 const bool is_last_spatial_layer;
68 const bool is_keyframe;
69 const size_t size;
70 const VideoContentType contentType;
71 const bool delayed_by_retransmission;
72 const uint32_t rtp_timestamp;
Florent Castelli8037fc62024-08-29 13:00:4073 const std::optional<Timestamp> receive_time;
Evan Shrubsole476f18d22022-08-15 15:21:1674};
75
Rasmus Brandt621cb292023-05-24 11:29:1476Timestamp MinReceiveTime(const EncodedFrame& frame) {
77 Timestamp first_recv_time = Timestamp::PlusInfinity();
78 for (const auto& packet_info : frame.PacketInfos()) {
79 if (packet_info.receive_time().IsFinite()) {
80 first_recv_time = std::min(first_recv_time, packet_info.receive_time());
81 }
82 }
83 return first_recv_time;
84}
85
Evan Shrubsole476f18d22022-08-15 15:21:1686Timestamp ReceiveTime(const EncodedFrame& frame) {
Florent Castelli8037fc62024-08-29 13:00:4087 std::optional<Timestamp> ts = frame.ReceivedTimestamp();
Evan Shrubsole476f18d22022-08-15 15:21:1688 RTC_DCHECK(ts.has_value()) << "Received frame must have a timestamp set!";
89 return *ts;
90}
91
Evan Shrubsole476f18d22022-08-15 15:21:1692} // namespace
93
Evan Shrubsole476f18d22022-08-15 15:21:1694VideoStreamBufferController::VideoStreamBufferController(
95 Clock* clock,
96 TaskQueueBase* worker_queue,
97 VCMTiming* timing,
Rasmus Brandt39250a42023-05-09 12:33:4398 VideoStreamBufferControllerStatsObserver* stats_proxy,
Evan Shrubsole476f18d22022-08-15 15:21:1699 FrameSchedulingReceiver* receiver,
100 TimeDelta max_wait_for_keyframe,
101 TimeDelta max_wait_for_frame,
102 std::unique_ptr<FrameDecodeScheduler> frame_decode_scheduler,
103 const FieldTrialsView& field_trials)
104 : field_trials_(field_trials),
105 clock_(clock),
Evan Shrubsole476f18d22022-08-15 15:21:16106 stats_proxy_(stats_proxy),
107 receiver_(receiver),
108 timing_(timing),
109 frame_decode_scheduler_(std::move(frame_decode_scheduler)),
110 jitter_estimator_(clock_, field_trials),
111 buffer_(std::make_unique<FrameBuffer>(kMaxFramesBuffered,
112 kMaxFramesHistory,
113 field_trials)),
114 decode_timing_(clock_, timing_),
115 timeout_tracker_(
116 clock_,
Evan Shrubsole214cab52022-08-16 09:48:23117 worker_queue,
Evan Shrubsole476f18d22022-08-15 15:21:16118 VideoReceiveStreamTimeoutTracker::Timeouts{
119 .max_wait_for_keyframe = max_wait_for_keyframe,
120 .max_wait_for_frame = max_wait_for_frame},
121 absl::bind_front(&VideoStreamBufferController::OnTimeout, this)),
122 zero_playout_delay_max_decode_queue_size_(
123 "max_decode_queue_size",
124 kZeroPlayoutDelayDefaultMaxDecodeQueueSize) {
Evan Shrubsole476f18d22022-08-15 15:21:16125 RTC_DCHECK(stats_proxy_);
126 RTC_DCHECK(receiver_);
127 RTC_DCHECK(timing_);
Evan Shrubsole476f18d22022-08-15 15:21:16128 RTC_DCHECK(clock_);
129 RTC_DCHECK(frame_decode_scheduler_);
Evan Shrubsole476f18d22022-08-15 15:21:16130
131 ParseFieldTrial({&zero_playout_delay_max_decode_queue_size_},
132 field_trials.Lookup("WebRTC-ZeroPlayoutDelay"));
133}
134
Evan Shrubsole214cab52022-08-16 09:48:23135void VideoStreamBufferController::Stop() {
Evan Shrubsole476f18d22022-08-15 15:21:16136 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
137 frame_decode_scheduler_->Stop();
138 timeout_tracker_.Stop();
139 decoder_ready_for_new_frame_ = false;
Evan Shrubsole476f18d22022-08-15 15:21:16140}
141
142void VideoStreamBufferController::SetProtectionMode(
143 VCMVideoProtection protection_mode) {
144 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
145 protection_mode_ = protection_mode;
146}
147
148void VideoStreamBufferController::Clear() {
149 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
150 stats_proxy_->OnDroppedFrames(buffer_->CurrentSize());
151 buffer_ = std::make_unique<FrameBuffer>(kMaxFramesBuffered, kMaxFramesHistory,
152 field_trials_);
153 frame_decode_scheduler_->CancelOutstanding();
154}
155
Florent Castelli8037fc62024-08-29 13:00:40156std::optional<int64_t> VideoStreamBufferController::InsertFrame(
Evan Shrubsole476f18d22022-08-15 15:21:16157 std::unique_ptr<EncodedFrame> frame) {
158 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
159 FrameMetadata metadata(*frame);
160 int complete_units = buffer_->GetTotalNumberOfContinuousTemporalUnits();
161 if (buffer_->InsertFrame(std::move(frame))) {
162 RTC_DCHECK(metadata.receive_time) << "Frame receive time must be set!";
philipel7446b602022-10-06 13:49:17163 if (!metadata.delayed_by_retransmission && metadata.receive_time &&
164 (field_trials_.IsDisabled("WebRTC-IncomingTimestampOnMarkerBitOnly") ||
165 metadata.is_last_spatial_layer)) {
Evan Shrubsole476f18d22022-08-15 15:21:16166 timing_->IncomingTimestamp(metadata.rtp_timestamp,
167 *metadata.receive_time);
philipel7446b602022-10-06 13:49:17168 }
Evan Shrubsole476f18d22022-08-15 15:21:16169 if (complete_units < buffer_->GetTotalNumberOfContinuousTemporalUnits()) {
170 stats_proxy_->OnCompleteFrame(metadata.is_keyframe, metadata.size,
171 metadata.contentType);
172 MaybeScheduleFrameForRelease();
173 }
174 }
175
176 return buffer_->LastContinuousFrameId();
177}
178
179void VideoStreamBufferController::UpdateRtt(int64_t max_rtt_ms) {
180 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
181 jitter_estimator_.UpdateRtt(TimeDelta::Millis(max_rtt_ms));
182}
183
184void VideoStreamBufferController::SetMaxWaits(TimeDelta max_wait_for_keyframe,
185 TimeDelta max_wait_for_frame) {
186 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
187 timeout_tracker_.SetTimeouts({.max_wait_for_keyframe = max_wait_for_keyframe,
188 .max_wait_for_frame = max_wait_for_frame});
189}
190
191void VideoStreamBufferController::StartNextDecode(bool keyframe_required) {
Evan Shrubsole476f18d22022-08-15 15:21:16192 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
193 if (!timeout_tracker_.Running())
194 timeout_tracker_.Start(keyframe_required);
195 keyframe_required_ = keyframe_required;
196 if (keyframe_required_) {
197 timeout_tracker_.SetWaitingForKeyframe();
198 }
199 decoder_ready_for_new_frame_ = true;
200 MaybeScheduleFrameForRelease();
201}
202
203int VideoStreamBufferController::Size() {
204 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
205 return buffer_->CurrentSize();
206}
207
208void VideoStreamBufferController::OnFrameReady(
209 absl::InlinedVector<std::unique_ptr<EncodedFrame>, 4> frames,
210 Timestamp render_time) {
211 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
Evan Shrubsole8fe55792022-10-27 11:05:44212 RTC_CHECK(!frames.empty())
213 << "Callers must ensure there is at least one frame to decode.";
Evan Shrubsole476f18d22022-08-15 15:21:16214
215 timeout_tracker_.OnEncodedFrameReleased();
216
217 Timestamp now = clock_->CurrentTime();
218 bool superframe_delayed_by_retransmission = false;
219 DataSize superframe_size = DataSize::Zero();
220 const EncodedFrame& first_frame = *frames.front();
Rasmus Brandt621cb292023-05-24 11:29:14221 Timestamp min_receive_time = MinReceiveTime(first_frame);
222 Timestamp max_receive_time = ReceiveTime(first_frame);
Evan Shrubsole476f18d22022-08-15 15:21:16223
224 if (first_frame.is_keyframe())
225 keyframe_required_ = false;
226
227 // Gracefully handle bad RTP timestamps and render time issues.
Rasmus Brandtfb3bd4a2022-10-13 11:43:27228 if (FrameHasBadRenderTiming(render_time, now) ||
229 TargetVideoDelayIsTooLarge(timing_->TargetVideoDelay())) {
230 RTC_LOG(LS_WARNING) << "Resetting jitter estimator and timing module due "
231 "to bad render timing for rtp_timestamp="
Danil Chapovalov9c584832023-09-18 13:48:49232 << first_frame.RtpTimestamp();
Evan Shrubsole476f18d22022-08-15 15:21:16233 jitter_estimator_.Reset();
234 timing_->Reset();
Danil Chapovalov9c584832023-09-18 13:48:49235 render_time = timing_->RenderTime(first_frame.RtpTimestamp(), now);
Evan Shrubsole476f18d22022-08-15 15:21:16236 }
237
238 for (std::unique_ptr<EncodedFrame>& frame : frames) {
239 frame->SetRenderTime(render_time.ms());
240
241 superframe_delayed_by_retransmission |= frame->delayed_by_retransmission();
Rasmus Brandt621cb292023-05-24 11:29:14242 min_receive_time = std::min(min_receive_time, MinReceiveTime(*frame));
243 max_receive_time = std::max(max_receive_time, ReceiveTime(*frame));
Evan Shrubsole476f18d22022-08-15 15:21:16244 superframe_size += DataSize::Bytes(frame->size());
245 }
246
247 if (!superframe_delayed_by_retransmission) {
Florent Castelli8037fc62024-08-29 13:00:40248 std::optional<TimeDelta> inter_frame_delay_variation =
Danil Chapovalov9c584832023-09-18 13:48:49249 ifdv_calculator_.Calculate(first_frame.RtpTimestamp(),
250 max_receive_time);
Rasmus Brandt65a6eca2023-03-03 08:22:18251 if (inter_frame_delay_variation) {
252 jitter_estimator_.UpdateEstimate(*inter_frame_delay_variation,
253 superframe_size);
Evan Shrubsole476f18d22022-08-15 15:21:16254 }
255
Danil Chapovalov358d6742024-03-22 16:00:40256 static constexpr float kRttMult = 0.9f;
257 static constexpr TimeDelta kRttMultAddCap = TimeDelta::Millis(200);
Evan Shrubsole476f18d22022-08-15 15:21:16258 timing_->SetJitterDelay(
Danil Chapovalov358d6742024-03-22 16:00:40259 jitter_estimator_.GetJitterEstimate(kRttMult, kRttMultAddCap));
Evan Shrubsole476f18d22022-08-15 15:21:16260 timing_->UpdateCurrentDelay(render_time, now);
Danil Chapovalov358d6742024-03-22 16:00:40261 } else {
Evan Shrubsole476f18d22022-08-15 15:21:16262 jitter_estimator_.FrameNacked();
263 }
264
265 // Update stats.
266 UpdateDroppedFrames();
Rasmus Brandt621cb292023-05-24 11:29:14267 UpdateFrameBufferTimings(min_receive_time, now);
Evan Shrubsole476f18d22022-08-15 15:21:16268 UpdateTimingFrameInfo();
269
270 std::unique_ptr<EncodedFrame> frame =
271 CombineAndDeleteFrames(std::move(frames));
272
273 timing_->SetLastDecodeScheduledTimestamp(now);
274
275 decoder_ready_for_new_frame_ = false;
Evan Shrubsole214cab52022-08-16 09:48:23276 receiver_->OnEncodedFrame(std::move(frame));
Evan Shrubsole476f18d22022-08-15 15:21:16277}
278
279void VideoStreamBufferController::OnTimeout(TimeDelta delay) {
280 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
Evan Shrubsole214cab52022-08-16 09:48:23281
282 // Stop sending timeouts until receiver starts waiting for a new frame.
283 timeout_tracker_.Stop();
284
Evan Shrubsole476f18d22022-08-15 15:21:16285 // If the stream is paused then ignore the timeout.
286 if (!decoder_ready_for_new_frame_) {
Evan Shrubsole476f18d22022-08-15 15:21:16287 return;
288 }
Evan Shrubsole476f18d22022-08-15 15:21:16289 decoder_ready_for_new_frame_ = false;
Evan Shrubsole214cab52022-08-16 09:48:23290 receiver_->OnDecodableFrameTimeout(delay);
Evan Shrubsole476f18d22022-08-15 15:21:16291}
292
293void VideoStreamBufferController::FrameReadyForDecode(uint32_t rtp_timestamp,
294 Timestamp render_time) {
295 RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
Evan Shrubsole8fe55792022-10-27 11:05:44296 // Check that the frame to decode is still valid before passing the frame for
297 // decoding.
298 auto decodable_tu_info = buffer_->DecodableTemporalUnitsInfo();
299 if (!decodable_tu_info) {
300 RTC_LOG(LS_ERROR)
301 << "The frame buffer became undecodable during the wait "
302 "to decode frame with rtp-timestamp "
303 << rtp_timestamp
304 << ". Cancelling the decode of this frame, decoding "
305 "will resume when the frame buffers become decodable again.";
306 return;
307 }
308 RTC_DCHECK_EQ(rtp_timestamp, decodable_tu_info->next_rtp_timestamp)
Evan Shrubsole476f18d22022-08-15 15:21:16309 << "Frame buffer's next decodable frame was not the one sent for "
Evan Shrubsole8fe55792022-10-27 11:05:44310 "extraction.";
311 auto frames = buffer_->ExtractNextDecodableTemporalUnit();
312 if (frames.empty()) {
313 RTC_LOG(LS_ERROR)
314 << "The frame buffer should never return an empty temporal until list "
315 "when there is a decodable temporal unit.";
316 RTC_DCHECK_NOTREACHED();
317 return;
318 }
Evan Shrubsole476f18d22022-08-15 15:21:16319 OnFrameReady(std::move(frames), render_time);
320}
321
322void VideoStreamBufferController::UpdateDroppedFrames()
323 RTC_RUN_ON(&worker_sequence_checker_) {
324 const int dropped_frames = buffer_->GetTotalNumberOfDroppedFrames() -
325 frames_dropped_before_last_new_frame_;
326 if (dropped_frames > 0)
327 stats_proxy_->OnDroppedFrames(dropped_frames);
328 frames_dropped_before_last_new_frame_ =
329 buffer_->GetTotalNumberOfDroppedFrames();
330}
331
Rasmus Brandt621cb292023-05-24 11:29:14332void VideoStreamBufferController::UpdateFrameBufferTimings(
333 Timestamp min_receive_time,
334 Timestamp now) {
335 // Update instantaneous delays.
Evan Shrubsole476f18d22022-08-15 15:21:16336 auto timings = timing_->GetTimings();
337 if (timings.num_decoded_frames) {
338 stats_proxy_->OnFrameBufferTimingsUpdated(
Rasmus Brandt24f9a8b2023-05-08 14:32:48339 timings.estimated_max_decode_time.ms(), timings.current_delay.ms(),
Rasmus Brandtf0820ff2023-05-25 07:37:16340 timings.target_delay.ms(), timings.minimum_delay.ms(),
Evan Shrubsole476f18d22022-08-15 15:21:16341 timings.min_playout_delay.ms(), timings.render_delay.ms());
342 }
Rasmus Brandt621cb292023-05-24 11:29:14343
344 // The spec mandates that `jitterBufferDelay` is the "time the first
345 // packet is received by the jitter buffer (ingest timestamp) to the time it
346 // exits the jitter buffer (emit timestamp)". Since the "jitter buffer"
347 // is not a monolith in the webrtc.org implementation, we take the freedom to
348 // define "ingest timestamp" as "first packet received by
349 // RtpVideoStreamReceiver2" and "emit timestamp" as "decodable frame released
350 // by VideoStreamBufferController".
351 //
352 // https://w3c.github.io/webrtc-stats/#dom-rtcinboundrtpstreamstats-jitterbufferdelay
353 TimeDelta jitter_buffer_delay =
354 std::max(TimeDelta::Zero(), now - min_receive_time);
Rasmus Brandtf0820ff2023-05-25 07:37:16355 stats_proxy_->OnDecodableFrame(jitter_buffer_delay, timings.target_delay,
356 timings.minimum_delay);
Evan Shrubsole476f18d22022-08-15 15:21:16357}
358
359void VideoStreamBufferController::UpdateTimingFrameInfo() {
Florent Castelli8037fc62024-08-29 13:00:40360 std::optional<TimingFrameInfo> info = timing_->GetTimingFrameInfo();
Evan Shrubsole476f18d22022-08-15 15:21:16361 if (info)
362 stats_proxy_->OnTimingFrameInfoUpdated(*info);
363}
364
365bool VideoStreamBufferController::IsTooManyFramesQueued() const
366 RTC_RUN_ON(&worker_sequence_checker_) {
367 return buffer_->CurrentSize() > zero_playout_delay_max_decode_queue_size_;
368}
369
370void VideoStreamBufferController::ForceKeyFrameReleaseImmediately()
371 RTC_RUN_ON(&worker_sequence_checker_) {
372 RTC_DCHECK(keyframe_required_);
373 // Iterate through the frame buffer until there is a complete keyframe and
374 // release this right away.
375 while (buffer_->DecodableTemporalUnitsInfo()) {
376 auto next_frame = buffer_->ExtractNextDecodableTemporalUnit();
377 if (next_frame.empty()) {
378 RTC_DCHECK_NOTREACHED()
379 << "Frame buffer should always return at least 1 frame.";
380 continue;
381 }
382 // Found keyframe - decode right away.
383 if (next_frame.front()->is_keyframe()) {
Danil Chapovalov9c584832023-09-18 13:48:49384 auto render_time = timing_->RenderTime(next_frame.front()->RtpTimestamp(),
Evan Shrubsole476f18d22022-08-15 15:21:16385 clock_->CurrentTime());
386 OnFrameReady(std::move(next_frame), render_time);
387 return;
388 }
389 }
390}
391
392void VideoStreamBufferController::MaybeScheduleFrameForRelease()
393 RTC_RUN_ON(&worker_sequence_checker_) {
394 auto decodable_tu_info = buffer_->DecodableTemporalUnitsInfo();
395 if (!decoder_ready_for_new_frame_ || !decodable_tu_info) {
396 return;
397 }
398
399 if (keyframe_required_) {
400 return ForceKeyFrameReleaseImmediately();
401 }
402
403 // If already scheduled then abort.
404 if (frame_decode_scheduler_->ScheduledRtpTimestamp() ==
405 decodable_tu_info->next_rtp_timestamp) {
406 return;
407 }
408
409 TimeDelta max_wait = timeout_tracker_.TimeUntilTimeout();
410 // Ensures the frame is scheduled for decode before the stream times out.
411 // This is otherwise a race condition.
412 max_wait = std::max(max_wait - TimeDelta::Millis(1), TimeDelta::Zero());
Florent Castelli8037fc62024-08-29 13:00:40413 std::optional<FrameDecodeTiming::FrameSchedule> schedule;
Evan Shrubsole476f18d22022-08-15 15:21:16414 while (decodable_tu_info) {
415 schedule = decode_timing_.OnFrameBufferUpdated(
416 decodable_tu_info->next_rtp_timestamp,
417 decodable_tu_info->last_rtp_timestamp, max_wait,
418 IsTooManyFramesQueued());
419 if (schedule) {
420 // Don't schedule if already waiting for the same frame.
421 if (frame_decode_scheduler_->ScheduledRtpTimestamp() !=
422 decodable_tu_info->next_rtp_timestamp) {
423 frame_decode_scheduler_->CancelOutstanding();
424 frame_decode_scheduler_->ScheduleFrame(
425 decodable_tu_info->next_rtp_timestamp, *schedule,
426 absl::bind_front(&VideoStreamBufferController::FrameReadyForDecode,
427 this));
428 }
429 return;
430 }
431 // If no schedule for current rtp, drop and try again.
432 buffer_->DropNextDecodableTemporalUnit();
433 decodable_tu_info = buffer_->DecodableTemporalUnitsInfo();
434 }
435}
436
437} // namespace webrtc