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

Side by Side Diff: chrome/browser/media/webrtc_video_quality_browsertest.cc

Issue 2307083002: Cleanup: move WebRTC related files from chrome/browser/media to chrome/browser/media/webrtc/ (Closed)
Patch Set: Removed file wrongly resuscitated during rebase Created 4 years, 3 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 2013 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 <stddef.h>
6
7 #include "base/base64.h"
8 #include "base/command_line.h"
9 #include "base/environment.h"
10 #include "base/files/file.h"
11 #include "base/files/file_util.h"
12 #include "base/files/scoped_temp_dir.h"
13 #include "base/path_service.h"
14 #include "base/process/launch.h"
15 #include "base/strings/string_number_conversions.h"
16 #include "base/strings/string_split.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/test/test_timeouts.h"
19 #include "base/time/time.h"
20 #include "build/build_config.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/infobars/infobar_service.h"
23 #include "chrome/browser/media/webrtc_browsertest_base.h"
24 #include "chrome/browser/media/webrtc_browsertest_common.h"
25 #include "chrome/browser/profiles/profile.h"
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/browser_tabstrip.h"
28 #include "chrome/browser/ui/tabs/tab_strip_model.h"
29 #include "chrome/common/chrome_switches.h"
30 #include "chrome/test/base/in_process_browser_test.h"
31 #include "components/infobars/core/infobar.h"
32 #include "content/public/browser/notification_service.h"
33 #include "content/public/common/feature_h264_with_openh264_ffmpeg.h"
34 #include "content/public/common/features.h"
35 #include "content/public/test/browser_test_utils.h"
36 #include "media/base/media_switches.h"
37 #include "net/test/embedded_test_server/embedded_test_server.h"
38 #include "net/test/python_utils.h"
39 #include "testing/perf/perf_test.h"
40 #include "ui/gl/gl_switches.h"
41
42 namespace {
43 std::string MakeLabel(const char* test_name, const std::string& video_codec) {
44 std::string codec_label = video_codec.empty() ? "" : "_" + video_codec;
45 return base::StringPrintf("%s%s", test_name, codec_label.c_str());
46 }
47 } // namespace
48
49 static const base::FilePath::CharType kFrameAnalyzerExecutable[] =
50 #if defined(OS_WIN)
51 FILE_PATH_LITERAL("frame_analyzer.exe");
52 #else
53 FILE_PATH_LITERAL("frame_analyzer");
54 #endif
55
56 static const base::FilePath::CharType kCapturedYuvFileName[] =
57 FILE_PATH_LITERAL("captured_video.yuv");
58 static const base::FilePath::CharType kCapturedWebmFileName[] =
59 FILE_PATH_LITERAL("captured_video.webm");
60 static const base::FilePath::CharType kStatsFileName[] =
61 FILE_PATH_LITERAL("stats.txt");
62 static const char kMainWebrtcTestHtmlPage[] =
63 "/webrtc/webrtc_jsep01_test.html";
64 static const char kCapturingWebrtcHtmlPage[] =
65 "/webrtc/webrtc_video_quality_test.html";
66
67 static const struct VideoQualityTestConfig {
68 const char* test_name;
69 int width;
70 int height;
71 const base::FilePath::CharType* reference_video;
72 const char* constraints;
73 } kVideoConfigurations[] = {
74 { "360p", 640, 360,
75 test::kReferenceFileName360p,
76 WebRtcTestBase::kAudioVideoCallConstraints360p },
77 { "720p", 1280, 720,
78 test::kReferenceFileName720p,
79 WebRtcTestBase::kAudioVideoCallConstraints720p },
80 };
81
82 // Test the video quality of the WebRTC output.
83 //
84 // Prerequisites: This test case must run on a machine with a chrome playing
85 // the video from the reference files located in GetReferenceFilesDir().
86 // The file kReferenceY4mFileName.kY4mFileExtension is played using a
87 // FileVideoCaptureDevice and its sibling with kYuvFileExtension is used for
88 // comparison.
89 //
90 // You must also compile the chromium_builder_webrtc target before you run this
91 // test to get all the tools built.
92 //
93 // The external compare_videos.py script also depends on two external
94 // executables which must be located in the PATH when running this test.
95 // * zxing (see the CPP version at https://code.google.com/p/zxing)
96 // * ffmpeg 0.11.1 or compatible version (see http://www.ffmpeg.org)
97 //
98 // The test runs several custom binaries - rgba_to_i420 converter and
99 // 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
101 // (pywebsocket) and a barcode_decoder script.
102 class WebRtcVideoQualityBrowserTest : public WebRtcTestBase,
103 public testing::WithParamInterface<VideoQualityTestConfig> {
104 public:
105 WebRtcVideoQualityBrowserTest()
106 : environment_(base::Environment::Create()) {
107 test_config_ = GetParam();
108 }
109
110 void SetUpInProcessBrowserTestFixture() override {
111 DetectErrorsInJavaScript(); // Look for errors in our rather complex js.
112
113 ASSERT_TRUE(temp_working_dir_.CreateUniqueTempDir());
114 }
115
116 void SetUpCommandLine(base::CommandLine* command_line) override {
117 // Set up the command line option with the expected file name. We will check
118 // its existence in HasAllRequiredResources().
119 webrtc_reference_video_y4m_ = test::GetReferenceFilesDir()
120 .Append(test_config_.reference_video)
121 .AddExtension(test::kY4mFileExtension);
122 command_line->AppendSwitchPath(switches::kUseFileForFakeVideoCapture,
123 webrtc_reference_video_y4m_);
124 command_line->AppendSwitch(switches::kUseFakeDeviceForMediaStream);
125
126 // The video playback will not work without a GPU, so force its use here.
127 command_line->AppendSwitch(switches::kUseGpuInTests);
128 }
129
130 // Writes the captured video to a webm file.
131 void WriteCapturedWebmVideo(content::WebContents* capturing_tab,
132 const base::FilePath& webm_video_filename) {
133 std::string base64_encoded_video =
134 ExecuteJavascript("getRecordedVideoAsBase64()", capturing_tab);
135 std::string recorded_video;
136 ASSERT_TRUE(base::Base64Decode(base64_encoded_video, &recorded_video));
137 base::File video_file(webm_video_filename,
138 base::File::FLAG_CREATE | base::File::FLAG_WRITE);
139 size_t written =
140 video_file.Write(0, recorded_video.c_str(), recorded_video.length());
141 ASSERT_EQ(recorded_video.length(), written);
142 }
143
144 // Runs ffmpeg on the captured webm video and writes it to a yuv video file.
145 bool RunWebmToI420Converter(const base::FilePath& webm_video_filename,
146 const base::FilePath& yuv_video_filename,
147 const int width,
148 const int height) {
149 base::FilePath path_to_ffmpeg = test::GetToolForPlatform("ffmpeg");
150 if (!base::PathExists(path_to_ffmpeg)) {
151 LOG(ERROR) << "Missing ffmpeg: should be in " << path_to_ffmpeg.value();
152 return false;
153 }
154
155 // Set up ffmpeg to output at a certain resolution (-s) and bitrate (-b:v).
156 // This is needed because WebRTC is free to start the call at a lower
157 // resolution before ramping up. Without these flags, ffmpeg would output a
158 // video in the inital lower resolution, causing the SSIM and PSNR results
159 // to become meaningless.
160 base::CommandLine ffmpeg_command(path_to_ffmpeg);
161 ffmpeg_command.AppendArg("-i");
162 ffmpeg_command.AppendArgPath(webm_video_filename);
163 ffmpeg_command.AppendArg("-s");
164 ffmpeg_command.AppendArg(base::StringPrintf("%dx%d", width, height));
165 ffmpeg_command.AppendArg("-b:v");
166 ffmpeg_command.AppendArg(base::StringPrintf("%d", 120 * width * height));
167 ffmpeg_command.AppendArgPath(yuv_video_filename);
168
169 // We produce an output file that will later be used as an input to the
170 // barcode decoder and frame analyzer tools.
171 DVLOG(0) << "Running " << ffmpeg_command.GetCommandLineString();
172 std::string result;
173 bool ok = base::GetAppOutputAndError(ffmpeg_command, &result);
174 DVLOG(0) << "Output was:\n\n" << result;
175 return ok;
176 }
177
178 // Compares the |captured_video_filename| with the |reference_video_filename|.
179 //
180 // The barcode decoder decodes the captured video containing barcodes overlaid
181 // into every frame of the video. It produces a set of PNG images and a
182 // |stats_file| that maps each captured frame to a frame in the reference
183 // video. The frames should be of size |width| x |height|.
184 // All measurements calculated are printed as perf parsable numbers to stdout.
185 bool CompareVideosAndPrintResult(
186 const std::string& test_label,
187 int width,
188 int height,
189 const base::FilePath& captured_video_filename,
190 const base::FilePath& reference_video_filename,
191 const base::FilePath& stats_file) {
192
193 base::FilePath path_to_analyzer = base::MakeAbsoluteFilePath(
194 GetBrowserDir().Append(kFrameAnalyzerExecutable));
195 base::FilePath path_to_compare_script = GetSourceDir().Append(
196 FILE_PATH_LITERAL("third_party/webrtc/tools/compare_videos.py"));
197
198 if (!base::PathExists(path_to_analyzer)) {
199 LOG(ERROR) << "Missing frame analyzer: should be in "
200 << path_to_analyzer.value()
201 << ". Try building the chromium_builder_webrtc target.";
202 return false;
203 }
204 if (!base::PathExists(path_to_compare_script)) {
205 LOG(ERROR) << "Missing video compare script: should be in "
206 << path_to_compare_script.value();
207 return false;
208 }
209
210 base::FilePath path_to_zxing = test::GetToolForPlatform("zxing");
211 if (!base::PathExists(path_to_zxing)) {
212 LOG(ERROR) << "Missing zxing: should be in " << path_to_zxing.value();
213 return false;
214 }
215 base::FilePath path_to_ffmpeg = test::GetToolForPlatform("ffmpeg");
216 if (!base::PathExists(path_to_ffmpeg)) {
217 LOG(ERROR) << "Missing ffmpeg: should be in " << path_to_ffmpeg.value();
218 return false;
219 }
220
221 // Note: don't append switches to this command since it will mess up the
222 // -u in the python invocation!
223 base::CommandLine compare_command(base::CommandLine::NO_PROGRAM);
224 EXPECT_TRUE(GetPythonCommand(&compare_command));
225
226 compare_command.AppendArgPath(path_to_compare_script);
227 compare_command.AppendArg("--label=" + test_label);
228 compare_command.AppendArg("--ref_video");
229 compare_command.AppendArgPath(reference_video_filename);
230 compare_command.AppendArg("--test_video");
231 compare_command.AppendArgPath(captured_video_filename);
232 compare_command.AppendArg("--frame_analyzer");
233 compare_command.AppendArgPath(path_to_analyzer);
234 compare_command.AppendArg("--yuv_frame_width");
235 compare_command.AppendArg(base::IntToString(width));
236 compare_command.AppendArg("--yuv_frame_height");
237 compare_command.AppendArg(base::IntToString(height));
238 compare_command.AppendArg("--zxing_path");
239 compare_command.AppendArgPath(path_to_zxing);
240 compare_command.AppendArg("--ffmpeg_path");
241 compare_command.AppendArgPath(path_to_ffmpeg);
242 compare_command.AppendArg("--stats_file");
243 compare_command.AppendArgPath(stats_file);
244
245 DVLOG(0) << "Running " << compare_command.GetCommandLineString();
246 std::string output;
247 bool ok = base::GetAppOutput(compare_command, &output);
248
249 // Print to stdout to ensure the perf numbers are parsed properly by the
250 // buildbot step. The tool should print a handful RESULT lines.
251 printf("Output was:\n\n%s\n", output.c_str());
252 bool has_result_lines = output.find("RESULT") != std::string::npos;
253 if (!ok || !has_result_lines) {
254 LOG(ERROR) << "Failed to compare videos; see output above to see what "
255 << "the error was.";
256 return false;
257 }
258 return true;
259 }
260
261 void TestVideoQuality(const std::string& video_codec) {
262 ASSERT_GE(TestTimeouts::action_max_timeout().InSeconds(), 150)
263 << "This is a long-running test; you must specify "
264 "--ui-test-action-max-timeout to have a value of at least 150000.";
265 ASSERT_TRUE(test::HasReferenceFilesInCheckout());
266 ASSERT_TRUE(embedded_test_server()->Start());
267
268 content::WebContents* left_tab =
269 OpenPageAndGetUserMediaInNewTabWithConstraints(
270 embedded_test_server()->GetURL(kMainWebrtcTestHtmlPage),
271 test_config_.constraints);
272 content::WebContents* right_tab =
273 OpenPageAndGetUserMediaInNewTabWithConstraints(
274 embedded_test_server()->GetURL(kCapturingWebrtcHtmlPage),
275 test_config_.constraints);
276
277 SetupPeerconnectionWithLocalStream(left_tab);
278 SetupPeerconnectionWithLocalStream(right_tab);
279
280 if (!video_codec.empty()) {
281 SetDefaultVideoCodec(left_tab, video_codec);
282 SetDefaultVideoCodec(right_tab, video_codec);
283 }
284 NegotiateCall(left_tab, right_tab);
285
286 // Poll slower here to avoid flooding the log with messages: capturing and
287 // sending frames take quite a bit of time.
288 int polling_interval_msec = 1000;
289
290 EXPECT_TRUE(test::PollingWaitUntil("doneFrameCapturing()", "done-capturing",
291 right_tab, polling_interval_msec));
292
293 HangUp(left_tab);
294
295 WriteCapturedWebmVideo(right_tab,
296 GetWorkingDir().Append(kCapturedWebmFileName));
297
298 // Shut everything down to avoid having the javascript race with the
299 // analysis tools. For instance, dont have console log printouts interleave
300 // with the RESULT lines from the analysis tools (crbug.com/323200).
301 chrome::CloseWebContents(browser(), left_tab, false);
302 chrome::CloseWebContents(browser(), right_tab, false);
303
304 RunWebmToI420Converter(GetWorkingDir().Append(kCapturedWebmFileName),
305 GetWorkingDir().Append(kCapturedYuvFileName),
306 test_config_.width, test_config_.height);
307
308 ASSERT_TRUE(CompareVideosAndPrintResult(
309 MakeLabel(test_config_.test_name, video_codec), test_config_.width,
310 test_config_.height, GetWorkingDir().Append(kCapturedYuvFileName),
311 test::GetReferenceFilesDir()
312 .Append(test_config_.reference_video)
313 .AddExtension(test::kYuvFileExtension),
314 GetWorkingDir().Append(kStatsFileName)));
315 }
316
317 protected:
318 VideoQualityTestConfig test_config_;
319
320 base::FilePath GetWorkingDir() { return temp_working_dir_.path(); }
321
322 private:
323 base::FilePath GetSourceDir() {
324 base::FilePath source_dir;
325 PathService::Get(base::DIR_SOURCE_ROOT, &source_dir);
326 return source_dir;
327 }
328
329 base::FilePath GetBrowserDir() {
330 base::FilePath browser_dir;
331 EXPECT_TRUE(PathService::Get(base::DIR_MODULE, &browser_dir));
332 return browser_dir;
333 }
334
335 std::unique_ptr<base::Environment> environment_;
336 base::FilePath webrtc_reference_video_y4m_;
337 base::ScopedTempDir temp_working_dir_;
338 };
339
340 INSTANTIATE_TEST_CASE_P(
341 WebRtcVideoQualityBrowserTests,
342 WebRtcVideoQualityBrowserTest,
343 testing::ValuesIn(kVideoConfigurations));
344
345 IN_PROC_BROWSER_TEST_P(WebRtcVideoQualityBrowserTest,
346 MANUAL_TestVideoQualityVp8) {
347 TestVideoQuality("VP8");
348 }
349
350 IN_PROC_BROWSER_TEST_P(WebRtcVideoQualityBrowserTest,
351 MANUAL_TestVideoQualityVp9) {
352 TestVideoQuality("VP9");
353 }
354
355 #if BUILDFLAG(RTC_USE_H264)
356
357 IN_PROC_BROWSER_TEST_P(WebRtcVideoQualityBrowserTest,
358 MANUAL_TestVideoQualityH264) {
359 // Only run test if run-time feature corresponding to |rtc_use_h264| is on.
360 if (!base::FeatureList::IsEnabled(content::kWebRtcH264WithOpenH264FFmpeg)) {
361 LOG(WARNING) << "Run-time feature WebRTC-H264WithOpenH264FFmpeg disabled. "
362 "Skipping WebRtcVideoQualityBrowserTest.MANUAL_TestVideoQualityH264 "
363 "(test \"OK\")";
364 return;
365 }
366 TestVideoQuality("H264");
367 }
368
369 #endif // BUILDFLAG(RTC_USE_H264)
OLDNEW
« no previous file with comments | « chrome/browser/media/webrtc_simulcast_browsertest.cc ('k') | chrome/browser/media/webrtc_webcam_browsertest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698