Index: webrtc/tools/run_video_analysis.py |
diff --git a/webrtc/tools/run_video_analysis.py b/webrtc/tools/run_video_analysis.py |
new file mode 100755 |
index 0000000000000000000000000000000000000000..a1376b896ffc69718d80d1bdeac58ea57da6d1d1 |
--- /dev/null |
+++ b/webrtc/tools/run_video_analysis.py |
@@ -0,0 +1,464 @@ |
+#!/usr/bin/env python |
+# Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
+# |
+# Use of this source code is governed by a BSD-style license |
+# that can be found in the LICENSE file in the root of the source |
+# tree. An additional intellectual property rights grant can be found |
+# in the file PATENTS. All contributing project authors may |
+# be found in the AUTHORS file in the root of the source tree. |
+ |
+import optparse |
+import os |
+import subprocess |
+import sys |
+import time |
+import glob |
+import re |
+ |
+# Used to time-stamp output files and directories |
+CURRENT_TIME = time.strftime("%d_%m_%Y-%H:%M:%S") |
+ |
+def _parseArgs(): |
kjellander_webrtc
2017/02/22 12:30:51
Chromium has two exceptions from the standard goog
janssonWebRTC
2017/03/07 14:23:45
In my opinion the linter should catch these things
kjellander_webrtc
2017/03/08 07:31:21
You're right, I filed https://bugs.chromium.org/p/
|
+ """Registers the command-line options.""" |
+ usage = 'usage: %prog [options]' |
+ parser = optparse.OptionParser(usage=usage) |
+ |
+ parser.add_option('--frame_width', type='string', default='1280', |
+ help='Width of the recording. Default: %default') |
+ parser.add_option('--frame_height', type='string', default='720', |
+ help='Height of the recording. Default: %default') |
+ parser.add_option('--framerate', type='string', default='60', |
+ help='Recording framerate. Default: %default') |
+ parser.add_option('--ref_duration', type='string', default='20', |
+ help='Reference recording duration. Default: %default') |
+ parser.add_option('--test_duration', type='string', default='10', |
+ help='Test recording duration. Default: %default') |
+ parser.add_option('--ref_video_device', type='string', default='/dev/video0', |
+ help='Reference recording device. Default: %default') |
+ parser.add_option('--test_video_device', type='string', default='/dev/video1', |
+ help='Test recording device. Default: %default') |
+ parser.add_option('--app_name', type='string', |
+ help='Name of the app under test.') |
+ parser.add_option('--recording_api', type='string', default='Video4Linux2', |
+ help='Recording API to use. Default: %default') |
+ parser.add_option('--pixel_format', type='string', default='yuv420p', |
+ help='Recording pixel format Default: %default') |
+ parser.add_option('--ref_ffmpeg', type='string', |
kjellander_webrtc
2017/02/22 12:30:50
When do you need two different ffmpeg binaries? Th
janssonWebRTC
2017/03/07 14:23:45
Initially I could not run the same executable at t
kjellander_webrtc
2017/03/08 07:31:20
Acknowledged.
|
+ help='Path to the ffmpeg executable for the reference \ |
+ device.') |
+ parser.add_option('--test_ffmpeg', type='string', |
+ help='Path to the ffmpeg executable for the test device.') |
+ parser.add_option('--video_container', type='string', default='yuv', |
+ help='Video container for the recordings. \ |
+ Default: %default') |
+ parser.add_option('--compare_videos_script', type='string', |
+ default='compare_videos.py', |
+ help='Path to script used to compare and generate metrics. \ |
+ Default: %default') |
+ parser.add_option('--frame_analyzer', type='string', |
+ default='../../out/Default/frame_analyzer', |
+ help='Path to the frame analyzer executable. \ |
+ Default: %default') |
+ parser.add_option('--zxing_path', type='string', |
+ help='Path to the zebra xing barcode analyzer.') |
+ parser.add_option('--ref_crop_width', type='string', default='950', |
+ help='Cropping width. \ |
+ Default: %default') |
+ parser.add_option('--ref_crop_height', type='string', default='420', |
+ help='Cropping height. \ |
+ Default: %default') |
+ parser.add_option('--ref_crop_x_axis_start', type='string', default='130', |
+ help='y coordinate where cropping starts from. \ |
+ Default: %default') |
+ parser.add_option('--ref_crop_y_axis_start', type='string', default='56', |
+ help='x coordinate where cropping starts from. \ |
+ Default: %default') |
+ parser.add_option('--test_crop_width', type='string', default='950', |
+ help='Cropping width. \ |
+ Default: %default') |
+ parser.add_option('--test_crop_height', type='string', default='420', |
+ help='Cropping height. \ |
+ Default: %default') |
+ parser.add_option('--test_crop_x_axis_start', type='string', default='130', |
+ help='y coordinate where cropping starts from. \ |
+ Default: %default') |
+ parser.add_option('--test_crop_y_axis_start', type='string', default='56', |
+ help='x coordinate where cropping starts from. \ |
+ Default: %default') |
+ parser.add_option('--ref_rec_dir', type='string', default='ref', |
+ help='Path to where reference recordings will be created. \ |
+ Ideally keep the ref and test directories on separate \ |
+ drives. Default: %default') |
+ parser.add_option('--test_rec_dir', type='string', default='test', |
+ help='Path to where test recordings will be created. \ |
+ Ideally keep the ref and test directories on separate \ |
+ drives. Default: %default') |
+ |
+ options, _ = parser.parse_args() |
+ |
+ if not options.app_name: |
+ parser.error('You must provide an application name!') |
+ |
+ if not options.ref_ffmpeg: |
+ parser.error('You most provide location for the reference device ffmpeg \ |
+ executable.') |
+ if not os.path.exists(options.ref_ffmpeg): |
kjellander_webrtc
2017/02/22 12:30:50
I usually use os.path.isfile instead, since if you
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ parser.error('Cannot find the reference device ffmpeg executable.') |
+ |
+ if not options.test_ffmpeg: |
+ parser.error('You most provide location for the test device ffmpeg \ |
kjellander_webrtc
2017/02/22 12:30:50
Skip the \, it's not needed if you end the string
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ executable.') |
+ if not os.path.exists(options.test_ffmpeg): |
+ parser.error('Cannot find the test device ffmpeg executable.') |
+ |
+ # compare_videos.py dependencies. |
+ if not os.path.exists(options.compare_videos_script): |
+ parser.warning('Cannot find compare_videos.py script, no metrics will be \ |
+ generated!') |
kjellander_webrtc
2017/02/22 12:30:51
align indent with the above (
https://google.githu
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ if not os.path.exists(options.frame_analyzer): |
+ parser.warning('Cannot find frame_analyzer, no metrics will be generated!') |
+ if not os.path.exists(options.frame_analyzer): |
kjellander_webrtc
2017/02/22 12:30:50
options.zxing_path
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ parser.warning('Cannot find Zebra Xing, no metrics will be generated!') |
+ |
+ return options |
+ |
+ |
+def create_recording_dirs(options): |
+ """Creates root directories for reference and test recordings and |
kjellander_webrtc
2017/02/22 12:30:49
Make the summary line fit on a single line
Quotin
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ sub-directories using <options.app_name + '_' + CURRENT_TIME>. |
+ |
+ Args: |
+ options(object): Contains all the provided command line options. |
+ Return: |
+ record_paths(dict): key: value pair with reference and test file |
+ absolute paths. |
kjellander_webrtc
2017/02/22 12:30:50
+4 spaces indent before "absolute" here.
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ """ |
+ # Create root directories for the video recordings. |
+ if not os.path.exists(options.ref_rec_dir): |
kjellander_webrtc
2017/02/22 12:30:50
Use os.path.isdir
janssonWebRTC
2017/03/07 14:23:44
Done.
|
+ os.makedirs(options.ref_rec_dir) |
+ if not os.path.exists(options.test_rec_dir): |
+ os.makedirs(options.test_rec_dir) |
+ # Create and time-stamp directories for all the output files. |
kjellander_webrtc
2017/02/22 12:30:50
+1 blank line before comment
janssonWebRTC
2017/03/07 14:23:44
Done.
|
+ ref_rec_dir = os.path.join(options.ref_rec_dir, options.app_name + '_' + \ |
+ CURRENT_TIME) |
+ test_rec_dir = os.path.join(options.test_rec_dir, options.app_name + '_' + \ |
+ CURRENT_TIME) |
+ |
+ os.makedirs(ref_rec_dir) |
+ os.makedirs(test_rec_dir) |
+ |
+ record_paths = { |
+ 'ref_rec_location' : os.path.abspath(ref_rec_dir), |
+ 'test_rec_location' : os.path.abspath(test_rec_dir) |
+ } |
+ |
+ return record_paths |
+ |
+ |
+def restart_magewell_devices(options): |
+ """Tries to find the provided options.ref_video_device and |
kjellander_webrtc
2017/02/22 12:30:50
Same comment here about the docstring summary line
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ options.test_video_device devices which use video4linux and then do a soft |
+ reset by using USB unbind and bind. This is due to Magewell capture devices |
+ have proven to be unstable after the first recording attempt. |
+ |
+ Args: |
+ options(object): Contains all the provided command line options. |
+ """ |
+ # Get the dev/videoN device name from the command line arguments. |
+ ref_magewell = options.ref_video_device.split('/')[2] |
+ test_magewell = options.test_video_device.split('/')[2] |
+ |
+ # Find the device location including USB and USB Bus ID's. |
+ ref_magewell_device = \ |
+ glob.glob('/sys/bus/usb/devices/usb*/**/**/video4linux/' + ref_magewell) |
+ test_magewell_device = \ |
+ glob.glob('/sys/bus/usb/devices/usb*/**/**/video4linux/' + test_magewell) |
+ |
+ magewell_usb_ports = [] |
+ # Figure out the USB bus and port ID for each device. |
+ ref_magewell_path = str(ref_magewell_device).split('/') |
+ for directory in ref_magewell_path: |
+ # Find the folder with pattern "N-N", e.g. "4-3" or \ |
+ # "[USB bus ID]-[USB port]" |
+ if re.match(r'^\d-\d$', directory): |
+ magewell_usb_ports.append(directory) |
+ |
+ test_magewell_path = str(test_magewell_device).split('/') |
+ for directory in test_magewell_path: |
+ # Find the folder with pattern "N-N", e.g. "4-3" or \ |
+ # "[USB bus ID]-[USB port]" |
+ if re.match(r'^\d-\d$', directory): |
+ magewell_usb_ports.append(directory) |
+ |
+ print '\nResetting USB ports where magewell devices are connected...' |
+ # Use the USB bus and port ID (e.g. 4-3) to unbind and bind the USB devices |
+ # (i.e. soft eject and insert). |
+ try: |
+ for usb_port in magewell_usb_ports: |
+ echo_cmd = ['echo', usb_port] |
+ unbind_cmd = ['sudo', 'tee', '/sys/bus/usb/drivers/usb/unbind'] |
+ bind_cmd = ['sudo', 'tee', '/sys/bus/usb/drivers/usb/bind'] |
kjellander_webrtc
2017/02/22 12:30:50
Will the script ask for sudo password in a clear w
janssonWebRTC
2017/03/07 14:23:45
Yes it will but for me it's quite clear that it as
kjellander_webrtc
2017/03/08 07:31:20
Acknowledged.
|
+ |
+ # TODO(jansson) Figure out a way to call on echo once for bind & unbind |
+ # if possible. |
+ echo_unbind = subprocess.Popen(echo_cmd, stdout=subprocess.PIPE) |
+ unbind = subprocess.Popen(unbind_cmd, stdin=echo_unbind.stdout) |
+ echo_unbind.stdout.close() |
+ unbind.communicate() |
+ unbind.wait() |
+ |
+ echo_bind = subprocess.Popen(echo_cmd, stdout=subprocess.PIPE) |
+ bind = subprocess.Popen(bind_cmd, stdin=echo_bind.stdout) |
+ echo_bind.stdout.close() |
+ bind.communicate() |
+ bind.wait() |
+ except OSError as e: |
+ print 'Error while resetting magewell devices: ' + e |
+ raise |
+ |
+ print 'Reset done!\n' |
+ |
+ |
+def start_recording(options, record_paths): |
+ """Starts recording from the two specified video devices with |
+ |
+ Args: |
+ options(object): Contains all the provided command line options. |
+ record_paths(dict): key: value pair with reference and test file |
+ absolute paths. |
+ """ |
+ ref_file_name = options.app_name + '_' + CURRENT_TIME + '_ref.' + \ |
kjellander_webrtc
2017/02/22 12:30:50
Use Python string formatters instead, i.e.
ref_fi
janssonWebRTC
2017/03/07 14:23:44
Done.
|
+ options.video_container |
+ ref_file_location = os.path.join(record_paths['ref_rec_location'], |
+ ref_file_name) |
+ |
+ test_file_name = options.app_name + '_' + CURRENT_TIME + '_test.' + \ |
+ options.video_container |
+ test_file_location = os.path.join(record_paths['test_rec_location'], |
+ test_file_name) |
+ |
+ # Reference video recorder command line. |
+ ref_cmd = [ |
+ options.ref_ffmpeg, |
+ '-v', 'error', |
+ '-s', options.frame_width + 'x' + options.frame_height, |
+ '-framerate', options.framerate, |
+ '-f', options.recording_api, |
+ '-i', options.ref_video_device, |
+ '-pix_fmt', options.pixel_format, |
+ '-s', options.frame_width + 'x' + options.frame_height, |
+ '-t', options.ref_duration, |
+ '-framerate', options.framerate, |
+ ref_file_location |
+ ] |
+ |
+ # Test video recorder command line. |
+ test_cmd = [ |
+ options.test_ffmpeg, |
+ '-v', 'error', |
+ '-s', options.frame_width + 'x' + options.frame_height, |
+ '-framerate', options.framerate, |
+ '-f', options.recording_api, |
+ '-i', options.test_video_device, |
+ '-pix_fmt', options.pixel_format, |
+ '-s', options.frame_width + 'x' + options.frame_height, |
+ '-t', options.test_duration, |
+ '-framerate', options.framerate, |
+ test_file_location |
+ ] |
+ try: |
+ print 'Trying to record from reference recorder...' |
+ ref_recorder = subprocess.Popen(ref_cmd, stderr=None) |
+ # Start the 2nd recording a little later to ensure the 1st one has started. |
+ # TODO(jansson) Check that the ref_recorder output file exists rather than |
+ # using sleep. |
+ time.sleep(5) |
kjellander_webrtc
2017/02/22 12:30:51
Maybe this should be a flag as well? Constants lik
janssonWebRTC
2017/03/07 14:23:45
Made it a flag.
kjellander_webrtc
2017/03/08 07:31:20
Acknowledged.
|
+ print 'Trying to record from test recorder...' |
+ test_recorder = subprocess.Popen(test_cmd, stderr=None) |
kjellander_webrtc
2017/02/22 12:30:50
Why stderr=None ? Don't you risk to ignore errors
janssonWebRTC
2017/03/07 14:23:45
This was just a default setting. Will fix.
kjellander_webrtc
2017/03/08 07:31:20
Acknowledged.
|
+ test_recorder.wait() |
+ ref_recorder.wait() |
+ |
+ print 'Ref file recorded to: ' + os.path.abspath(ref_file_location) |
+ print 'Test file recorded to: ' + os.path.abspath(test_file_location) |
+ print 'Recording done!\n' |
+ return flip_and_crop_recordings(options, test_file_name, |
+ record_paths['test_rec_location'], ref_file_name, |
+ record_paths['ref_rec_location']) |
+ except subprocess.CalledProcessError as e: |
+ print 'Something went wrong when trying to record: ' + e |
+ raise |
+ |
+ |
+def flip_and_crop_recordings(options, test_file_name, test_file_location, |
+ ref_file_name, ref_file_location): |
kjellander_webrtc
2017/02/22 12:30:50
indent aligning with ( above
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ """Performs a horizontal flip of the reference video to match the test video |
+ orientation and then crops the ref and test videos using |
+ options.ref_crop_height, options.ref_crop_width, options.test_crop_height and |
+ options.test_crop_width. Crop starting position is taken from |
+ options.ref_crop_x_axis_start, options.ref_crop_y_axis_start, |
+ options.test_crop_x_axis_start and options.test_crop_x_axis_start. |
+ |
+ Args: |
+ options(object): Contains all the provided command line options. |
+ test_file_name(string): Name of the test video file recording. |
+ test_file_location(string): Path to the test video file recording. |
+ ref_file_name(string): Name of the reference video file recording. |
+ ref_file_location(string): Path to the reference video file recording. |
+ Return: |
+ recording_files_and_time(dict): key: value pair with the path to cropped |
+ test and reference video files. |
kjellander_webrtc
2017/02/22 12:30:50
+4 indent
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ """ |
+ print 'Trying to crop videos...' |
+ # Ref file cropping. |
kjellander_webrtc
2017/02/22 12:30:50
+blank line
janssonWebRTC
2017/03/07 14:23:44
Done.
|
+ cropped_ref_file_name = 'cropped_' + ref_file_name |
+ cropped_ref_file = os.path.abspath(\ |
kjellander_webrtc
2017/02/22 12:30:50
remove \
janssonWebRTC
2017/03/07 14:23:44
Done.
|
+ os.path.join(ref_file_location, cropped_ref_file_name)) |
+ ref_crop_parameters = options.ref_crop_width + ':' + \ |
kjellander_webrtc
2017/02/22 12:30:51
use string formatter
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ options.ref_crop_height + ':' + options.ref_crop_x_axis_start + ':' + \ |
+ options.ref_crop_y_axis_start |
+ |
+ ref_video_crop_cmd = [ |
+ options.ref_ffmpeg, |
+ '-v', 'error', |
+ '-s', options.frame_width + 'x' + options.frame_height, |
+ '-i', os.path.join(ref_file_location, ref_file_name), |
+ # Flip the ref video horizontally before cropping so that we can use the |
+ # same coordinates on both ref and test recordings. |
+ # Also keep in mind that the X:Y starting positions are critical for the |
+ # zxing library, if the barcode is moved within the recording, these |
+ # probably need to be changed otherwise barcode decoding will fail. |
+ # TODO(jansson) make the entire crop parameter section a command line |
+ # argument. |
+ '-vf', 'hflip, crop=' + ref_crop_parameters, |
+ '-c:a', 'copy', |
+ cropped_ref_file |
+ ] |
+ # Test file cropping. |
+ cropped_test_file_name = 'cropped_' + test_file_name |
+ cropped_test_file = os.path.abspath(\ |
+ os.path.join(test_file_location, cropped_test_file_name)) |
+ test_crop_parameters = options.test_crop_width + ':' + \ |
+ options.test_crop_height + ':' + options.test_crop_x_axis_start + ':' + \ |
+ options.test_crop_y_axis_start |
+ |
+ test_video_crop_cmd = [ |
+ options.test_ffmpeg, |
+ '-v', 'error', |
+ '-s', options.frame_width + 'x' + options.frame_height, |
+ '-i', os.path.join(test_file_location, test_file_name), |
+ # TODO(jansson) make the entire crop parameter section a command line |
+ # argument. |
+ '-vf', 'crop=' + test_crop_parameters, |
+ '-c:a', 'copy', |
+ cropped_test_file |
+ ] |
+ |
+ ref_crop = subprocess.Popen(ref_video_crop_cmd) |
+ ref_crop.wait() |
+ print 'Ref file cropped to: ' + cropped_ref_file |
+ |
+ try: |
+ test_crop = subprocess.Popen(test_video_crop_cmd) |
+ test_crop.wait() |
+ print 'Test file cropped to: ' + cropped_test_file |
+ print 'Cropping done!\n' |
+ # Need to return these so they can be used by other parts. |
+ cropped_recordings = { |
+ 'cropped_test_file' : cropped_test_file, |
+ 'cropped_ref_file' : cropped_ref_file |
+ } |
+ |
+ return cropped_recordings |
+ except subprocess.CalledProcessError as e: |
+ print 'Something went wrong during cropping: ' + e |
+ raise |
+ |
+ |
+def compare_videos(options, recording_result): |
+ """Runs the compare_video.py script from src/webrtc/tools using the file paths |
+ from recording_result and writes the output to a file named |
+ <options.app_name + '_' + CURRENT_TIME + '_result.txt> in the reference video |
+ recording folder taken from recording_result. |
+ |
+ Args: |
+ options(object): Contains all the provided command line options. |
+ recording_files_and_time(dict): key: value pair with the path to cropped |
+ test and reference video files |
+ """ |
+ print 'Starting comparison...' |
+ print 'Grab a coffee, this might take a few minutes...' |
+ cropped_ref_file = recording_result['cropped_ref_file'] |
+ cropped_test_file = recording_result['cropped_test_file'] |
+ compare_videos_script = os.path.abspath(options.compare_videos_script) |
+ result_file_name = \ |
kjellander_webrtc
2017/02/22 12:30:50
remove \ and use string formatter instead.
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ os.path.join(os.path.dirname(recording_result['cropped_ref_file']), |
+ options.app_name + '_' + CURRENT_TIME + '_result.txt') |
+ |
+ compare_cmd = [ |
+ sys.executable, |
+ compare_videos_script, |
+ '--ref_video', cropped_ref_file, |
+ '--test_video', cropped_test_file, |
+ '--frame_analyzer', os.path.abspath(options.frame_analyzer), |
+ '--zxing_path', options.zxing_path, |
+ '--ffmpeg_path', options.ref_ffmpeg, |
+ '--stats_file_ref', os.path.join(os.path.dirname(cropped_ref_file), |
+ cropped_ref_file + '_stats.txt'), |
+ '--stats_file_test', os.path.join(os.path.dirname(cropped_test_file), |
+ cropped_test_file + '_stats.txt'), |
+ '--yuv_frame_height', options.ref_crop_height, |
+ '--yuv_frame_width', options.ref_crop_width |
+ ] |
+ |
+ try: |
+ with open(result_file_name, 'w') as f: |
+ compare_video_recordings = subprocess.Popen(compare_cmd, stdout=f) |
+ compare_video_recordings.wait() |
+ print 'Result recorded to: ' + os.path.abspath(result_file_name) |
+ print 'Comparison done!' |
+ except subprocess.CalledProcessError as e: |
+ print 'Something went wrong when trying to compare videos: ' + e |
+ raise |
+ |
+ |
+def main(): |
+ """The main function. |
+ |
+ A simple invocation is: |
+ ./run_video_analysis.py \ |
+ --app_name AppRTCMobile \ |
+ --ref_ffmpeg ./ref_ffmpeg --ref_video_device=/dev/video0 \ |
+ --test_ffmpeg ./test_ffmpeg --test_video_device=/dev/video1 \ |
+ --zxing_path ./zxing \ |
+ --test_crop_width 950 --test_crop_height 420 \ |
+ --ref_crop_width 950 --ref_crop_height 420 \ |
+ --test_crop_x_axis_start 130 --test_crop_y_axis_start 56 \ |
+ --ref_crop_x_axis_start 130 --ref_crop_y_axis_start 56 \ |
+ --ref_rec_dir /tmp/ref \ |
+ --test_rec_dir /tmp/test |
+ |
+ This will produce the following files if successful: |
+ # Original video recordings. |
+ /tmp/ref/AppRTCMobile_<recording date and time>_ref.yuv |
+ /tmp/test/AppRTCMobile_<recording date and time>_test.yuv |
+ |
+ # Cropped video recordings according to the crop parameters. |
+ /tmp/ref/cropped_AppRTCMobile_<recording date and time>_ref.yuv |
+ /tmp/test/cropped_AppRTCMobile_<recording date and time>_ref.yuv |
+ |
+ # Comparison metrics from cropped test and ref videos. |
+ /tmp/test/AppRTCMobile_<recording date and time>_result.text |
+ |
+ """ |
+ options = _parseArgs() |
+ restart_magewell_devices(options) |
+ record_paths = create_recording_dirs(options) |
+ recording_result = start_recording(options, record_paths) |
+ # Do not require compare_video.py script to run, no metrics will be generated. |
+ if os.path.exists(options.frame_analyzer) or \ |
+ os.path.exists(options.compare_videos_script) or \ |
+ os.path.exists(options.zxing_path): |
+ compare_videos(options, recording_result) |
kjellander_webrtc
2017/02/22 12:30:50
This is a bit unexpected. I suggest you at least a
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+ |
kjellander_webrtc
2017/02/22 12:30:50
+1 blank line for top-level statements.
janssonWebRTC
2017/03/07 14:23:45
Done.
|
+if __name__ == '__main__': |
+ sys.exit(main()) |