Remove unused method VCMTiming::UpdateCurrentDelay. Bug: b/493549134 Change-Id: Iff72142e90d617c3e94a72716c2b39d17baee9c7 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/458265 Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Commit-Queue: Åsa Persson <asapersson@webrtc.org> Cr-Commit-Position: refs/heads/main@{#47217}
diff --git a/modules/video_coding/timing/timing.cc b/modules/video_coding/timing/timing.cc index 9485ded..a947b38 100644 --- a/modules/video_coding/timing/timing.cc +++ b/modules/video_coding/timing/timing.cc
@@ -64,7 +64,6 @@ max_playout_delay_(TimeDelta::Seconds(10)), jitter_delay_(TimeDelta::Zero()), current_delay_(TimeDelta::Zero()), - prev_frame_timestamp_(0), num_decoded_frames_(0), zero_playout_delay_min_pacing_("min_pacing", kZeroPlayoutDelayDefaultMinPacing), @@ -81,7 +80,6 @@ min_playout_delay_ = TimeDelta::Zero(); jitter_delay_ = TimeDelta::Zero(); current_delay_ = TimeDelta::Zero(); - prev_frame_timestamp_ = 0; } void VCMTiming::set_render_delay(TimeDelta render_delay) { @@ -121,47 +119,6 @@ } } -void VCMTiming::UpdateCurrentDelay(uint32_t frame_timestamp) { - MutexLock lock(&mutex_); - TimeDelta target_delay = TargetDelayInternal(); - - if (current_delay_.IsZero()) { - // Not initialized, set current delay to target. - current_delay_ = target_delay; - } else if (target_delay != current_delay_) { - TimeDelta delay_diff = target_delay - current_delay_; - // Never change the delay with more than 100 ms every second. If we're - // changing the delay in too large steps we will get noticeable freezes. By - // limiting the change we can increase the delay in smaller steps, which - // will be experienced as the video is played in slow motion. When lowering - // the delay the video will be played at a faster pace. - TimeDelta max_change = TimeDelta::Zero(); - if (frame_timestamp < 0x0000ffff && prev_frame_timestamp_ > 0xffff0000) { - // wrap - max_change = - TimeDelta::Millis(kDelayMaxChangeMsPerS * - (frame_timestamp + (static_cast<int64_t>(1) << 32) - - prev_frame_timestamp_) / - 90000); - } else { - max_change = - TimeDelta::Millis(kDelayMaxChangeMsPerS * - (frame_timestamp - prev_frame_timestamp_) / 90000); - } - - if (max_change <= TimeDelta::Zero()) { - // Any changes less than 1 ms are truncated and will be postponed. - // Negative change will be due to reordering and should be ignored. - return; - } - delay_diff = std::max(delay_diff, -max_change); - delay_diff = std::min(delay_diff, max_change); - - current_delay_ = current_delay_ + delay_diff; - } - prev_frame_timestamp_ = frame_timestamp; -} - void VCMTiming::UpdateCurrentDelay(Timestamp render_time, Timestamp actual_decode_time) { MutexLock lock(&mutex_);
diff --git a/modules/video_coding/timing/timing.h b/modules/video_coding/timing/timing.h index fe35e8a..2ccf154 100644 --- a/modules/video_coding/timing/timing.h +++ b/modules/video_coding/timing/timing.h
@@ -57,7 +57,6 @@ }; static constexpr TimeDelta kDefaultRenderDelay = TimeDelta::Millis(10); - static constexpr int kDelayMaxChangeMsPerS = 100; VCMTiming(Clock* clock, const FieldTrialsView& field_trials); virtual ~VCMTiming() = default; @@ -80,11 +79,6 @@ void set_playout_delay(const VideoPlayoutDelay& playout_delay); // Increases or decreases the current delay to get closer to the target delay. - // Calculates how long it has been since the previous call to this function, - // and increases/decreases the delay in proportion to the time difference. - void UpdateCurrentDelay(uint32_t frame_timestamp); - - // Increases or decreases the current delay to get closer to the target delay. // Given the actual decode time in ms and the render time in ms for a frame, // this function calculates how late the frame is and increases the delay // accordingly. @@ -158,7 +152,6 @@ TimeDelta max_playout_delay_ RTC_GUARDED_BY(mutex_); TimeDelta jitter_delay_ RTC_GUARDED_BY(mutex_); TimeDelta current_delay_ RTC_GUARDED_BY(mutex_); - uint32_t prev_frame_timestamp_ RTC_GUARDED_BY(mutex_); std::optional<TimingFrameInfo> timing_frame_info_ RTC_GUARDED_BY(mutex_); size_t num_decoded_frames_ RTC_GUARDED_BY(mutex_); std::optional<int> max_composition_delay_in_frames_ RTC_GUARDED_BY(mutex_);
diff --git a/modules/video_coding/timing/timing_unittest.cc b/modules/video_coding/timing/timing_unittest.cc index 17e1d3d..45b26ab 100644 --- a/modules/video_coding/timing/timing_unittest.cc +++ b/modules/video_coding/timing/timing_unittest.cc
@@ -26,6 +26,9 @@ constexpr Frequency k25Fps = Frequency::Hertz(25); constexpr Frequency k90kHz = Frequency::KiloHertz(90); +constexpr TimeDelta kJitterDelay = TimeDelta::Millis(100); +constexpr TimeDelta kDecodeTime = TimeDelta::Millis(20); +constexpr TimeDelta kRenderDelay = TimeDelta::Millis(15); MATCHER(HasConsistentVideoDelayTimings, "") { // Delays should be non-negative. @@ -79,101 +82,14 @@ return p && m; } -} // namespace - -TEST(VCMTimingTest, JitterDelay) { - FieldTrials field_trials = CreateTestFieldTrials(); - SimulatedClock clock(0); - VCMTiming timing(&clock, field_trials); - timing.Reset(); - - uint32_t timestamp = 0; - timing.UpdateCurrentDelay(timestamp); - - timing.Reset(); - - timing.IncomingTimestamp(timestamp, clock.CurrentTime()); - TimeDelta jitter_delay = TimeDelta::Millis(20); - timing.SetJitterDelay(jitter_delay); - timing.UpdateCurrentDelay(timestamp); - timing.set_render_delay(TimeDelta::Zero()); - auto wait_time = timing.MaxWaitingTime( - timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), - /*too_many_frames_queued=*/false); - // First update initializes the render time. Since we have no decode delay - // we get wait_time = renderTime - now - renderDelay = jitter. - EXPECT_EQ(jitter_delay, wait_time); - - jitter_delay += TimeDelta::Millis(VCMTiming::kDelayMaxChangeMsPerS + 10); - timestamp += 90000; - clock.AdvanceTimeMilliseconds(1000); - timing.SetJitterDelay(jitter_delay); - timing.UpdateCurrentDelay(timestamp); - wait_time = timing.MaxWaitingTime( - timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), - /*too_many_frames_queued=*/false); - // Since we gradually increase the delay we only get 100 ms every second. - EXPECT_EQ(jitter_delay - TimeDelta::Millis(10), wait_time); - - timestamp += 90000; - clock.AdvanceTimeMilliseconds(1000); - timing.UpdateCurrentDelay(timestamp); - wait_time = timing.MaxWaitingTime( - timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), - /*too_many_frames_queued=*/false); - EXPECT_EQ(jitter_delay, wait_time); - - // Insert frames without jitter, verify that this gives the exact wait time. - const int kNumFrames = 300; - for (int i = 0; i < kNumFrames; i++) { - clock.AdvanceTime(1 / k25Fps); - timestamp += k90kHz / k25Fps; - timing.IncomingTimestamp(timestamp, clock.CurrentTime()); +void UpdateDecodeTimer(VCMTiming& timing, + SimulatedClock& clock, + TimeDelta decode_time) { + for (int i = 0; i < k25Fps.hertz(); ++i) { + clock.AdvanceTime(decode_time); + timing.StopDecodeTimer(decode_time, clock.CurrentTime()); + clock.AdvanceTime(1 / k25Fps - decode_time); } - timing.UpdateCurrentDelay(timestamp); - wait_time = timing.MaxWaitingTime( - timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), - /*too_many_frames_queued=*/false); - EXPECT_EQ(jitter_delay, wait_time); - - // Add decode time estimates for 1 second. - const TimeDelta kDecodeTime = TimeDelta::Millis(10); - for (int i = 0; i < k25Fps.hertz(); i++) { - clock.AdvanceTime(kDecodeTime); - timing.StopDecodeTimer(kDecodeTime, clock.CurrentTime()); - timestamp += k90kHz / k25Fps; - clock.AdvanceTime(1 / k25Fps - kDecodeTime); - timing.IncomingTimestamp(timestamp, clock.CurrentTime()); - } - timing.UpdateCurrentDelay(timestamp); - wait_time = timing.MaxWaitingTime( - timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), - /*too_many_frames_queued=*/false); - EXPECT_EQ(jitter_delay, wait_time); - - const TimeDelta kMinTotalDelay = TimeDelta::Millis(200); - timing.set_min_playout_delay(kMinTotalDelay); - clock.AdvanceTimeMilliseconds(5000); - timestamp += 5 * 90000; - timing.UpdateCurrentDelay(timestamp); - const TimeDelta kRenderDelay = TimeDelta::Millis(10); - timing.set_render_delay(kRenderDelay); - wait_time = timing.MaxWaitingTime( - timing.RenderTime(timestamp, clock.CurrentTime()), clock.CurrentTime(), - /*too_many_frames_queued=*/false); - // We should at least have kMinTotalDelayMs - decodeTime (10) - renderTime - // (10) to wait. - EXPECT_EQ(kMinTotalDelay - kDecodeTime - kRenderDelay, wait_time); - // The total video delay should be equal to the min total delay. - EXPECT_EQ(kMinTotalDelay, timing.TargetVideoDelay()); - - // Reset playout delay. - timing.set_min_playout_delay(TimeDelta::Zero()); - clock.AdvanceTimeMilliseconds(5000); - timestamp += 5 * 90000; - timing.UpdateCurrentDelay(timestamp); - - EXPECT_THAT(timing.GetTimings(), HasConsistentVideoDelayTimings()); } TEST(VCMTimingTest, TimestampWrapAround) { @@ -386,6 +302,34 @@ EXPECT_THAT(timing.GetTimings(), HasConsistentVideoDelayTimings()); } +TEST(VCMTimingTest, MaxWaitingTime) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(0); + VCMTiming timing(&clock, field_trials); + timing.set_render_delay(kRenderDelay); + UpdateDecodeTimer(timing, clock, kDecodeTime); + + Timestamp on_time = clock.CurrentTime() + kDecodeTime + kRenderDelay; + + // Early frame. + Timestamp render_time = on_time + TimeDelta::Millis(1); + EXPECT_EQ(timing.MaxWaitingTime(render_time, clock.CurrentTime(), + /*too_many_frames_queued=*/false), + TimeDelta::Millis(1)); + + // Exactly on time. + render_time = on_time; + EXPECT_EQ(timing.MaxWaitingTime(render_time, clock.CurrentTime(), + /*too_many_frames_queued=*/false), + TimeDelta::Zero()); + + // Late frame. + render_time = on_time - TimeDelta::Millis(1); + EXPECT_EQ(timing.MaxWaitingTime(render_time, clock.CurrentTime(), + /*too_many_frames_queued=*/false), + TimeDelta::Millis(-1)); +} + TEST(VCMTimingTest, UpdateCurrentDelayCapsWhenOffByMicroseconds) { FieldTrials field_trials = CreateTestFieldTrials(); SimulatedClock clock(0); @@ -413,7 +357,6 @@ FieldTrials field_trials = CreateTestFieldTrials(); SimulatedClock clock(33); VCMTiming timing(&clock, field_trials); - timing.Reset(); // Setup. TimeDelta render_delay = TimeDelta::Millis(11); @@ -435,14 +378,12 @@ clock.AdvanceTimeMilliseconds(100); // On decoded. - TimeDelta decode_time = TimeDelta::Millis(4); - timing.StopDecodeTimer(decode_time, clock.CurrentTime()); + UpdateDecodeTimer(timing, clock, kDecodeTime); VCMTiming::VideoDelayTimings timings = timing.GetTimings(); - EXPECT_EQ(timings.num_decoded_frames, 1u); + EXPECT_GT(timings.num_decoded_frames, 0u); EXPECT_EQ(timings.minimum_delay, minimum_delay); - // A single decoded frame is not enough to calculate p95. - EXPECT_EQ(timings.estimated_max_decode_time, TimeDelta::Zero()); + EXPECT_EQ(timings.estimated_max_decode_time, kDecodeTime); EXPECT_EQ(timings.render_delay, render_delay); EXPECT_EQ(timings.min_playout_delay, min_playout_delay); EXPECT_EQ(timings.max_playout_delay, max_playout_delay); @@ -451,6 +392,41 @@ EXPECT_THAT(timings, HasConsistentVideoDelayTimings()); } +TEST(VCMTimingTest, Reset) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(Timestamp::Millis(33)); + VCMTiming timing(&clock, field_trials); + + timing.set_render_delay(TimeDelta::Millis(11)); + TimeDelta min_playout_delay = TimeDelta::Millis(50); + TimeDelta max_playout_delay = TimeDelta::Millis(500); + timing.set_playout_delay({min_playout_delay, max_playout_delay}); + + // On complete. + timing.IncomingTimestamp(3000, clock.CurrentTime()); + + // On decodable. + Timestamp render_time = timing.RenderTime(3000, clock.CurrentTime()); + timing.SetJitterDelay(TimeDelta::Millis(123)); + timing.UpdateCurrentDelay(render_time, clock.CurrentTime()); + + // On decoded. + UpdateDecodeTimer(timing, clock, kDecodeTime); + + timing.Reset(); + + VCMTiming::VideoDelayTimings timings = timing.GetTimings(); + EXPECT_GT(timings.num_decoded_frames, 0u); + EXPECT_EQ(timings.minimum_delay, TimeDelta::Zero()); + EXPECT_EQ(timings.estimated_max_decode_time, TimeDelta::Zero()); + EXPECT_EQ(timings.render_delay, VCMTiming::kDefaultRenderDelay); + EXPECT_EQ(timings.min_playout_delay, TimeDelta::Zero()); + EXPECT_EQ(timings.max_playout_delay, max_playout_delay); + EXPECT_EQ(timings.target_delay, TimeDelta::Zero()); + EXPECT_EQ(timings.current_delay, TimeDelta::Zero()); + EXPECT_THAT(timings, HasConsistentVideoDelayTimings()); +} + TEST(VCMTimingTest, GetTimingsBeforeAndAfterValidRtpTimestamp) { SimulatedClock clock(33); FieldTrials field_trials = CreateTestFieldTrials(); @@ -492,4 +468,123 @@ min_playout_delay); } +TEST(VCMTimingTest, IncreasesCurrentDelayWhenFrameIsLate) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(0); + VCMTiming timing(&clock, field_trials); + timing.SetJitterDelay(kJitterDelay); + 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); + + const TimeDelta kFrameDelay = TimeDelta::Millis(4); + // Current delay should be increased to get closer to target delay. + Timestamp render_time = clock.CurrentTime() + kRenderDelay; + Timestamp actual_decode_time = clock.CurrentTime() + kFrameDelay; + timing.UpdateCurrentDelay(render_time, actual_decode_time); + + EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay + kFrameDelay); +} + +TEST(VCMTimingTest, CapsCurrentDelayIncreaseToTarget) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(0); + VCMTiming timing(&clock, field_trials); + timing.SetJitterDelay(kJitterDelay); + 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); + + const TimeDelta kFrameDelay = TimeDelta::Millis(588); + // Current delay should be increased but not exceed target delay. + Timestamp render_time = clock.CurrentTime() + kRenderDelay; + Timestamp actual_decode_time = clock.CurrentTime() + kFrameDelay; + timing.UpdateCurrentDelay(render_time, actual_decode_time); + + EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay + kRenderDelay); +} + +TEST(VCMTimingTest, KeepsCurrentDelayWhenFrameIsEarly) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(0); + VCMTiming timing(&clock, field_trials); + timing.SetJitterDelay(kJitterDelay); + 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); + + // Frame is early. + // Delay should remain unchanged. + Timestamp render_time = clock.CurrentTime() + kRenderDelay * 2; + Timestamp actual_decode_time = clock.CurrentTime(); + timing.UpdateCurrentDelay(render_time, actual_decode_time); + + EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay); +} + +TEST(VCMTimingTest, IncreasesCurrentDelayWhenFrameIsLateWithDecodeTime) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(0); + VCMTiming timing(&clock, field_trials); + timing.SetJitterDelay(kJitterDelay); + 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.TargetVideoDelay(), + kJitterDelay + kDecodeTime + kRenderDelay); + + const TimeDelta kFrameDelay = TimeDelta::Millis(4); + // Current delay should be increased to get closer to target delay. + Timestamp render_time = clock.CurrentTime() + kDecodeTime + kRenderDelay; + Timestamp actual_decode_time = clock.CurrentTime() + kFrameDelay; + timing.UpdateCurrentDelay(render_time, actual_decode_time); + + EXPECT_EQ(timing.GetTimings().current_delay, kJitterDelay + kFrameDelay); +} + +TEST(VCMTimingTest, DecreasesCurrentDelayToTarget) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(0); + VCMTiming timing(&clock, field_trials); + timing.SetJitterDelay(kJitterDelay); + timing.set_render_delay(kRenderDelay); + + // Current delay should be increased to target for late frame. + timing.UpdateCurrentDelay(clock.CurrentTime(), + clock.CurrentTime() + TimeDelta::Millis(588)); + EXPECT_EQ(timing.GetTimings().current_delay, timing.TargetVideoDelay()); + + // Reduce jitter delay. + timing.SetJitterDelay(kJitterDelay / 2); + EXPECT_EQ(timing.TargetVideoDelay(), kJitterDelay / 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); +} + +TEST(VCMTimingTest, MinPlayoutDelayUpdatesTargetDelay) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(0); + VCMTiming timing(&clock, field_trials); + timing.SetJitterDelay(kJitterDelay); + timing.set_render_delay(kRenderDelay); + + const TimeDelta kMinPlayout = + kJitterDelay + kRenderDelay + TimeDelta::Millis(50); + timing.set_min_playout_delay(kMinPlayout); + + EXPECT_EQ(timing.TargetVideoDelay(), kMinPlayout); +} + +} // namespace } // namespace webrtc