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

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

Issue 1219923011: Added image pattern comparison logic for test interface and fixture. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: "Added image pattern comparison logic" 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
« no previous file with comments | « remoting/test/app_remoting_latency_test_fixture.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 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 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "remoting/test/test_video_renderer.h" 5 #include "remoting/test/test_video_renderer.h"
6 6
7 #include <algorithm>
8 #include <cmath>
liaoyuke 2015/07/08 18:58:15 Usage: algorithm: std::min, std::max, cmath: sqrt
9
7 #include "base/bind.h" 10 #include "base/bind.h"
8 #include "base/logging.h" 11 #include "base/logging.h"
9 #include "base/synchronization/lock.h" 12 #include "base/synchronization/lock.h"
10 #include "base/thread_task_runner_handle.h" 13 #include "base/thread_task_runner_handle.h"
11 #include "base/threading/thread.h" 14 #include "base/threading/thread.h"
12 #include "remoting/codec/video_decoder.h" 15 #include "remoting/codec/video_decoder.h"
13 #include "remoting/codec/video_decoder_verbatim.h" 16 #include "remoting/codec/video_decoder_verbatim.h"
14 #include "remoting/codec/video_decoder_vpx.h" 17 #include "remoting/codec/video_decoder_vpx.h"
15 #include "remoting/proto/video.pb.h" 18 #include "remoting/proto/video.pb.h"
16 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" 19 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h"
17 20
21 namespace {
22 const int kBytesPerPixel = 4;
23 } // namespace
24
18 namespace remoting { 25 namespace remoting {
19 namespace test { 26 namespace test {
20 27
21 // Implements video decoding functionality. 28 // Implements video decoding functionality.
22 class TestVideoRenderer::Core { 29 class TestVideoRenderer::Core {
23 public: 30 public:
24 Core(); 31 Core();
25 ~Core(); 32 ~Core();
26 33
27 // Initializes the internal structures of the class. 34 // Initializes the internal structures of the class.
(...skipping 10 matching lines...) Expand all
38 scoped_ptr<webrtc::DesktopFrame> GetBufferForTest() const; 45 scoped_ptr<webrtc::DesktopFrame> GetBufferForTest() const;
39 46
40 // Set expected image pattern for comparison and the callback will be called 47 // Set expected image pattern for comparison and the callback will be called
41 // when the pattern is matched. 48 // when the pattern is matched.
42 void SetImagePatternAndMatchedCallback( 49 void SetImagePatternAndMatchedCallback(
43 const webrtc::DesktopRect& expected_rect, 50 const webrtc::DesktopRect& expected_rect,
44 const RgbaColor& expected_color, 51 const RgbaColor& expected_color,
45 const base::Closure& image_pattern_matched_callback); 52 const base::Closure& image_pattern_matched_callback);
46 53
47 private: 54 private:
55 // Converts a set of RGB color to the RgbaColor format by adding the alpha
56 // values of 0x00.
57 RgbaColor ColorEncode(const int red, const int green, const int blue) const;
joedow 2015/07/09 03:03:43 Why are the int values const here? ints are passe
liaoyuke 2015/07/09 18:18:32 I think you are right, they shouldn't be const
58
59 // Converts a RgbaColor instance to an array of RGBA colors.
60 scoped_ptr<int> ColorDecode(const RgbaColor& rgba_color) const;
61
62 // Returns true if |rect2| falls within |rect1|, allowing for certain amount
63 // of error specified by a fuzzy threshold.
64 bool ContainsRect(const webrtc::DesktopRect& rect1,
65 const webrtc::DesktopRect& rect2) const;
66
67 // Expand the |accumulating_rect_| to a minimum rectangle that contains both
68 // |rect| and itself.
69 void MergeRectToAccumulatingRect(const webrtc::DesktopRect& rect);
70
71 // Update |accumulating_color_| to reflect the average color value of pixels
72 // fall within |accumulating_rect_|.
73 void UpdateAccumulatingColor();
74
75 // Compares |accumulating_color_| to |expected_color_|.
76 // Returns true if the root mean square of the errors in the R, G and B
77 // components does not exceed a fuzzy threshold.
78 bool ExpectedColorIsMatched() const;
79
80 // Returns true if |expected_rect_| and |accumulating_rect_| contains each
81 // other and expected color is matched.
82 bool ExpectedImagePatternIsMatched() const;
83
48 // Used to ensure Core methods are called on the same thread. 84 // Used to ensure Core methods are called on the same thread.
49 base::ThreadChecker thread_checker_; 85 base::ThreadChecker thread_checker_;
50 86
51 // Used to decode video packets. 87 // Used to decode video packets.
52 scoped_ptr<VideoDecoder> decoder_; 88 scoped_ptr<VideoDecoder> decoder_;
53 89
54 // Updated region of the current desktop frame compared to previous one. 90 // Updated region of the current desktop frame compared to previous one.
55 webrtc::DesktopRegion updated_region_; 91 webrtc::DesktopRegion updated_region_;
56 92
57 // Screen size of the remote host. 93 // Screen size of the remote host.
(...skipping 12 matching lines...) Expand all
70 webrtc::DesktopRect expected_rect_; 106 webrtc::DesktopRect expected_rect_;
71 RgbaColor expected_color_; 107 RgbaColor expected_color_;
72 108
73 // Maintains accumulating image pattern. 109 // Maintains accumulating image pattern.
74 webrtc::DesktopRect accumulating_rect_; 110 webrtc::DesktopRect accumulating_rect_;
75 RgbaColor accumulating_color_; 111 RgbaColor accumulating_color_;
76 112
77 // Used to store the callback when expected pattern is matched. 113 // Used to store the callback when expected pattern is matched.
78 base::Closure image_pattern_matched_callback_; 114 base::Closure image_pattern_matched_callback_;
79 115
116 // Used to account for video frame resizing and lossy encoding.
117 const double fuzzy_threshold_ = 0.05;
joedow 2015/07/09 03:03:43 Does this need to be a class member or can it just
liaoyuke 2015/07/09 18:18:32 Done.
118
80 DISALLOW_COPY_AND_ASSIGN(Core); 119 DISALLOW_COPY_AND_ASSIGN(Core);
81 }; 120 };
82 121
83 TestVideoRenderer::Core::Core() 122 TestVideoRenderer::Core::Core()
84 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()) { 123 : main_task_runner_(base::ThreadTaskRunnerHandle::Get()) {
85 thread_checker_.DetachFromThread(); 124 thread_checker_.DetachFromThread();
86 } 125 }
87 126
88 TestVideoRenderer::Core::~Core() { 127 TestVideoRenderer::Core::~Core() {
89 DCHECK(thread_checker_.CalledOnValidThread()); 128 DCHECK(thread_checker_.CalledOnValidThread());
90 } 129 }
91 130
92 void TestVideoRenderer::Core::Initialize() { 131 void TestVideoRenderer::Core::Initialize() {
93 DCHECK(thread_checker_.CalledOnValidThread()); 132 DCHECK(thread_checker_.CalledOnValidThread());
133
134 accumulating_rect_ = webrtc::DesktopRect::MakeLTRB(0, 0, 0, 0);
94 } 135 }
95 136
96 void TestVideoRenderer::Core::SetCodecForDecoding( 137 void TestVideoRenderer::Core::SetCodecForDecoding(
97 const protocol::ChannelConfig::Codec codec) { 138 const protocol::ChannelConfig::Codec codec) {
98 DCHECK(thread_checker_.CalledOnValidThread()); 139 DCHECK(thread_checker_.CalledOnValidThread());
99 140
100 if (decoder_) { 141 if (decoder_) {
101 LOG(WARNING) << "Decoder is set more than once"; 142 LOG(WARNING) << "Decoder is set more than once";
102 } 143 }
103 144
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after
165 // Note that the |updated_region_| maintains the changed regions compared to 206 // Note that the |updated_region_| maintains the changed regions compared to
166 // previous video frame. 207 // previous video frame.
167 decoder_->RenderFrame(screen_size_, 208 decoder_->RenderFrame(screen_size_,
168 webrtc::DesktopRect::MakeWH(screen_size_.width(), 209 webrtc::DesktopRect::MakeWH(screen_size_.width(),
169 screen_size_.height()), buffer_->data(), 210 screen_size_.height()), buffer_->data(),
170 buffer_->stride(), &updated_region_); 211 buffer_->stride(), &updated_region_);
171 } 212 }
172 213
173 main_task_runner_->PostTask(FROM_HERE, done); 214 main_task_runner_->PostTask(FROM_HERE, done);
174 215
175 // TODO(liaoyuke): Update |accumulating_rect_| and |accumulating_color_|, then 216 // Check to see if a image pattern matched reply is passed in.
176 // compare to the expected image pattern to check whether the pattern is 217 if (!image_pattern_matched_callback_.is_null()) {
joedow 2015/07/09 03:03:43 This be simpler if you return here if the callback
liaoyuke 2015/07/09 18:18:32 Done.
177 // matched or not and update |image_pattern_matched| accordingly. 218 for (webrtc::DesktopRegion::Iterator dirty_region(updated_region_);
219 !dirty_region.IsAtEnd(); dirty_region.Advance()) {
220 webrtc::DesktopRect dirty_rect = dirty_region.rect();
221
222 // Dirty rects not falling within |expected_rect_| doesn't affect the
223 // result.
224 if (ContainsRect(expected_rect_, dirty_rect)) {
225 MergeRectToAccumulatingRect(dirty_rect);
226 }
227 }
228
229 UpdateAccumulatingColor();
230 if (ExpectedImagePatternIsMatched()) {
231 image_pattern_matched_callback_.Run();
232 image_pattern_matched_callback_.Reset();
joedow 2015/07/09 03:03:43 base::ResetAndReturn() can replace lines 231 and 2
liaoyuke 2015/07/09 18:18:32 Done.
233 accumulating_rect_ = webrtc::DesktopRect::MakeLTRB(0, 0, 0, 0);
234 }
235 }
178 } 236 }
179 237
180 void TestVideoRenderer::Core::SetImagePatternAndMatchedCallback( 238 void TestVideoRenderer::Core::SetImagePatternAndMatchedCallback(
181 const webrtc::DesktopRect& expected_rect, 239 const webrtc::DesktopRect& expected_rect,
182 const RgbaColor& expected_color, 240 const RgbaColor& expected_color,
183 const base::Closure& image_pattern_matched_callback) { 241 const base::Closure& image_pattern_matched_callback) {
184 DCHECK(thread_checker_.CalledOnValidThread()); 242 DCHECK(thread_checker_.CalledOnValidThread());
185 243
186 expected_rect_ = expected_rect; 244 expected_rect_ = expected_rect;
187 expected_color_ = expected_color; 245 expected_color_ = expected_color;
188 image_pattern_matched_callback_ = image_pattern_matched_callback; 246 image_pattern_matched_callback_ = image_pattern_matched_callback;
189 } 247 }
190 248
249 RgbaColor TestVideoRenderer::Core::ColorEncode(const int red,
250 const int green,
251 const int blue) const {
252 RgbaColor rgba_color = red;
253 rgba_color = (rgba_color << 8) + green;
254 rgba_color = (rgba_color << 8) + blue;
255 rgba_color = (rgba_color << 8) + 0;
256
257 return rgba_color;
258 }
259
260 scoped_ptr<int> TestVideoRenderer::Core::ColorDecode(
261 const RgbaColor& rgba_color) const {
joedow 2015/07/09 03:03:43 If you are going to return an array, you want scop
262 int* rgba_colors = new int[3];
263 uint32 mask = (1 << 9) - 1;
264 rgba_colors[2] = ((rgba_color >> 8) & mask);
265 rgba_colors[1] = ((rgba_color >> 16) & mask);
266 rgba_colors[0] = ((rgba_color >> 24) & mask);
267
268 return make_scoped_ptr(rgba_colors);
269 }
270
271 bool TestVideoRenderer::Core::ContainsRect(
joedow 2015/07/09 03:03:43 rect1 and rect2 aren't quite descriptive enough, w
liaoyuke 2015/07/09 18:18:32 Done.
272 const webrtc::DesktopRect& rect1,
273 const webrtc::DesktopRect& rect2) const {
274 DCHECK(thread_checker_.CalledOnValidThread());
275 DCHECK(!image_pattern_matched_callback_.is_null());
joedow 2015/07/09 03:03:43 Does it matter if the callback is not null here?
liaoyuke 2015/07/09 18:18:32 At first, I thought this function will only be cal
276
277 return rect2.left() >= (1 - fuzzy_threshold_) * rect1.left() &&
278 rect2.top() >= (1 - fuzzy_threshold_) * rect1.top() &&
279 rect2.right() <= (1 + fuzzy_threshold_) * rect1.right() &&
280 rect2.bottom() <= (1 + fuzzy_threshold_) * rect1.bottom();
281 }
282
283 void TestVideoRenderer::Core::MergeRectToAccumulatingRect(
284 const webrtc::DesktopRect& rect) {
285 if (accumulating_rect_.width() == 0 && accumulating_rect_.height() == 0) {
joedow 2015/07/09 03:03:43 if (!accumulating_rect_.width() && !accumulating_r
liaoyuke 2015/07/09 18:18:32 I think it's not possible, that's why I use it as
286 accumulating_rect_ = rect;
287 } else {
288 accumulating_rect_ = webrtc::DesktopRect::MakeLTRB(
289 std::min(accumulating_rect_.left(), rect.left()),
290 std::min(accumulating_rect_.top(), rect.top()),
291 std::max(accumulating_rect_.right(), rect.right()),
292 std::max(accumulating_rect_.bottom(), rect.bottom()));
293 }
294 }
295
296 void TestVideoRenderer::Core::UpdateAccumulatingColor() {
297 int red_sum = 0;
298 int green_sum = 0;
299 int blue_sum = 0;
300 for (int y = accumulating_rect_.top(); y < accumulating_rect_.bottom(); ++y) {
301 for (int x = accumulating_rect_.left(); x < accumulating_rect_.right();
302 ++x) {
303 int offset =
304 y * kBytesPerPixel * screen_size_.width() + x * kBytesPerPixel;
joedow 2015/07/09 03:03:43 some parens would help with the readability here
liaoyuke 2015/07/09 18:18:32 Done.
305 red_sum += buffer_->data()[offset + 2];
306 green_sum += buffer_->data()[offset + 1];
liaoyuke 2015/07/09 18:18:32 Here, I should mention that the decoded frame is i
307 blue_sum += buffer_->data()[offset + 0];
308 }
309 }
310
311 int area = screen_size_.width() * screen_size_.height();
312 accumulating_color_ =
313 ColorEncode(red_sum / area, green_sum / area, blue_sum / area);
314 }
315
316 bool TestVideoRenderer::Core::ExpectedColorIsMatched() const {
317 scoped_ptr<int> decoded_expected_color = ColorDecode(expected_color_);
318 scoped_ptr<int> decoded_accumulating_color = ColorDecode(accumulating_color_);
319 double error_sum_squares = 0;
320 for (int i = 0; i < 3; i++) {
321 double expected_value =
322 static_cast<double>(decoded_expected_color.get()[i]);
323 double accumulating_value =
324 static_cast<double>(decoded_accumulating_color.get()[i]);
325 double error = expected_value - accumulating_value;
326 error /= 255.0;
327 error_sum_squares += error * error;
328 }
329
330 return sqrt(error_sum_squares / 3) < fuzzy_threshold_;
331 }
332
333 bool TestVideoRenderer::Core::ExpectedImagePatternIsMatched() const {
334 return ContainsRect(accumulating_rect_, expected_rect_) &&
335 ContainsRect(expected_rect_, accumulating_rect_) &&
336 ExpectedColorIsMatched();
337 }
338
191 TestVideoRenderer::TestVideoRenderer() 339 TestVideoRenderer::TestVideoRenderer()
192 : video_decode_thread_( 340 : video_decode_thread_(
193 new base::Thread("TestVideoRendererVideoDecodingThread")), 341 new base::Thread("TestVideoRendererVideoDecodingThread")),
194 weak_factory_(this) { 342 weak_factory_(this) {
195 DCHECK(thread_checker_.CalledOnValidThread()); 343 DCHECK(thread_checker_.CalledOnValidThread());
196 344
197 core_.reset(new Core()); 345 core_.reset(new Core());
198 if (!video_decode_thread_->Start()) { 346 if (!video_decode_thread_->Start()) {
199 LOG(ERROR) << "Cannot start TestVideoRenderer"; 347 LOG(ERROR) << "Cannot start TestVideoRenderer";
200 } else { 348 } else {
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after
281 429
282 DVLOG(2) << "TestVideoRenderer::SetImagePatternAndMatchedCallback() Called"; 430 DVLOG(2) << "TestVideoRenderer::SetImagePatternAndMatchedCallback() Called";
283 video_decode_task_runner_->PostTask( 431 video_decode_task_runner_->PostTask(
284 FROM_HERE, base::Bind(&Core::SetImagePatternAndMatchedCallback, 432 FROM_HERE, base::Bind(&Core::SetImagePatternAndMatchedCallback,
285 base::Unretained(core_.get()), expected_rect, 433 base::Unretained(core_.get()), expected_rect,
286 expected_color, image_pattern_matched_callback)); 434 expected_color, image_pattern_matched_callback));
287 } 435 }
288 436
289 } // namespace test 437 } // namespace test
290 } // namespace remoting 438 } // namespace remoting
OLDNEW
« no previous file with comments | « remoting/test/app_remoting_latency_test_fixture.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698