Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1452)

Side by Side Diff: remoting/test/test_video_renderer_unittest.cc

Issue 1214113009: Update TestVideoRenderer with video decoding capabilities (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 5 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
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.
4
5 #include "remoting/test/test_video_renderer.h"
6
7 #include <cmath>
8
9 #include "base/memory/scoped_vector.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/run_loop.h"
12 #include "base/timer/timer.h"
13 #include "media/base/video_frame.h"
14 #include "remoting/codec/video_encoder.h"
15 #include "remoting/codec/video_encoder_verbatim.h"
16 #include "remoting/codec/video_encoder_vpx.h"
17 #include "remoting/proto/video.pb.h"
18 #include "testing/gtest/include/gtest/gtest.h"
19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
20 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h"
21
22 namespace {
23 const int kBytesPerPixel = 4;
24 const int kDefaultScreenWidth = 1024;
25 const int kDefaultScreenHeight = 768;
26 const double kDefaultErrorLimit = 0.02;
27 }
28
29 namespace remoting {
30 namespace test {
31
32 // Provides basic functionality for for the TestVideoRenderer Tests below.
33 // This fixture also creates an MessageLoop to test decoding video packets.
34 class TestVideoRendererTest : public testing::Test {
35 public:
36 TestVideoRendererTest();
37 ~TestVideoRendererTest() override;
38
39 // Generate a frame containing a gradient and test decoding of
40 // TestVideoRenderer. The original frame is compared to the one obtained from
41 // decoding the video packet, and the error at each pixel is the root mean
42 // square of the errors in the R, G and B components, each normalized to
43 // [0, 1]. This routine checks that the mean error over all pixels do not
44 // exceed a given limit.
45 void TestVideoPacketProcessing(int screen_width, int screen_height,
46 double error_limit);
47
48 // Generate a basic desktop frame containing a gradient.
49 scoped_ptr<webrtc::DesktopFrame> CreateDesktopFrameWithGradient(
50 int screen_width, int screen_height) const;
51
52 protected:
53 // Used to post tasks to the message loop.
54 scoped_ptr<base::RunLoop> run_loop_;
55
56 // Used to set timeouts and delays.
57 scoped_ptr<base::Timer> timer_;
58
59 // Manages the decoder and process generated video packets.
60 scoped_ptr<TestVideoRenderer> test_video_renderer_;
61
62 // Used to encode desktop frames to generate video packets.
63 scoped_ptr<VideoEncoder> encoder_;
64
65 private:
66 // testing::Test interface.
67 void SetUp() override;
68
69 // return the mean error of two frames.
70 double CalculateError(const webrtc::DesktopFrame* original_frame,
71 const webrtc::DesktopFrame* decoded_frame) const;
72
73 // Fill a desktop frame with a gradient.
74 void FillFrameWithGradient(webrtc::DesktopFrame* frame) const;
75
76 // The thread's message loop. Valid only when the thread is alive.
77 scoped_ptr<base::MessageLoop> message_loop_;
78
79 DISALLOW_COPY_AND_ASSIGN(TestVideoRendererTest);
80 };
81
82 TestVideoRendererTest::TestVideoRendererTest()
83 : timer_(new base::Timer(true, false)) {}
84
85 TestVideoRendererTest::~TestVideoRendererTest() {}
86
87 void TestVideoRendererTest::SetUp() {
88 if (!base::MessageLoop::current()) {
89 // Create a temporary message loop if the current thread does not already
90 // have one.
91 message_loop_.reset(new base::MessageLoop);
92 }
93 test_video_renderer_.reset(new TestVideoRenderer());
94 }
95
96 void TestVideoRendererTest::TestVideoPacketProcessing(int screen_width,
97 int screen_height,
98 double error_limit) {
99 DCHECK(encoder_);
100 DCHECK(test_video_renderer_);
101
102 scoped_ptr<webrtc::DesktopFrame> original_frame =
103 CreateDesktopFrameWithGradient(screen_width, screen_height);
104 EXPECT_TRUE(original_frame.get());
105 scoped_ptr<VideoPacket> packet = encoder_->Encode(*original_frame.get());
106 test_video_renderer_->ProcessVideoPacket(packet.Pass(),
107 base::Bind(&base::DoNothing));
108
109 // wait for the video packet to be processed and rendered to buffer.
110 run_loop_.reset(new base::RunLoop());
111 test_video_renderer_->WaitForPacketDone(run_loop_->QuitClosure());
112 run_loop_->Run();
113
114 scoped_ptr<webrtc::DesktopFrame> buffer_copy =
115 test_video_renderer_->GetBufferForTest();
116 EXPECT_NE(buffer_copy, nullptr);
117 double error = CalculateError(original_frame.get(), buffer_copy.get());
118 EXPECT_LT(error, error_limit);
119 }
120
121 double TestVideoRendererTest::CalculateError(
122 const webrtc::DesktopFrame* original_frame,
123 const webrtc::DesktopFrame* decoded_frame) const {
124 DCHECK(original_frame);
125 DCHECK(decoded_frame);
126
127 // Check size remains the same after encoding and decoding.
128 EXPECT_EQ(original_frame->size().width(), decoded_frame->size().width());
129 EXPECT_EQ(original_frame->size().height(), decoded_frame->size().height());
130 EXPECT_EQ(original_frame->stride(), decoded_frame->stride());
131 int screen_width = original_frame->size().width();
132 int screen_height = original_frame->size().height();
133
134 // Error is calculated as the sum of the square error at each pixel in the
135 // R, G and B components, each normalized to [0, 1]
136 double error_sum_squares = 0.0;
137
138 // The mapping between the position of a pixel on 3-dimensional image
139 // (origin at top left corner) and its position in 1-dimensional buffer.
140 //
141 // _______________
142 // | | | stride = 4 * width;
143 // | | |
144 // | | height | height * stride + width + 0; Red channel.
145 // | | | => height * stride + width + 1; Green channel.
146 // |------- | height * stride + width + 2; Blue channel.
147 // | width |
148 // |_______________|
149 //
150 for (int height = 0; height < screen_height; ++height) {
151 uint8_t* original_ptr = original_frame->data() +
152 height * original_frame->stride();
153 uint8_t* decoded_ptr = decoded_frame->data() +
154 height * decoded_frame->stride();
155
156 for (int width = 0; width < screen_width; ++width) {
157 // Errors are calculated in the R, G, B components.
158 for (int j = 0; j < 3; ++j) {
159 int offset = kBytesPerPixel * width + j;
160 double original_value = static_cast<double>(*(original_ptr + offset));
161 double decoded_value = static_cast<double>(*(decoded_ptr + offset));
162 double error = original_value - decoded_value;
163
164 // Normalize the error to [0, 1].
165 error /= 255.0;
166 error_sum_squares += error * error;
167 }
168 }
169 }
170 return sqrt(error_sum_squares / (3 * screen_width * screen_height));
171 }
172
173 scoped_ptr<webrtc::DesktopFrame>
174 TestVideoRendererTest::CreateDesktopFrameWithGradient(
175 int screen_width, int screen_height) const {
176 webrtc::DesktopSize screen_size(screen_width, screen_height);
177 scoped_ptr<webrtc::DesktopFrame> frame(
178 new webrtc::BasicDesktopFrame(screen_size));
179 frame->mutable_updated_region()->SetRect(
180 webrtc::DesktopRect::MakeSize(screen_size));
181 FillFrameWithGradient(frame.get());
182 return frame.Pass();
183 }
184
185 void TestVideoRendererTest::FillFrameWithGradient(
186 webrtc::DesktopFrame* frame) const {
187 for (int y = 0; y < frame->size().height(); ++y) {
188 uint8* p = frame->data() + y * frame->stride();
189 for (int x = 0; x < frame->size().width(); ++x) {
190 *p++ = (255.0 * x) / frame->size().width();
191 *p++ = (164.0 * y) / frame->size().height();
192 *p++ = (82.0 * (x + y)) /
193 (frame->size().width() + frame->size().height());
194 *p++ = 0;
195 }
196 }
197 }
198
199 // Verify video decoding for VP8 Codec.
200 TEST_F(TestVideoRendererTest, VerifyVideoDecodingForVP8) {
201 encoder_ = VideoEncoderVpx::CreateForVP8();
202 test_video_renderer_->SetDecoder(protocol::ChannelConfig::CODEC_VP8);
203 TestVideoPacketProcessing(kDefaultScreenWidth, kDefaultScreenHeight,
204 kDefaultErrorLimit);
205 }
206
207 // Verify video decoding for VP9 Codec.
208 TEST_F(TestVideoRendererTest, VerifyVideoDecodingForVP9) {
209 encoder_ = VideoEncoderVpx::CreateForVP9();
210 test_video_renderer_->SetDecoder(protocol::ChannelConfig::CODEC_VP9);
211 TestVideoPacketProcessing(kDefaultScreenWidth, kDefaultScreenHeight,
212 kDefaultErrorLimit);
213 }
214
215
216 // Verify video decoding for VERBATIM Codec.
217 TEST_F(TestVideoRendererTest, VerifyVideoDecodingForVERBATIM) {
218 encoder_.reset(new VideoEncoderVerbatim());
219 test_video_renderer_->SetDecoder(protocol::ChannelConfig::CODEC_VERBATIM);
220 TestVideoPacketProcessing(kDefaultScreenWidth, kDefaultScreenHeight,
221 kDefaultErrorLimit);
222 }
223
224 // Verify a set of video packets are processed correctly.
225 TEST_F(TestVideoRendererTest, VerifyMultipleVideoProcessing) {
226 encoder_ = VideoEncoderVpx::CreateForVP8();
227 test_video_renderer_->SetDecoder(protocol::ChannelConfig::CODEC_VP8);
228
229 // Post multiple tasks to |test_video_renderer_|, and it should not crash.
230 // 20 is chosen because it's large enough to make sure that there will be
231 // more than one task on the video decode thread, while not too large to wait
232 // for too long for the unit test to complete.
233 int task_num = 20;
234 ScopedVector<VideoPacket> video_packets;
235 for (int i = 0; i < task_num; ++i) {
236 scoped_ptr<webrtc::DesktopFrame> original_frame =
237 CreateDesktopFrameWithGradient(kDefaultScreenWidth,
238 kDefaultScreenHeight);
239 video_packets.push_back(encoder_->Encode(*original_frame.get()));
240 }
241
242 for (int i = 0; i < task_num; ++i) {
243 // Transfer ownership of video packet.
244 VideoPacket* packet = video_packets[i];
245 video_packets[i] = nullptr;
246 test_video_renderer_->ProcessVideoPacket(make_scoped_ptr(packet),
247 base::Bind(&base::DoNothing));
248 }
249 }
250
251 // Verify video packet size change is handled properly.
252 TEST_F(TestVideoRendererTest, VerifyVideoPacketSizeChange) {
253 encoder_ = VideoEncoderVpx::CreateForVP8();
254 test_video_renderer_->SetDecoder(protocol::ChannelConfig::Codec::CODEC_VP8);
255
256 TestVideoPacketProcessing(kDefaultScreenWidth, kDefaultScreenHeight,
257 kDefaultErrorLimit);
258
259 TestVideoPacketProcessing(2 * kDefaultScreenWidth, 2 * kDefaultScreenHeight,
260 kDefaultErrorLimit);
261
262 TestVideoPacketProcessing(kDefaultScreenWidth / 2, kDefaultScreenHeight / 2,
263 kDefaultErrorLimit);
264 }
265
266 } // namespace test
267 } // namespace remoting
OLDNEW
« remoting/test/test_video_renderer.cc ('K') | « remoting/test/test_video_renderer.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698