Source code
Revision control
Copy as Markdown
Other Tools
/*
* 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