blob: 33a23e48987262dcbb1fa0f706225d58ee356d34 [file] [log] [blame]
// Copyright 2016 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/client/dual_buffer_frame_consumer.h"
#include <memory>
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
#include "third_party/webrtc/modules/desktop_capture/shared_desktop_frame.h"
namespace remoting {
namespace {
webrtc::DesktopFrame* GetUnderlyingFrame(
const std::unique_ptr<webrtc::DesktopFrame>& frame) {
return reinterpret_cast<webrtc::SharedDesktopFrame*>(frame.get())->
GetUnderlyingFrame();
}
void FillRGBARect(uint8_t r,
uint8_t g,
uint8_t b,
uint8_t a,
const webrtc::DesktopRect& rect,
webrtc::DesktopFrame* frame) {
for (int x = 0; x < rect.width(); x++) {
for (int y = 0; y < rect.height(); y++) {
uint8_t* data = frame->GetFrameDataAtPos(
rect.top_left().add(webrtc::DesktopVector(x, y)));
data[0] = r;
data[1] = g;
data[2] = b;
data[3] = a;
}
}
frame->mutable_updated_region()->SetRect(rect);
}
void CheckFrameColor(uint8_t r,
uint8_t g,
uint8_t b,
uint8_t a,
const webrtc::DesktopVector& pos,
const webrtc::DesktopFrame& frame) {
uint8_t* data = frame.GetFrameDataAtPos(pos);
EXPECT_EQ(r, data[0]);
EXPECT_EQ(g, data[1]);
EXPECT_EQ(b, data[2]);
EXPECT_EQ(a, data[3]);
}
} // namespace
class DualBufferFrameConsumerTest : public testing::Test {
public:
void SetUp() override;
protected:
std::unique_ptr<DualBufferFrameConsumer> consumer_;
std::unique_ptr<webrtc::DesktopFrame> received_frame_;
base::OnceClosure done_closure_;
private:
void OnFrameReceived(std::unique_ptr<webrtc::DesktopFrame> frame,
base::OnceClosure done);
};
void DualBufferFrameConsumerTest::SetUp() {
consumer_ = std::make_unique<DualBufferFrameConsumer>(
base::BindRepeating(&DualBufferFrameConsumerTest::OnFrameReceived,
base::Unretained(this)),
nullptr, protocol::FrameConsumer::FORMAT_RGBA);
}
void DualBufferFrameConsumerTest::OnFrameReceived(
std::unique_ptr<webrtc::DesktopFrame> frame,
base::OnceClosure done) {
received_frame_ = std::move(frame);
done_closure_ = std::move(done);
}
TEST_F(DualBufferFrameConsumerTest, AllocateOneFrame) {
std::unique_ptr<webrtc::DesktopFrame> frame =
consumer_->AllocateFrame(webrtc::DesktopSize(16, 16));
ASSERT_TRUE(frame->size().equals(webrtc::DesktopSize(16, 16)));
webrtc::DesktopFrame* raw_frame = frame.get();
consumer_->DrawFrame(std::move(frame), base::NullCallback());
EXPECT_EQ(raw_frame, received_frame_.get());
}
TEST_F(DualBufferFrameConsumerTest, BufferRotation) {
webrtc::DesktopSize size16x16(16, 16);
std::unique_ptr<webrtc::DesktopFrame> frame =
consumer_->AllocateFrame(size16x16);
webrtc::DesktopFrame* underlying_frame_1 = GetUnderlyingFrame(frame);
consumer_->DrawFrame(std::move(frame), base::NullCallback());
frame = consumer_->AllocateFrame(size16x16);
webrtc::DesktopFrame* underlying_frame_2 = GetUnderlyingFrame(frame);
EXPECT_NE(underlying_frame_1, underlying_frame_2);
consumer_->DrawFrame(std::move(frame), base::NullCallback());
frame = consumer_->AllocateFrame(size16x16);
webrtc::DesktopFrame* underlying_frame_3 = GetUnderlyingFrame(frame);
EXPECT_EQ(underlying_frame_1, underlying_frame_3);
consumer_->DrawFrame(std::move(frame), base::NullCallback());
frame = consumer_->AllocateFrame(size16x16);
webrtc::DesktopFrame* underlying_frame_4 = GetUnderlyingFrame(frame);
EXPECT_EQ(underlying_frame_2, underlying_frame_4);
consumer_->DrawFrame(std::move(frame), base::NullCallback());
}
TEST_F(DualBufferFrameConsumerTest, DrawAndMergeFrames) {
webrtc::DesktopSize size2x2(2, 2);
// X means uninitialized color.
// Frame 1:
// RR
// RR
std::unique_ptr<webrtc::DesktopFrame> frame =
consumer_->AllocateFrame(size2x2);
FillRGBARect(0xff, 0, 0, 0xff, webrtc::DesktopRect::MakeXYWH(0, 0, 2, 2),
frame.get());
consumer_->DrawFrame(std::move(frame), base::NullCallback());
// Frame 2:
// GG
// XX
frame = consumer_->AllocateFrame(size2x2);
FillRGBARect(0, 0xff, 0, 0xff, webrtc::DesktopRect::MakeXYWH(0, 0, 2, 1),
frame.get());
consumer_->DrawFrame(std::move(frame), base::NullCallback());
// Merged Frame:
// GG
// RR
consumer_->RequestFullDesktopFrame();
ASSERT_TRUE(received_frame_->size().equals(size2x2));
CheckFrameColor(0, 0xff, 0, 0xff, webrtc::DesktopVector(0, 0),
*received_frame_);
CheckFrameColor(0xff, 0, 0, 0xff, webrtc::DesktopVector(0, 1),
*received_frame_);
CheckFrameColor(0, 0xff, 0, 0xff, webrtc::DesktopVector(1, 0),
*received_frame_);
CheckFrameColor(0xff, 0, 0, 0xff, webrtc::DesktopVector(1, 1),
*received_frame_);
// Frame 3:
// BX
// BX
frame = consumer_->AllocateFrame(size2x2);
FillRGBARect(0, 0, 0xff, 0xff, webrtc::DesktopRect::MakeXYWH(0, 0, 1, 2),
frame.get());
consumer_->DrawFrame(std::move(frame), base::NullCallback());
// Merged Frame:
// BG
// BR
consumer_->RequestFullDesktopFrame();
ASSERT_TRUE(received_frame_->size().equals(size2x2));
CheckFrameColor(0, 0, 0xff, 0xff, webrtc::DesktopVector(0, 0),
*received_frame_);
CheckFrameColor(0, 0, 0xff, 0xff, webrtc::DesktopVector(0, 1),
*received_frame_);
CheckFrameColor(0, 0xff, 0, 0xff, webrtc::DesktopVector(1, 0),
*received_frame_);
CheckFrameColor(0xff, 0, 0, 0xff, webrtc::DesktopVector(1, 1),
*received_frame_);
}
TEST_F(DualBufferFrameConsumerTest, ChangeScreenSizeAndReallocateBuffers) {
webrtc::DesktopSize size16x16(16, 16);
std::unique_ptr<webrtc::DesktopFrame> frame =
consumer_->AllocateFrame(size16x16);
webrtc::DesktopFrame* underlying_frame_1 = GetUnderlyingFrame(frame);
consumer_->DrawFrame(std::move(frame), base::NullCallback());
frame = consumer_->AllocateFrame(size16x16);
webrtc::DesktopFrame* underlying_frame_2 = GetUnderlyingFrame(frame);
EXPECT_NE(underlying_frame_1, underlying_frame_2);
consumer_->DrawFrame(std::move(frame), base::NullCallback());
webrtc::DesktopSize size32x32(32, 32);
frame = consumer_->AllocateFrame(size32x32);
webrtc::DesktopFrame* underlying_frame_3 = GetUnderlyingFrame(frame);
EXPECT_NE(underlying_frame_1, underlying_frame_3);
consumer_->DrawFrame(std::move(frame), base::NullCallback());
frame = consumer_->AllocateFrame(size32x32);
webrtc::DesktopFrame* underlying_frame_4 = GetUnderlyingFrame(frame);
EXPECT_NE(underlying_frame_2, underlying_frame_4);
consumer_->DrawFrame(std::move(frame), base::NullCallback());
}
} // namespace remoting