summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/rtc_tools/compare_videos.py
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/rtc_tools/compare_videos.py')
-rwxr-xr-xthird_party/libwebrtc/rtc_tools/compare_videos.py210
1 files changed, 210 insertions, 0 deletions
diff --git a/third_party/libwebrtc/rtc_tools/compare_videos.py b/third_party/libwebrtc/rtc_tools/compare_videos.py
new file mode 100755
index 0000000000..a54eb42979
--- /dev/null
+++ b/third_party/libwebrtc/rtc_tools/compare_videos.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+# Copyright (c) 2013 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.
+
+from __future__ import absolute_import
+from __future__ import division
+from __future__ import print_function
+import json
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+
+SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
+
+# Chrome browsertests will throw away stderr; avoid that output gets lost.
+sys.stderr = sys.stdout
+
+
+def _ParseArgs():
+ """Registers the command-line options."""
+ usage = 'usage: %prog [options]'
+ parser = optparse.OptionParser(usage=usage)
+
+ parser.add_option('--label',
+ type='string',
+ default='MY_TEST',
+ help=('Label of the test, used to identify different '
+ 'tests. Default: %default'))
+ parser.add_option('--ref_video',
+ type='string',
+ help='Reference video to compare with (YUV).')
+ parser.add_option('--test_video',
+ type='string',
+ help=('Test video to be compared with the reference '
+ 'video (YUV).'))
+ parser.add_option('--frame_analyzer',
+ type='string',
+ help='Path to the frame analyzer executable.')
+ parser.add_option('--aligned_output_file',
+ type='string',
+ help='Path for output aligned YUV or Y4M file.')
+ parser.add_option('--vmaf', type='string', help='Path to VMAF executable.')
+ parser.add_option('--vmaf_model',
+ type='string',
+ help='Path to VMAF model.')
+ parser.add_option('--vmaf_phone_model',
+ action='store_true',
+ help='Whether to use phone model in VMAF.')
+ parser.add_option(
+ '--yuv_frame_width',
+ type='int',
+ default=640,
+ help='Width of the YUV file\'s frames. Default: %default')
+ parser.add_option(
+ '--yuv_frame_height',
+ type='int',
+ default=480,
+ help='Height of the YUV file\'s frames. Default: %default')
+ parser.add_option('--chartjson_result_file',
+ type='str',
+ default=None,
+ help='Where to store perf results in chartjson format.')
+ options, _ = parser.parse_args()
+
+ if not options.ref_video:
+ parser.error('You must provide a path to the reference video!')
+ if not os.path.exists(options.ref_video):
+ parser.error('Cannot find the reference video at %s' %
+ options.ref_video)
+
+ if not options.test_video:
+ parser.error('You must provide a path to the test video!')
+ if not os.path.exists(options.test_video):
+ parser.error('Cannot find the test video at %s' % options.test_video)
+
+ if not options.frame_analyzer:
+ parser.error(
+ 'You must provide the path to the frame analyzer executable!')
+ if not os.path.exists(options.frame_analyzer):
+ parser.error('Cannot find frame analyzer executable at %s!' %
+ options.frame_analyzer)
+
+ if options.vmaf and not options.vmaf_model:
+ parser.error('You must provide a path to a VMAF model to use VMAF.')
+
+ return options
+
+
+def _DevNull():
+ """On Windows, sometimes the inherited stdin handle from the parent process
+ fails. Workaround this by passing null to stdin to the subprocesses commands.
+ This function can be used to create the null file handler.
+ """
+ return open(os.devnull, 'r')
+
+
+def _RunFrameAnalyzer(options, yuv_directory=None):
+ """Run frame analyzer to compare the videos and print output."""
+ cmd = [
+ options.frame_analyzer,
+ '--label=%s' % options.label,
+ '--reference_file=%s' % options.ref_video,
+ '--test_file=%s' % options.test_video,
+ '--width=%d' % options.yuv_frame_width,
+ '--height=%d' % options.yuv_frame_height,
+ ]
+ if options.chartjson_result_file:
+ cmd.append('--chartjson_result_file=%s' %
+ options.chartjson_result_file)
+ if options.aligned_output_file:
+ cmd.append('--aligned_output_file=%s' % options.aligned_output_file)
+ if yuv_directory:
+ cmd.append('--yuv_directory=%s' % yuv_directory)
+ frame_analyzer = subprocess.Popen(cmd,
+ stdin=_DevNull(),
+ stdout=sys.stdout,
+ stderr=sys.stderr)
+ frame_analyzer.wait()
+ if frame_analyzer.returncode != 0:
+ print('Failed to run frame analyzer.')
+ return frame_analyzer.returncode
+
+
+def _RunVmaf(options, yuv_directory, logfile):
+ """ Run VMAF to compare videos and print output.
+
+ The yuv_directory is assumed to have been populated with a reference and test
+ video in .yuv format, with names according to the label.
+ """
+ cmd = [
+ options.vmaf,
+ 'yuv420p',
+ str(options.yuv_frame_width),
+ str(options.yuv_frame_height),
+ os.path.join(yuv_directory, "ref.yuv"),
+ os.path.join(yuv_directory, "test.yuv"),
+ options.vmaf_model,
+ '--log',
+ logfile,
+ '--log-fmt',
+ 'json',
+ ]
+ if options.vmaf_phone_model:
+ cmd.append('--phone-model')
+
+ vmaf = subprocess.Popen(cmd,
+ stdin=_DevNull(),
+ stdout=sys.stdout,
+ stderr=sys.stderr)
+ vmaf.wait()
+ if vmaf.returncode != 0:
+ print('Failed to run VMAF.')
+ return 1
+
+ # Read per-frame scores from VMAF output and print.
+ with open(logfile) as f:
+ vmaf_data = json.load(f)
+ vmaf_scores = []
+ for frame in vmaf_data['frames']:
+ vmaf_scores.append(frame['metrics']['vmaf'])
+ print('RESULT VMAF: %s=' % options.label, vmaf_scores)
+
+ return 0
+
+
+def main():
+ """The main function.
+
+ A simple invocation is:
+ ./webrtc/rtc_tools/compare_videos.py
+ --ref_video=<path_and_name_of_reference_video>
+ --test_video=<path_and_name_of_test_video>
+ --frame_analyzer=<path_and_name_of_the_frame_analyzer_executable>
+
+ Running vmaf requires the following arguments:
+ --vmaf, --vmaf_model, --yuv_frame_width, --yuv_frame_height
+ """
+ options = _ParseArgs()
+
+ if options.vmaf:
+ try:
+ # Directory to save temporary YUV files for VMAF in frame_analyzer.
+ yuv_directory = tempfile.mkdtemp()
+ _, vmaf_logfile = tempfile.mkstemp()
+
+ # Run frame analyzer to compare the videos and print output.
+ if _RunFrameAnalyzer(options, yuv_directory=yuv_directory) != 0:
+ return 1
+
+ # Run VMAF for further video comparison and print output.
+ return _RunVmaf(options, yuv_directory, vmaf_logfile)
+ finally:
+ shutil.rmtree(yuv_directory)
+ os.remove(vmaf_logfile)
+ else:
+ return _RunFrameAnalyzer(options)
+
+ return 0
+
+
+if __name__ == '__main__':
+ sys.exit(main())