Add jitter estimation logic to `DefaultVideoJitterTiming`. Adds `JitterEstimator` and `InterFrameDelayVariationCalculator` to `DefaultVideoJitterTiming`. Usage will be wired up separately. Bug: b/493549134 Change-Id: I29b5d5eaf0ce8349ab9345f0b06786cb4cdc76e6 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/480460 Reviewed-by: Rasmus Brandt <brandtr@webrtc.org> Commit-Queue: Åsa Persson <asapersson@webrtc.org> Cr-Commit-Position: refs/heads/main@{#47958}
diff --git a/modules/video_coding/timing/BUILD.gn b/modules/video_coding/timing/BUILD.gn index db022ba..70ef264 100644 --- a/modules/video_coding/timing/BUILD.gn +++ b/modules/video_coding/timing/BUILD.gn
@@ -101,8 +101,12 @@ "default_video_jitter_timing.h", ] deps = [ + ":inter_frame_delay_variation_calculator", + ":jitter_estimator", ":timestamp_extrapolator", "../../../api:field_trials_view", + "../../../api/units:data_size", + "../../../api/units:time_delta", "../../../api/units:timestamp", "../../../system_wrappers", ]
diff --git a/modules/video_coding/timing/default_video_jitter_timing.cc b/modules/video_coding/timing/default_video_jitter_timing.cc index 76e4238..01a3335 100644 --- a/modules/video_coding/timing/default_video_jitter_timing.cc +++ b/modules/video_coding/timing/default_video_jitter_timing.cc
@@ -14,7 +14,11 @@ #include <optional> #include "api/field_trials_view.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "modules/video_coding/timing/inter_frame_delay_variation_calculator.h" +#include "modules/video_coding/timing/jitter_estimator.h" #include "modules/video_coding/timing/timestamp_extrapolator.h" #include "system_wrappers/include/clock.h" @@ -23,10 +27,13 @@ DefaultVideoJitterTiming::DefaultVideoJitterTiming( Clock* clock, const FieldTrialsView& field_trials) - : clock_(clock), ts_extrapolator_(clock_->CurrentTime(), field_trials) {} + : clock_(clock), + ts_extrapolator_(clock_->CurrentTime(), field_trials), + jitter_estimator_(clock_, field_trials) {} void DefaultVideoJitterTiming::Reset() { ts_extrapolator_.Reset(clock_->CurrentTime()); + jitter_estimator_.Reset(); } void DefaultVideoJitterTiming::OnCompleteTemporalUnit(uint32_t rtp_timestamp, @@ -39,4 +46,26 @@ return ts_extrapolator_.ExtrapolateLocalTime(rtp_timestamp); } +std::optional<TimeDelta> DefaultVideoJitterTiming::OnDecodableTemporalUnit( + uint32_t rtp_timestamp, + DataSize superframe_size, + Timestamp max_receive_time, + bool was_retransmitted) { + if (was_retransmitted) { + jitter_estimator_.FrameNacked(); + return std::nullopt; + } + std::optional<TimeDelta> inter_frame_delay_variation = + ifdv_calculator_.Calculate(rtp_timestamp, max_receive_time); + if (inter_frame_delay_variation) { + jitter_estimator_.UpdateEstimate(*inter_frame_delay_variation, + superframe_size); + } + return jitter_estimator_.GetEstimate(); +} + +void DefaultVideoJitterTiming::UpdateRtt(TimeDelta rtt) { + jitter_estimator_.UpdateRtt(rtt); +} + } // namespace webrtc
diff --git a/modules/video_coding/timing/default_video_jitter_timing.h b/modules/video_coding/timing/default_video_jitter_timing.h index fc5398c..a88eb0a 100644 --- a/modules/video_coding/timing/default_video_jitter_timing.h +++ b/modules/video_coding/timing/default_video_jitter_timing.h
@@ -15,7 +15,11 @@ #include <optional> #include "api/field_trials_view.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" #include "api/units/timestamp.h" +#include "modules/video_coding/timing/inter_frame_delay_variation_calculator.h" +#include "modules/video_coding/timing/jitter_estimator.h" #include "modules/video_coding/timing/timestamp_extrapolator.h" #include "system_wrappers/include/clock.h" @@ -36,9 +40,21 @@ // Returns the extrapolated local time for a given RTP timestamp. std::optional<Timestamp> ExtrapolateLocalTime(uint32_t rtp_timestamp) const; + // Updates the jitter estimator with the information of a decodable temporal + // unit. Returns the current jitter estimate if available. + std::optional<TimeDelta> OnDecodableTemporalUnit(uint32_t rtp_timestamp, + DataSize superframe_size, + Timestamp max_receive_time, + bool was_retransmitted); + + // Updates the jitter estimator with the current RTT. + void UpdateRtt(TimeDelta rtt); + private: Clock* const clock_; TimestampExtrapolator ts_extrapolator_; + JitterEstimator jitter_estimator_; + InterFrameDelayVariationCalculator ifdv_calculator_; }; } // namespace webrtc
diff --git a/modules/video_coding/timing/default_video_jitter_timing_unittest.cc b/modules/video_coding/timing/default_video_jitter_timing_unittest.cc index 4710156..f73cdda 100644 --- a/modules/video_coding/timing/default_video_jitter_timing_unittest.cc +++ b/modules/video_coding/timing/default_video_jitter_timing_unittest.cc
@@ -14,6 +14,8 @@ #include <optional> #include "api/field_trials.h" +#include "api/units/data_size.h" +#include "api/units/time_delta.h" #include "api/units/timestamp.h" #include "system_wrappers/include/clock.h" #include "test/create_test_field_trials.h" @@ -24,6 +26,8 @@ constexpr uint32_t kRtpTimestamp = 12345; constexpr Timestamp kInitialTime = Timestamp::Millis(789); +constexpr DataSize kFrameSize = DataSize::Bytes(1000); +constexpr TimeDelta kRtt = TimeDelta::Millis(100); TEST(DefaultVideoJitterTimingTest, ExtrapolatorReturnsNulloptInitially) { FieldTrials field_trials = CreateTestFieldTrials(); @@ -54,5 +58,88 @@ EXPECT_EQ(timing.ExtrapolateLocalTime(kRtpTimestamp), std::nullopt); } +TEST(DefaultVideoJitterTimingTest, OnDecodableTemporalUnitReturnsEstimate) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(kInitialTime); + DefaultVideoJitterTiming timing(&clock, field_trials); + + EXPECT_NE(timing.OnDecodableTemporalUnit(kRtpTimestamp, kFrameSize, + clock.CurrentTime(), + /*was_retransmitted=*/false), + std::nullopt); +} + +TEST(DefaultVideoJitterTimingTest, + OnDecodableTemporalUnitReturnsNulloptOnRetransmission) { + FieldTrials field_trials = CreateTestFieldTrials(); + SimulatedClock clock(kInitialTime); + DefaultVideoJitterTiming timing(&clock, field_trials); + + EXPECT_EQ(timing.OnDecodableTemporalUnit(kRtpTimestamp, kFrameSize, + clock.CurrentTime(), + /*was_retransmitted=*/true), + std::nullopt); +} + +TEST(DefaultVideoJitterTimingTest, EstimateIncludesRttAfterRetransmission) { + constexpr double kMargin = 0.8; + FieldTrials field_trials = + CreateTestFieldTrials("WebRTC-JitterEstimatorConfig/nack_limit:1/"); + SimulatedClock clock(kInitialTime); + DefaultVideoJitterTiming timing(&clock, field_trials); + + timing.UpdateRtt(kRtt); + + std::optional<TimeDelta> initial_estimate = timing.OnDecodableTemporalUnit( + /*rtp_timestamp=*/3000, kFrameSize, clock.CurrentTime(), + /*was_retransmitted=*/false); + ASSERT_TRUE(initial_estimate.has_value()); + + // Retransmitted frame. + clock.AdvanceTime(TimeDelta::Millis(33)); + EXPECT_EQ(timing.OnDecodableTemporalUnit(/*rtp_timestamp=*/6000, kFrameSize, + clock.CurrentTime(), + /*was_retransmitted=*/true), + std::nullopt); + + // Get estimate after retransmission. + clock.AdvanceTime(TimeDelta::Millis(33)); + EXPECT_GT(timing.OnDecodableTemporalUnit(/*rtp_timestamp=*/9000, kFrameSize, + clock.CurrentTime(), + /*was_retransmitted=*/false), + *initial_estimate + kMargin * kRtt); +} + +TEST(DefaultVideoJitterTimingTest, ResetClearsJitterEstimator) { + constexpr double kMargin = 0.5; + FieldTrials field_trials = + CreateTestFieldTrials("WebRTC-JitterEstimatorConfig/nack_limit:1/"); + SimulatedClock clock(kInitialTime); + DefaultVideoJitterTiming timing(&clock, field_trials); + + timing.UpdateRtt(kRtt); + + std::optional<TimeDelta> initial_estimate = timing.OnDecodableTemporalUnit( + /*rtp_timestamp=*/3000, kFrameSize, clock.CurrentTime(), + /*was_retransmitted=*/false); + ASSERT_TRUE(initial_estimate.has_value()); + + // Retransmitted frame. + clock.AdvanceTime(TimeDelta::Millis(33)); + EXPECT_EQ(timing.OnDecodableTemporalUnit(/*rtp_timestamp=*/6000, kFrameSize, + clock.CurrentTime(), + /*was_retransmitted=*/true), + std::nullopt); + + timing.Reset(); + + // Get estimate after retransmission and reset, should not include RTT. + clock.AdvanceTime(TimeDelta::Millis(33)); + EXPECT_LT(timing.OnDecodableTemporalUnit(/*rtp_timestamp=*/9000, kFrameSize, + clock.CurrentTime(), + /*was_retransmitted=*/false), + *initial_estimate + kMargin * kRtt); +} + } // namespace } // namespace webrtc