Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(29)

Unified Diff: webrtc/tools/run_video_analysis.py

Issue 2789533002: Improve USB device reset logic (Closed)
Patch Set: fix test Created 3 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « PRESUBMIT.py ('k') | webrtc/tools/video_analysis.py » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: webrtc/tools/run_video_analysis.py
diff --git a/webrtc/tools/run_video_analysis.py b/webrtc/tools/run_video_analysis.py
deleted file mode 100755
index 29682aa02917779742ececaca52b0662a6d80546..0000000000000000000000000000000000000000
--- a/webrtc/tools/run_video_analysis.py
+++ /dev/null
@@ -1,484 +0,0 @@
-#!/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
-import shutil
-
-# Used to time-stamp output files and directories
-CURRENT_TIME = time.strftime("%d_%m_%Y-%H:%M:%S")
-
-
-class Error(Exception):
- pass
-
-
-class FfmpegError(Error):
- pass
-
-
-class MagewellError(Error):
- pass
-
-
-class CompareVideosError(Error):
- pass
-
-
-def _ParseArgs():
- """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('--time_between_recordings', type=float, default=5,
- help='Time between starting test recording after ref.'
- '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('--ffmpeg', type='string',
- help='Path to the ffmpeg executable for the reference '
- '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_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')
- parser.add_option('--test_crop_parameters', type='string',
- help='ffmpeg processing parameters for the test video.')
- parser.add_option('--ref_crop_parameters', type='string',
- help='ffmpeg processing parameters for the ref video.')
-
- options, _ = parser.parse_args()
-
- if not options.app_name:
- parser.error('You must provide an application name!')
-
- if not options.test_crop_parameters or not options.ref_crop_parameters:
- parser.error('You must provide ref and test crop parameters!')
-
- # Ensure the crop filter is included in the crop parameters used for ffmpeg.
- if 'crop' not in options.ref_crop_parameters:
- parser.error('You must provide a reference crop filter for ffmpeg.')
- if 'crop' not in options.test_crop_parameters:
- parser.error('You must provide a test crop filter for ffmpeg.')
-
- if not options.ffmpeg:
- parser.error('You most provide location for the ffmpeg executable.')
- if not os.path.isfile(options.ffmpeg):
- parser.error('Cannot find the ffmpeg executable.')
-
- # compare_videos.py dependencies.
- if not os.path.isfile(options.compare_videos_script):
- parser.warning('Cannot find compare_videos.py script, no metrics will be '
- 'generated!')
- if not os.path.isfile(options.frame_analyzer):
- parser.warning('Cannot find frame_analyzer, no metrics will be generated!')
- if not os.path.isfile(options.zxing_path):
- parser.warning('Cannot find Zebra Xing, no metrics will be generated!')
-
- return options
-
-
-def CreateRecordingDirs(options):
- """Create root + sub directories for reference and test recordings.
-
- Args:
- options(object): Contains all the provided command line options.
-
- Returns:
- record_paths(dict): key: value pair with reference and test file
- absolute paths.
- """
-
- # Create root directories for the video recordings.
- if not os.path.isdir(options.ref_rec_dir):
- os.makedirs(options.ref_rec_dir)
- if not os.path.isdir(options.test_rec_dir):
- os.makedirs(options.test_rec_dir)
-
- # Create and time-stamp directories for all the output files.
- 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 RestartMagewellDevices(ref_video_device, test_video_device):
- """Reset the USB ports where Magewell capture devices are connected to.
-
- Tries to find the provided ref_video_device and 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 :
- ref_video_device(string): reference recording device path.
- test_video_device(string): test recording device path
-
- Raises:
- MagewellError: If no magewell devices are found.
- """
-
- # Get the dev/videoN device name from the command line arguments.
- ref_magewell = ref_video_device.split('/')[2]
- test_magewell = test_video_device.split('/')[2]
-
- # Find the device location including USB and USB Bus ID's.
- device_string = '/sys/bus/usb/devices/usb*/**/**/video4linux/'
- ref_magewell_device = glob.glob('%s%s' % (device_string, ref_magewell))
- test_magewell_device = glob.glob('%s%s' % (device_string, 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)
-
- # Abort early if no devices are found.
- if len(magewell_usb_ports) == 0:
- raise MagewellError('No magewell devices found.')
- else:
- 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).
- 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']
-
- # 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.wait()
-
- echo_bind = subprocess.Popen(echo_cmd, stdout=subprocess.PIPE)
- bind = subprocess.Popen(bind_cmd, stdin=echo_bind.stdout)
- echo_bind.stdout.close()
- bind.wait()
- if bind.returncode == 0:
- print 'Reset done!\n'
-
-
-def StartRecording(options, ref_file_location, test_file_location):
- """Starts recording from the two specified video devices.
-
- Args:
- options(object): Contains all the provided command line options.
- record_paths(dict): key: value pair with reference and test file
- absolute paths.
-
- Returns:
- recording_files_and_time(dict): key: value pair with the path to cropped
- test and reference video files.
-
- Raises:
- FfmpegError: If the ffmpeg command fails.
- """
- ref_file_name = '%s_%s_ref.%s' % (options.app_name, CURRENT_TIME,
- options.video_container)
- ref_file = os.path.join(ref_file_location, ref_file_name)
-
- test_file_name = '%s_%s_test.%s' % (options.app_name, CURRENT_TIME,
- options.video_container)
- test_file = os.path.join(test_file_location, test_file_name)
-
- # Reference video recorder command line.
- ref_cmd = [
- options.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
- ]
-
- # Test video recorder command line.
- test_cmd = [
- options.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
- ]
- print 'Trying to record from reference recorder...'
- ref_recorder = subprocess.Popen(ref_cmd, stderr=sys.stderr)
-
- # 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(options.time_between_recordings)
- print 'Trying to record from test recorder...'
- test_recorder = subprocess.Popen(test_cmd, stderr=sys.stderr)
- test_recorder.wait()
- ref_recorder.wait()
-
- # ffmpeg does not abort when it fails, need to check return code.
- if ref_recorder.returncode != 0 or test_recorder.returncode != 0:
- # Cleanup recording directories.
- shutil.rmtree(ref_file_location)
- shutil.rmtree(test_file_location)
- raise FfmpegError('Recording failed, check ffmpeg output.')
- else:
- print 'Ref file recorded to: ' + os.path.abspath(ref_file)
- print 'Test file recorded to: ' + os.path.abspath(test_file)
- print 'Recording done!\n'
- return FlipAndCropRecordings(options, test_file_name, test_file_location,
- ref_file_name, ref_file_location)
-
-
-def FlipAndCropRecordings(options, test_file_name, test_file_location,
- ref_file_name, ref_file_location):
- """Performs a horizontal flip of the reference video to match the test video.
-
- This is done to the match orientation and then crops the ref and test videos
- using the options.test_crop_parameters and options.ref_crop_parameters.
-
- 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.
-
- Returns:
- recording_files_and_time(dict): key: value pair with the path to cropped
- test and reference video files.
-
- Raises:
- FfmpegError: If the ffmpeg command fails.
- """
- print 'Trying to crop videos...'
-
- # Ref file cropping.
- cropped_ref_file_name = 'cropped_' + ref_file_name
- cropped_ref_file = os.path.abspath(
- os.path.join(ref_file_location, cropped_ref_file_name))
-
- ref_video_crop_cmd = [
- options.ffmpeg,
- '-v', 'error',
- '-s', options.frame_width + 'x' + options.frame_height,
- '-i', os.path.join(ref_file_location, ref_file_name),
- '-vf', options.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_video_crop_cmd = [
- options.ffmpeg,
- '-v', 'error',
- '-s', options.frame_width + 'x' + options.frame_height,
- '-i', os.path.join(test_file_location, test_file_name),
- '-vf', options.test_crop_parameters,
- '-c:a', 'copy',
- cropped_test_file
- ]
-
- ref_crop = subprocess.Popen(ref_video_crop_cmd)
- ref_crop.wait()
- test_crop = subprocess.Popen(test_video_crop_cmd)
- test_crop.wait()
-
- # ffmpeg does not abort when it fails, need to check return code.
- if ref_crop.returncode != 0 or test_crop.returncode != 0:
- # Cleanup recording directories.
- shutil.rmtree(ref_file_location)
- shutil.rmtree(test_file_location)
- raise FfmpegError('Cropping failed, check ffmpeg output.')
- else:
- print 'Ref file cropped to: ' + cropped_ref_file
- 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
-
-
-def CompareVideos(options, cropped_ref_file, cropped_test_file):
- """Runs the compare_video.py script from src/webrtc/tools using the file path.
-
- Uses the path 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.
- cropped_ref_file(string): Path to cropped reference video file.
- cropped_test_file(string): Path to cropped test video file.
-
- Raises:
- CompareVideosError: If compare_videos.py fails.
- """
- print 'Starting comparison...'
- print 'Grab a coffee, this might take a few minutes...'
- compare_videos_script = os.path.abspath(options.compare_videos_script)
- rec_path = os.path.abspath(os.path.join(
- os.path.dirname(cropped_test_file)))
- result_file_name = os.path.join(rec_path, '%s_%s_result.txt') % (
- options.app_name, CURRENT_TIME)
-
- # Find the crop dimensions (e.g. 950 and 420) in the ref crop parameter
- # string: 'hflip, crop=950:420:130:56'
- for param in options.ref_crop_parameters.split('crop'):
- if param[0] == '=':
- crop_width = param.split(':')[0].split('=')[1]
- crop_height = param.split(':')[1]
-
- 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.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', crop_height,
- '--yuv_frame_width', crop_width
- ]
-
- with open(result_file_name, 'w') as f:
- compare_video_recordings = subprocess.Popen(compare_cmd, stdout=f)
- compare_video_recordings.wait()
- if compare_video_recordings.returncode != 0:
- raise CompareVideosError('Failed to perform comparison.')
- else:
- print 'Result recorded to: ' + os.path.abspath(result_file_name)
- print 'Comparison done!'
-
-
-def main():
- """The main function.
-
- A simple invocation is:
- ./run_video_analysis.py \
- --app_name AppRTCMobile \
- --ffmpeg ./ffmpeg --ref_video_device=/dev/video0 \
- --test_video_device=/dev/video1 \
- --zxing_path ./zxing \
- --test_crop_parameters 'crop=950:420:130:56' \
- --ref_crop_parameters 'hflip, crop=950:420:130: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()
- RestartMagewellDevices(options.ref_video_device, options.test_video_device)
- record_paths = CreateRecordingDirs(options)
- recording_result = StartRecording(options, record_paths['ref_rec_location'],
- record_paths['test_rec_location'])
-
- # Do not require compare_video.py script to run, no metrics will be generated.
- if options.compare_videos_script:
- CompareVideos(options, recording_result['cropped_ref_file'],
- recording_result['cropped_test_file'])
- else:
- print ('Skipping compare videos step due to compare_videos flag were not '
- 'passed.')
-
-
-if __name__ == '__main__':
- sys.exit(main())
« no previous file with comments | « PRESUBMIT.py ('k') | webrtc/tools/video_analysis.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698