| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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 "base/command_line.h" | 5 #include "base/command_line.h" |
| 6 #include "base/environment.h" | 6 #include "base/environment.h" |
| 7 #include "base/file_util.h" | 7 #include "base/file_util.h" |
| 8 #include "base/path_service.h" | 8 #include "base/path_service.h" |
| 9 #include "base/process/launch.h" | 9 #include "base/process/launch.h" |
| 10 #include "base/strings/string_split.h" | 10 #include "base/strings/string_split.h" |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 46 | 46 |
| 47 static const base::FilePath::CharType kArgbToI420ConverterExecutable[] = | 47 static const base::FilePath::CharType kArgbToI420ConverterExecutable[] = |
| 48 #if defined(OS_WIN) | 48 #if defined(OS_WIN) |
| 49 FILE_PATH_LITERAL("rgba_to_i420_converter.exe"); | 49 FILE_PATH_LITERAL("rgba_to_i420_converter.exe"); |
| 50 #else | 50 #else |
| 51 FILE_PATH_LITERAL("rgba_to_i420_converter"); | 51 FILE_PATH_LITERAL("rgba_to_i420_converter"); |
| 52 #endif | 52 #endif |
| 53 | 53 |
| 54 static const char kHomeEnvName[] = | 54 static const char kHomeEnvName[] = |
| 55 #if defined(OS_WIN) | 55 #if defined(OS_WIN) |
| 56 "HOMEPATH"; | 56 "USERPROFILE"; |
| 57 #else | 57 #else |
| 58 "HOME"; | 58 "HOME"; |
| 59 #endif | 59 #endif |
| 60 | 60 |
| 61 // The working dir should be in the user's home folder. | 61 // The working dir should be in the user's home folder. |
| 62 static const base::FilePath::CharType kWorkingDirName[] = | 62 static const base::FilePath::CharType kWorkingDirName[] = |
| 63 FILE_PATH_LITERAL("webrtc_video_quality"); | 63 FILE_PATH_LITERAL("webrtc_video_quality"); |
| 64 static const base::FilePath::CharType kCapturedYuvFileName[] = | 64 static const base::FilePath::CharType kCapturedYuvFileName[] = |
| 65 FILE_PATH_LITERAL("captured_video.yuv"); | 65 FILE_PATH_LITERAL("captured_video.yuv"); |
| 66 static const base::FilePath::CharType kStatsFileName[] = | 66 static const base::FilePath::CharType kStatsFileName[] = |
| 67 FILE_PATH_LITERAL("stats.txt"); | 67 FILE_PATH_LITERAL("stats.txt"); |
| 68 static const char kMainWebrtcTestHtmlPage[] = | 68 static const char kMainWebrtcTestHtmlPage[] = |
| 69 "/webrtc/webrtc_jsep01_test.html"; | 69 "/webrtc/webrtc_jsep01_test.html"; |
| 70 static const char kCapturingWebrtcHtmlPage[] = | |
| 71 "/webrtc/webrtc_video_quality_test.html"; | |
| 72 static const int k360pWidth = 640; | |
| 73 static const int k360pHeight = 360; | |
| 74 | 70 |
| 75 // If you change the port number, don't forget to modify video_extraction.js | 71 // If you change the port number, don't forget to modify video_extraction.js |
| 76 // too! | 72 // too! |
| 77 static const char kPyWebSocketPortNumber[] = "12221"; | 73 static const char kPyWebSocketPortNumber[] = "12221"; |
| 78 | 74 |
| 75 static const struct VideoQualityTestConfig { |
| 76 const char* test_name; |
| 77 int width; |
| 78 int height; |
| 79 const char* capture_page; |
| 80 const base::FilePath::CharType* reference_video; |
| 81 const char* constraints; |
| 82 } kVideoConfigurations[] = { |
| 83 { "360p", 640, 360, |
| 84 "/webrtc/webrtc_video_quality_test.html", |
| 85 test::kReferenceFileName360p, |
| 86 WebRtcTestBase::kAudioVideoCallConstraints360p }, |
| 87 { "720p", 1280, 720, |
| 88 "/webrtc/webrtc_video_quality_test_hd.html", |
| 89 test::kReferenceFileName720p, |
| 90 WebRtcTestBase::kAudioVideoCallConstraints720p }, |
| 91 }; |
| 92 |
| 79 // Test the video quality of the WebRTC output. | 93 // Test the video quality of the WebRTC output. |
| 80 // | 94 // |
| 81 // Prerequisites: This test case must run on a machine with a chrome playing | 95 // Prerequisites: This test case must run on a machine with a chrome playing |
| 82 // the video from the reference files located in GetReferenceFilesDir(). | 96 // the video from the reference files located in GetReferenceFilesDir(). |
| 83 // The file kReferenceY4mFileName.kY4mFileExtension is played using a | 97 // The file kReferenceY4mFileName.kY4mFileExtension is played using a |
| 84 // FileVideoCaptureDevice and its sibling with kYuvFileExtension is used for | 98 // FileVideoCaptureDevice and its sibling with kYuvFileExtension is used for |
| 85 // comparison. | 99 // comparison. |
| 86 // | 100 // |
| 87 // You must also compile the chromium_builder_webrtc target before you run this | 101 // You must also compile the chromium_builder_webrtc target before you run this |
| 88 // test to get all the tools built. | 102 // test to get all the tools built. |
| 89 // | 103 // |
| 90 // The external compare_videos.py script also depends on two external | 104 // The external compare_videos.py script also depends on two external |
| 91 // executables which must be located in the PATH when running this test. | 105 // executables which must be located in the PATH when running this test. |
| 92 // * zxing (see the CPP version at https://code.google.com/p/zxing) | 106 // * zxing (see the CPP version at https://code.google.com/p/zxing) |
| 93 // * ffmpeg 0.11.1 or compatible version (see http://www.ffmpeg.org) | 107 // * ffmpeg 0.11.1 or compatible version (see http://www.ffmpeg.org) |
| 94 // | 108 // |
| 95 // The test case will launch a custom binary (peerconnection_server) which will | 109 // The test case will launch a custom binary (peerconnection_server) which will |
| 96 // allow two WebRTC clients to find each other. | 110 // allow two WebRTC clients to find each other. |
| 97 // | 111 // |
| 98 // The test also runs several other custom binaries - rgba_to_i420 converter and | 112 // The test also runs several other custom binaries - rgba_to_i420 converter and |
| 99 // frame_analyzer. Both tools can be found under third_party/webrtc/tools. The | 113 // frame_analyzer. Both tools can be found under third_party/webrtc/tools. The |
| 100 // test also runs a stand alone Python implementation of a WebSocket server | 114 // test also runs a stand alone Python implementation of a WebSocket server |
| 101 // (pywebsocket) and a barcode_decoder script. | 115 // (pywebsocket) and a barcode_decoder script. |
| 102 class WebRtcVideoQualityBrowserTest : public WebRtcTestBase { | 116 class WebRtcVideoQualityBrowserTest : public WebRtcTestBase, |
| 117 public testing::WithParamInterface<VideoQualityTestConfig> { |
| 103 public: | 118 public: |
| 104 WebRtcVideoQualityBrowserTest() | 119 WebRtcVideoQualityBrowserTest() |
| 105 : pywebsocket_server_(0), | 120 : pywebsocket_server_(0), |
| 106 environment_(base::Environment::Create()) {} | 121 environment_(base::Environment::Create()) { |
| 122 test_config_ = GetParam(); |
| 123 } |
| 107 | 124 |
| 108 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { | 125 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { |
| 109 test::PeerConnectionServerRunner::KillAllPeerConnectionServers(); | 126 test::PeerConnectionServerRunner::KillAllPeerConnectionServers(); |
| 110 DetectErrorsInJavaScript(); // Look for errors in our rather complex js. | 127 DetectErrorsInJavaScript(); // Look for errors in our rather complex js. |
| 111 } | 128 } |
| 112 | 129 |
| 113 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { | 130 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { |
| 114 // Set up the command line option with the expected file name. We will check | 131 // Set up the command line option with the expected file name. We will check |
| 115 // its existence in HasAllRequiredResources(). | 132 // its existence in HasAllRequiredResources(). |
| 116 webrtc_reference_video_y4m_ = test::GetReferenceFilesDir() | 133 webrtc_reference_video_y4m_ = test::GetReferenceFilesDir() |
| 117 .Append(test::kReferenceFileName360p) | 134 .Append(test_config_.reference_video) |
| 118 .AddExtension(test::kY4mFileExtension); | 135 .AddExtension(test::kY4mFileExtension); |
| 119 command_line->AppendSwitchPath(switches::kUseFileForFakeVideoCapture, | 136 command_line->AppendSwitchPath(switches::kUseFileForFakeVideoCapture, |
| 120 webrtc_reference_video_y4m_); | 137 webrtc_reference_video_y4m_); |
| 121 command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream); | 138 command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream); |
| 122 | 139 |
| 123 // The video playback will not work without a GPU, so force its use here. | 140 // The video playback will not work without a GPU, so force its use here. |
| 124 command_line->AppendSwitch(switches::kUseGpuInTests); | 141 command_line->AppendSwitch(switches::kUseGpuInTests); |
| 125 } | 142 } |
| 126 | 143 |
| 127 bool HasAllRequiredResources() { | 144 bool HasAllRequiredResources() { |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 213 | 230 |
| 214 // Compares the |captured_video_filename| with the |reference_video_filename|. | 231 // Compares the |captured_video_filename| with the |reference_video_filename|. |
| 215 // | 232 // |
| 216 // The barcode decoder decodes the captured video containing barcodes overlaid | 233 // The barcode decoder decodes the captured video containing barcodes overlaid |
| 217 // into every frame of the video (produced by rgba_to_i420_converter). It | 234 // into every frame of the video (produced by rgba_to_i420_converter). It |
| 218 // produces a set of PNG images and a |stats_file| that maps each captured | 235 // produces a set of PNG images and a |stats_file| that maps each captured |
| 219 // frame to a frame in the reference video. The frames should be of size | 236 // frame to a frame in the reference video. The frames should be of size |
| 220 // |width| x |height|. | 237 // |width| x |height|. |
| 221 // All measurements calculated are printed as perf parsable numbers to stdout. | 238 // All measurements calculated are printed as perf parsable numbers to stdout. |
| 222 bool CompareVideosAndPrintResult( | 239 bool CompareVideosAndPrintResult( |
| 240 const char* test_label, |
| 223 int width, | 241 int width, |
| 224 int height, | 242 int height, |
| 225 const base::FilePath& captured_video_filename, | 243 const base::FilePath& captured_video_filename, |
| 226 const base::FilePath& reference_video_filename, | 244 const base::FilePath& reference_video_filename, |
| 227 const base::FilePath& stats_file) { | 245 const base::FilePath& stats_file) { |
| 228 | 246 |
| 229 base::FilePath path_to_analyzer = base::MakeAbsoluteFilePath( | 247 base::FilePath path_to_analyzer = base::MakeAbsoluteFilePath( |
| 230 GetBrowserDir().Append(kFrameAnalyzerExecutable)); | 248 GetBrowserDir().Append(kFrameAnalyzerExecutable)); |
| 231 base::FilePath path_to_compare_script = GetSourceDir().Append( | 249 base::FilePath path_to_compare_script = GetSourceDir().Append( |
| 232 FILE_PATH_LITERAL("third_party/webrtc/tools/compare_videos.py")); | 250 FILE_PATH_LITERAL("third_party/webrtc/tools/compare_videos.py")); |
| 233 | 251 |
| 234 if (!base::PathExists(path_to_analyzer)) { | 252 if (!base::PathExists(path_to_analyzer)) { |
| 235 LOG(ERROR) << "Missing frame analyzer: should be in " | 253 LOG(ERROR) << "Missing frame analyzer: should be in " |
| 236 << path_to_analyzer.value(); | 254 << path_to_analyzer.value(); |
| 237 return false; | 255 return false; |
| 238 } | 256 } |
| 239 if (!base::PathExists(path_to_compare_script)) { | 257 if (!base::PathExists(path_to_compare_script)) { |
| 240 LOG(ERROR) << "Missing video compare script: should be in " | 258 LOG(ERROR) << "Missing video compare script: should be in " |
| 241 << path_to_compare_script.value(); | 259 << path_to_compare_script.value(); |
| 242 return false; | 260 return false; |
| 243 } | 261 } |
| 244 | 262 |
| 245 // Note: don't append switches to this command since it will mess up the | 263 // Note: don't append switches to this command since it will mess up the |
| 246 // -u in the python invocation! | 264 // -u in the python invocation! |
| 247 CommandLine compare_command(CommandLine::NO_PROGRAM); | 265 CommandLine compare_command(CommandLine::NO_PROGRAM); |
| 248 EXPECT_TRUE(GetPythonCommand(&compare_command)); | 266 EXPECT_TRUE(GetPythonCommand(&compare_command)); |
| 249 | 267 |
| 250 compare_command.AppendArgPath(path_to_compare_script); | 268 compare_command.AppendArgPath(path_to_compare_script); |
| 251 compare_command.AppendArg("--label=360p"); | 269 compare_command.AppendArg(base::StringPrintf("--label=%s", test_label)); |
| 252 compare_command.AppendArg("--ref_video"); | 270 compare_command.AppendArg("--ref_video"); |
| 253 compare_command.AppendArgPath(reference_video_filename); | 271 compare_command.AppendArgPath(reference_video_filename); |
| 254 compare_command.AppendArg("--test_video"); | 272 compare_command.AppendArg("--test_video"); |
| 255 compare_command.AppendArgPath(captured_video_filename); | 273 compare_command.AppendArgPath(captured_video_filename); |
| 256 compare_command.AppendArg("--frame_analyzer"); | 274 compare_command.AppendArg("--frame_analyzer"); |
| 257 compare_command.AppendArgPath(path_to_analyzer); | 275 compare_command.AppendArgPath(path_to_analyzer); |
| 258 compare_command.AppendArg("--yuv_frame_width"); | 276 compare_command.AppendArg("--yuv_frame_width"); |
| 259 compare_command.AppendArg(base::StringPrintf("%d", width)); | 277 compare_command.AppendArg(base::StringPrintf("%d", width)); |
| 260 compare_command.AppendArg("--yuv_frame_height"); | 278 compare_command.AppendArg("--yuv_frame_height"); |
| 261 compare_command.AppendArg(base::StringPrintf("%d", height)); | 279 compare_command.AppendArg(base::StringPrintf("%d", height)); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 272 } | 290 } |
| 273 | 291 |
| 274 base::FilePath GetWorkingDir() { | 292 base::FilePath GetWorkingDir() { |
| 275 std::string home_dir; | 293 std::string home_dir; |
| 276 environment_->GetVar(kHomeEnvName, &home_dir); | 294 environment_->GetVar(kHomeEnvName, &home_dir); |
| 277 base::FilePath::StringType native_home_dir(home_dir.begin(), | 295 base::FilePath::StringType native_home_dir(home_dir.begin(), |
| 278 home_dir.end()); | 296 home_dir.end()); |
| 279 return base::FilePath(native_home_dir).Append(kWorkingDirName); | 297 return base::FilePath(native_home_dir).Append(kWorkingDirName); |
| 280 } | 298 } |
| 281 | 299 |
| 300 protected: |
| 282 test::PeerConnectionServerRunner peerconnection_server_; | 301 test::PeerConnectionServerRunner peerconnection_server_; |
| 302 VideoQualityTestConfig test_config_; |
| 283 | 303 |
| 284 private: | 304 private: |
| 285 base::FilePath GetSourceDir() { | 305 base::FilePath GetSourceDir() { |
| 286 base::FilePath source_dir; | 306 base::FilePath source_dir; |
| 287 PathService::Get(base::DIR_SOURCE_ROOT, &source_dir); | 307 PathService::Get(base::DIR_SOURCE_ROOT, &source_dir); |
| 288 return source_dir; | 308 return source_dir; |
| 289 } | 309 } |
| 290 | 310 |
| 291 base::FilePath GetBrowserDir() { | 311 base::FilePath GetBrowserDir() { |
| 292 base::FilePath browser_dir; | 312 base::FilePath browser_dir; |
| 293 EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &browser_dir)); | 313 EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &browser_dir)); |
| 294 return browser_dir; | 314 return browser_dir; |
| 295 } | 315 } |
| 296 | 316 |
| 297 base::ProcessHandle pywebsocket_server_; | 317 base::ProcessHandle pywebsocket_server_; |
| 298 scoped_ptr<base::Environment> environment_; | 318 scoped_ptr<base::Environment> environment_; |
| 299 base::FilePath webrtc_reference_video_y4m_; | 319 base::FilePath webrtc_reference_video_y4m_; |
| 300 }; | 320 }; |
| 301 | 321 |
| 302 IN_PROC_BROWSER_TEST_F(WebRtcVideoQualityBrowserTest, | 322 INSTANTIATE_TEST_CASE_P( |
| 303 MANUAL_TestVGAVideoQuality) { | 323 WebRtcVideoQualityBrowserTests, |
| 324 WebRtcVideoQualityBrowserTest, |
| 325 testing::ValuesIn(kVideoConfigurations)); |
| 326 |
| 327 IN_PROC_BROWSER_TEST_P(WebRtcVideoQualityBrowserTest, |
| 328 MANUAL_TestVideoQuality) { |
| 329 |
| 304 #if defined(OS_WIN) | 330 #if defined(OS_WIN) |
| 305 // Fails on XP. http://crbug.com/353078 | 331 // Fails on XP. http://crbug.com/353078 |
| 306 if (base::win::GetVersion() <= base::win::VERSION_XP) | 332 if (base::win::GetVersion() <= base::win::VERSION_XP) |
| 307 return; | 333 return; |
| 308 #endif | 334 #endif |
| 309 | 335 |
| 310 ASSERT_GE(TestTimeouts::action_max_timeout().InSeconds(), 150) << | 336 ASSERT_GE(TestTimeouts::action_max_timeout().InSeconds(), 150) << |
| 311 "This is a long-running test; you must specify " | 337 "This is a long-running test; you must specify " |
| 312 "--ui-test-action-max-timeout to have a value of at least 150000."; | 338 "--ui-test-action-max-timeout to have a value of at least 150000."; |
| 313 | |
| 314 ASSERT_TRUE(HasAllRequiredResources()); | 339 ASSERT_TRUE(HasAllRequiredResources()); |
| 315 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); | 340 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady()); |
| 316 ASSERT_TRUE(StartPyWebSocketServer()); | 341 ASSERT_TRUE(StartPyWebSocketServer()); |
| 317 ASSERT_TRUE(peerconnection_server_.Start()); | 342 ASSERT_TRUE(peerconnection_server_.Start()); |
| 318 | 343 |
| 319 content::WebContents* left_tab = | 344 content::WebContents* left_tab = |
| 320 OpenPageAndGetUserMediaInNewTabWithConstraints( | 345 OpenPageAndGetUserMediaInNewTabWithConstraints( |
| 321 embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage), | 346 embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage), |
| 322 kAudioVideoCallConstraints360p); | 347 test_config_.constraints); |
| 323 content::WebContents* right_tab = | 348 content::WebContents* right_tab = |
| 324 OpenPageAndGetUserMediaInNewTabWithConstraints( | 349 OpenPageAndGetUserMediaInNewTabWithConstraints( |
| 325 embedded_test_server()->GetURL(kCapturingWebrtcHtmlPage), | 350 embedded_test_server()->GetURL(test_config_.capture_page), |
| 326 kAudioVideoCallConstraints360p); | 351 test_config_.constraints); |
| 327 | 352 |
| 328 EstablishCall(left_tab, right_tab); | 353 EstablishCall(left_tab, right_tab); |
| 329 | 354 |
| 330 // Poll slower here to avoid flooding the log with messages: capturing and | 355 // Poll slower here to avoid flooding the log with messages: capturing and |
| 331 // sending frames take quite a bit of time. | 356 // sending frames take quite a bit of time. |
| 332 int polling_interval_msec = 1000; | 357 int polling_interval_msec = 1000; |
| 333 | 358 |
| 334 EXPECT_TRUE(test::PollingWaitUntil( | 359 EXPECT_TRUE(test::PollingWaitUntil( |
| 335 "doneFrameCapturing()", "done-capturing", right_tab, | 360 "doneFrameCapturing()", "done-capturing", right_tab, |
| 336 polling_interval_msec)); | 361 polling_interval_msec)); |
| 337 | 362 |
| 338 HangUp(left_tab); | 363 HangUp(left_tab); |
| 339 WaitUntilHangupVerified(left_tab); | 364 WaitUntilHangupVerified(left_tab); |
| 340 WaitUntilHangupVerified(right_tab); | 365 WaitUntilHangupVerified(right_tab); |
| 341 | 366 |
| 342 EXPECT_TRUE(test::PollingWaitUntil( | 367 EXPECT_TRUE(test::PollingWaitUntil( |
| 343 "haveMoreFramesToSend()", "no-more-frames", right_tab, | 368 "haveMoreFramesToSend()", "no-more-frames", right_tab, |
| 344 polling_interval_msec)); | 369 polling_interval_msec)); |
| 345 | 370 |
| 346 // Shut everything down to avoid having the javascript race with the analysis | 371 // Shut everything down to avoid having the javascript race with the analysis |
| 347 // tools. For instance, dont have console log printouts interleave with the | 372 // tools. For instance, dont have console log printouts interleave with the |
| 348 // RESULT lines from the analysis tools (crbug.com/323200). | 373 // RESULT lines from the analysis tools (crbug.com/323200). |
| 349 ASSERT_TRUE(peerconnection_server_.Stop()); | 374 ASSERT_TRUE(peerconnection_server_.Stop()); |
| 350 ASSERT_TRUE(ShutdownPyWebSocketServer()); | 375 ASSERT_TRUE(ShutdownPyWebSocketServer()); |
| 351 | 376 |
| 352 chrome::CloseWebContents(browser(), left_tab, false); | 377 chrome::CloseWebContents(browser(), left_tab, false); |
| 353 chrome::CloseWebContents(browser(), right_tab, false); | 378 chrome::CloseWebContents(browser(), right_tab, false); |
| 354 | 379 |
| 355 RunARGBtoI420Converter( | 380 RunARGBtoI420Converter( |
| 356 k360pWidth, k360pHeight, GetWorkingDir().Append(kCapturedYuvFileName)); | 381 test_config_.width, test_config_.height, |
| 382 GetWorkingDir().Append(kCapturedYuvFileName)); |
| 357 ASSERT_TRUE(CompareVideosAndPrintResult( | 383 ASSERT_TRUE(CompareVideosAndPrintResult( |
| 358 k360pWidth, | 384 test_config_.test_name, |
| 359 k360pHeight, | 385 test_config_.width, |
| 386 test_config_.height, |
| 360 GetWorkingDir().Append(kCapturedYuvFileName), | 387 GetWorkingDir().Append(kCapturedYuvFileName), |
| 361 test::GetReferenceFilesDir() | 388 test::GetReferenceFilesDir() |
| 362 .Append(test::kReferenceFileName360p) | 389 .Append(test_config_.reference_video) |
| 363 .AddExtension(test::kYuvFileExtension), | 390 .AddExtension(test::kYuvFileExtension), |
| 364 GetWorkingDir().Append(kStatsFileName))); | 391 GetWorkingDir().Append(kStatsFileName))); |
| 365 } | 392 } |
| OLD | NEW |