FrameGeneratorCapturer: add methods OnOutputFormatRequest and GetResolution

To be used in tests.

Bug: none
Change-Id: Ia7b551b3ac66ed23d1907df56ddc4e09e3667a2b
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/245644
Reviewed-by: Artem Titov <titovartem@webrtc.org>
Commit-Queue: Åsa Persson <asapersson@webrtc.org>
Cr-Commit-Position: refs/heads/main@{#35703}
This commit is contained in:
Asa Persson
2022-01-13 17:51:18 +01:00
committed by WebRTC LUCI CQ
parent 2e85b5fa51
commit 42eec3db27
5 changed files with 119 additions and 22 deletions

View File

@ -175,31 +175,49 @@ bool FrameGeneratorCapturer::Init() {
}
void FrameGeneratorCapturer::InsertFrame() {
MutexLock lock(&lock_);
if (sending_) {
FrameGeneratorInterface::VideoFrameData frame_data =
frame_generator_->NextFrame();
// TODO(srte): Use more advanced frame rate control to allow arbritrary
// fractions.
int decimation =
std::round(static_cast<double>(source_fps_) / target_capture_fps_);
for (int i = 1; i < decimation; ++i)
frame_data = frame_generator_->NextFrame();
absl::optional<Resolution> resolution;
VideoFrame frame = VideoFrame::Builder()
.set_video_frame_buffer(frame_data.buffer)
.set_rotation(fake_rotation_)
.set_timestamp_us(clock_->TimeInMicroseconds())
.set_ntp_time_ms(clock_->CurrentNtpInMilliseconds())
.set_update_rect(frame_data.update_rect)
.set_color_space(fake_color_space_)
.build();
if (first_frame_capture_time_ == -1) {
first_frame_capture_time_ = frame.ntp_time_ms();
{
MutexLock lock(&lock_);
if (sending_) {
FrameGeneratorInterface::VideoFrameData frame_data =
frame_generator_->NextFrame();
// TODO(srte): Use more advanced frame rate control to allow arbritrary
// fractions.
int decimation =
std::round(static_cast<double>(source_fps_) / target_capture_fps_);
for (int i = 1; i < decimation; ++i)
frame_data = frame_generator_->NextFrame();
VideoFrame frame =
VideoFrame::Builder()
.set_video_frame_buffer(frame_data.buffer)
.set_rotation(fake_rotation_)
.set_timestamp_us(clock_->TimeInMicroseconds())
.set_ntp_time_ms(clock_->CurrentNtpInMilliseconds())
.set_update_rect(frame_data.update_rect)
.set_color_space(fake_color_space_)
.build();
if (first_frame_capture_time_ == -1) {
first_frame_capture_time_ = frame.ntp_time_ms();
}
resolution = Resolution{frame.width(), frame.height()};
TestVideoCapturer::OnFrame(frame);
}
TestVideoCapturer::OnFrame(frame);
}
if (resolution) {
MutexLock lock(&stats_lock_);
source_resolution_ = resolution;
}
}
absl::optional<FrameGeneratorCapturer::Resolution>
FrameGeneratorCapturer::GetResolution() {
MutexLock lock(&stats_lock_);
return source_resolution_;
}
void FrameGeneratorCapturer::Start() {
@ -243,6 +261,13 @@ void FrameGeneratorCapturer::ChangeFramerate(int target_framerate) {
target_capture_fps_ = std::min(source_fps_, target_framerate);
}
void FrameGeneratorCapturer::OnOutputFormatRequest(
int width,
int height,
const absl::optional<int>& max_fps) {
TestVideoCapturer::OnOutputFormatRequest(width, height, max_fps);
}
void FrameGeneratorCapturer::SetSinkWantsObserver(SinkWantsObserver* observer) {
MutexLock lock(&lock_);
RTC_DCHECK(!sink_wants_observer_);

View File

@ -132,6 +132,16 @@ class FrameGeneratorCapturer : public TestVideoCapturer {
void ChangeResolution(size_t width, size_t height);
void ChangeFramerate(int target_framerate);
struct Resolution {
int width;
int height;
};
absl::optional<Resolution> GetResolution();
void OnOutputFormatRequest(int width,
int height,
const absl::optional<int>& max_fps);
void SetSinkWantsObserver(SinkWantsObserver* observer);
void AddOrUpdateSink(rtc::VideoSinkInterface<VideoFrame>* sink,
@ -167,6 +177,10 @@ class FrameGeneratorCapturer : public TestVideoCapturer {
absl::optional<ColorSpace> fake_color_space_ RTC_GUARDED_BY(&lock_);
int64_t first_frame_capture_time_;
Mutex stats_lock_;
absl::optional<Resolution> source_resolution_ RTC_GUARDED_BY(&stats_lock_);
// Must be the last field, so it will be deconstructed first as tasks
// in the TaskQueue access other fields of the instance of this class.
rtc::TaskQueue task_queue_;

View File

@ -19,6 +19,9 @@ namespace {
using ::testing::Eq;
using ::testing::Property;
constexpr int kWidth = 640;
constexpr int kHeight = 360;
class MockVideoSinkInterfaceVideoFrame
: public rtc::VideoSinkInterface<VideoFrame> {
public:
@ -26,6 +29,7 @@ class MockVideoSinkInterfaceVideoFrame
MOCK_METHOD(void, OnDiscardedFrame, (), (override));
};
} // namespace
TEST(FrameGeneratorCapturerTest, CreateFromConfig) {
GlobalSimulatedTimeController time(Timestamp::Seconds(1000));
FrameGeneratorCapturerConfig config;
@ -41,5 +45,45 @@ TEST(FrameGeneratorCapturerTest, CreateFromConfig) {
.Times(21);
time.AdvanceTime(TimeDelta::Seconds(1));
}
TEST(FrameGeneratorCapturerTest, OnOutputFormatRequest) {
GlobalSimulatedTimeController time(Timestamp::Seconds(1000));
FrameGeneratorCapturerConfig config;
config.squares_video->width = kWidth;
config.squares_video->height = kHeight;
config.squares_video->framerate = 20;
auto capturer = FrameGeneratorCapturer::Create(
time.GetClock(), *time.GetTaskQueueFactory(), config);
testing::StrictMock<MockVideoSinkInterfaceVideoFrame> mock_sink;
capturer->AddOrUpdateSink(&mock_sink, rtc::VideoSinkWants());
capturer->OnOutputFormatRequest(kWidth / 2, kHeight / 2, /*max_fps=*/10);
capturer->Start();
EXPECT_CALL(mock_sink, OnFrame(Property(&VideoFrame::width, Eq(kWidth / 2))))
.Times(11);
time.AdvanceTime(TimeDelta::Seconds(1));
}
TEST(FrameGeneratorCapturerTest, ChangeResolution) {
GlobalSimulatedTimeController time(Timestamp::Seconds(1000));
FrameGeneratorCapturerConfig config;
config.squares_video->width = kWidth;
config.squares_video->height = kHeight;
config.squares_video->framerate = 20;
auto capturer = FrameGeneratorCapturer::Create(
time.GetClock(), *time.GetTaskQueueFactory(), config);
EXPECT_FALSE(capturer->GetResolution());
capturer->Start();
time.AdvanceTime(TimeDelta::Seconds(1));
ASSERT_TRUE(capturer->GetResolution());
EXPECT_EQ(kWidth, capturer->GetResolution()->width);
EXPECT_EQ(kHeight, capturer->GetResolution()->height);
capturer->ChangeResolution(kWidth / 2, kHeight / 2);
time.AdvanceTime(TimeDelta::Seconds(1));
ASSERT_TRUE(capturer->GetResolution());
EXPECT_EQ(kWidth / 2, capturer->GetResolution()->width);
EXPECT_EQ(kHeight / 2, capturer->GetResolution()->height);
}
} // namespace test
} // namespace webrtc

View File

@ -21,6 +21,17 @@ namespace webrtc {
namespace test {
TestVideoCapturer::~TestVideoCapturer() = default;
void TestVideoCapturer::OnOutputFormatRequest(
int width,
int height,
const absl::optional<int>& max_fps) {
absl::optional<std::pair<int, int>> target_aspect_ratio =
std::make_pair(width, height);
absl::optional<int> max_pixel_count = width * height;
video_adapter_.OnOutputFormatRequest(target_aspect_ratio, max_pixel_count,
max_fps);
}
void TestVideoCapturer::OnFrame(const VideoFrame& original_frame) {
int cropped_width = 0;
int cropped_height = 0;

View File

@ -41,6 +41,9 @@ class TestVideoCapturer : public rtc::VideoSourceInterface<VideoFrame> {
MutexLock lock(&lock_);
preprocessor_ = std::move(preprocessor);
}
void OnOutputFormatRequest(int width,
int height,
const absl::optional<int>& max_fps);
protected:
void OnFrame(const VideoFrame& frame);