diff --git a/.gitignore b/.gitignore index 2104635e82..bf937369ae 100644 --- a/.gitignore +++ b/.gitignore @@ -55,6 +55,7 @@ /tools_webrtc/audio_quality/win/*.exe /tools_webrtc/audio_quality/win/*.dll /tools_webrtc/video_quality_toolchain/linux/ffmpeg +/tools_webrtc/video_quality_toolchain/linux/frame_analyzer /tools_webrtc/video_quality_toolchain/linux/zxing /tools_webrtc/video_quality_toolchain/mac/ffmpeg /tools_webrtc/video_quality_toolchain/mac/zxing diff --git a/examples/BUILD.gn b/examples/BUILD.gn index 1bbcf743a4..434c4649b9 100644 --- a/examples/BUILD.gn +++ b/examples/BUILD.gn @@ -146,7 +146,19 @@ if (is_android) { ] data = [ + "../build/android/adb_reverse_forwarder.py", + "../examples/androidtests/video_quality_loopback_test.py", "../resources/reference_video_640x360_30fps.y4m", + "../rtc_tools/barcode_tools/barcode_decoder.py", + "../rtc_tools/barcode_tools/helper_functions.py", + "../rtc_tools/compare_videos.py", + "../rtc_tools/testing/prebuilt_apprtc.zip", + "../rtc_tools/testing/golang/linux/go.tar.gz", + "../rtc_tools/testing/build_apprtc.py", + "../rtc_tools/testing/utils.py", + "../tools_webrtc/video_quality_toolchain/linux/ffmpeg", + "../tools_webrtc/video_quality_toolchain/linux/frame_analyzer", + "../tools_webrtc/video_quality_toolchain/linux/zxing", ] } } diff --git a/examples/androidtests/video_quality_loopback_test.py b/examples/androidtests/video_quality_loopback_test.py index 6991a0a57b..bd4e94e4f3 100755 --- a/examples/androidtests/video_quality_loopback_test.py +++ b/examples/androidtests/video_quality_loopback_test.py @@ -22,7 +22,6 @@ import argparse import json import logging import os -import shutil import subprocess import sys import tempfile @@ -31,11 +30,15 @@ import time SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) SRC_DIR = os.path.normpath(os.path.join(SCRIPT_DIR, os.pardir, os.pardir)) +RTC_TOOLS_DIR = os.path.join(SRC_DIR, 'rtc_tools', 'testing') +TOOLCHAIN_DIR = os.path.join(SRC_DIR, 'tools_webrtc', 'video_quality_toolchain', + 'linux') BAD_DEVICES_JSON = os.path.join(SRC_DIR, os.environ.get('CHROMIUM_OUT_DIR', 'out'), 'bad_devices.json') -sys.path.append(os.path.join(SRC_DIR, 'build')) -import find_depot_tools + +sys.path.append(RTC_TOOLS_DIR) +import utils class Error(Exception): @@ -66,6 +69,14 @@ def _RunBackgroundCommand(argv, cwd=SRC_DIR): return process +def CreateEmptyDir(suggested_dir): + if not suggested_dir: + return tempfile.mkdtemp() + utils.RemoveDirectory(suggested_dir) + os.makedirs(suggested_dir) + return suggested_dir + + def _ParseArgs(): parser = argparse.ArgumentParser(description='Start loopback video analysis.') parser.add_argument('build_dir_android', @@ -80,45 +91,8 @@ def _ParseArgs(): return args -def main(): - logging.basicConfig(level=logging.INFO) - - args = _ParseArgs() - - build_dir_android = args.build_dir_android - build_dir_x86 = args.build_dir_x86 - temp_dir = args.temp_dir - adb_path = args.adb_path - if not temp_dir: - temp_dir = tempfile.mkdtemp() - else: - if not os.path.exists(temp_dir): - os.makedirs(temp_dir) - - if not build_dir_x86: - build_dir_x86 = os.path.join(temp_dir, 'LocalBuild') - - def DepotToolPath(*args): - return os.path.join(find_depot_tools.DEPOT_TOOLS_PATH, *args) - - _RunCommand([sys.executable, DepotToolPath('gn.py'), 'gen', build_dir_x86]) - _RunCommand([DepotToolPath('ninja'), '-C', build_dir_x86, - 'frame_analyzer']) - - tools_dir = os.path.join(SRC_DIR, 'tools_webrtc') - toolchain_dir = os.path.join(tools_dir, 'video_quality_toolchain') - - # Download ffmpeg and zxing. - download_tools_script = os.path.join(tools_dir, 'download_tools.py') - _RunCommand([sys.executable, download_tools_script, toolchain_dir]) - - testing_tools_dir = os.path.join(SRC_DIR, 'rtc_tools', 'testing') - - # Download, extract and build AppRTC. - setup_apprtc_script = os.path.join(testing_tools_dir, 'setup_apprtc.py') - _RunCommand([sys.executable, setup_apprtc_script, temp_dir]) - - # Select an Android device in case multiple are connected +def SelectAndroidDevice(adb_path): + # Select an Android device in case multiple are connected. try: with open(BAD_DEVICES_JSON) as bad_devices_file: bad_devices = json.load(bad_devices_file) @@ -131,91 +105,117 @@ def main(): if line.endswith('\tdevice'): android_device = line.split('\t')[0] if android_device not in bad_devices: - break - else: - raise VideoQualityTestError('Cannot find any connected Android device.') + return android_device + raise VideoQualityTestError('Cannot find any connected Android device.') + + +def SetUpTools(android_device, temp_dir, processes): + # Extract AppRTC. + apprtc_archive = os.path.join(RTC_TOOLS_DIR, 'prebuilt_apprtc.zip') + golang_archive = os.path.join(RTC_TOOLS_DIR, 'golang', 'linux', 'go.tar.gz') + + utils.UnpackArchiveTo(apprtc_archive, temp_dir) + utils.UnpackArchiveTo(golang_archive, temp_dir) + + # Build AppRTC. + build_apprtc_script = os.path.join(RTC_TOOLS_DIR, 'build_apprtc.py') + apprtc_src_dir = os.path.join(temp_dir, 'apprtc', 'src') + go_dir = os.path.join(temp_dir, 'go') + collider_dir = os.path.join(temp_dir, 'collider') + + _RunCommand([sys.executable, build_apprtc_script, apprtc_src_dir, go_dir, + collider_dir]) + + # Start AppRTC Server. + dev_appserver = os.path.join(temp_dir, 'apprtc', 'temp', 'google-cloud-sdk', + 'bin', 'dev_appserver.py') + appengine_dir = os.path.join(temp_dir, 'apprtc', 'out', 'app_engine') + processes.append(_RunBackgroundCommand([ + sys.executable, dev_appserver, appengine_dir, '--port=9999', + '--admin_port=9998', '--skip_sdk_update_check', '--clear_datastore=yes'])) + + # Start Collider. + collider_path = os.path.join(temp_dir, 'collider', 'collidermain') + processes.append(_RunBackgroundCommand([ + collider_path, '-tls=false', '-port=8089', + '-room-server=http://localhost:9999'])) + + # Start adb reverse forwarder. + reverseforwarder_path = os.path.join( + SRC_DIR, 'build', 'android', 'adb_reverse_forwarder.py') + processes.append(_RunBackgroundCommand([ + reverseforwarder_path, '--device', android_device, '9999', '9999', '8089', + '8089'])) + + +def RunTest(android_device, adb_path, build_dir, temp_dir): + ffmpeg_path = os.path.join(TOOLCHAIN_DIR, 'ffmpeg') + def ConvertVideo(input_video, output_video): + _RunCommand([ffmpeg_path, '-y', '-i', input_video, output_video]) + + # Start loopback call and record video. + test_script = os.path.join( + build_dir, 'bin', 'run_AppRTCMobileTestStubbedVideoIO') + _RunCommand([test_script, '--device', android_device]) + + # Pull the recorded video. + test_video = os.path.join(temp_dir, 'test_video.y4m') + _RunCommand([adb_path, '-s', android_device, + 'pull', '/sdcard/output.y4m', test_video]) + + # Convert the recorded and reference videos to YUV. + reference_video = os.path.join(SRC_DIR, + 'resources', 'reference_video_640x360_30fps.y4m') + + test_video_yuv = os.path.join(temp_dir, 'test_video.yuv') + reference_video_yuv = os.path.join( + temp_dir, 'reference_video_640x360_30fps.yuv') + + ConvertVideo(test_video, test_video_yuv) + ConvertVideo(reference_video, reference_video_yuv) + + # Run comparison script. + compare_script = os.path.join(SRC_DIR, 'rtc_tools', 'compare_videos.py') + frame_analyzer = os.path.join(TOOLCHAIN_DIR, 'frame_analyzer') + zxing_path = os.path.join(TOOLCHAIN_DIR, 'zxing') + stats_file_ref = os.path.join(temp_dir, 'stats_ref.txt') + stats_file_test = os.path.join(temp_dir, 'stats_test.txt') + + _RunCommand([ + sys.executable, compare_script, + '--ref_video', reference_video_yuv, + '--test_video', test_video_yuv, + '--yuv_frame_width', '640', + '--yuv_frame_height', '360', + '--stats_file_ref', stats_file_ref, + '--stats_file_test', stats_file_test, + '--frame_analyzer', frame_analyzer, + '--ffmpeg_path', ffmpeg_path, + '--zxing_path', zxing_path]) + + +def main(): + logging.basicConfig(level=logging.INFO) + + args = _ParseArgs() + + temp_dir = args.temp_dir + build_dir = args.build_dir_android + adb_path = args.adb_path processes = [] + temp_dir = CreateEmptyDir(temp_dir) try: - # Start AppRTC Server - dev_appserver = os.path.join(temp_dir, 'apprtc', 'temp', 'google-cloud-sdk', - 'bin', 'dev_appserver.py') - appengine_dir = os.path.join(temp_dir, 'apprtc', 'out', 'app_engine') - processes.append(_RunBackgroundCommand([ - 'python', dev_appserver, appengine_dir, - '--port=9999', '--admin_port=9998', - '--skip_sdk_update_check', '--clear_datastore=yes'])) - - # Start Collider - collider_path = os.path.join(temp_dir, 'collider', 'collidermain') - processes.append(_RunBackgroundCommand([ - collider_path, '-tls=false', '-port=8089', - '-room-server=http://localhost:9999'])) - - # Start adb reverse forwarder - reverseforwarder_path = os.path.join( - SRC_DIR, 'build', 'android', 'adb_reverse_forwarder.py') - processes.append(_RunBackgroundCommand([ - reverseforwarder_path, '--device', android_device, - '9999', '9999', '8089', '8089'])) - - # Run the Espresso code. - test_script = os.path.join(build_dir_android, - 'bin', 'run_AppRTCMobileTestStubbedVideoIO') - _RunCommand([test_script, '--device', android_device]) - - # Pull the output video. - test_video = os.path.join(temp_dir, 'test_video.y4m') - _RunCommand([adb_path, '-s', android_device, - 'pull', '/sdcard/output.y4m', test_video]) - - test_video_yuv = os.path.join(temp_dir, 'test_video.yuv') - - ffmpeg_path = os.path.join(toolchain_dir, 'linux', 'ffmpeg') - - def ConvertVideo(input_video, output_video): - _RunCommand([ffmpeg_path, '-y', '-i', input_video, output_video]) - - ConvertVideo(test_video, test_video_yuv) - - reference_video = os.path.join(SRC_DIR, - 'resources', 'reference_video_640x360_30fps.y4m') - - reference_video_yuv = os.path.join(temp_dir, - 'reference_video_640x360_30fps.yuv') - - ConvertVideo(reference_video, reference_video_yuv) - - # Run compare script. - compare_script = os.path.join(SRC_DIR, 'rtc_tools', 'compare_videos.py') - zxing_path = os.path.join(toolchain_dir, 'linux', 'zxing') - - # The frame_analyzer binary should be built for local computer and not for - # Android - frame_analyzer = os.path.join(build_dir_x86, 'frame_analyzer') - - frame_width = 640 - frame_height = 360 - - stats_file_ref = os.path.join(temp_dir, 'stats_ref.txt') - stats_file_test = os.path.join(temp_dir, 'stats_test.txt') - - _RunCommand([ - sys.executable, compare_script, '--ref_video', reference_video_yuv, - '--test_video', test_video_yuv, '--yuv_frame_width', str(frame_width), - '--yuv_frame_height', str(frame_height), - '--stats_file_ref', stats_file_ref, - '--stats_file_test', stats_file_test, - '--frame_analyzer', frame_analyzer, - '--ffmpeg_path', ffmpeg_path, '--zxing_path', zxing_path]) - + android_device = SelectAndroidDevice(adb_path) + SetUpTools(android_device, temp_dir, processes) + RunTest(android_device, adb_path, build_dir, temp_dir) finally: for process in processes: if process: process.terminate() process.wait() - shutil.rmtree(temp_dir) + utils.RemoveDirectory(temp_dir) if __name__ == '__main__': diff --git a/tools_webrtc/mb/gn_isolate_map.pyl b/tools_webrtc/mb/gn_isolate_map.pyl index 4905bbd94e..6e6130bc76 100644 --- a/tools_webrtc/mb/gn_isolate_map.pyl +++ b/tools_webrtc/mb/gn_isolate_map.pyl @@ -122,6 +122,12 @@ "label": "//:video_engine_tests", "type": "console_test_launcher", }, + "video_quality_loopback_test": { + "label": "//examples:AppRTCMobileTestStubbedVideoIO", + "type": "script", + "script": "//examples/androidtests/video_quality_loopback_test.py", + "args": ["."], + }, "webrtc_nonparallel_tests": { "label": "//:webrtc_nonparallel_tests", "type": "non_parallel_console_test_launcher", diff --git a/tools_webrtc/video_quality_toolchain/linux/frame_analyzer.sha1 b/tools_webrtc/video_quality_toolchain/linux/frame_analyzer.sha1 new file mode 100644 index 0000000000..e5fc34e117 --- /dev/null +++ b/tools_webrtc/video_quality_toolchain/linux/frame_analyzer.sha1 @@ -0,0 +1 @@ +1f7b4528bbda3c8e2170b23b348b73b56df4e0d1 \ No newline at end of file