Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 #!/usr/bin/env python | 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. | 2 # Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. |
| 3 # | 3 # |
| 4 # Use of this source code is governed by a BSD-style license | 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 | 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 | 6 # tree. An additional intellectual property rights grant can be found |
| 7 # in the file PATENTS. All contributing project authors may | 7 # in the file PATENTS. All contributing project authors may |
| 8 # be found in the AUTHORS file in the root of the source tree. | 8 # be found in the AUTHORS file in the root of the source tree. |
| 9 | 9 |
| 10 import optparse | 10 import optparse |
| 11 import os | 11 import os |
| 12 import subprocess | 12 import subprocess |
| 13 import sys | 13 import sys |
| 14 import time | 14 import time |
| 15 import glob | 15 import glob |
| 16 import re | 16 import re |
| 17 import shutil | |
| 17 | 18 |
| 18 # Used to time-stamp output files and directories | 19 # Used to time-stamp output files and directories |
| 19 CURRENT_TIME = time.strftime("%d_%m_%Y-%H:%M:%S") | 20 CURRENT_TIME = time.strftime("%d_%m_%Y-%H:%M:%S") |
| 20 | 21 |
| 22 | |
| 23 class Error(Exception): | |
| 24 pass | |
| 25 | |
| 26 | |
| 27 class FfmpegError(Error): | |
| 28 pass | |
| 29 | |
| 30 | |
| 31 class MagewellError(Error): | |
| 32 pass | |
| 33 | |
| 34 | |
| 35 class CompareVideosError(Error): | |
| 36 pass | |
| 37 | |
| 38 | |
| 21 def _ParseArgs(): | 39 def _ParseArgs(): |
| 22 """Registers the command-line options.""" | 40 """Registers the command-line options.""" |
| 23 usage = 'usage: %prog [options]' | 41 usage = 'usage: %prog [options]' |
| 24 parser = optparse.OptionParser(usage=usage) | 42 parser = optparse.OptionParser(usage=usage) |
| 25 | 43 |
| 26 parser.add_option('--frame_width', type='string', default='1280', | 44 parser.add_option('--frame_width', type='string', default='1280', |
| 27 help='Width of the recording. Default: %default') | 45 help='Width of the recording. Default: %default') |
| 28 parser.add_option('--frame_height', type='string', default='720', | 46 parser.add_option('--frame_height', type='string', default='720', |
| 29 help='Height of the recording. Default: %default') | 47 help='Height of the recording. Default: %default') |
| 30 parser.add_option('--framerate', type='string', default='60', | 48 parser.add_option('--framerate', type='string', default='60', |
| (...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 68 'drives. Default: %default') | 86 'drives. Default: %default') |
| 69 parser.add_option('--test_rec_dir', type='string', default='test', | 87 parser.add_option('--test_rec_dir', type='string', default='test', |
| 70 help='Path to where test recordings will be created.' | 88 help='Path to where test recordings will be created.' |
| 71 'Ideally keep the ref and test directories on separate ' | 89 'Ideally keep the ref and test directories on separate ' |
| 72 'drives. Default: %default') | 90 'drives. Default: %default') |
| 73 parser.add_option('--test_crop_parameters', type='string', | 91 parser.add_option('--test_crop_parameters', type='string', |
| 74 help='ffmpeg processing parameters for the test video.') | 92 help='ffmpeg processing parameters for the test video.') |
| 75 parser.add_option('--ref_crop_parameters', type='string', | 93 parser.add_option('--ref_crop_parameters', type='string', |
| 76 help='ffmpeg processing parameters for the ref video.') | 94 help='ffmpeg processing parameters for the ref video.') |
| 77 | 95 |
| 96 | |
|
kjellander_webrtc
2017/03/15 14:00:29
You can skip this blank line
| |
| 78 options, _ = parser.parse_args() | 97 options, _ = parser.parse_args() |
| 79 | 98 |
| 80 if not options.app_name: | 99 if not options.app_name: |
| 81 parser.error('You must provide an application name!') | 100 parser.error('You must provide an application name!') |
| 82 | 101 |
| 83 if not options.test_crop_parameters or not options.ref_crop_parameters: | 102 if not options.test_crop_parameters or not options.ref_crop_parameters: |
| 84 parser.error('You must provide ref and test crop parameters!') | 103 parser.error('You must provide ref and test crop parameters!') |
| 85 | 104 |
| 86 # Ensure the crop filter is included in the crop parameters used for ffmpeg. | 105 # Ensure the crop filter is included in the crop parameters used for ffmpeg. |
| 87 if 'crop' not in options.ref_crop_parameters: | 106 if 'crop' not in options.ref_crop_parameters: |
| (...skipping 16 matching lines...) Expand all Loading... | |
| 104 parser.warning('Cannot find Zebra Xing, no metrics will be generated!') | 123 parser.warning('Cannot find Zebra Xing, no metrics will be generated!') |
| 105 | 124 |
| 106 return options | 125 return options |
| 107 | 126 |
| 108 | 127 |
| 109 def CreateRecordingDirs(options): | 128 def CreateRecordingDirs(options): |
| 110 """Create root + sub directories for reference and test recordings. | 129 """Create root + sub directories for reference and test recordings. |
| 111 | 130 |
| 112 Args: | 131 Args: |
| 113 options(object): Contains all the provided command line options. | 132 options(object): Contains all the provided command line options. |
| 114 Return: | 133 |
| 134 Returns: | |
| 115 record_paths(dict): key: value pair with reference and test file | 135 record_paths(dict): key: value pair with reference and test file |
| 116 absolute paths. | 136 absolute paths. |
| 117 """ | 137 """ |
| 118 | 138 |
| 119 # Create root directories for the video recordings. | 139 # Create root directories for the video recordings. |
| 120 if not os.path.isdir(options.ref_rec_dir): | 140 if not os.path.isdir(options.ref_rec_dir): |
| 121 os.makedirs(options.ref_rec_dir) | 141 os.makedirs(options.ref_rec_dir) |
| 122 if not os.path.isdir(options.test_rec_dir): | 142 if not os.path.isdir(options.test_rec_dir): |
| 123 os.makedirs(options.test_rec_dir) | 143 os.makedirs(options.test_rec_dir) |
| 124 | 144 |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 140 | 160 |
| 141 | 161 |
| 142 def RestartMagewellDevices(ref_video_device, test_video_device): | 162 def RestartMagewellDevices(ref_video_device, test_video_device): |
| 143 """Reset the USB ports where Magewell capture devices are connected to. | 163 """Reset the USB ports where Magewell capture devices are connected to. |
| 144 | 164 |
| 145 Tries to find the provided ref_video_device and test_video_device devices | 165 Tries to find the provided ref_video_device and test_video_device devices |
| 146 which use video4linux and then do a soft reset by using USB unbind and bind. | 166 which use video4linux and then do a soft reset by using USB unbind and bind. |
| 147 This is due to Magewell capture devices have proven to be unstable after the | 167 This is due to Magewell capture devices have proven to be unstable after the |
| 148 first recording attempt. | 168 first recording attempt. |
| 149 | 169 |
| 150 Args: | 170 Args : |
| 151 ref_video_device(string): reference recording device path. | 171 ref_video_device(string): reference recording device path. |
| 152 test_video_device(string): test recording device path | 172 test_video_device(string): test recording device path |
| 173 | |
| 174 Raises: | |
| 175 MagewellError: If no magewell devices are found. | |
| 153 """ | 176 """ |
| 154 | 177 |
| 155 # Get the dev/videoN device name from the command line arguments. | 178 # Get the dev/videoN device name from the command line arguments. |
| 156 ref_magewell = ref_video_device.split('/')[2] | 179 ref_magewell = ref_video_device.split('/')[2] |
| 157 test_magewell = test_video_device.split('/')[2] | 180 test_magewell = test_video_device.split('/')[2] |
| 158 | 181 |
| 159 # Find the device location including USB and USB Bus ID's. | 182 # Find the device location including USB and USB Bus ID's. |
| 160 device_string = '/sys/bus/usb/devices/usb*/**/**/video4linux/' | 183 device_string = '/sys/bus/usb/devices/usb*/**/**/video4linux/' |
| 161 ref_magewell_device = glob.glob('%s%s' % (device_string, ref_magewell)) | 184 ref_magewell_device = glob.glob('%s%s' % (device_string, ref_magewell)) |
| 162 test_magewell_device = glob.glob('%s%s' % (device_string, test_magewell)) | 185 test_magewell_device = glob.glob('%s%s' % (device_string, test_magewell)) |
| 163 | 186 |
| 164 magewell_usb_ports = [] | 187 magewell_usb_ports = [] |
| 165 | 188 |
| 166 # Figure out the USB bus and port ID for each device. | 189 # Figure out the USB bus and port ID for each device. |
| 167 ref_magewell_path = str(ref_magewell_device).split('/') | 190 ref_magewell_path = str(ref_magewell_device).split('/') |
| 168 for directory in ref_magewell_path: | 191 for directory in ref_magewell_path: |
| 169 | |
| 170 # Find the folder with pattern "N-N", e.g. "4-3" or \ | 192 # Find the folder with pattern "N-N", e.g. "4-3" or \ |
| 171 # "[USB bus ID]-[USB port]" | 193 # "[USB bus ID]-[USB port]" |
| 172 if re.match(r'^\d-\d$', directory): | 194 if re.match(r'^\d-\d$', directory): |
| 173 magewell_usb_ports.append(directory) | 195 magewell_usb_ports.append(directory) |
| 174 | 196 |
| 175 test_magewell_path = str(test_magewell_device).split('/') | 197 test_magewell_path = str(test_magewell_device).split('/') |
| 176 for directory in test_magewell_path: | 198 for directory in test_magewell_path: |
| 177 | |
| 178 # Find the folder with pattern "N-N", e.g. "4-3" or \ | 199 # Find the folder with pattern "N-N", e.g. "4-3" or \ |
| 179 # "[USB bus ID]-[USB port]" | 200 # "[USB bus ID]-[USB port]" |
| 180 if re.match(r'^\d-\d$', directory): | 201 if re.match(r'^\d-\d$', directory): |
| 181 magewell_usb_ports.append(directory) | 202 magewell_usb_ports.append(directory) |
| 182 | 203 |
| 183 print '\nResetting USB ports where magewell devices are connected...' | 204 # Abort early if no devices are found. |
| 184 | 205 if len(magewell_usb_ports) == 0: |
| 185 # Use the USB bus and port ID (e.g. 4-3) to unbind and bind the USB devices | 206 raise MagewellError('No magewell devices found.') |
| 186 # (i.e. soft eject and insert). | 207 else: |
| 187 try: | 208 print '\nResetting USB ports where magewell devices are connected...' |
| 209 # Use the USB bus and port ID (e.g. 4-3) to unbind and bind the USB devices | |
| 210 # (i.e. soft eject and insert). | |
| 188 for usb_port in magewell_usb_ports: | 211 for usb_port in magewell_usb_ports: |
| 189 echo_cmd = ['echo', usb_port] | 212 echo_cmd = ['echo', usb_port] |
| 190 unbind_cmd = ['sudo', 'tee', '/sys/bus/usb/drivers/usb/unbind'] | 213 unbind_cmd = ['sudo', 'tee', '/sys/bus/usb/drivers/usb/unbind'] |
| 191 bind_cmd = ['sudo', 'tee', '/sys/bus/usb/drivers/usb/bind'] | 214 bind_cmd = ['sudo', 'tee', '/sys/bus/usb/drivers/usb/bind'] |
| 192 | 215 |
| 193 # TODO(jansson) Figure out a way to call on echo once for bind & unbind | 216 # TODO(jansson) Figure out a way to call on echo once for bind & unbind |
| 194 # if possible. | 217 # if possible. |
| 195 echo_unbind = subprocess.Popen(echo_cmd, stdout=subprocess.PIPE) | 218 echo_unbind = subprocess.Popen(echo_cmd, stdout=subprocess.PIPE) |
| 196 unbind = subprocess.Popen(unbind_cmd, stdin=echo_unbind.stdout) | 219 unbind = subprocess.Popen(unbind_cmd, stdin=echo_unbind.stdout) |
| 197 echo_unbind.stdout.close() | 220 echo_unbind.stdout.close() |
| 198 unbind.communicate() | |
| 199 unbind.wait() | 221 unbind.wait() |
| 200 | 222 |
| 201 echo_bind = subprocess.Popen(echo_cmd, stdout=subprocess.PIPE) | 223 echo_bind = subprocess.Popen(echo_cmd, stdout=subprocess.PIPE) |
| 202 bind = subprocess.Popen(bind_cmd, stdin=echo_bind.stdout) | 224 bind = subprocess.Popen(bind_cmd, stdin=echo_bind.stdout) |
| 203 echo_bind.stdout.close() | 225 echo_bind.stdout.close() |
| 204 bind.communicate() | |
| 205 bind.wait() | 226 bind.wait() |
| 206 except OSError as e: | 227 if bind.returncode == 0: |
| 207 print 'Error while resetting magewell devices: ' + e | 228 print 'Reset done!\n' |
| 208 raise | |
| 209 | |
| 210 print 'Reset done!\n' | |
| 211 | 229 |
| 212 | 230 |
| 213 def StartRecording(options, record_paths): | 231 def StartRecording(options, ref_file_location, test_file_location): |
| 214 """Starts recording from the two specified video devices. | 232 """Starts recording from the two specified video devices. |
| 215 | 233 |
| 216 Args: | 234 Args: |
| 217 options(object): Contains all the provided command line options. | 235 options(object): Contains all the provided command line options. |
| 218 record_paths(dict): key: value pair with reference and test file | 236 record_paths(dict): key: value pair with reference and test file |
| 219 absolute paths. | 237 absolute paths. |
| 238 | |
| 239 Returns: | |
| 240 recording_files_and_time(dict): key: value pair with the path to cropped | |
| 241 test and reference video files. | |
| 242 | |
| 243 Raises: | |
| 244 FfmpegError: If the ffmpeg command fails. | |
| 220 """ | 245 """ |
| 221 ref_file_name = '%s_%s_ref.%s' % (options.app_name, CURRENT_TIME, | 246 ref_file_name = '%s_%s_ref.%s' % (options.app_name, CURRENT_TIME, |
| 222 options.video_container) | 247 options.video_container) |
| 223 ref_file_location = os.path.join(record_paths['ref_rec_location'], | 248 ref_file = os.path.join(ref_file_location, ref_file_name) |
| 224 ref_file_name) | |
| 225 | 249 |
| 226 test_file_name = '%s_%s_test.%s' % (options.app_name, CURRENT_TIME, | 250 test_file_name = '%s_%s_test.%s' % (options.app_name, CURRENT_TIME, |
| 227 options.video_container) | 251 options.video_container) |
| 228 test_file_location = os.path.join(record_paths['test_rec_location'], | 252 test_file = os.path.join(test_file_location, test_file_name) |
| 229 test_file_name) | |
| 230 | 253 |
| 231 # Reference video recorder command line. | 254 # Reference video recorder command line. |
| 232 ref_cmd = [ | 255 ref_cmd = [ |
| 233 options.ffmpeg, | 256 options.ffmpeg, |
| 234 '-v', 'error', | 257 '-v', 'error', |
| 235 '-s', options.frame_width + 'x' + options.frame_height, | 258 '-s', options.frame_width + 'x' + options.frame_height, |
| 236 '-framerate', options.framerate, | 259 '-framerate', options.framerate, |
| 237 '-f', options.recording_api, | 260 '-f', options.recording_api, |
| 238 '-i', options.ref_video_device, | 261 '-i', options.ref_video_device, |
| 239 '-pix_fmt', options.pixel_format, | 262 '-pix_fmt', options.pixel_format, |
| 240 '-s', options.frame_width + 'x' + options.frame_height, | 263 '-s', options.frame_width + 'x' + options.frame_height, |
| 241 '-t', options.ref_duration, | 264 '-t', options.ref_duration, |
| 242 '-framerate', options.framerate, | 265 '-framerate', options.framerate, |
| 243 ref_file_location | 266 ref_file |
| 244 ] | 267 ] |
| 245 | 268 |
| 246 # Test video recorder command line. | 269 # Test video recorder command line. |
| 247 test_cmd = [ | 270 test_cmd = [ |
| 248 options.ffmpeg, | 271 options.ffmpeg, |
| 249 '-v', 'error', | 272 '-v', 'error', |
| 250 '-s', options.frame_width + 'x' + options.frame_height, | 273 '-s', options.frame_width + 'x' + options.frame_height, |
| 251 '-framerate', options.framerate, | 274 '-framerate', options.framerate, |
| 252 '-f', options.recording_api, | 275 '-f', options.recording_api, |
| 253 '-i', options.test_video_device, | 276 '-i', options.test_video_device, |
| 254 '-pix_fmt', options.pixel_format, | 277 '-pix_fmt', options.pixel_format, |
| 255 '-s', options.frame_width + 'x' + options.frame_height, | 278 '-s', options.frame_width + 'x' + options.frame_height, |
| 256 '-t', options.test_duration, | 279 '-t', options.test_duration, |
| 257 '-framerate', options.framerate, | 280 '-framerate', options.framerate, |
| 258 test_file_location | 281 test_file |
| 259 ] | 282 ] |
| 260 print 'Trying to record from reference recorder...' | 283 print 'Trying to record from reference recorder...' |
| 261 ref_recorder = subprocess.Popen(ref_cmd, stderr=sys.stderr) | 284 ref_recorder = subprocess.Popen(ref_cmd, stderr=sys.stderr) |
| 262 | 285 |
| 263 # Start the 2nd recording a little later to ensure the 1st one has started. | 286 # Start the 2nd recording a little later to ensure the 1st one has started. |
| 264 # TODO(jansson) Check that the ref_recorder output file exists rather than | 287 # TODO(jansson) Check that the ref_recorder output file exists rather than |
| 265 # using sleep. | 288 # using sleep. |
| 266 time.sleep(options.time_between_recordings) | 289 time.sleep(options.time_between_recordings) |
| 267 print 'Trying to record from test recorder...' | 290 print 'Trying to record from test recorder...' |
| 268 test_recorder = subprocess.Popen(test_cmd, stderr=sys.stderr) | 291 test_recorder = subprocess.Popen(test_cmd, stderr=sys.stderr) |
| 269 test_recorder.wait() | 292 test_recorder.wait() |
| 270 ref_recorder.wait() | 293 ref_recorder.wait() |
| 271 | 294 |
| 272 # ffmpeg does not abort when it fails, need to check return code. | 295 # ffmpeg does not abort when it fails, need to check return code. |
| 273 assert ref_recorder.returncode == 0, ( | 296 if ref_recorder.returncode != 0 or test_recorder.returncode != 0: |
| 274 'Ref recording failed, check ffmpeg output and device: %s' | 297 # Cleanup recording directories. |
| 275 % options.ref_video_device) | 298 shutil.rmtree(ref_file_location) |
| 276 assert test_recorder.returncode == 0, ( | 299 shutil.rmtree(test_file_location) |
| 277 'Test recording failed, check ffmpeg output and device: %s' | 300 raise FfmpegError('Recording failed, check ffmpeg output.') |
| 278 % options.test_video_device) | 301 else: |
| 279 | 302 print 'Ref file recorded to: ' + os.path.abspath(ref_file) |
| 280 print 'Ref file recorded to: ' + os.path.abspath(ref_file_location) | 303 print 'Test file recorded to: ' + os.path.abspath(test_file) |
| 281 print 'Test file recorded to: ' + os.path.abspath(test_file_location) | 304 print 'Recording done!\n' |
| 282 print 'Recording done!\n' | 305 return FlipAndCropRecordings(options, test_file_name, test_file_location, |
| 283 return FlipAndCropRecordings(options, test_file_name, | 306 ref_file_name, ref_file_location) |
| 284 record_paths['test_rec_location'], ref_file_name, | |
| 285 record_paths['ref_rec_location']) | |
| 286 | 307 |
| 287 | 308 |
| 288 def FlipAndCropRecordings(options, test_file_name, test_file_location, | 309 def FlipAndCropRecordings(options, test_file_name, test_file_location, |
| 289 ref_file_name, ref_file_location): | 310 ref_file_name, ref_file_location): |
| 290 """Performs a horizontal flip of the reference video to match the test video. | 311 """Performs a horizontal flip of the reference video to match the test video. |
| 291 | 312 |
| 292 This is done to the match orientation and then crops the ref and test videos | 313 This is done to the match orientation and then crops the ref and test videos |
| 293 using the options.test_crop_parameters and options.ref_crop_parameters. | 314 using the options.test_crop_parameters and options.ref_crop_parameters. |
| 294 | 315 |
| 295 Args: | 316 Args: |
| 296 options(object): Contains all the provided command line options. | 317 options(object): Contains all the provided command line options. |
| 297 test_file_name(string): Name of the test video file recording. | 318 test_file_name(string): Name of the test video file recording. |
| 298 test_file_location(string): Path to the test video file recording. | 319 test_file_location(string): Path to the test video file recording. |
| 299 ref_file_name(string): Name of the reference video file recording. | 320 ref_file_name(string): Name of the reference video file recording. |
| 300 ref_file_location(string): Path to the reference video file recording. | 321 ref_file_location(string): Path to the reference video file recording. |
| 301 Return: | 322 |
| 323 Returns: | |
| 302 recording_files_and_time(dict): key: value pair with the path to cropped | 324 recording_files_and_time(dict): key: value pair with the path to cropped |
| 303 test and reference video files. | 325 test and reference video files. |
| 326 | |
| 327 Raises: | |
| 328 FfmpegError: If the ffmpeg command fails. | |
| 304 """ | 329 """ |
| 305 print 'Trying to crop videos...' | 330 print 'Trying to crop videos...' |
| 306 | 331 |
| 307 # Ref file cropping. | 332 # Ref file cropping. |
| 308 cropped_ref_file_name = 'cropped_' + ref_file_name | 333 cropped_ref_file_name = 'cropped_' + ref_file_name |
| 309 cropped_ref_file = os.path.abspath( | 334 cropped_ref_file = os.path.abspath( |
| 310 os.path.join(ref_file_location, cropped_ref_file_name)) | 335 os.path.join(ref_file_location, cropped_ref_file_name)) |
| 311 | 336 |
| 312 ref_video_crop_cmd = [ | 337 ref_video_crop_cmd = [ |
| 313 options.ffmpeg, | 338 options.ffmpeg, |
| (...skipping 15 matching lines...) Expand all Loading... | |
| 329 '-v', 'error', | 354 '-v', 'error', |
| 330 '-s', options.frame_width + 'x' + options.frame_height, | 355 '-s', options.frame_width + 'x' + options.frame_height, |
| 331 '-i', os.path.join(test_file_location, test_file_name), | 356 '-i', os.path.join(test_file_location, test_file_name), |
| 332 '-vf', options.test_crop_parameters, | 357 '-vf', options.test_crop_parameters, |
| 333 '-c:a', 'copy', | 358 '-c:a', 'copy', |
| 334 cropped_test_file | 359 cropped_test_file |
| 335 ] | 360 ] |
| 336 | 361 |
| 337 ref_crop = subprocess.Popen(ref_video_crop_cmd) | 362 ref_crop = subprocess.Popen(ref_video_crop_cmd) |
| 338 ref_crop.wait() | 363 ref_crop.wait() |
| 339 print 'Ref file cropped to: ' + cropped_ref_file | 364 test_crop = subprocess.Popen(test_video_crop_cmd) |
| 365 test_crop.wait() | |
| 340 | 366 |
| 341 try: | 367 # ffmpeg does not abort when it fails, need to check return code. |
| 342 test_crop = subprocess.Popen(test_video_crop_cmd) | 368 if ref_crop.returncode != 0 or test_crop.returncode != 0: |
| 343 test_crop.wait() | 369 # Cleanup recording directories. |
| 370 shutil.rmtree(ref_file_location) | |
| 371 shutil.rmtree(test_file_location) | |
| 372 raise FfmpegError('Cropping failed, check ffmpeg output.') | |
| 373 else: | |
| 374 print 'Ref file cropped to: ' + cropped_ref_file | |
| 344 print 'Test file cropped to: ' + cropped_test_file | 375 print 'Test file cropped to: ' + cropped_test_file |
| 345 print 'Cropping done!\n' | 376 print 'Cropping done!\n' |
| 346 | 377 |
| 347 # Need to return these so they can be used by other parts. | 378 # Need to return these so they can be used by other parts. |
| 348 cropped_recordings = { | 379 cropped_recordings = { |
| 349 'cropped_test_file' : cropped_test_file, | 380 'cropped_test_file' : cropped_test_file, |
| 350 'cropped_ref_file' : cropped_ref_file | 381 'cropped_ref_file' : cropped_ref_file |
| 351 } | 382 } |
| 352 | |
| 353 return cropped_recordings | 383 return cropped_recordings |
| 354 except subprocess.CalledProcessError as e: | |
| 355 print 'Something went wrong during cropping: ' + e | |
| 356 raise | |
| 357 | 384 |
| 358 | 385 |
| 359 def CompareVideos(options, recording_result): | 386 def CompareVideos(options, cropped_ref_file, cropped_test_file): |
| 360 """Runs the compare_video.py script from src/webrtc/tools using the file path. | 387 """Runs the compare_video.py script from src/webrtc/tools using the file path. |
| 361 | 388 |
| 362 Uses the path from recording_result and writes the output to a file named | 389 Uses the path from recording_result and writes the output to a file named |
| 363 <options.app_name + '_' + CURRENT_TIME + '_result.txt> in the reference video | 390 <options.app_name + '_' + CURRENT_TIME + '_result.txt> in the reference video |
| 364 recording folder taken from recording_result. | 391 recording folder taken from recording_result. |
| 365 | 392 |
| 366 Args: | 393 Args: |
| 367 options(object): Contains all the provided command line options. | 394 options(object): Contains all the provided command line options. |
| 368 recording_files_and_time(dict): key: value pair with the path to cropped | 395 cropped_ref_file(string): Path to cropped reference video file. |
| 369 test and reference video files | 396 cropped_test_file(string): Path to cropped test video file. |
| 397 | |
| 398 Raises: | |
| 399 CompareVideosError: If compare_videos.py fails. | |
| 370 """ | 400 """ |
| 371 print 'Starting comparison...' | 401 print 'Starting comparison...' |
| 372 print 'Grab a coffee, this might take a few minutes...' | 402 print 'Grab a coffee, this might take a few minutes...' |
| 373 cropped_ref_file = recording_result['cropped_ref_file'] | |
| 374 cropped_test_file = recording_result['cropped_test_file'] | |
| 375 compare_videos_script = os.path.abspath(options.compare_videos_script) | 403 compare_videos_script = os.path.abspath(options.compare_videos_script) |
| 376 rec_path = os.path.abspath(os.path.join( | 404 rec_path = os.path.abspath(os.path.join( |
| 377 os.path.dirname(recording_result['cropped_ref_file']))) | 405 os.path.dirname(cropped_test_file))) |
| 378 result_file_name = os.path.join(rec_path, '%s_%s_result.txt') % ( | 406 result_file_name = os.path.join(rec_path, '%s_%s_result.txt') % ( |
| 379 options.app_name, CURRENT_TIME) | 407 options.app_name, CURRENT_TIME) |
| 380 | 408 |
| 381 # Find the crop dimensions (950 and 420) in the ref crop parameter string: | 409 # Find the crop dimensions (e.g. 950 and 420) in the ref crop parameter |
| 382 # 'hflip, crop=950:420:130:56' | 410 # string: 'hflip, crop=950:420:130:56' |
| 383 for param in options.ref_crop_parameters.split('crop'): | 411 for param in options.ref_crop_parameters.split('crop'): |
| 384 if param[0] == '=': | 412 if param[0] == '=': |
| 385 crop_width = param.split(':')[0].split('=')[1] | 413 crop_width = param.split(':')[0].split('=')[1] |
| 386 crop_height = param.split(':')[1] | 414 crop_height = param.split(':')[1] |
| 387 | 415 |
| 388 compare_cmd = [ | 416 compare_cmd = [ |
| 389 sys.executable, | 417 sys.executable, |
| 390 compare_videos_script, | 418 compare_videos_script, |
| 391 '--ref_video', cropped_ref_file, | 419 '--ref_video', cropped_ref_file, |
| 392 '--test_video', cropped_test_file, | 420 '--test_video', cropped_test_file, |
| 393 '--frame_analyzer', os.path.abspath(options.frame_analyzer), | 421 '--frame_analyzer', os.path.abspath(options.frame_analyzer), |
| 394 '--zxing_path', options.zxing_path, | 422 '--zxing_path', options.zxing_path, |
| 395 '--ffmpeg_path', options.ffmpeg, | 423 '--ffmpeg_path', options.ffmpeg, |
| 396 '--stats_file_ref', os.path.join(os.path.dirname(cropped_ref_file), | 424 '--stats_file_ref', os.path.join(os.path.dirname(cropped_ref_file), |
| 397 cropped_ref_file + '_stats.txt'), | 425 cropped_ref_file + '_stats.txt'), |
| 398 '--stats_file_test', os.path.join(os.path.dirname(cropped_test_file), | 426 '--stats_file_test', os.path.join(os.path.dirname(cropped_test_file), |
| 399 cropped_test_file + '_stats.txt'), | 427 cropped_test_file + '_stats.txt'), |
| 400 '--yuv_frame_height', crop_height, | 428 '--yuv_frame_height', crop_height, |
| 401 '--yuv_frame_width', crop_width | 429 '--yuv_frame_width', crop_width |
| 402 ] | 430 ] |
| 403 | 431 |
| 404 try: | 432 with open(result_file_name, 'w') as f: |
| 405 with open(result_file_name, 'w') as f: | 433 compare_video_recordings = subprocess.Popen(compare_cmd, stdout=f) |
| 406 compare_video_recordings = subprocess.Popen(compare_cmd, stdout=f) | 434 compare_video_recordings.wait() |
| 407 compare_video_recordings.wait() | 435 if compare_video_recordings.returncode != 0: |
| 408 print 'Result recorded to: ' + os.path.abspath(result_file_name) | 436 raise CompareVideosError('Failed to perform comparison.') |
| 409 print 'Comparison done!' | 437 else: |
| 410 except subprocess.CalledProcessError as e: | 438 print 'Result recorded to: ' + os.path.abspath(result_file_name) |
| 411 print 'Something went wrong when trying to compare videos: ' + e | 439 print 'Comparison done!' |
| 412 raise | |
| 413 | 440 |
| 414 | 441 |
| 415 def main(): | 442 def main(): |
| 416 """The main function. | 443 """The main function. |
| 417 | 444 |
| 418 A simple invocation is: | 445 A simple invocation is: |
| 419 ./run_video_analysis.py \ | 446 ./run_video_analysis.py \ |
| 420 --app_name AppRTCMobile \ | 447 --app_name AppRTCMobile \ |
| 421 --ffmpeg ./ffmpeg --ref_video_device=/dev/video0 \ | 448 --ffmpeg ./ffmpeg --ref_video_device=/dev/video0 \ |
| 422 --test_video_device=/dev/video1 \ | 449 --test_video_device=/dev/video1 \ |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 435 /tmp/ref/cropped_AppRTCMobile_<recording date and time>_ref.yuv | 462 /tmp/ref/cropped_AppRTCMobile_<recording date and time>_ref.yuv |
| 436 /tmp/test/cropped_AppRTCMobile_<recording date and time>_ref.yuv | 463 /tmp/test/cropped_AppRTCMobile_<recording date and time>_ref.yuv |
| 437 | 464 |
| 438 # Comparison metrics from cropped test and ref videos. | 465 # Comparison metrics from cropped test and ref videos. |
| 439 /tmp/test/AppRTCMobile_<recording date and time>_result.text | 466 /tmp/test/AppRTCMobile_<recording date and time>_result.text |
| 440 | 467 |
| 441 """ | 468 """ |
| 442 options = _ParseArgs() | 469 options = _ParseArgs() |
| 443 RestartMagewellDevices(options.ref_video_device, options.test_video_device) | 470 RestartMagewellDevices(options.ref_video_device, options.test_video_device) |
| 444 record_paths = CreateRecordingDirs(options) | 471 record_paths = CreateRecordingDirs(options) |
| 445 recording_result = StartRecording(options, record_paths) | 472 recording_result = StartRecording(options, record_paths['ref_rec_location'], |
| 473 record_paths['test_rec_location']) | |
| 446 | 474 |
| 447 # Do not require compare_video.py script to run, no metrics will be generated. | 475 # Do not require compare_video.py script to run, no metrics will be generated. |
| 448 if options.compare_videos_script: | 476 if options.compare_videos_script: |
| 449 CompareVideos(options, recording_result) | 477 CompareVideos(options, recording_result['cropped_ref_file'], |
| 478 recording_result['cropped_test_file']) | |
| 450 else: | 479 else: |
| 451 print ('Skipping compare videos step due to compare_videos flag were not ' | 480 print ('Skipping compare videos step due to compare_videos flag were not ' |
| 452 'passed.') | 481 'passed.') |
| 453 | 482 |
| 454 | 483 |
| 455 if __name__ == '__main__': | 484 if __name__ == '__main__': |
| 456 sys.exit(main()) | 485 sys.exit(main()) |
| OLD | NEW |