blob: a8c118ef200a4d3426596b7baa2384250a57855c [file] [log] [blame]
/*
* 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 "modules/video_coding/codecs/test/video_codec_tester_impl.h"
#include <memory>
#include <tuple>
#include <utility>
#include <vector>
#include "api/units/frequency.h"
#include "api/units/time_delta.h"
#include "api/video/encoded_image.h"
#include "api/video/i420_buffer.h"
#include "api/video/video_frame.h"
#include "rtc_base/fake_clock.h"
#include "rtc_base/gunit.h"
#include "rtc_base/task_queue_for_test.h"
#include "rtc_base/time_utils.h"
#include "test/gmock.h"
#include "test/gtest.h"
namespace webrtc {
namespace test {
namespace {
using ::testing::_;
using ::testing::Invoke;
using ::testing::InvokeWithoutArgs;
using ::testing::Return;
using Decoder = VideoCodecTester::Decoder;
using Encoder = VideoCodecTester::Encoder;
using CodedVideoSource = VideoCodecTester::CodedVideoSource;
using RawVideoSource = VideoCodecTester::RawVideoSource;
using DecoderSettings = VideoCodecTester::DecoderSettings;
using EncoderSettings = VideoCodecTester::EncoderSettings;
using PacingSettings = VideoCodecTester::PacingSettings;
using PacingMode = PacingSettings::PacingMode;
constexpr Frequency k90kHz = Frequency::Hertz(90000);
struct PacingTestParams {
PacingSettings pacing_settings;
Frequency framerate;
int num_frames;
std::vector<int> expected_delta_ms;
};
VideoFrame CreateVideoFrame(uint32_t timestamp_rtp) {
rtc::scoped_refptr<I420Buffer> buffer(I420Buffer::Create(2, 2));
return VideoFrame::Builder()
.set_video_frame_buffer(buffer)
.set_timestamp_rtp(timestamp_rtp)
.build();
}
EncodedImage CreateEncodedImage(uint32_t timestamp_rtp) {
EncodedImage encoded_image;
encoded_image.SetRtpTimestamp(timestamp_rtp);
return encoded_image;
}
class MockRawVideoSource : public RawVideoSource {
public:
MockRawVideoSource(int num_frames, Frequency framerate)
: num_frames_(num_frames), frame_num_(0), framerate_(framerate) {}
absl::optional<VideoFrame> PullFrame() override {
if (frame_num_ >= num_frames_) {
return absl::nullopt;
}
uint32_t timestamp_rtp = frame_num_ * k90kHz / framerate_;
++frame_num_;
return CreateVideoFrame(timestamp_rtp);
}
MOCK_METHOD(VideoFrame,
GetFrame,
(uint32_t timestamp_rtp, Resolution),
(override));
private:
int num_frames_;
int frame_num_;
Frequency framerate_;
};
class MockCodedVideoSource : public CodedVideoSource {
public:
MockCodedVideoSource(int num_frames, Frequency framerate)
: num_frames_(num_frames), frame_num_(0), framerate_(framerate) {}
absl::optional<EncodedImage> PullFrame() override {
if (frame_num_ >= num_frames_) {
return absl::nullopt;
}
uint32_t timestamp_rtp = frame_num_ * k90kHz / framerate_;
++frame_num_;
return CreateEncodedImage(timestamp_rtp);
}
private:
int num_frames_;
int frame_num_;
Frequency framerate_;
};
class MockDecoder : public Decoder {
public:
MOCK_METHOD(void, Initialize, (), (override));
MOCK_METHOD(void,
Decode,
(const EncodedImage& frame, DecodeCallback callback),
(override));
MOCK_METHOD(void, Flush, (), (override));
};
class MockEncoder : public Encoder {
public:
MOCK_METHOD(void, Initialize, (), (override));
MOCK_METHOD(void,
Encode,
(const VideoFrame& frame, EncodeCallback callback),
(override));
MOCK_METHOD(void, Flush, (), (override));
};
} // namespace
class VideoCodecTesterImplPacingTest
: public ::testing::TestWithParam<PacingTestParams> {
public:
VideoCodecTesterImplPacingTest() : test_params_(GetParam()) {}
protected:
PacingTestParams test_params_;
};
TEST_P(VideoCodecTesterImplPacingTest, PaceEncode) {
MockRawVideoSource video_source(test_params_.num_frames,
test_params_.framerate);
MockEncoder encoder;
EncoderSettings encoder_settings;
encoder_settings.pacing = test_params_.pacing_settings;
VideoCodecTesterImpl tester;
auto fs =
tester.RunEncodeTest(&video_source, &encoder, encoder_settings)->Slice();
ASSERT_EQ(static_cast<int>(fs.size()), test_params_.num_frames);
for (size_t i = 1; i < fs.size(); ++i) {
int delta_ms = (fs[i].encode_start - fs[i - 1].encode_start).ms();
EXPECT_NEAR(delta_ms, test_params_.expected_delta_ms[i - 1], 10);
}
}
TEST_P(VideoCodecTesterImplPacingTest, PaceDecode) {
MockCodedVideoSource video_source(test_params_.num_frames,
test_params_.framerate);
MockDecoder decoder;
DecoderSettings decoder_settings;
decoder_settings.pacing = test_params_.pacing_settings;
VideoCodecTesterImpl tester;
auto fs =
tester.RunDecodeTest(&video_source, &decoder, decoder_settings)->Slice();
ASSERT_EQ(static_cast<int>(fs.size()), test_params_.num_frames);
for (size_t i = 1; i < fs.size(); ++i) {
int delta_ms = (fs[i].decode_start - fs[i - 1].decode_start).ms();
EXPECT_NEAR(delta_ms, test_params_.expected_delta_ms[i - 1], 20);
}
}
INSTANTIATE_TEST_SUITE_P(
DISABLED_All,
VideoCodecTesterImplPacingTest,
::testing::ValuesIn(
{// No pacing.
PacingTestParams({.pacing_settings = {.mode = PacingMode::kNoPacing},
.framerate = Frequency::Hertz(10),
.num_frames = 3,
.expected_delta_ms = {0, 0}}),
// Real-time pacing.
PacingTestParams({.pacing_settings = {.mode = PacingMode::kRealTime},
.framerate = Frequency::Hertz(10),
.num_frames = 3,
.expected_delta_ms = {100, 100}}),
// Pace with specified constant rate.
PacingTestParams(
{.pacing_settings = {.mode = PacingMode::kConstantRate,
.constant_rate = Frequency::Hertz(20)},
.framerate = Frequency::Hertz(10),
.num_frames = 3,
.expected_delta_ms = {50, 50}})}));
} // namespace test
} // namespace webrtc