| OLD | NEW |
| 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 <cmath> | 7 #include <cmath> |
| 8 | 8 |
| 9 #include "base/memory/scoped_vector.h" | 9 #include "base/memory/scoped_vector.h" |
| 10 #include "base/message_loop/message_loop.h" | 10 #include "base/message_loop/message_loop.h" |
| 11 #include "base/run_loop.h" | 11 #include "base/run_loop.h" |
| 12 #include "base/thread_task_runner_handle.h" | 12 #include "base/thread_task_runner_handle.h" |
| 13 #include "base/timer/timer.h" | 13 #include "base/timer/timer.h" |
| 14 #include "media/base/video_frame.h" | 14 #include "media/base/video_frame.h" |
| 15 #include "remoting/codec/video_encoder.h" | 15 #include "remoting/codec/video_encoder.h" |
| 16 #include "remoting/codec/video_encoder_verbatim.h" | 16 #include "remoting/codec/video_encoder_verbatim.h" |
| 17 #include "remoting/codec/video_encoder_vpx.h" | 17 #include "remoting/codec/video_encoder_vpx.h" |
| 18 #include "remoting/proto/video.pb.h" | 18 #include "remoting/proto/video.pb.h" |
| 19 #include "remoting/test/rgb_value.h" |
| 19 #include "testing/gtest/include/gtest/gtest.h" | 20 #include "testing/gtest/include/gtest/gtest.h" |
| 20 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" | 21 #include "third_party/webrtc/modules/desktop_capture/desktop_frame.h" |
| 21 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" | 22 #include "third_party/webrtc/modules/desktop_capture/desktop_region.h" |
| 22 | 23 |
| 23 namespace { | 24 namespace { |
| 24 | 25 |
| 25 // Used to verify if image pattern is matched. | 26 // Used to verify if image pattern is matched. |
| 26 void ProcessPacketDoneHandler(const base::Closure& done_closure, | 27 void ProcessPacketDoneHandler(const base::Closure& done_closure, |
| 27 bool* handler_called) { | 28 bool* handler_called) { |
| 28 *handler_called = true; | 29 *handler_called = true; |
| (...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 79 scoped_ptr<VideoEncoder> encoder_; | 80 scoped_ptr<VideoEncoder> encoder_; |
| 80 | 81 |
| 81 private: | 82 private: |
| 82 // testing::Test interface. | 83 // testing::Test interface. |
| 83 void SetUp() override; | 84 void SetUp() override; |
| 84 | 85 |
| 85 // Set image pattern, send video packet and returns if the expected pattern is | 86 // Set image pattern, send video packet and returns if the expected pattern is |
| 86 // matched. | 87 // matched. |
| 87 bool SendPacketAndWaitForMatch(scoped_ptr<VideoPacket> packet, | 88 bool SendPacketAndWaitForMatch(scoped_ptr<VideoPacket> packet, |
| 88 const webrtc::DesktopRect& expected_rect, | 89 const webrtc::DesktopRect& expected_rect, |
| 89 uint32_t expected_average_color); | 90 const RGBValue& expected_average_color); |
| 90 | 91 |
| 91 // Returns the average color value of pixels fall within |rect|. | 92 // Returns the average color value of pixels fall within |rect|. |
| 92 // NOTE: Callers should not release the objects. | 93 // NOTE: Callers should not release the objects. |
| 93 uint32_t CalculateAverageColorValueForFrame( | 94 RGBValue CalculateAverageColorValueForFrame( |
| 94 const webrtc::DesktopFrame* frame, | 95 const webrtc::DesktopFrame* frame, |
| 95 const webrtc::DesktopRect& rect) const; | 96 const webrtc::DesktopRect& rect) const; |
| 96 | 97 |
| 97 // Return the mean error of two frames over all pixels, where error at each | 98 // Return the mean error of two frames over all pixels, where error at each |
| 98 // pixel is the root mean square of the errors in the R, G and B components, | 99 // pixel is the root mean square of the errors in the R, G and B components, |
| 99 // each normalized to [0, 1]. | 100 // each normalized to [0, 1]. |
| 100 double CalculateError(const webrtc::DesktopFrame* original_frame, | 101 double CalculateError(const webrtc::DesktopFrame* original_frame, |
| 101 const webrtc::DesktopFrame* decoded_frame) const; | 102 const webrtc::DesktopFrame* decoded_frame) const; |
| 102 | 103 |
| 103 // Fill a desktop frame with a gradient. | 104 // Fill a desktop frame with a gradient. |
| (...skipping 57 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 | 162 |
| 162 // The original frame is compared to the decoded video frame to check that | 163 // The original frame is compared to the decoded video frame to check that |
| 163 // the mean error over all pixels does not exceed a given limit. | 164 // the mean error over all pixels does not exceed a given limit. |
| 164 double error = CalculateError(original_frame.get(), buffer_copy.get()); | 165 double error = CalculateError(original_frame.get(), buffer_copy.get()); |
| 165 EXPECT_LT(error, error_limit); | 166 EXPECT_LT(error, error_limit); |
| 166 } | 167 } |
| 167 | 168 |
| 168 bool TestVideoRendererTest::SendPacketAndWaitForMatch( | 169 bool TestVideoRendererTest::SendPacketAndWaitForMatch( |
| 169 scoped_ptr<VideoPacket> packet, | 170 scoped_ptr<VideoPacket> packet, |
| 170 const webrtc::DesktopRect& expected_rect, | 171 const webrtc::DesktopRect& expected_rect, |
| 171 uint32_t expected_average_color) { | 172 const RGBValue& expected_average_color) { |
| 172 DCHECK(!run_loop_ || !run_loop_->running()); | 173 DCHECK(!run_loop_ || !run_loop_->running()); |
| 173 DCHECK(!timer_->IsRunning()); | 174 DCHECK(!timer_->IsRunning()); |
| 174 run_loop_.reset(new base::RunLoop()); | 175 run_loop_.reset(new base::RunLoop()); |
| 175 | 176 |
| 176 // Set an extremely long time: 10 min to prevent bugs from hanging the system. | 177 // Set an extremely long time: 10 min to prevent bugs from hanging the system. |
| 177 // NOTE: We've seen cases which take up to 1 min to process a packet, so an | 178 // NOTE: We've seen cases which take up to 1 min to process a packet, so an |
| 178 // extremely long time as 10 min is chosen to avoid being variable/flaky. | 179 // extremely long time as 10 min is chosen to avoid being variable/flaky. |
| 179 timer_->Start(FROM_HERE, base::TimeDelta::FromMinutes(10), | 180 timer_->Start(FROM_HERE, base::TimeDelta::FromMinutes(10), |
| 180 run_loop_->QuitClosure()); | 181 run_loop_->QuitClosure()); |
| 181 | 182 |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 217 void TestVideoRendererTest::TestImagePatternMatch( | 218 void TestVideoRendererTest::TestImagePatternMatch( |
| 218 int screen_width, | 219 int screen_width, |
| 219 int screen_height, | 220 int screen_height, |
| 220 const webrtc::DesktopRect& expected_rect, | 221 const webrtc::DesktopRect& expected_rect, |
| 221 bool expect_to_match) { | 222 bool expect_to_match) { |
| 222 DCHECK(encoder_); | 223 DCHECK(encoder_); |
| 223 DCHECK(test_video_renderer_); | 224 DCHECK(test_video_renderer_); |
| 224 | 225 |
| 225 scoped_ptr<webrtc::DesktopFrame> frame = | 226 scoped_ptr<webrtc::DesktopFrame> frame = |
| 226 CreateDesktopFrameWithGradient(screen_width, screen_height); | 227 CreateDesktopFrameWithGradient(screen_width, screen_height); |
| 227 uint32_t expected_average_color = | 228 RGBValue expected_average_color = |
| 228 CalculateAverageColorValueForFrame(frame.get(), expected_rect); | 229 CalculateAverageColorValueForFrame(frame.get(), expected_rect); |
| 229 scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame.get()); | 230 scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame.get()); |
| 230 | 231 |
| 231 if (expect_to_match) { | 232 if (expect_to_match) { |
| 232 EXPECT_TRUE(SendPacketAndWaitForMatch(packet.Pass(), expected_rect, | 233 EXPECT_TRUE(SendPacketAndWaitForMatch(packet.Pass(), expected_rect, |
| 233 expected_average_color)); | 234 expected_average_color)); |
| 234 } else { | 235 } else { |
| 235 // Shift each channel by 128. | 236 // Shift each channel by 128. |
| 236 // e.g. (10, 127, 200) -> (138, 255, 73). | 237 // e.g. (10, 127, 200) -> (138, 255, 73). |
| 237 // In this way, the error between expected color and true value is always | 238 // In this way, the error between expected color and true value is always |
| 238 // around 0.5. | 239 // around 0.5. |
| 239 int red_shift = (((expected_average_color >> 16) & 0xFF) + 128) % 255; | 240 int red_shift = (expected_average_color.red + 128) % 255; |
| 240 int green_shift = (((expected_average_color >> 8) & 0xFF) + 128) % 255; | 241 int green_shift = (expected_average_color.green + 128) % 255; |
| 241 int blue_shift = ((expected_average_color & 0xFF) + 128) % 255; | 242 int blue_shift = (expected_average_color.blue + 128) % 255; |
| 242 | 243 |
| 243 int expected_average_color_shift = | 244 RGBValue expected_average_color_shift = |
| 244 0xFF000000 | (red_shift << 16) | (green_shift << 8) | blue_shift; | 245 RGBValue(red_shift, green_shift, blue_shift); |
| 245 | 246 |
| 246 EXPECT_FALSE(SendPacketAndWaitForMatch(packet.Pass(), expected_rect, | 247 EXPECT_FALSE(SendPacketAndWaitForMatch(packet.Pass(), expected_rect, |
| 247 expected_average_color_shift)); | 248 expected_average_color_shift)); |
| 248 } | 249 } |
| 249 } | 250 } |
| 250 | 251 |
| 251 uint32_t TestVideoRendererTest::CalculateAverageColorValueForFrame( | 252 RGBValue TestVideoRendererTest::CalculateAverageColorValueForFrame( |
| 252 const webrtc::DesktopFrame* frame, | 253 const webrtc::DesktopFrame* frame, |
| 253 const webrtc::DesktopRect& rect) const { | 254 const webrtc::DesktopRect& rect) const { |
| 254 int red_sum = 0; | 255 int red_sum = 0; |
| 255 int green_sum = 0; | 256 int green_sum = 0; |
| 256 int blue_sum = 0; | 257 int blue_sum = 0; |
| 257 | 258 |
| 258 // Loop through pixels that fall within |accumulating_rect_| to obtain the | 259 // Loop through pixels that fall within |accumulating_rect_| to obtain the |
| 259 // average color value. | 260 // average color value. |
| 260 for (int y = rect.top(); y < rect.bottom(); ++y) { | 261 for (int y = rect.top(); y < rect.bottom(); ++y) { |
| 261 uint8_t* frame_pos = | 262 uint8_t* frame_pos = |
| 262 frame->data() + (y * frame->stride() + | 263 frame->data() + (y * frame->stride() + |
| 263 rect.left() * webrtc::DesktopFrame::kBytesPerPixel); | 264 rect.left() * webrtc::DesktopFrame::kBytesPerPixel); |
| 264 | 265 |
| 265 // Pixels of decoded video frame are presented in ARGB format. | 266 // Pixels of decoded video frame are presented in ARGB format. |
| 266 for (int x = 0; x < rect.width(); ++x) { | 267 for (int x = 0; x < rect.width(); ++x) { |
| 267 red_sum += frame_pos[2]; | 268 red_sum += frame_pos[2]; |
| 268 green_sum += frame_pos[1]; | 269 green_sum += frame_pos[1]; |
| 269 blue_sum += frame_pos[0]; | 270 blue_sum += frame_pos[0]; |
| 270 frame_pos += 4; | 271 frame_pos += 4; |
| 271 } | 272 } |
| 272 } | 273 } |
| 273 | 274 |
| 274 int area = rect.width() * rect.height(); | 275 int area = rect.width() * rect.height(); |
| 275 return 0xFF000000 | ((red_sum / area) << 16) | ((green_sum / area) << 8) | | 276 |
| 276 (blue_sum / area); | 277 return RGBValue(red_sum / area, green_sum / area, blue_sum / area); |
| 277 } | 278 } |
| 278 | 279 |
| 279 double TestVideoRendererTest::CalculateError( | 280 double TestVideoRendererTest::CalculateError( |
| 280 const webrtc::DesktopFrame* original_frame, | 281 const webrtc::DesktopFrame* original_frame, |
| 281 const webrtc::DesktopFrame* decoded_frame) const { | 282 const webrtc::DesktopFrame* decoded_frame) const { |
| 282 DCHECK(original_frame); | 283 DCHECK(original_frame); |
| 283 DCHECK(decoded_frame); | 284 DCHECK(decoded_frame); |
| 284 | 285 |
| 285 // Check size remains the same after encoding and decoding. | 286 // Check size remains the same after encoding and decoding. |
| 286 EXPECT_EQ(original_frame->size().width(), decoded_frame->size().width()); | 287 EXPECT_EQ(original_frame->size().width(), decoded_frame->size().width()); |
| (...skipping 146 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 433 protocol::ChannelConfig::Codec::CODEC_VP8); | 434 protocol::ChannelConfig::Codec::CODEC_VP8); |
| 434 | 435 |
| 435 DCHECK(encoder_); | 436 DCHECK(encoder_); |
| 436 DCHECK(test_video_renderer_); | 437 DCHECK(test_video_renderer_); |
| 437 | 438 |
| 438 scoped_ptr<webrtc::DesktopFrame> frame = CreateDesktopFrameWithGradient( | 439 scoped_ptr<webrtc::DesktopFrame> frame = CreateDesktopFrameWithGradient( |
| 439 kDefaultScreenWidthPx, kDefaultScreenHeightPx); | 440 kDefaultScreenWidthPx, kDefaultScreenHeightPx); |
| 440 | 441 |
| 441 // Since we don't care whether expected image pattern is matched or not in | 442 // Since we don't care whether expected image pattern is matched or not in |
| 442 // this case, an expected color is chosen arbitrarily. | 443 // this case, an expected color is chosen arbitrarily. |
| 443 uint32_t black_color = 0xFF000000; | 444 RGBValue black_color = RGBValue(); |
| 444 | 445 |
| 445 // Set expected image pattern. | 446 // Set expected image pattern. |
| 446 test_video_renderer_->ExpectAverageColorInRect( | 447 test_video_renderer_->ExpectAverageColorInRect( |
| 447 kDefaultExpectedRect, black_color, base::Bind(&base::DoNothing)); | 448 kDefaultExpectedRect, black_color, base::Bind(&base::DoNothing)); |
| 448 | 449 |
| 449 // Post test video packet. | 450 // Post test video packet. |
| 450 scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame.get()); | 451 scoped_ptr<VideoPacket> packet = encoder_->Encode(*frame.get()); |
| 451 test_video_renderer_->ProcessVideoPacket(packet.Pass(), | 452 test_video_renderer_->ProcessVideoPacket(packet.Pass(), |
| 452 base::Bind(&base::DoNothing)); | 453 base::Bind(&base::DoNothing)); |
| 453 } | 454 } |
| (...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 501 TEST_F(TestVideoRendererTest, VerifyImagePatternNotMatchForVERBATIM) { | 502 TEST_F(TestVideoRendererTest, VerifyImagePatternNotMatchForVERBATIM) { |
| 502 encoder_.reset(new VideoEncoderVerbatim()); | 503 encoder_.reset(new VideoEncoderVerbatim()); |
| 503 test_video_renderer_->SetCodecForDecoding( | 504 test_video_renderer_->SetCodecForDecoding( |
| 504 protocol::ChannelConfig::Codec::CODEC_VERBATIM); | 505 protocol::ChannelConfig::Codec::CODEC_VERBATIM); |
| 505 TestImagePatternMatch(kDefaultScreenWidthPx, kDefaultScreenHeightPx, | 506 TestImagePatternMatch(kDefaultScreenWidthPx, kDefaultScreenHeightPx, |
| 506 kDefaultExpectedRect, false); | 507 kDefaultExpectedRect, false); |
| 507 } | 508 } |
| 508 | 509 |
| 509 } // namespace test | 510 } // namespace test |
| 510 } // namespace remoting | 511 } // namespace remoting |
| OLD | NEW |