1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "remoting/client/software_video_renderer.h"
10 #include "base/memory/scoped_vector.h"
11 #include "base/message_loop/message_loop.h"
12 #include "base/run_loop.h"
13 #include "base/threading/thread.h"
14 #include "remoting/client/frame_consumer.h"
15 #include "remoting/codec/video_encoder_verbatim.h"
16 #include "remoting/proto/video.pb.h"
17 #include "remoting/protocol/session_config.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
21 using webrtc::DesktopFrame
;
27 const int kFrameWidth
= 200;
28 const int kFrameHeight
= 200;
30 class TestFrameConsumer
: public FrameConsumer
{
32 TestFrameConsumer() {}
33 ~TestFrameConsumer() override
{}
35 scoped_ptr
<DesktopFrame
> WaitForNextFrame(
36 base::Closure
* out_done_callback
) {
37 EXPECT_TRUE(thread_checker_
.CalledOnValidThread());
38 frame_run_loop_
.reset(new base::RunLoop());
39 frame_run_loop_
->Run();
40 frame_run_loop_
.reset();
41 *out_done_callback
= last_frame_done_callback_
;
42 last_frame_done_callback_
.Reset();
43 return last_frame_
.Pass();
46 // FrameConsumer interface.
47 scoped_ptr
<DesktopFrame
> AllocateFrame(
48 const webrtc::DesktopSize
& size
) override
{
49 EXPECT_TRUE(thread_checker_
.CalledOnValidThread());
50 return make_scoped_ptr(new webrtc::BasicDesktopFrame(size
));
53 void DrawFrame(scoped_ptr
<DesktopFrame
> frame
,
54 const base::Closure
& done
) override
{
55 EXPECT_TRUE(thread_checker_
.CalledOnValidThread());
56 last_frame_
= frame
.Pass();
57 last_frame_done_callback_
= done
;
58 frame_run_loop_
->Quit();
61 PixelFormat
GetPixelFormat() override
{
62 EXPECT_TRUE(thread_checker_
.CalledOnValidThread());
67 base::ThreadChecker thread_checker_
;
69 scoped_ptr
<base::RunLoop
> frame_run_loop_
;
71 scoped_ptr
<DesktopFrame
> last_frame_
;
72 base::Closure last_frame_done_callback_
;
75 scoped_ptr
<DesktopFrame
> CreateTestFrame(int index
) {
76 scoped_ptr
<DesktopFrame
> frame(new webrtc::BasicDesktopFrame(
77 webrtc::DesktopSize(kFrameWidth
, kFrameHeight
)));
79 for (int y
= 0; y
< kFrameHeight
; y
++) {
80 for (int x
= 0; x
< kFrameWidth
; x
++) {
81 uint8_t* out
= frame
->data() + x
* DesktopFrame::kBytesPerPixel
+
83 out
[0] = index
+ x
+ y
* kFrameWidth
;
84 out
[1] = index
+ x
+ y
* kFrameWidth
+ 1;
85 out
[2] = index
+ x
+ y
* kFrameWidth
+ 2;
91 frame
->mutable_updated_region()->SetRect(
92 webrtc::DesktopRect::MakeWH(kFrameWidth
, kFrameHeight
));
94 frame
->mutable_updated_region()->SetRect(
95 webrtc::DesktopRect::MakeWH(index
, index
));
101 // Returns true when frames a and b are equivalent.
102 bool CompareFrames(const DesktopFrame
& a
, const DesktopFrame
& b
) {
103 if (!a
.size().equals(b
.size()) ||
104 !a
.updated_region().Equals(b
.updated_region())) {
108 for (webrtc::DesktopRegion::Iterator
i(a
.updated_region()); !i
.IsAtEnd();
110 for (int row
= i
.rect().top(); row
< i
.rect().bottom(); ++row
) {
111 if (memcmp(a
.data() + a
.stride() * row
+
112 i
.rect().left() * DesktopFrame::kBytesPerPixel
,
113 b
.data() + b
.stride() * row
+
114 i
.rect().left() * DesktopFrame::kBytesPerPixel
,
115 i
.rect().width() * DesktopFrame::kBytesPerPixel
) != 0) {
124 // Helper to set value at |out| to 1.
125 void SetTrue(int* out
) {
131 class SoftwareVideoRendererTest
: public ::testing::Test
{
133 SoftwareVideoRendererTest() : decode_thread_("TestDecodeThread") {
134 decode_thread_
.Start();
135 renderer_
.reset(new SoftwareVideoRenderer(decode_thread_
.task_runner(),
136 &frame_consumer_
, nullptr));
137 renderer_
->OnSessionConfig(
138 *protocol::SessionConfig::ForTestWithVerbatimVideo());
142 base::MessageLoop message_loop_
;
143 base::Thread decode_thread_
;
145 TestFrameConsumer frame_consumer_
;
146 scoped_ptr
<SoftwareVideoRenderer
> renderer_
;
148 VideoEncoderVerbatim encoder_
;
151 TEST_F(SoftwareVideoRendererTest
, DecodeFrame
) {
152 const int kFrameCount
= 5;
154 ScopedVector
<DesktopFrame
> test_frames
;
156 // std::vector<bool> doesn't allow to get pointer to individual values, so
157 // int needs to be used instead.
158 std::vector
<int> callback_called(kFrameCount
);
160 for (int frame_index
= 0; frame_index
< kFrameCount
; frame_index
++) {
161 test_frames
.push_back(CreateTestFrame(frame_index
));
162 callback_called
[frame_index
] = 0;
164 renderer_
->ProcessVideoPacket(
165 encoder_
.Encode(*test_frames
[frame_index
]),
166 base::Bind(&SetTrue
, &(callback_called
[frame_index
])));
169 for (int frame_index
= 0; frame_index
< kFrameCount
; frame_index
++) {
170 base::Closure done_callback
;
171 scoped_ptr
<DesktopFrame
> decoded_frame
=
172 frame_consumer_
.WaitForNextFrame(&done_callback
);
174 EXPECT_FALSE(callback_called
[frame_index
]);
176 EXPECT_TRUE(callback_called
[frame_index
]);
178 EXPECT_TRUE(CompareFrames(*test_frames
[frame_index
], *decoded_frame
));
182 } // namespace remoting