blob: 52ae3b1f6fde10070a1d27395bad06a9ecf3c49b [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
mandermoed582f72017-01-23 07:55:42 -080025import 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__))
Henrik Kjellandercb3b1c12017-09-18 06:20:33 +020032SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir))
Edward Lemur70ba9b42018-01-22 13:46:58 +010033RTC_TOOLS_DIR = os.path.join(SRC_DIR, 'rtc_tools', 'testing')
34TOOLCHAIN_DIR = os.path.join(SRC_DIR, 'tools_webrtc', 'video_quality_toolchain',
35 'linux')
oprypinbed7a6b2017-06-19 01:16:45 -070036BAD_DEVICES_JSON = os.path.join(SRC_DIR,
37 os.environ.get('CHROMIUM_OUT_DIR', 'out'),
38 'bad_devices.json')
Edward Lemur70ba9b42018-01-22 13:46:58 +010039
40sys.path.append(RTC_TOOLS_DIR)
41import utils
oprypin30cda5e2017-04-24 04:15:13 -070042
43
44class Error(Exception):
45 pass
46
47
48class VideoQualityTestError(Error):
49 pass
mandermoed582f72017-01-23 07:55:42 -080050
51
Edward Lemurd5e17d62018-01-31 17:28:28 +010052def _RunCommand(argv, **kwargs):
mandermoed582f72017-01-23 07:55:42 -080053 logging.info('Running %r', argv)
Edward Lemurd5e17d62018-01-31 17:28:28 +010054 subprocess.check_call(argv, **kwargs)
mandermoed582f72017-01-23 07:55:42 -080055
56
Edward Lemurd5e17d62018-01-31 17:28:28 +010057def _RunCommandWithOutput(argv, **kwargs):
oprypin30cda5e2017-04-24 04:15:13 -070058 logging.info('Running %r', argv)
Edward Lemurd5e17d62018-01-31 17:28:28 +010059 return subprocess.check_output(argv, **kwargs)
oprypin30cda5e2017-04-24 04:15:13 -070060
61
Edward Lemurd5e17d62018-01-31 17:28:28 +010062def _RunBackgroundCommand(argv):
oprypin30cda5e2017-04-24 04:15:13 -070063 logging.info('Running %r', argv)
Edward Lemurd5e17d62018-01-31 17:28:28 +010064 process = subprocess.Popen(argv)
oprypin30cda5e2017-04-24 04:15:13 -070065 time.sleep(0.5)
66 status = process.poll()
67 if status: # is not None or 0
68 raise subprocess.CalledProcessError(status, argv)
69 return process
70
71
Edward Lemur70ba9b42018-01-22 13:46:58 +010072def CreateEmptyDir(suggested_dir):
73 if not suggested_dir:
74 return tempfile.mkdtemp()
75 utils.RemoveDirectory(suggested_dir)
76 os.makedirs(suggested_dir)
77 return suggested_dir
78
79
mandermoed582f72017-01-23 07:55:42 -080080def _ParseArgs():
81 parser = argparse.ArgumentParser(description='Start loopback video analysis.')
mandermoed582f72017-01-23 07:55:42 -080082 parser.add_argument('build_dir_android',
83 help='The path to the build directory for Android.')
84 parser.add_argument('--build_dir_x86',
85 help='The path to the build directory for building locally.')
86 parser.add_argument('--temp_dir',
87 help='A temporary directory to put the output.')
oprypin30cda5e2017-04-24 04:15:13 -070088 parser.add_argument('--adb-path', help='Path to adb binary.', default='adb')
Edward Lesmes9599fd42018-03-12 16:43:05 -040089 parser.add_argument('--num-retries', default='0',
Edward Lesmes5b9c6842018-03-09 13:07:22 -050090 help='Number of times to retry the test on Android.')
Edward Lemur71d766e2018-02-05 21:59:36 +010091 parser.add_argument('--isolated-script-test-perf-output',
Edward Lemur2e5966b2018-01-30 15:33:02 +010092 help='Where to store perf results in chartjson format.', default=None)
mandermoed582f72017-01-23 07:55:42 -080093
Edward Lemur21a35bc2018-01-31 13:46:50 +010094 args, unknown_args = parser.parse_known_args()
95
96 # Ignore Chromium-specific flags
97 parser = argparse.ArgumentParser()
98 parser.add_argument('--isolated-script-test-output',
99 type=str, default=None)
Edward Lemur21a35bc2018-01-31 13:46:50 +0100100 parser.add_argument('--test-launcher-summary-output',
101 type=str, default=None)
102
103 parser.parse_args(unknown_args)
104
mandermoed582f72017-01-23 07:55:42 -0800105 return args
106
107
Edward Lemur70ba9b42018-01-22 13:46:58 +0100108def SelectAndroidDevice(adb_path):
109 # Select an Android device in case multiple are connected.
oprypinbed7a6b2017-06-19 01:16:45 -0700110 try:
111 with open(BAD_DEVICES_JSON) as bad_devices_file:
112 bad_devices = json.load(bad_devices_file)
113 except IOError:
114 if os.environ.get('CHROME_HEADLESS'):
115 logging.warning('Cannot read %r', BAD_DEVICES_JSON)
116 bad_devices = {}
117
oprypin30cda5e2017-04-24 04:15:13 -0700118 for line in _RunCommandWithOutput([adb_path, 'devices']).splitlines():
119 if line.endswith('\tdevice'):
120 android_device = line.split('\t')[0]
oprypinbed7a6b2017-06-19 01:16:45 -0700121 if android_device not in bad_devices:
Edward Lemur70ba9b42018-01-22 13:46:58 +0100122 return android_device
123 raise VideoQualityTestError('Cannot find any connected Android device.')
124
125
126def SetUpTools(android_device, temp_dir, processes):
127 # Extract AppRTC.
128 apprtc_archive = os.path.join(RTC_TOOLS_DIR, 'prebuilt_apprtc.zip')
129 golang_archive = os.path.join(RTC_TOOLS_DIR, 'golang', 'linux', 'go.tar.gz')
130
131 utils.UnpackArchiveTo(apprtc_archive, temp_dir)
132 utils.UnpackArchiveTo(golang_archive, temp_dir)
133
134 # Build AppRTC.
135 build_apprtc_script = os.path.join(RTC_TOOLS_DIR, 'build_apprtc.py')
Oleh Prypin1e908452018-04-04 14:31:58 +0200136 apprtc_dir = os.path.join(temp_dir, 'apprtc')
Edward Lemur70ba9b42018-01-22 13:46:58 +0100137 go_dir = os.path.join(temp_dir, 'go')
138 collider_dir = os.path.join(temp_dir, 'collider')
139
Oleh Prypin1e908452018-04-04 14:31:58 +0200140 _RunCommand([sys.executable, build_apprtc_script, apprtc_dir, go_dir,
141 collider_dir])
Edward Lemur70ba9b42018-01-22 13:46:58 +0100142
143 # Start AppRTC Server.
144 dev_appserver = os.path.join(temp_dir, 'apprtc', 'temp', 'google-cloud-sdk',
145 'bin', 'dev_appserver.py')
146 appengine_dir = os.path.join(temp_dir, 'apprtc', 'out', 'app_engine')
147 processes.append(_RunBackgroundCommand([
148 sys.executable, dev_appserver, appengine_dir, '--port=9999',
149 '--admin_port=9998', '--skip_sdk_update_check', '--clear_datastore=yes']))
150
151 # Start Collider.
152 collider_path = os.path.join(temp_dir, 'collider', 'collidermain')
153 processes.append(_RunBackgroundCommand([
154 collider_path, '-tls=false', '-port=8089',
155 '-room-server=http://localhost:9999']))
156
157 # Start adb reverse forwarder.
158 reverseforwarder_path = os.path.join(
159 SRC_DIR, 'build', 'android', 'adb_reverse_forwarder.py')
160 processes.append(_RunBackgroundCommand([
161 reverseforwarder_path, '--device', android_device, '9999', '9999', '8089',
162 '8089']))
163
164
Edward Lesmes5b9c6842018-03-09 13:07:22 -0500165def RunTest(android_device, adb_path, build_dir, temp_dir, num_retries,
Edward Lemur2e5966b2018-01-30 15:33:02 +0100166 chartjson_result_file):
Edward Lemur70ba9b42018-01-22 13:46:58 +0100167 ffmpeg_path = os.path.join(TOOLCHAIN_DIR, 'ffmpeg')
Edward Lemur70ba9b42018-01-22 13:46:58 +0100168
169 # Start loopback call and record video.
170 test_script = os.path.join(
Sami Kalliomäkid54f5f52018-08-03 13:23:05 +0200171 build_dir, 'bin', 'run_AppRTCMobile_stubbed_video_io_test_apk')
Edward Lesmes5b9c6842018-03-09 13:07:22 -0500172 _RunCommand([test_script, '--device', android_device,
173 '--num-retries', num_retries])
Edward Lemur70ba9b42018-01-22 13:46:58 +0100174
175 # Pull the recorded video.
176 test_video = os.path.join(temp_dir, 'test_video.y4m')
177 _RunCommand([adb_path, '-s', android_device,
178 'pull', '/sdcard/output.y4m', test_video])
179
180 # Convert the recorded and reference videos to YUV.
181 reference_video = os.path.join(SRC_DIR,
182 'resources', 'reference_video_640x360_30fps.y4m')
183
Edward Lemur70ba9b42018-01-22 13:46:58 +0100184 # Run comparison script.
185 compare_script = os.path.join(SRC_DIR, 'rtc_tools', 'compare_videos.py')
186 frame_analyzer = os.path.join(TOOLCHAIN_DIR, 'frame_analyzer')
187 zxing_path = os.path.join(TOOLCHAIN_DIR, 'zxing')
188 stats_file_ref = os.path.join(temp_dir, 'stats_ref.txt')
189 stats_file_test = os.path.join(temp_dir, 'stats_test.txt')
190
Edward Lemur2e5966b2018-01-30 15:33:02 +0100191 args = [
Magnus Jedvert9bb55fc2018-08-24 14:56:03 +0200192 '--ref_video', reference_video,
193 '--test_video', test_video,
Edward Lemur70ba9b42018-01-22 13:46:58 +0100194 '--yuv_frame_width', '640',
195 '--yuv_frame_height', '360',
196 '--stats_file_ref', stats_file_ref,
197 '--stats_file_test', stats_file_test,
198 '--frame_analyzer', frame_analyzer,
199 '--ffmpeg_path', ffmpeg_path,
Edward Lemur2e5966b2018-01-30 15:33:02 +0100200 '--zxing_path', zxing_path,
201 ]
202 if chartjson_result_file:
203 args.extend(['--chartjson_result_file', chartjson_result_file])
204
205 _RunCommand([sys.executable, compare_script] + args)
Edward Lemur70ba9b42018-01-22 13:46:58 +0100206
207
208def main():
209 logging.basicConfig(level=logging.INFO)
210
211 args = _ParseArgs()
212
213 temp_dir = args.temp_dir
214 build_dir = args.build_dir_android
215 adb_path = args.adb_path
oprypin30cda5e2017-04-24 04:15:13 -0700216
oprypin1d7392a2017-05-16 05:36:15 -0700217 processes = []
Edward Lemur70ba9b42018-01-22 13:46:58 +0100218 temp_dir = CreateEmptyDir(temp_dir)
oprypin1d7392a2017-05-16 05:36:15 -0700219 try:
Edward Lemur70ba9b42018-01-22 13:46:58 +0100220 android_device = SelectAndroidDevice(adb_path)
221 SetUpTools(android_device, temp_dir, processes)
Edward Lesmes5b9c6842018-03-09 13:07:22 -0500222 RunTest(android_device, adb_path, build_dir, temp_dir, args.num_retries,
Edward Lemur71d766e2018-02-05 21:59:36 +0100223 args.isolated_script_test_perf_output)
oprypin1d7392a2017-05-16 05:36:15 -0700224 finally:
225 for process in processes:
226 if process:
227 process.terminate()
228 process.wait()
229
Edward Lemur70ba9b42018-01-22 13:46:58 +0100230 utils.RemoveDirectory(temp_dir)
mandermoed582f72017-01-23 07:55:42 -0800231
232
233if __name__ == '__main__':
234 sys.exit(main())
235