blob: e8c4381f1f94fff230e8acc26c1ab92b59cbe363 [file] [log] [blame]
mandermoed582f72017-01-23 07:55:42 -08001#!/usr/bin/env python
2# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
3#
4# Use of this source code is governed by a BSD-style license
5# that can be found in the LICENSE file in the root of the source
6# tree. An additional intellectual property rights grant can be found
7# in the file PATENTS. All contributing project authors may
8# be found in the AUTHORS file in the root of the source tree.
9
10"""
11This script is the wrapper that starts a loopback call with stubbed video in
12and out. It then analyses the video quality of the output video against the
13reference input video.
14
15It expect to be given the webrtc output build directory as the first argument
16all other arguments are optional.
17
18It assumes you have a Android device plugged in.
19"""
20
21import argparse
22import logging
23import os
24import shutil
25import subprocess
26import sys
27import tempfile
oprypin30cda5e2017-04-24 04:15:13 -070028import time
mandermoed582f72017-01-23 07:55:42 -080029
30
31SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
kjellander30292102017-02-09 01:05:54 -080032SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir,
33 os.pardir))
oprypin30cda5e2017-04-24 04:15:13 -070034
35
36class Error(Exception):
37 pass
38
39
40class VideoQualityTestError(Error):
41 pass
mandermoed582f72017-01-23 07:55:42 -080042
43
ehmaldonadod103f4b2017-02-16 07:20:26 -080044def _RunCommand(argv, cwd=SRC_DIR, **kwargs):
mandermoed582f72017-01-23 07:55:42 -080045 logging.info('Running %r', argv)
ehmaldonadod103f4b2017-02-16 07:20:26 -080046 subprocess.check_call(argv, cwd=cwd, **kwargs)
mandermoed582f72017-01-23 07:55:42 -080047
48
oprypin30cda5e2017-04-24 04:15:13 -070049def _RunCommandWithOutput(argv, cwd=SRC_DIR, **kwargs):
50 logging.info('Running %r', argv)
51 return subprocess.check_output(argv, cwd=cwd, **kwargs)
52
53
54def _RunBackgroundCommand(argv, cwd=SRC_DIR):
55 logging.info('Running %r', argv)
56 process = subprocess.Popen(argv, cwd=cwd)
oprypin30cda5e2017-04-24 04:15:13 -070057 time.sleep(0.5)
58 status = process.poll()
59 if status: # is not None or 0
60 raise subprocess.CalledProcessError(status, argv)
61 return process
62
63
mandermoed582f72017-01-23 07:55:42 -080064def _ParseArgs():
65 parser = argparse.ArgumentParser(description='Start loopback video analysis.')
mandermoed582f72017-01-23 07:55:42 -080066 parser.add_argument('build_dir_android',
67 help='The path to the build directory for Android.')
68 parser.add_argument('--build_dir_x86',
69 help='The path to the build directory for building locally.')
70 parser.add_argument('--temp_dir',
71 help='A temporary directory to put the output.')
oprypin30cda5e2017-04-24 04:15:13 -070072 parser.add_argument('--adb-path', help='Path to adb binary.', default='adb')
mandermoed582f72017-01-23 07:55:42 -080073
74 args = parser.parse_args()
75 return args
76
77
78def main():
79 logging.basicConfig(level=logging.INFO)
80
81 args = _ParseArgs()
82
mandermoed582f72017-01-23 07:55:42 -080083 build_dir_android = args.build_dir_android
84 build_dir_x86 = args.build_dir_x86
85 temp_dir = args.temp_dir
oprypin30cda5e2017-04-24 04:15:13 -070086 adb_path = args.adb_path
mandermoed582f72017-01-23 07:55:42 -080087 if not temp_dir:
88 temp_dir = tempfile.mkdtemp()
89 else:
90 if not os.path.exists(temp_dir):
91 os.makedirs(temp_dir)
92
93 if not build_dir_x86:
94 build_dir_x86 = os.path.join(temp_dir, 'LocalBuild')
95 _RunCommand(['gn', 'gen', build_dir_x86])
96 _RunCommand(['ninja', '-C', build_dir_x86, 'frame_analyzer'])
97
Henrik Kjellander90fd7d82017-05-09 08:30:10 +020098 tools_dir = os.path.join(SRC_DIR, 'tools_webrtc')
oprypin3b2fb202017-03-06 02:23:34 -080099 toolchain_dir = os.path.join(tools_dir, 'video_quality_toolchain')
mandermoed582f72017-01-23 07:55:42 -0800100
101 # Download ffmpeg and zxing.
oprypin1d7392a2017-05-16 05:36:15 -0700102 download_tools_script = os.path.join(tools_dir, 'download_tools.py')
103 _RunCommand([sys.executable, download_tools_script, toolchain_dir])
104
105 testing_tools_dir = os.path.join(SRC_DIR, 'webrtc', 'tools', 'testing')
106
107 # Download, extract and build AppRTC.
108 setup_apprtc_script = os.path.join(testing_tools_dir, 'setup_apprtc.py')
109 _RunCommand([sys.executable, setup_apprtc_script, temp_dir])
mandermoed582f72017-01-23 07:55:42 -0800110
oprypin30cda5e2017-04-24 04:15:13 -0700111 # Select an Android device in case multiple are connected
112 for line in _RunCommandWithOutput([adb_path, 'devices']).splitlines():
113 if line.endswith('\tdevice'):
114 android_device = line.split('\t')[0]
115 break
116 else:
117 raise VideoQualityTestError('Cannot find any connected Android device.')
118
oprypin1d7392a2017-05-16 05:36:15 -0700119 processes = []
120 try:
121 # Start AppRTC Server
122 dev_appserver = os.path.join(temp_dir, 'apprtc', 'temp', 'google-cloud-sdk',
123 'bin', 'dev_appserver.py')
124 appengine_dir = os.path.join(temp_dir, 'apprtc', 'out', 'app_engine')
125 processes.append(_RunBackgroundCommand([
126 'python', dev_appserver, appengine_dir,
127 '--port=9999', '--admin_port=9998',
128 '--skip_sdk_update_check', '--clear_datastore=yes']))
oprypin30cda5e2017-04-24 04:15:13 -0700129
oprypin1d7392a2017-05-16 05:36:15 -0700130 # Start Collider
131 collider_path = os.path.join(temp_dir, 'collider', 'collidermain')
132 processes.append(_RunBackgroundCommand([
133 collider_path, '-tls=false', '-port=8089',
134 '-room-server=http://localhost:9999']))
oprypin30cda5e2017-04-24 04:15:13 -0700135
oprypin1d7392a2017-05-16 05:36:15 -0700136 # Start adb reverse forwarder
137 reverseforwarder_path = os.path.join(
138 SRC_DIR, 'build', 'android', 'adb_reverse_forwarder.py')
139 processes.append(_RunBackgroundCommand([
140 reverseforwarder_path, '--device', android_device,
141 '9999', '9999', '8089', '8089']))
oprypin30cda5e2017-04-24 04:15:13 -0700142
oprypin1d7392a2017-05-16 05:36:15 -0700143 # Run the Espresso code.
144 test_script = os.path.join(build_dir_android,
145 'bin', 'run_AppRTCMobileTestStubbedVideoIO')
146 _RunCommand([test_script, '--device', android_device])
mandermoed582f72017-01-23 07:55:42 -0800147
oprypin1d7392a2017-05-16 05:36:15 -0700148 # Pull the output video.
149 test_video = os.path.join(temp_dir, 'test_video.y4m')
150 _RunCommand([adb_path, '-s', android_device,
151 'pull', '/sdcard/output.y4m', test_video])
mandermoed582f72017-01-23 07:55:42 -0800152
oprypin1d7392a2017-05-16 05:36:15 -0700153 test_video_yuv = os.path.join(temp_dir, 'test_video.yuv')
mandermoed582f72017-01-23 07:55:42 -0800154
oprypin1d7392a2017-05-16 05:36:15 -0700155 ffmpeg_path = os.path.join(toolchain_dir, 'linux', 'ffmpeg')
mandermoed582f72017-01-23 07:55:42 -0800156
oprypin1d7392a2017-05-16 05:36:15 -0700157 def ConvertVideo(input_video, output_video):
158 _RunCommand([ffmpeg_path, '-y', '-i', input_video, output_video])
mandermoed582f72017-01-23 07:55:42 -0800159
oprypin1d7392a2017-05-16 05:36:15 -0700160 ConvertVideo(test_video, test_video_yuv)
mandermoed582f72017-01-23 07:55:42 -0800161
oprypin1d7392a2017-05-16 05:36:15 -0700162 reference_video = os.path.join(SRC_DIR,
163 'resources', 'reference_video_640x360_30fps.y4m')
mandermoed582f72017-01-23 07:55:42 -0800164
oprypin1d7392a2017-05-16 05:36:15 -0700165 reference_video_yuv = os.path.join(temp_dir,
166 'reference_video_640x360_30fps.yuv')
mandermoed582f72017-01-23 07:55:42 -0800167
oprypin1d7392a2017-05-16 05:36:15 -0700168 ConvertVideo(reference_video, reference_video_yuv)
mandermoed582f72017-01-23 07:55:42 -0800169
oprypin1d7392a2017-05-16 05:36:15 -0700170 # Run compare script.
171 compare_script = os.path.join(SRC_DIR, 'webrtc', 'tools',
172 'compare_videos.py')
173 zxing_path = os.path.join(toolchain_dir, 'linux', 'zxing')
mandermoed582f72017-01-23 07:55:42 -0800174
oprypin1d7392a2017-05-16 05:36:15 -0700175 # The frame_analyzer binary should be built for local computer and not for
176 # Android
177 frame_analyzer = os.path.join(build_dir_x86, 'frame_analyzer')
mandermoed582f72017-01-23 07:55:42 -0800178
oprypin1d7392a2017-05-16 05:36:15 -0700179 frame_width = 640
180 frame_height = 360
mandermoed582f72017-01-23 07:55:42 -0800181
oprypin1d7392a2017-05-16 05:36:15 -0700182 stats_file_ref = os.path.join(temp_dir, 'stats_ref.txt')
183 stats_file_test = os.path.join(temp_dir, 'stats_test.txt')
mandermoed582f72017-01-23 07:55:42 -0800184
oprypin1d7392a2017-05-16 05:36:15 -0700185 _RunCommand([
186 sys.executable, compare_script, '--ref_video', reference_video_yuv,
187 '--test_video', test_video_yuv, '--yuv_frame_width', str(frame_width),
188 '--yuv_frame_height', str(frame_height),
189 '--stats_file_ref', stats_file_ref,
190 '--stats_file_test', stats_file_test,
191 '--frame_analyzer', frame_analyzer,
192 '--ffmpeg_path', ffmpeg_path, '--zxing_path', zxing_path])
mandermoed582f72017-01-23 07:55:42 -0800193
oprypin1d7392a2017-05-16 05:36:15 -0700194 finally:
195 for process in processes:
196 if process:
197 process.terminate()
198 process.wait()
199
200 shutil.rmtree(temp_dir)
mandermoed582f72017-01-23 07:55:42 -0800201
202
203if __name__ == '__main__':
204 sys.exit(main())
205