| // Copyright 2017 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "remoting/codec/webrtc_video_encoder_selector.h" |
| |
| #include <string> |
| |
| #include "base/bind.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| |
| namespace remoting { |
| |
| namespace { |
| |
| class FakeWebrtcVideoEncoder : public WebrtcVideoEncoder { |
| public: |
| explicit FakeWebrtcVideoEncoder(int index) : index_(index) {} |
| ~FakeWebrtcVideoEncoder() override = default; |
| |
| int index() const { return index_; } |
| |
| void Encode(std::unique_ptr<webrtc::DesktopFrame> frame, |
| const FrameParams& param, |
| EncodeCallback done) override {} |
| |
| private: |
| const int index_; |
| }; |
| |
| } // namespace |
| |
| class WebrtcVideoEncoderSelectorTest : public ::testing::Test { |
| public: |
| WebrtcVideoEncoderSelectorTest() { |
| // Register three encoders. |
| for (int i = 0; i < kEncoderCount; i++) { |
| int j = selector_.RegisterEncoder( |
| base::Bind(&WebrtcVideoEncoderSelectorTest::IsProfileSupported, |
| base::Unretained(this), i), |
| base::Bind(&WebrtcVideoEncoderSelectorTest::CreateEncoder, |
| base::Unretained(this), i)); |
| EXPECT_EQ(i, j); |
| } |
| // Set the default DesktopFrame. |
| SetDesktopFrame(); |
| } |
| |
| protected: |
| void SetDesktopFrame() { |
| selector_.SetDesktopFrame(webrtc::BasicDesktopFrame( |
| webrtc::DesktopSize(frame_width_, frame_height_))); |
| } |
| |
| static constexpr int kEncoderCount = 3; |
| |
| WebrtcVideoEncoderSelector selector_; |
| |
| // IsProfileSupported() increments |is_supported_called_times_| each time it's |
| // called. |
| int is_supported_called_times_ = 0; |
| |
| bool is_supported_[kEncoderCount] = { false }; |
| |
| // Some arbitrary integers to test |
| // WebrtcVideoEncoderSelector::SetDesktopFrame() function. |
| int frame_width_ = 1001; |
| int frame_height_ = 999; |
| |
| private: |
| bool IsProfileSupported(int index, |
| const WebrtcVideoEncoderSelector::Profile& profile) { |
| EXPECT_EQ(profile.resolution.width(), frame_width_); |
| EXPECT_EQ(profile.resolution.height(), frame_height_); |
| is_supported_called_times_++; |
| return is_supported_[index]; |
| } |
| |
| // Returns a FakeWebrtcVideoEncoder with |index| as its index. |
| std::unique_ptr<WebrtcVideoEncoder> CreateEncoder(int index) { |
| return std::make_unique<FakeWebrtcVideoEncoder>(index); |
| } |
| }; |
| |
| TEST_F(WebrtcVideoEncoderSelectorTest, ReturnsNullIfCodecIsNotSupported) { |
| ASSERT_EQ(nullptr, selector_.CreateEncoder()); |
| ASSERT_EQ(3, is_supported_called_times_); |
| } |
| |
| TEST_F(WebrtcVideoEncoderSelectorTest, ReturnsPreferredCodecFirst) { |
| memset(is_supported_, -1, sizeof(is_supported_)); |
| selector_.SetPreferredCodec(1); |
| std::unique_ptr<WebrtcVideoEncoder> encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(1, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(1, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(0, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(2, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(2, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(3, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_EQ(nullptr, encoder); |
| ASSERT_EQ(3, is_supported_called_times_); |
| } |
| |
| TEST_F(WebrtcVideoEncoderSelectorTest, PreferredCodecIsNotQualified) { |
| is_supported_[1] = true; |
| is_supported_[2] = true; |
| selector_.SetPreferredCodec(0); |
| std::unique_ptr<WebrtcVideoEncoder> encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(1, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(2, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(2, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(3, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_EQ(nullptr, encoder); |
| ASSERT_EQ(3, is_supported_called_times_); |
| } |
| |
| TEST_F(WebrtcVideoEncoderSelectorTest, OtherCodecsAreNotQualified) { |
| is_supported_[2] = true; |
| selector_.SetPreferredCodec(2); |
| std::unique_ptr<WebrtcVideoEncoder> encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(2, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(1, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_EQ(nullptr, encoder); |
| ASSERT_EQ(3, is_supported_called_times_); |
| } |
| |
| TEST_F(WebrtcVideoEncoderSelectorTest, SetNewDesktopFrame) { |
| memset(is_supported_, -1, sizeof(is_supported_)); |
| selector_.SetPreferredCodec(1); |
| std::unique_ptr<WebrtcVideoEncoder> encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(1, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(1, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(0, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(2, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(2, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(3, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_EQ(nullptr, encoder); |
| ASSERT_EQ(3, is_supported_called_times_); |
| |
| // Setting an unchanged DesktopFrame should not reset the internal state of |
| // WebrtcVideoEncoderSelector. |
| SetDesktopFrame(); |
| encoder = selector_.CreateEncoder(); |
| ASSERT_EQ(nullptr, encoder); |
| ASSERT_EQ(3, is_supported_called_times_); |
| |
| // Setting a new DesktopFrame should reset the internal state of |
| // WebrtcVideoEncoderSelector: it should start from the preferred codec. |
| frame_width_++; |
| SetDesktopFrame(); |
| |
| selector_.SetPreferredCodec(2); |
| encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(2, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(4, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(0, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(5, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_NE(nullptr, encoder); |
| ASSERT_EQ(1, static_cast<FakeWebrtcVideoEncoder*>(encoder.get())->index()); |
| ASSERT_EQ(6, is_supported_called_times_); |
| |
| encoder = selector_.CreateEncoder(); |
| ASSERT_EQ(nullptr, encoder); |
| ASSERT_EQ(6, is_supported_called_times_); |
| } |
| |
| } // namespace remoting |