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

Side by Side Diff: chrome/test/functional/webrtc_video_quality.py

Issue 14208006: Use updated toolchain for video quality comparison (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Updated documentation Created 7 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « no previous file | 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 #!/usr/bin/env python 1 #!/usr/bin/env python
2 # Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 # Copyright (c) 2012 The Chromium Authors. All rights reserved.
3 # Use of this source code is governed by a BSD-style license that can be 3 # Use of this source code is governed by a BSD-style license that can be
4 # found in the LICENSE file. 4 # found in the LICENSE file.
5 5
6 import os 6 import os
7 import subprocess 7 import subprocess
8 import sys 8 import sys
9 9
10 import pyauto_functional 10 import pyauto_functional
(...skipping 12 matching lines...) Expand all
23 _REFERENCE_YUV_FILE = os.path.join(_WORKING_DIR, 'reference_video.yuv') 23 _REFERENCE_YUV_FILE = os.path.join(_WORKING_DIR, 'reference_video.yuv')
24 24
25 # The YUV file is the file produced by rgba_to_i420_converter. 25 # The YUV file is the file produced by rgba_to_i420_converter.
26 _OUTPUT_YUV_FILE = os.path.join(_WORKING_DIR, 'captured_video.yuv') 26 _OUTPUT_YUV_FILE = os.path.join(_WORKING_DIR, 'captured_video.yuv')
27 27
28 28
29 class MissingRequiredToolException(Exception): 29 class MissingRequiredToolException(Exception):
30 pass 30 pass
31 31
32 32
33 class FailedToRunToolException(Exception):
34 pass
35
36
33 class WebrtcVideoQualityTest(webrtc_test_base.WebrtcTestBase): 37 class WebrtcVideoQualityTest(webrtc_test_base.WebrtcTestBase):
34 """Test the video quality of the WebRTC output. 38 """Test the video quality of the WebRTC output.
35 39
36 Prerequisites: This test case must run on a machine with a virtual webcam that 40 Prerequisites: This test case must run on a machine with a virtual webcam that
37 plays video from the reference file located in the location defined by 41 plays video from the reference file located in the location defined by
38 _REFERENCE_YUV_FILE. You must also compile the peerconnection_server target 42 _REFERENCE_YUV_FILE. You must also compile the chromium_builder_webrtc target
39 before you run this test. 43 before you run this test to get all the tools built.
44 The external compare_videos.py script also depends on two external executables
45 which must be located in the PATH when running this test.
46 * zxing (see the CPP version at https://code.google.com/p/zxing)
47 * ffmpeg 0.11.1 or compatible version (see http://www.ffmpeg.org)
40 48
41 The test case will launch a custom binary (peerconnection_server) which will 49 The test case will launch a custom binary (peerconnection_server) which will
42 allow two WebRTC clients to find each other. 50 allow two WebRTC clients to find each other.
43 51
44 The test also runs several other custom binaries - rgba_to_i420 converter and 52 The test also runs several other custom binaries - rgba_to_i420 converter and
45 frame_analyzer. Both tools can be found under third_party/webrtc/tools. The 53 frame_analyzer. Both tools can be found under third_party/webrtc/tools. The
46 test also runs a stand alone Python implementation of a WebSocket server 54 test also runs a stand alone Python implementation of a WebSocket server
47 (pywebsocket) and a barcode_decoder script. 55 (pywebsocket) and a barcode_decoder script.
48 """ 56 """
49 57
(...skipping 133 matching lines...) Expand 10 before | Expand all | Expand 10 after
183 no_more_frames = self.WaitUntil( 191 no_more_frames = self.WaitUntil(
184 function=lambda: self.ExecuteJavascript('haveMoreFramesToSend()', 192 function=lambda: self.ExecuteJavascript('haveMoreFramesToSend()',
185 tab_index=1), 193 tab_index=1),
186 expect_retval='no-more-frames', retry_sleep=1, timeout=150) 194 expect_retval='no-more-frames', retry_sleep=1, timeout=150)
187 self.assertTrue(no_more_frames, 195 self.assertTrue(no_more_frames,
188 msg='Timed out while waiting for frames to send.') 196 msg='Timed out while waiting for frames to send.')
189 197
190 self.assertTrue(self._RunRGBAToI420Converter(width, height)) 198 self.assertTrue(self._RunRGBAToI420Converter(width, height))
191 199
192 stats_file = os.path.join(_WORKING_DIR, 'pyauto_stats.txt') 200 stats_file = os.path.join(_WORKING_DIR, 'pyauto_stats.txt')
193 self.assertTrue(self._RunBarcodeDecoder(width, height, _OUTPUT_YUV_FILE, 201 analysis_result = self._CompareVideos(width, height, _OUTPUT_YUV_FILE,
194 stats_file)) 202 reference_yuv, stats_file)
195
196 analysis_result = self._RunFrameAnalyzer(width, height, reference_yuv,
197 _OUTPUT_YUV_FILE, stats_file)
198 self._ProcessPsnrAndSsimOutput(analysis_result) 203 self._ProcessPsnrAndSsimOutput(analysis_result)
199 self._ProcessFramesCountOutput(analysis_result) 204 self._ProcessFramesCountOutput(analysis_result)
200 205
201 def _StartPywebsocketServer(self): 206 def _StartPywebsocketServer(self):
202 """Starts the pywebsocket server.""" 207 """Starts the pywebsocket server."""
203 print 'Starting pywebsocket server.' 208 print 'Starting pywebsocket server.'
204 209
205 # Pywebsocket source directory. 210 # Pywebsocket source directory.
206 path_pyws_dir = os.path.join(pyauto_paths.GetThirdPartyDir(), 'pywebsocket', 211 path_pyws_dir = os.path.join(pyauto_paths.GetThirdPartyDir(), 'pywebsocket',
207 'src') 212 'src')
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after
266 # barcode decoder and frame analyzer tools. 271 # barcode decoder and frame analyzer tools.
267 start_cmd = [path_to_rgba_converter, '--frames_dir=%s' % _WORKING_DIR, 272 start_cmd = [path_to_rgba_converter, '--frames_dir=%s' % _WORKING_DIR,
268 '--output_file=%s' % _OUTPUT_YUV_FILE, '--width=%d' % width, 273 '--output_file=%s' % _OUTPUT_YUV_FILE, '--width=%d' % width,
269 '--height=%d' % height, '--delete_frames'] 274 '--height=%d' % height, '--delete_frames']
270 print 'Start command: ', ' '.join(start_cmd) 275 print 'Start command: ', ' '.join(start_cmd)
271 rgba_converter = subprocess.Popen(start_cmd, stdout=sys.stdout, 276 rgba_converter = subprocess.Popen(start_cmd, stdout=sys.stdout,
272 stderr=sys.stderr) 277 stderr=sys.stderr)
273 rgba_converter.wait() 278 rgba_converter.wait()
274 return rgba_converter.returncode == 0 279 return rgba_converter.returncode == 0
275 280
276 def _RunBarcodeDecoder(self, width, height, captured_video_filename, 281 def _CompareVideos(self, width, height, captured_video_filename,
277 stats_filename): 282 reference_video_filename, stats_filename):
278 """Runs the barcode decoder script. 283 """Compares the captured video with the reference video.
279 284
280 The barcode decoder decodes the captured video containing barcodes overlaid 285 The barcode decoder decodes the captured video containing barcodes overlaid
281 into every frame of the video (produced by rgba_to_i420_converter). It 286 into every frame of the video (produced by rgba_to_i420_converter). It
282 produces a set of PNG images and a stats file that describes the relation 287 produces a set of PNG images and a stats file that describes the relation
283 between the filenames and the (decoded) frame number of each frame. 288 between the filenames and the (decoded) frame number of each frame.
284 289
285 The script depends on an external executable which is a part of the Zxing
286 barcode library, which must be located in the PATH when running this test.
287
288 Args: 290 Args:
289 width(int): The frames width of the video to be decoded. 291 width(int): The frames width of the video to be decoded.
290 height(int): The frames height of the video to be decoded. 292 height(int): The frames height of the video to be decoded.
291 captured_video_filename(string): The captured video file we want to 293 captured_video_filename(string): The captured video file we want to
292 extract frame images and decode frame numbers from. 294 extract frame images and decode frame numbers from.
295 reference_video_filename(string): The reference video file we want to
296 compare the captured video quality with.
293 stats_filename(string): Filename for the output file containing 297 stats_filename(string): Filename for the output file containing
294 data that shows the relation between each frame filename and the 298 data that shows the relation between each frame filename and the
295 reference file's frame numbers. 299 reference file's frame numbers.
296 300
297 Returns: 301 Returns:
298 (bool): True if the decoding was successful, False otherwise. 302 (string): The output of the script.
299 """
300 path_to_decoder = os.path.join(pyauto_paths.GetThirdPartyDir(), 'webrtc',
301 'tools', 'barcode_tools',
302 'barcode_decoder.py')
303 if not os.path.exists(path_to_decoder):
304 raise MissingRequiredToolException(
305 'Could not locate the barcode decoder script! The barcode decoder '
306 'decodes the barcodes overlaid on top of every frame of the captured '
307 'video.')
308 python_interp = sys.executable
309 start_cmd = [python_interp, path_to_decoder,
310 '--yuv_file=%s' % captured_video_filename,
311 '--yuv_frame_width=%d' % width,
312 '--yuv_frame_height=%d' % height,
313 '--stats_file=%s' % stats_filename]
314 print 'Start command: ', ' '.join(start_cmd)
315 303
316 barcode_decoder = subprocess.Popen(start_cmd, stdout=sys.stdout, 304 Raises:
317 stderr=sys.stderr) 305 FailedToRunToolException: If the script fails to run.
318 barcode_decoder.wait()
319 return barcode_decoder.returncode == 0
320
321 def _RunFrameAnalyzer(self, width, height, reference_video_file,
322 captured_video_file, stats_file):
323 """Runs the frame analyzer tool for PSNR and SSIM analysis.
324
325 The frame analyzer is also part of the webrtc_test_tools. It should be
326 built before running this test. We assume that the binary will end up next
327 to Chrome.
328
329 Frame analyzer prints its output to the standard output from where it has to
330 be read and processed.
331
332 Args:
333 width(int): The width of the video frames to be analyzed.
334 height(int): The height of the video frames to be analyzed.
335 reference_video_file(string): Filename of the video to be used as a
336 reference during the analysis.
337 captured_video_file(string): Filename for the video containing the
338 captured frames.
339 stats_file(string): Filename for the file that contains frame
340 synchronization data for the captured frames.
341
342 Returns:
343 (string): The output from the frame_analyzer.
344 """ 306 """
345 path_to_analyzer = os.path.join(self.BrowserPath(), 'frame_analyzer') 307 path_to_analyzer = os.path.join(self.BrowserPath(), 'frame_analyzer')
346 path_to_analyzer = os.path.abspath(path_to_analyzer) 308 path_to_analyzer = os.path.abspath(path_to_analyzer)
347
348 path_to_analyzer = self.BinPathForPlatform(path_to_analyzer) 309 path_to_analyzer = self.BinPathForPlatform(path_to_analyzer)
349 310
350 if not os.path.exists(path_to_analyzer): 311 path_to_compare_script = os.path.join(pyauto_paths.GetThirdPartyDir(),
351 raise webrtc_test_base.MissingRequiredBinaryException( 312 'webrtc', 'tools',
352 'Could not locate frame_analyzer! Did you build the ' 313 'compare_videos.py')
353 'webrtc_test_tools target?') 314 if not os.path.exists(path_to_compare_script):
315 raise MissingRequiredToolException('Cannot find the script at %s' %
316 path_to_compare_script)
317 python_interp = sys.executable
318 cmd = [
319 python_interp,
320 path_to_compare_script,
321 '--ref_video=%s' % reference_video_filename,
322 '--test_video=%s' % captured_video_filename,
323 '--frame_analyzer=%s' % path_to_analyzer,
324 '--yuv_frame_width=%d' % width,
325 '--yuv_frame_height=%d' % height,
326 '--stats_file=%s' % stats_filename,
327 ]
328 print 'Start command: ', ' '.join(cmd)
354 329
355 start_cmd = [path_to_analyzer, '--reference_file=%s' % reference_video_file, 330 compare_videos = subprocess.Popen(cmd, stdout=subprocess.PIPE,
356 '--test_file=%s' % captured_video_file, 331 stderr=subprocess.PIPE)
357 '--stats_file=%s' % stats_file, 332 output, error = compare_videos.communicate()
358 '--width=%d' % width, '--height=%d' % height] 333 if compare_videos.returncode != 0:
359 print 'Start command: ', ' '.join(start_cmd) 334 raise FailedToRunToolException('Failed to run compare videos script!')
360 335
361 frame_analyzer = subprocess.Popen(start_cmd, stdout=subprocess.PIPE,
362 stderr=subprocess.PIPE)
363 output, error = frame_analyzer.communicate()
364 if error:
365 print 'Error: ', error
366 return 'BSTATS undef undef; ESTATS'
367 return output 336 return output
368 337
369 def _ProcessFramesCountOutput(self, output): 338 def _ProcessFramesCountOutput(self, output):
370 """Processes the analyzer output for the different frame counts. 339 """Processes the analyzer output for the different frame counts.
371 340
372 The frame analyzer outputs additional information about the number of unique 341 The frame analyzer outputs additional information about the number of unique
373 frames captured, The max number of repeated frames in a sequence and the 342 frames captured, The max number of repeated frames in a sequence and the
374 max number of skipped frames. These values are then written to the Perf 343 max number of skipped frames. These values are then written to the Perf
375 Graph. (Note: Some of the repeated or skipped frames will probably be due to 344 Graph. (Note: Some of the repeated or skipped frames will probably be due to
376 the imperfection of JavaScript timers.) 345 the imperfection of JavaScript timers.)
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
423 entry = item.split(' ') 392 entry = item.split(' ')
424 psnr.append(float(entry[0])) 393 psnr.append(float(entry[0]))
425 ssim.append(float(entry[1])) 394 ssim.append(float(entry[1]))
426 395
427 pyauto_utils.PrintPerfResult('PSNR', 'VGA', psnr, '') 396 pyauto_utils.PrintPerfResult('PSNR', 'VGA', psnr, '')
428 pyauto_utils.PrintPerfResult('SSIM', 'VGA', ssim, '') 397 pyauto_utils.PrintPerfResult('SSIM', 'VGA', ssim, '')
429 398
430 399
431 if __name__ == '__main__': 400 if __name__ == '__main__':
432 pyauto_functional.Main() 401 pyauto_functional.Main()
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698