Skip to content

Commit 93081d5

Browse files
Evan ShrubsoleWebRTC LUCI CQ
authored andcommitted
[Merge M108] Ensure video frame buffer is still decodable before decoding
This ensures that if for some reason, the frame buffer becomes undecodable while waiting to decode a frame, the decoding is halted. This also guards against receiving an empty temporal unit from the frame buffer, even though this should never happen when the frame buffer has a decodable temporal unit. (cherry picked from commit 8fe5579) Bug: chromium:1378253, chromium:1361623 Change-Id: I8c4c897bf474d5cbda5f0f357781bf1dc0701fe4 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/280701 Commit-Queue: Evan Shrubsole <[email protected]> Reviewed-by: Erik Språng <[email protected]> Cr-Original-Commit-Position: refs/heads/main@{#38494} Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/281720 Cr-Commit-Position: refs/branch-heads/5359@{webrtc-sdk#5} Cr-Branched-From: fb3bd4a-refs/heads/main@{#38387}
1 parent 1cd97e2 commit 93081d5

File tree

3 files changed

+70
-7
lines changed

3 files changed

+70
-7
lines changed

video/task_queue_frame_decode_scheduler.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,8 @@ void TaskQueueFrameDecodeScheduler::ScheduleFrame(
4949
SafeTask(task_safety_.flag(),
5050
[this, rtp, schedule, cb = std::move(cb)]() mutable {
5151
RTC_DCHECK_RUN_ON(bookkeeping_queue_);
52-
// If the next frame rtp has changed since this task was
53-
// this scheduled release should be skipped.
52+
// If the next frame rtp has changed since this task was
53+
// this scheduled release should be skipped.
5454
if (scheduled_rtp_ != rtp)
5555
return;
5656
scheduled_rtp_ = absl::nullopt;

video/video_stream_buffer_controller.cc

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,8 @@ void VideoStreamBufferController::OnFrameReady(
192192
absl::InlinedVector<std::unique_ptr<EncodedFrame>, 4> frames,
193193
Timestamp render_time) {
194194
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
195-
RTC_DCHECK(!frames.empty());
195+
RTC_CHECK(!frames.empty())
196+
<< "Callers must ensure there is at least one frame to decode.";
196197

197198
timeout_tracker_.OnEncodedFrameReleased();
198199

@@ -276,11 +277,29 @@ void VideoStreamBufferController::OnTimeout(TimeDelta delay) {
276277
void VideoStreamBufferController::FrameReadyForDecode(uint32_t rtp_timestamp,
277278
Timestamp render_time) {
278279
RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
279-
auto frames = buffer_->ExtractNextDecodableTemporalUnit();
280-
RTC_DCHECK(frames[0]->Timestamp() == rtp_timestamp)
280+
// Check that the frame to decode is still valid before passing the frame for
281+
// decoding.
282+
auto decodable_tu_info = buffer_->DecodableTemporalUnitsInfo();
283+
if (!decodable_tu_info) {
284+
RTC_LOG(LS_ERROR)
285+
<< "The frame buffer became undecodable during the wait "
286+
"to decode frame with rtp-timestamp "
287+
<< rtp_timestamp
288+
<< ". Cancelling the decode of this frame, decoding "
289+
"will resume when the frame buffers become decodable again.";
290+
return;
291+
}
292+
RTC_DCHECK_EQ(rtp_timestamp, decodable_tu_info->next_rtp_timestamp)
281293
<< "Frame buffer's next decodable frame was not the one sent for "
282-
"extraction rtp="
283-
<< rtp_timestamp << " extracted rtp=" << frames[0]->Timestamp();
294+
"extraction.";
295+
auto frames = buffer_->ExtractNextDecodableTemporalUnit();
296+
if (frames.empty()) {
297+
RTC_LOG(LS_ERROR)
298+
<< "The frame buffer should never return an empty temporal until list "
299+
"when there is a decodable temporal unit.";
300+
RTC_DCHECK_NOTREACHED();
301+
return;
302+
}
284303
OnFrameReady(std::move(frames), render_time);
285304
}
286305

video/video_stream_buffer_controller_unittest.cc

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -754,6 +754,50 @@ TEST_P(VideoStreamBufferControllerTest, NextFrameWithOldTimestamp) {
754754
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(2)));
755755
}
756756

757+
TEST_P(VideoStreamBufferControllerTest,
758+
FrameNotSetForDecodedIfFrameBufferBecomesNonDecodable) {
759+
// This can happen if the frame buffer receives non-standard input. This test
760+
// will simply clear the frame buffer to replicate this.
761+
StartNextDecodeForceKeyframe();
762+
// Initial keyframe.
763+
buffer_->InsertFrame(WithReceiveTimeFromRtpTimestamp(
764+
test::FakeFrameBuilder().Id(0).Time(0).SpatialLayer(1).AsLast().Build()));
765+
EXPECT_THAT(WaitForFrameOrTimeout(TimeDelta::Zero()), Frame(test::WithId(0)));
766+
767+
// Insert a frame that will become non-decodable.
768+
buffer_->InsertFrame(WithReceiveTimeFromRtpTimestamp(test::FakeFrameBuilder()
769+
.Id(11)
770+
.Time(kFps30Rtp)
771+
.Refs({0})
772+
.SpatialLayer(1)
773+
.AsLast()
774+
.Build()));
775+
StartNextDecode();
776+
// Second layer inserted after last layer for the same frame out-of-order.
777+
// This second frame requires some older frame to be decoded and so now the
778+
// super-frame is no longer decodable despite already being scheduled.
779+
buffer_->InsertFrame(WithReceiveTimeFromRtpTimestamp(test::FakeFrameBuilder()
780+
.Id(10)
781+
.Time(kFps30Rtp)
782+
.SpatialLayer(0)
783+
.Refs({2})
784+
.Build()));
785+
EXPECT_THAT(WaitForFrameOrTimeout(kMaxWaitForFrame), TimedOut());
786+
787+
// Ensure that this frame can be decoded later.
788+
StartNextDecode();
789+
buffer_->InsertFrame(WithReceiveTimeFromRtpTimestamp(test::FakeFrameBuilder()
790+
.Id(2)
791+
.Time(kFps30Rtp / 2)
792+
.SpatialLayer(0)
793+
.Refs({0})
794+
.AsLast()
795+
.Build()));
796+
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(2)));
797+
StartNextDecode();
798+
EXPECT_THAT(WaitForFrameOrTimeout(kFps30Delay), Frame(test::WithId(10)));
799+
}
800+
757801
INSTANTIATE_TEST_SUITE_P(VideoStreamBufferController,
758802
VideoStreamBufferControllerTest,
759803
::testing::Combine(::testing::Bool(),

0 commit comments

Comments
 (0)