blob: 6991a0a57b6cb485cfe7402ce32c2b80383e9eb6 [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
oprypinbed7a6b2017-06-19 01:16:45 -070022import json
mandermoed582f72017-01-23 07:55:42 -080023import logging
24import os
Edward Lemur9c184892018-01-22 16:11:58 +000025import shutil
mandermoed582f72017-01-23 07:55:42 -080026import subprocess
27import sys
28import tempfile
oprypin30cda5e2017-04-24 04:15:13 -070029import time
mandermoed582f72017-01-23 07:55:42 -080030
31
32SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
Henrik Kjellandercb3b1c12017-09-18 06:20:33 +020033SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir))
oprypinbed7a6b2017-06-19 01:16:45 -070034BAD_DEVICES_JSON = os.path.join(SRC_DIR,
35 os.environ.get('CHROMIUM_OUT_DIR', 'out'),
36 'bad_devices.json')
Edward Lemur9c184892018-01-22 16:11:58 +000037sys.path.append(os.path.join(SRC_DIR, 'build'))
38import find_depot_tools
oprypin30cda5e2017-04-24 04:15:13 -070039
40
41class Error(Exception):
42 pass
43
44
45class VideoQualityTestError(Error):
46 pass
mandermoed582f72017-01-23 07:55:42 -080047
48
ehmaldonadod103f4b2017-02-16 07:20:26 -080049def _RunCommand(argv, cwd=SRC_DIR, **kwargs):
mandermoed582f72017-01-23 07:55:42 -080050 logging.info('Running %r', argv)
ehmaldonadod103f4b2017-02-16 07:20:26 -080051 subprocess.check_call(argv, cwd=cwd, **kwargs)
mandermoed582f72017-01-23 07:55:42 -080052
53
oprypin30cda5e2017-04-24 04:15:13 -070054def _RunCommandWithOutput(argv, cwd=SRC_DIR, **kwargs):
55 logging.info('Running %r', argv)
56 return subprocess.check_output(argv, cwd=cwd, **kwargs)
57
58
59def _RunBackgroundCommand(argv, cwd=SRC_DIR):
60 logging.info('Running %r', argv)
61 process = subprocess.Popen(argv, cwd=cwd)
oprypin30cda5e2017-04-24 04:15:13 -070062 time.sleep(0.5)
63 status = process.poll()
64 if status: # is not None or 0
65 raise subprocess.CalledProcessError(status, argv)
66 return process
67
68
mandermoed582f72017-01-23 07:55:42 -080069def _ParseArgs():
70 parser = argparse.ArgumentParser(description='Start loopback video analysis.')
mandermoed582f72017-01-23 07:55:42 -080071 parser.add_argument('build_dir_android',
72 help='The path to the build directory for Android.')
73 parser.add_argument('--build_dir_x86',
74 help='The path to the build directory for building locally.')
75 parser.add_argument('--temp_dir',
76 help='A temporary directory to put the output.')
oprypin30cda5e2017-04-24 04:15:13 -070077 parser.add_argument('--adb-path', help='Path to adb binary.', default='adb')
mandermoed582f72017-01-23 07:55:42 -080078
79 args = parser.parse_args()
80 return args
81
82
Edward Lemur9c184892018-01-22 16:11:58 +000083def main():
84 logging.basicConfig(level=logging.INFO)
85
86 args = _ParseArgs()
87
88 build_dir_android = args.build_dir_android
89 build_dir_x86 = args.build_dir_x86
90 temp_dir = args.temp_dir
91 adb_path = args.adb_path
92 if not temp_dir:
93 temp_dir = tempfile.mkdtemp()
94 else:
95 if not os.path.exists(temp_dir):
96 os.makedirs(temp_dir)
97
98 if not build_dir_x86:
99 build_dir_x86 = os.path.join(temp_dir, 'LocalBuild')
100
101 def DepotToolPath(*args):
102 return os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, *args)
103
104 _RunCommand([sys.executable, DepotToolPath('gn.py'), 'gen', build_dir_x86])
105 _RunCommand([DepotToolPath('ninja'), '-C', build_dir_x86,
106 'frame_analyzer'])
107
108 tools_dir = os.path.join(SRC_DIR, 'tools_webrtc')
109 toolchain_dir = os.path.join(tools_dir, 'video_quality_toolchain')
110
111 # Download ffmpeg and zxing.
112 download_tools_script = os.path.join(tools_dir, 'download_tools.py')
113 _RunCommand([sys.executable, download_tools_script, toolchain_dir])
114
115 testing_tools_dir = os.path.join(SRC_DIR, 'rtc_tools', 'testing')
116
117 # Download, extract and build AppRTC.
118 setup_apprtc_script = os.path.join(testing_tools_dir, 'setup_apprtc.py')
119 _RunCommand([sys.executable, setup_apprtc_script, temp_dir])
120
121 # Select an Android device in case multiple are connected
oprypinbed7a6b2017-06-19 01:16:45 -0700122 try:
123 with open(BAD_DEVICES_JSON) as bad_devices_file:
124 bad_devices = json.load(bad_devices_file)
125 except IOError:
126 if os.environ.get('CHROME_HEADLESS'):
127 logging.warning('Cannot read %r', BAD_DEVICES_JSON)
128 bad_devices = {}
129
oprypin30cda5e2017-04-24 04:15:13 -0700130 for line in _RunCommandWithOutput([adb_path, 'devices']).splitlines():
131 if line.endswith('\tdevice'):
132 android_device = line.split('\t')[0]
oprypinbed7a6b2017-06-19 01:16:45 -0700133 if android_device not in bad_devices:
Edward Lemur9c184892018-01-22 16:11:58 +0000134 break
135 else:
136 raise VideoQualityTestError('Cannot find any connected Android device.')
oprypin30cda5e2017-04-24 04:15:13 -0700137
oprypin1d7392a2017-05-16 05:36:15 -0700138 processes = []
139 try:
Edward Lemur9c184892018-01-22 16:11:58 +0000140 # Start AppRTC Server
141 dev_appserver = os.path.join(temp_dir, 'apprtc', 'temp', 'google-cloud-sdk',
142 'bin', 'dev_appserver.py')
143 appengine_dir = os.path.join(temp_dir, 'apprtc', 'out', 'app_engine')
144 processes.append(_RunBackgroundCommand([
145 'python', dev_appserver, appengine_dir,
146 '--port=9999', '--admin_port=9998',
147 '--skip_sdk_update_check', '--clear_datastore=yes']))
148
149 # Start Collider
150 collider_path = os.path.join(temp_dir, 'collider', 'collidermain')
151 processes.append(_RunBackgroundCommand([
152 collider_path, '-tls=false', '-port=8089',
153 '-room-server=http://localhost:9999']))
154
155 # Start adb reverse forwarder
156 reverseforwarder_path = os.path.join(
157 SRC_DIR, 'build', 'android', 'adb_reverse_forwarder.py')
158 processes.append(_RunBackgroundCommand([
159 reverseforwarder_path, '--device', android_device,
160 '9999', '9999', '8089', '8089']))
161
162 # Run the Espresso code.
163 test_script = os.path.join(build_dir_android,
164 'bin', 'run_AppRTCMobileTestStubbedVideoIO')
165 _RunCommand([test_script, '--device', android_device])
166
167 # Pull the output video.
168 test_video = os.path.join(temp_dir, 'test_video.y4m')
169 _RunCommand([adb_path, '-s', android_device,
170 'pull', '/sdcard/output.y4m', test_video])
171
172 test_video_yuv = os.path.join(temp_dir, 'test_video.yuv')
173
174 ffmpeg_path = os.path.join(toolchain_dir, 'linux', 'ffmpeg')
175
176 def ConvertVideo(input_video, output_video):
177 _RunCommand([ffmpeg_path, '-y', '-i', input_video, output_video])
178
179 ConvertVideo(test_video, test_video_yuv)
180
181 reference_video = os.path.join(SRC_DIR,
182 'resources', 'reference_video_640x360_30fps.y4m')
183
184 reference_video_yuv = os.path.join(temp_dir,
185 'reference_video_640x360_30fps.yuv')
186
187 ConvertVideo(reference_video, reference_video_yuv)
188
189 # Run compare script.
190 compare_script = os.path.join(SRC_DIR, 'rtc_tools', 'compare_videos.py')
191 zxing_path = os.path.join(toolchain_dir, 'linux', 'zxing')
192
193 # The frame_analyzer binary should be built for local computer and not for
194 # Android
195 frame_analyzer = os.path.join(build_dir_x86, 'frame_analyzer')
196
197 frame_width = 640
198 frame_height = 360
199
200 stats_file_ref = os.path.join(temp_dir, 'stats_ref.txt')
201 stats_file_test = os.path.join(temp_dir, 'stats_test.txt')
202
203 _RunCommand([
204 sys.executable, compare_script, '--ref_video', reference_video_yuv,
205 '--test_video', test_video_yuv, '--yuv_frame_width', str(frame_width),
206 '--yuv_frame_height', str(frame_height),
207 '--stats_file_ref', stats_file_ref,
208 '--stats_file_test', stats_file_test,
209 '--frame_analyzer', frame_analyzer,
210 '--ffmpeg_path', ffmpeg_path, '--zxing_path', zxing_path])
211
oprypin1d7392a2017-05-16 05:36:15 -0700212 finally:
213 for process in processes:
214 if process:
215 process.terminate()
216 process.wait()
217
Edward Lemur9c184892018-01-22 16:11:58 +0000218 shutil.rmtree(temp_dir)
mandermoed582f72017-01-23 07:55:42 -0800219
220
221if __name__ == '__main__':
222 sys.exit(main())
223