Smaller updates to VCMTiming. - Rename SetJitterDelay to SetMinimumDelay. - Rename IncomingTimestamp to OnCompleteTemporalUnit. Bug: b/493549134 Change-Id: Ie9fde71e242fba19b783c8c66b54b14fba3f2217 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/467741 Commit-Queue: Åsa Persson <asapersson@webrtc.org> Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Cr-Commit-Position: refs/heads/main@{#47579}
diff --git a/modules/video_coding/timing/timing.cc b/modules/video_coding/timing/timing.cc index 5db6208..e1d8114 100644 --- a/modules/video_coding/timing/timing.cc +++ b/modules/video_coding/timing/timing.cc
@@ -124,7 +124,7 @@ timings_.max_playout_delay = playout_delay.max(); } -void VCMTiming::SetJitterDelay(TimeDelta minimum_delay) { +void VCMTiming::SetMinimumDelay(TimeDelta minimum_delay) { MutexLock lock(&mutex_); if (minimum_delay != timings_.minimum_delay) { timings_.minimum_delay = minimum_delay; @@ -163,32 +163,25 @@ TimeDelta::Millis(decode_time_filter_->GetPercentileMs()); } -void VCMTiming::IncomingTimestamp(uint32_t rtp_timestamp, Timestamp now) { +void VCMTiming::OnCompleteTemporalUnit(uint32_t rtp_timestamp, Timestamp now) { MutexLock lock(&mutex_); ts_extrapolator_->Update(now, rtp_timestamp); } -Timestamp VCMTiming::RenderTime(uint32_t frame_timestamp, Timestamp now) const { +Timestamp VCMTiming::RenderTime(uint32_t rtp_timestamp, Timestamp now) const { MutexLock lock(&mutex_); if (timings_.UseLowLatencyRendering()) { // Render as soon as possible or with low-latency renderer algorithm. return Timestamp::Zero(); } - // Note that TimestampExtrapolator::ExtrapolateLocalTime is not a const - // method; it mutates the object's wraparound state. std::optional<Timestamp> local_time = - ts_extrapolator_->ExtrapolateLocalTime(frame_timestamp); + ts_extrapolator_->ExtrapolateLocalTime(rtp_timestamp); if (!local_time.has_value()) { return now; } - Timestamp estimated_complete_time = *local_time; - - // Make sure the actual delay stays in the range of `min_playout_delay` - // and `max_playout_delay`. - TimeDelta actual_delay = - std::clamp(timings_.current_delay, timings_.min_playout_delay, - timings_.max_playout_delay); - return estimated_complete_time + actual_delay; + return *local_time + std::clamp(timings_.current_delay, + timings_.min_playout_delay, + timings_.max_playout_delay); } void VCMTiming::SetLastDecodeScheduledTimestamp(
diff --git a/modules/video_coding/timing/timing.h b/modules/video_coding/timing/timing.h index adc1ec5..6caae0b 100644 --- a/modules/video_coding/timing/timing.h +++ b/modules/video_coding/timing/timing.h
@@ -76,7 +76,7 @@ // Sets the minimum time the video must be delayed on the receiver to // get the desired jitter buffer level. - void SetJitterDelay(TimeDelta required_delay); + void SetMinimumDelay(TimeDelta minimum_delay); // Sets/gets the minimum playout delay from capture to render. TimeDelta min_playout_delay() const; @@ -97,13 +97,11 @@ // Used to report that a frame is passed to decoding. Updates the timestamp // filter which is used to map between timestamps and receiver system time. - virtual void IncomingTimestamp(uint32_t rtp_timestamp, - Timestamp last_packet_time); + virtual void OnCompleteTemporalUnit(uint32_t rtp_timestamp, Timestamp now); - // Returns the receiver system time when the frame with timestamp - // `frame_timestamp` should be rendered, assuming that the system time - // currently is `now`. - virtual Timestamp RenderTime(uint32_t frame_timestamp, Timestamp now) const; + // Returns the receiver system time when the frame with `rtp_timestamp` + // should be rendered, assuming that the system time currently is `now`. + virtual Timestamp RenderTime(uint32_t rtp_timestamp, Timestamp now) const; // Returns the maximum time in ms that we can wait for a frame to become // complete before we must pass it to the decoder. render_time==0 indicates @@ -116,7 +114,7 @@ Timestamp now, bool too_many_frames_queued) const; - // Returns the current target delay which is required delay + decode time + + // Returns the current target delay which is minimum delay + decode time + // render delay. TimeDelta TargetVideoDelay() const;
diff --git a/modules/video_coding/timing/timing_unittest.cc b/modules/video_coding/timing/timing_unittest.cc index fb139e8..87d163a 100644 --- a/modules/video_coding/timing/timing_unittest.cc +++ b/modules/video_coding/timing/timing_unittest.cc
@@ -26,9 +26,10 @@ constexpr Frequency k25Fps = Frequency::Hertz(25); constexpr Frequency k90kHz = Frequency::KiloHertz(90); -constexpr TimeDelta kJitterDelay = TimeDelta::Millis(100); +constexpr TimeDelta kMinimumDelay = TimeDelta::Millis(100); constexpr TimeDelta kDecodeTime = TimeDelta::Millis(20); constexpr TimeDelta kRenderDelay = TimeDelta::Millis(15); +constexpr Timestamp kUnusedTimestamp = Timestamp::MinusInfinity(); MATCHER(HasConsistentVideoDelayTimings, "") { // Delays should be non-negative. @@ -102,7 +103,7 @@ constexpr uint32_t kRtpTicksPerFrame = k90kHz / k25Fps; uint32_t timestamp = 0xFFFFFFFFu - 3 * kRtpTicksPerFrame; for (int i = 0; i < 5; ++i) { - timing.IncomingTimestamp(timestamp, clock.CurrentTime()); + timing.OnCompleteTemporalUnit(timestamp, clock.CurrentTime()); clock.AdvanceTime(1 / k25Fps); timestamp += kRtpTicksPerFrame; EXPECT_EQ(kStartTime + 3 / k25Fps, @@ -401,14 +402,14 @@ timing.set_playout_delay({min_playout_delay, max_playout_delay}); // On complete. - timing.IncomingTimestamp(3000, clock.CurrentTime()); + timing.OnCompleteTemporalUnit(3000, clock.CurrentTime()); clock.AdvanceTimeMilliseconds(1); // On decodable. Timestamp render_time = timing.RenderTime(/*next_temporal_unit_rtp=*/3000, clock.CurrentTime()); TimeDelta minimum_delay = TimeDelta::Millis(123); - timing.SetJitterDelay(minimum_delay); + timing.SetMinimumDelay(minimum_delay); timing.UpdateCurrentDelay(render_time, clock.CurrentTime()); clock.AdvanceTimeMilliseconds(100); @@ -438,11 +439,11 @@ timing.set_playout_delay({min_playout_delay, max_playout_delay}); // On complete. - timing.IncomingTimestamp(3000, clock.CurrentTime()); + timing.OnCompleteTemporalUnit(3000, clock.CurrentTime()); // On decodable. Timestamp render_time = timing.RenderTime(3000, clock.CurrentTime()); - timing.SetJitterDelay(TimeDelta::Millis(123)); + timing.SetMinimumDelay(TimeDelta::Millis(123)); timing.UpdateCurrentDelay(render_time, clock.CurrentTime()); // On decoded. @@ -473,26 +474,26 @@ timing.set_playout_delay({min_playout_delay, TimeDelta::Millis(500)}); // On decodable frames before valid rtp timestamp. - constexpr int decodeable_frame_cnt = 10; + constexpr int decodable_frame_cnt = 10; constexpr uint32_t any_time_elapsed = 17; constexpr uint32_t rtp_ts_base = 3000; constexpr uint32_t rtp_ts_delta_10fps = 9000; constexpr uint32_t frame_ts_delta_10fps = 100; uint32_t rtp_ts = rtp_ts_base; - for (int i = 0; i < decodeable_frame_cnt; i++) { + for (int i = 0; i < decodable_frame_cnt; i++) { clock.AdvanceTimeMilliseconds(any_time_elapsed); rtp_ts += rtp_ts_delta_10fps; Timestamp render_time = timing.RenderTime(rtp_ts, clock.CurrentTime()); - // Render time should be CurrentTime, because timing.IncomingTimestamp has - // not been called yet. + // Render time should be CurrentTime, because timing.OnCompleteTemporalUnit + // has not been called yet. EXPECT_EQ(render_time, clock.CurrentTime()); } // On frame complete, which one not 'metadata.delayed_by_retransmission' Timestamp valid_frame_ts = clock.CurrentTime(); - timing.IncomingTimestamp(rtp_ts, valid_frame_ts); + timing.OnCompleteTemporalUnit(rtp_ts, valid_frame_ts); clock.AdvanceTimeMilliseconds(any_time_elapsed); rtp_ts += rtp_ts_delta_10fps; @@ -504,16 +505,58 @@ min_playout_delay); } +TEST(VCMTimingTest, RenderTimeAccountsForCurrentDelay) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(Timestamp::Millis(88)); + VCMTiming timing(&clock, field_trials); + + timing.set_playout_delay({TimeDelta::Millis(100), TimeDelta::Millis(200)}); + timing.OnCompleteTemporalUnit(/*rtp_timestamp=*/0, clock.CurrentTime()); + // Current delay is initialized to minimum delay. + timing.SetMinimumDelay(TimeDelta::Millis(123)); + + EXPECT_EQ(timing.RenderTime(/*rtp_timestamp=*/0, kUnusedTimestamp), + clock.CurrentTime() + TimeDelta::Millis(123)); +} + +TEST(VCMTimingTest, RenderTimeRespectsMinPlayoutDelay) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(Timestamp::Millis(88)); + VCMTiming timing(&clock, field_trials); + + timing.set_playout_delay({TimeDelta::Millis(100), TimeDelta::Millis(200)}); + timing.OnCompleteTemporalUnit(/*rtp_timestamp=*/0, clock.CurrentTime()); + // Current delay is initialized to minimum delay. + timing.SetMinimumDelay(TimeDelta::Millis(90)); + + EXPECT_EQ(timing.RenderTime(/*rtp_timestamp=*/0, kUnusedTimestamp), + clock.CurrentTime() + TimeDelta::Millis(100)); +} + +TEST(VCMTimingTest, RenderTimeRespectsMaxPlayoutDelay) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(Timestamp::Millis(88)); + VCMTiming timing(&clock, field_trials); + + timing.set_playout_delay({TimeDelta::Millis(100), TimeDelta::Millis(200)}); + timing.OnCompleteTemporalUnit(/*rtp_timestamp=*/0, clock.CurrentTime()); + // Current delay is initialized to minimum delay. + timing.SetMinimumDelay(TimeDelta::Millis(210)); + + EXPECT_EQ(timing.RenderTime(/*rtp_timestamp=*/0, kUnusedTimestamp), + clock.CurrentTime() + TimeDelta::Millis(200)); +} + TEST(VCMTimingTest, IncreasesCurrentDelayWhenFrameIsLate) { FieldTrials field_trials = CreateTestFieldTrials(); SimulatedClock clock(0); VCMTiming timing(&clock, field_trials); - timing.SetJitterDelay(kJitterDelay); + timing.SetMinimumDelay(kMinimumDelay); timing.set_render_delay(kRenderDelay); // Current delay is initialized to jitter delay. - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay); - EXPECT_EQ(timing.TargetVideoDelay(), kJitterDelay + kRenderDelay); + EXPECT_EQ(timing.GetTimings().current_delay, kMinimumDelay); + EXPECT_EQ(timing.TargetVideoDelay(), kMinimumDelay + kRenderDelay); const TimeDelta kFrameDelay = TimeDelta::Millis(4); // Current delay should be increased to get closer to target delay. @@ -521,19 +564,19 @@ Timestamp actual_decode_time = clock.CurrentTime() + kFrameDelay; timing.UpdateCurrentDelay(render_time, actual_decode_time); - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay + kFrameDelay); + EXPECT_EQ(timing.GetTimings().current_delay, kMinimumDelay + kFrameDelay); } TEST(VCMTimingTest, CapsCurrentDelayIncreaseToTarget) { FieldTrials field_trials = CreateTestFieldTrials(); SimulatedClock clock(0); VCMTiming timing(&clock, field_trials); - timing.SetJitterDelay(kJitterDelay); + timing.SetMinimumDelay(kMinimumDelay); timing.set_render_delay(kRenderDelay); // Current delay is initialized to jitter delay. - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay); - EXPECT_EQ(timing.TargetVideoDelay(), kJitterDelay + kRenderDelay); + EXPECT_EQ(timing.GetTimings().current_delay, kMinimumDelay); + EXPECT_EQ(timing.TargetVideoDelay(), kMinimumDelay + kRenderDelay); const TimeDelta kFrameDelay = TimeDelta::Millis(588); // Current delay should be increased but not exceed target delay. @@ -541,19 +584,19 @@ Timestamp actual_decode_time = clock.CurrentTime() + kFrameDelay; timing.UpdateCurrentDelay(render_time, actual_decode_time); - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay + kRenderDelay); + EXPECT_EQ(timing.GetTimings().current_delay, kMinimumDelay + kRenderDelay); } TEST(VCMTimingTest, KeepsCurrentDelayWhenFrameIsEarly) { FieldTrials field_trials = CreateTestFieldTrials(); SimulatedClock clock(0); VCMTiming timing(&clock, field_trials); - timing.SetJitterDelay(kJitterDelay); + timing.SetMinimumDelay(kMinimumDelay); timing.set_render_delay(kRenderDelay); // Current delay is initialized to jitter delay. - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay); - EXPECT_EQ(timing.TargetVideoDelay(), kJitterDelay + kRenderDelay); + EXPECT_EQ(timing.GetTimings().current_delay, kMinimumDelay); + EXPECT_EQ(timing.TargetVideoDelay(), kMinimumDelay + kRenderDelay); // Frame is early. // Delay should remain unchanged. @@ -561,21 +604,21 @@ Timestamp actual_decode_time = clock.CurrentTime(); timing.UpdateCurrentDelay(render_time, actual_decode_time); - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay); + EXPECT_EQ(timing.GetTimings().current_delay, kMinimumDelay); } TEST(VCMTimingTest, IncreasesCurrentDelayWhenFrameIsLateWithDecodeTime) { FieldTrials field_trials = CreateTestFieldTrials(); SimulatedClock clock(0); VCMTiming timing(&clock, field_trials); - timing.SetJitterDelay(kJitterDelay); + timing.SetMinimumDelay(kMinimumDelay); timing.set_render_delay(kRenderDelay); UpdateDecodeTimer(timing, clock, kDecodeTime); // Current delay is initialized to jitter delay. - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay); + EXPECT_EQ(timing.GetTimings().current_delay, kMinimumDelay); EXPECT_EQ(timing.TargetVideoDelay(), - kJitterDelay + kDecodeTime + kRenderDelay); + kMinimumDelay + kDecodeTime + kRenderDelay); const TimeDelta kFrameDelay = TimeDelta::Millis(4); // Current delay should be increased to get closer to target delay. @@ -583,14 +626,14 @@ Timestamp actual_decode_time = clock.CurrentTime() + kFrameDelay; timing.UpdateCurrentDelay(render_time, actual_decode_time); - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay + kFrameDelay); + EXPECT_EQ(timing.GetTimings().current_delay, kMinimumDelay + kFrameDelay); } TEST(VCMTimingTest, DecreasesCurrentDelayToTarget) { FieldTrials field_trials = CreateTestFieldTrials(); SimulatedClock clock(0); VCMTiming timing(&clock, field_trials); - timing.SetJitterDelay(kJitterDelay); + timing.SetMinimumDelay(kMinimumDelay); timing.set_render_delay(kRenderDelay); // Current delay should be increased to target for late frame. @@ -599,24 +642,25 @@ EXPECT_EQ(timing.GetTimings().current_delay, timing.TargetVideoDelay()); // Reduce jitter delay. - timing.SetJitterDelay(kJitterDelay / 2); - EXPECT_EQ(timing.TargetVideoDelay(), kJitterDelay / 2 + kRenderDelay); + timing.SetMinimumDelay(kMinimumDelay / 2); + EXPECT_EQ(timing.TargetVideoDelay(), kMinimumDelay / 2 + kRenderDelay); // Current delay should be decreased to new target for frame on-time. timing.UpdateCurrentDelay(clock.CurrentTime() + kRenderDelay, clock.CurrentTime()); - EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay / 2 + kRenderDelay); + EXPECT_EQ(timing.GetTimings().current_delay, + kMinimumDelay / 2 + kRenderDelay); } TEST(VCMTimingTest, MinPlayoutDelayUpdatesTargetDelay) { FieldTrials field_trials = CreateTestFieldTrials(); SimulatedClock clock(0); VCMTiming timing(&clock, field_trials); - timing.SetJitterDelay(kJitterDelay); + timing.SetMinimumDelay(kMinimumDelay); timing.set_render_delay(kRenderDelay); const TimeDelta kMinPlayout = - kJitterDelay + kRenderDelay + TimeDelta::Millis(50); + kMinimumDelay + kRenderDelay + TimeDelta::Millis(50); timing.set_min_playout_delay(kMinPlayout); EXPECT_EQ(timing.TargetVideoDelay(), kMinPlayout);
diff --git a/video/video_stream_buffer_controller.cc b/video/video_stream_buffer_controller.cc index d0ecd07..edf78d1 100644 --- a/video/video_stream_buffer_controller.cc +++ b/video/video_stream_buffer_controller.cc
@@ -162,8 +162,8 @@ if (!metadata.delayed_by_retransmission && metadata.receive_time && (field_trials_.IsDisabled("WebRTC-IncomingTimestampOnMarkerBitOnly") || metadata.is_last_spatial_layer)) { - timing_->IncomingTimestamp(metadata.rtp_timestamp, - *metadata.receive_time); + timing_->OnCompleteTemporalUnit(metadata.rtp_timestamp, + *metadata.receive_time); } if (complete_units < buffer_->GetTotalNumberOfContinuousTemporalUnits()) { stats_proxy_->OnCompleteFrame(metadata.is_keyframe, metadata.size, @@ -252,7 +252,7 @@ superframe_size); } - timing_->SetJitterDelay(jitter_estimator_.GetEstimate()); + timing_->SetMinimumDelay(jitter_estimator_.GetEstimate()); timing_->UpdateCurrentDelay(render_time, now); } else { jitter_estimator_.FrameNacked();
diff --git a/video/video_stream_buffer_controller_unittest.cc b/video/video_stream_buffer_controller_unittest.cc index 79bcbb5..9925644 100644 --- a/video/video_stream_buffer_controller_unittest.cc +++ b/video/video_stream_buffer_controller_unittest.cc
@@ -85,15 +85,14 @@ class VCMTimingTest : public VCMTiming { public: using VCMTiming::VCMTiming; - void IncomingTimestamp(uint32_t rtp_timestamp, - Timestamp last_packet_time) override { - IncomingTimestampMocked(rtp_timestamp, last_packet_time); - VCMTiming::IncomingTimestamp(rtp_timestamp, last_packet_time); + void OnCompleteTemporalUnit(uint32_t rtp_timestamp, Timestamp now) override { + OnCompleteTemporalUnitMocked(rtp_timestamp, now); + VCMTiming::OnCompleteTemporalUnit(rtp_timestamp, now); } MOCK_METHOD(void, - IncomingTimestampMocked, - (uint32_t rtp_timestamp, Timestamp last_packet_time), + OnCompleteTemporalUnitMocked, + (uint32_t rtp_timestamp, Timestamp now), ()); }; @@ -925,7 +924,7 @@ TEST_P(IncomingTimestampVideoStreamBufferControllerTest, IncomingTimestampOnMarkerBitOnly) { StartNextDecodeForceKeyframe(); - EXPECT_CALL(timing_, IncomingTimestampMocked) + EXPECT_CALL(timing_, OnCompleteTemporalUnitMocked) .Times(field_trials_.IsDisabled("WebRTC-IncomingTimestampOnMarkerBitOnly") ? 3 : 1);