| /* | 
 |  *  Copyright (c) 2022 The WebRTC project authors. All Rights Reserved. | 
 |  * | 
 |  *  Use of this source code is governed by a BSD-style license | 
 |  *  that can be found in the LICENSE file in the root of the source | 
 |  *  tree. An additional intellectual property rights grant can be found | 
 |  *  in the file PATENTS.  All contributing project authors may | 
 |  *  be found in the AUTHORS file in the root of the source tree. | 
 |  */ | 
 |  | 
 | #include "video/frame_decode_timing.h" | 
 |  | 
 | #include <stdint.h> | 
 |  | 
 | #include "absl/types/optional.h" | 
 | #include "api/units/time_delta.h" | 
 | #include "modules/video_coding/timing/timing.h" | 
 | #include "rtc_base/containers/flat_map.h" | 
 | #include "test/gmock.h" | 
 | #include "test/gtest.h" | 
 | #include "test/scoped_key_value_config.h" | 
 | #include "video/video_receive_stream2.h" | 
 |  | 
 | namespace webrtc { | 
 |  | 
 | using ::testing::AllOf; | 
 | using ::testing::Eq; | 
 | using ::testing::Field; | 
 | using ::testing::Optional; | 
 |  | 
 | namespace { | 
 |  | 
 | class FakeVCMTiming : public webrtc::VCMTiming { | 
 |  public: | 
 |   explicit FakeVCMTiming(Clock* clock, const FieldTrialsView& field_trials) | 
 |       : webrtc::VCMTiming(clock, field_trials) {} | 
 |  | 
 |   Timestamp RenderTime(uint32_t frame_timestamp, Timestamp now) const override { | 
 |     RTC_DCHECK(render_time_map_.contains(frame_timestamp)); | 
 |     auto it = render_time_map_.find(frame_timestamp); | 
 |     return it->second; | 
 |   } | 
 |  | 
 |   TimeDelta MaxWaitingTime(Timestamp render_time, | 
 |                            Timestamp now, | 
 |                            bool too_many_frames_queued) const override { | 
 |     RTC_DCHECK(wait_time_map_.contains(render_time)); | 
 |     auto it = wait_time_map_.find(render_time); | 
 |     return it->second; | 
 |   } | 
 |  | 
 |   void SetTimes(uint32_t frame_timestamp, | 
 |                 Timestamp render_time, | 
 |                 TimeDelta max_decode_wait) { | 
 |     render_time_map_.insert_or_assign(frame_timestamp, render_time); | 
 |     wait_time_map_.insert_or_assign(render_time, max_decode_wait); | 
 |   } | 
 |  | 
 |  protected: | 
 |   flat_map<uint32_t, Timestamp> render_time_map_; | 
 |   flat_map<Timestamp, TimeDelta> wait_time_map_; | 
 | }; | 
 | }  // namespace | 
 |  | 
 | class FrameDecodeTimingTest : public ::testing::Test { | 
 |  public: | 
 |   FrameDecodeTimingTest() | 
 |       : clock_(Timestamp::Millis(1000)), | 
 |         timing_(&clock_, field_trials_), | 
 |         frame_decode_scheduler_(&clock_, &timing_) {} | 
 |  | 
 |  protected: | 
 |   test::ScopedKeyValueConfig field_trials_; | 
 |   SimulatedClock clock_; | 
 |   FakeVCMTiming timing_; | 
 |   FrameDecodeTiming frame_decode_scheduler_; | 
 | }; | 
 |  | 
 | TEST_F(FrameDecodeTimingTest, ReturnsWaitTimesWhenValid) { | 
 |   const TimeDelta decode_delay = TimeDelta::Millis(42); | 
 |   const Timestamp render_time = clock_.CurrentTime() + TimeDelta::Millis(60); | 
 |   timing_.SetTimes(90000, render_time, decode_delay); | 
 |  | 
 |   EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated( | 
 |                   90000, 180000, kMaxWaitForFrame, false), | 
 |               Optional(AllOf( | 
 |                   Field(&FrameDecodeTiming::FrameSchedule::latest_decode_time, | 
 |                         Eq(clock_.CurrentTime() + decode_delay)), | 
 |                   Field(&FrameDecodeTiming::FrameSchedule::render_time, | 
 |                         Eq(render_time))))); | 
 | } | 
 |  | 
 | TEST_F(FrameDecodeTimingTest, FastForwardsFrameTooFarInThePast) { | 
 |   const TimeDelta decode_delay = | 
 |       -FrameDecodeTiming::kMaxAllowedFrameDelay - TimeDelta::Millis(1); | 
 |   const Timestamp render_time = clock_.CurrentTime(); | 
 |   timing_.SetTimes(90000, render_time, decode_delay); | 
 |  | 
 |   EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated( | 
 |                   90000, 180000, kMaxWaitForFrame, false), | 
 |               Eq(absl::nullopt)); | 
 | } | 
 |  | 
 | TEST_F(FrameDecodeTimingTest, NoFastForwardIfOnlyFrameToDecode) { | 
 |   const TimeDelta decode_delay = | 
 |       -FrameDecodeTiming::kMaxAllowedFrameDelay - TimeDelta::Millis(1); | 
 |   const Timestamp render_time = clock_.CurrentTime(); | 
 |   timing_.SetTimes(90000, render_time, decode_delay); | 
 |  | 
 |   // Negative `decode_delay` means that `latest_decode_time` is now. | 
 |   EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated( | 
 |                   90000, 90000, kMaxWaitForFrame, false), | 
 |               Optional(AllOf( | 
 |                   Field(&FrameDecodeTiming::FrameSchedule::latest_decode_time, | 
 |                         Eq(clock_.CurrentTime())), | 
 |                   Field(&FrameDecodeTiming::FrameSchedule::render_time, | 
 |                         Eq(render_time))))); | 
 | } | 
 |  | 
 | TEST_F(FrameDecodeTimingTest, MaxWaitCapped) { | 
 |   TimeDelta frame_delay = TimeDelta::Millis(30); | 
 |   const TimeDelta decode_delay = TimeDelta::Seconds(3); | 
 |   const Timestamp render_time = clock_.CurrentTime() + TimeDelta::Seconds(3); | 
 |   timing_.SetTimes(90000, render_time, decode_delay); | 
 |   timing_.SetTimes(180000, render_time + frame_delay, | 
 |                    decode_delay + frame_delay); | 
 |  | 
 |   EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated( | 
 |                   90000, 270000, kMaxWaitForFrame, false), | 
 |               Optional(AllOf( | 
 |                   Field(&FrameDecodeTiming::FrameSchedule::latest_decode_time, | 
 |                         Eq(clock_.CurrentTime() + kMaxWaitForFrame)), | 
 |                   Field(&FrameDecodeTiming::FrameSchedule::render_time, | 
 |                         Eq(render_time))))); | 
 |  | 
 |   // Test cap keyframe. | 
 |   clock_.AdvanceTime(frame_delay); | 
 |   EXPECT_THAT(frame_decode_scheduler_.OnFrameBufferUpdated( | 
 |                   180000, 270000, kMaxWaitForKeyFrame, false), | 
 |               Optional(AllOf( | 
 |                   Field(&FrameDecodeTiming::FrameSchedule::latest_decode_time, | 
 |                         Eq(clock_.CurrentTime() + kMaxWaitForKeyFrame)), | 
 |                   Field(&FrameDecodeTiming::FrameSchedule::render_time, | 
 |                         Eq(render_time + frame_delay))))); | 
 | } | 
 |  | 
 | }  // namespace webrtc |