/* * Copyright 2020 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/video_source_sink_controller.h" #include #include "api/video/video_frame.h" #include "api/video/video_source_interface.h" #include "call/adaptation/video_source_restrictions.h" #include "test/gmock.h" #include "test/gtest.h" using testing::_; namespace webrtc { namespace { constexpr int kIntUnconstrained = std::numeric_limits::max(); class MockVideoSinkWithVideoFrame : public rtc::VideoSinkInterface { public: ~MockVideoSinkWithVideoFrame() override {} MOCK_METHOD(void, OnFrame, (const VideoFrame& frame), (override)); MOCK_METHOD(void, OnDiscardedFrame, (), (override)); }; class MockVideoSourceWithVideoFrame : public rtc::VideoSourceInterface { public: ~MockVideoSourceWithVideoFrame() override {} MOCK_METHOD(void, AddOrUpdateSink, (rtc::VideoSinkInterface*, const rtc::VideoSinkWants&), (override)); MOCK_METHOD(void, RemoveSink, (rtc::VideoSinkInterface*), (override)); }; } // namespace TEST(VideoSourceSinkControllerTest, UnconstrainedByDefault) { MockVideoSinkWithVideoFrame sink; MockVideoSourceWithVideoFrame source; VideoSourceSinkController controller(&sink, &source); EXPECT_EQ(controller.restrictions(), VideoSourceRestrictions()); EXPECT_FALSE(controller.pixels_per_frame_upper_limit().has_value()); EXPECT_FALSE(controller.frame_rate_upper_limit().has_value()); EXPECT_FALSE(controller.rotation_applied()); EXPECT_EQ(controller.resolution_alignment(), 1); EXPECT_CALL(source, AddOrUpdateSink(_, _)) .WillOnce([](rtc::VideoSinkInterface* sink, const rtc::VideoSinkWants& wants) { EXPECT_FALSE(wants.rotation_applied); EXPECT_EQ(wants.max_pixel_count, kIntUnconstrained); EXPECT_EQ(wants.target_pixel_count, absl::nullopt); EXPECT_EQ(wants.max_framerate_fps, kIntUnconstrained); EXPECT_EQ(wants.resolution_alignment, 1); }); controller.PushSourceSinkSettings(); } TEST(VideoSourceSinkControllerTest, VideoRestrictionsToSinkWants) { MockVideoSinkWithVideoFrame sink; MockVideoSourceWithVideoFrame source; VideoSourceSinkController controller(&sink, &source); VideoSourceRestrictions restrictions = controller.restrictions(); // max_pixels_per_frame() maps to |max_pixel_count|. restrictions.set_max_pixels_per_frame(42u); // target_pixels_per_frame() maps to |target_pixel_count|. restrictions.set_target_pixels_per_frame(200u); // max_frame_rate() maps to |max_framerate_fps|. restrictions.set_max_frame_rate(30.0); controller.SetRestrictions(restrictions); EXPECT_CALL(source, AddOrUpdateSink(_, _)) .WillOnce([](rtc::VideoSinkInterface* sink, const rtc::VideoSinkWants& wants) { EXPECT_EQ(wants.max_pixel_count, 42); EXPECT_EQ(wants.target_pixel_count, 200); EXPECT_EQ(wants.max_framerate_fps, 30); }); controller.PushSourceSinkSettings(); // pixels_per_frame_upper_limit() caps |max_pixel_count|. controller.SetPixelsPerFrameUpperLimit(24); // frame_rate_upper_limit() caps |max_framerate_fps|. controller.SetFrameRateUpperLimit(10.0); EXPECT_CALL(source, AddOrUpdateSink(_, _)) .WillOnce([](rtc::VideoSinkInterface* sink, const rtc::VideoSinkWants& wants) { EXPECT_EQ(wants.max_pixel_count, 24); EXPECT_EQ(wants.max_framerate_fps, 10); }); controller.PushSourceSinkSettings(); } TEST(VideoSourceSinkControllerTest, RotationApplied) { MockVideoSinkWithVideoFrame sink; MockVideoSourceWithVideoFrame source; VideoSourceSinkController controller(&sink, &source); controller.SetRotationApplied(true); EXPECT_TRUE(controller.rotation_applied()); EXPECT_CALL(source, AddOrUpdateSink(_, _)) .WillOnce([](rtc::VideoSinkInterface* sink, const rtc::VideoSinkWants& wants) { EXPECT_TRUE(wants.rotation_applied); }); controller.PushSourceSinkSettings(); } TEST(VideoSourceSinkControllerTest, ResolutionAlignment) { MockVideoSinkWithVideoFrame sink; MockVideoSourceWithVideoFrame source; VideoSourceSinkController controller(&sink, &source); controller.SetResolutionAlignment(13); EXPECT_EQ(controller.resolution_alignment(), 13); EXPECT_CALL(source, AddOrUpdateSink(_, _)) .WillOnce([](rtc::VideoSinkInterface* sink, const rtc::VideoSinkWants& wants) { EXPECT_EQ(wants.resolution_alignment, 13); }); controller.PushSourceSinkSettings(); } TEST(VideoSourceSinkControllerTest, PushSourceSinkSettingsWithoutSourceDoesNotCrash) { MockVideoSinkWithVideoFrame sink; VideoSourceSinkController controller(&sink, nullptr); controller.PushSourceSinkSettings(); } } // namespace webrtc