
Speculatively fixes Chromium test for cut: crbug.com/877968 Reverts CLs: https://webrtc-review.googlesource.com/c/src/+/94772 https://webrtc-review.googlesource.com/c/src/+/95648 https://webrtc-review.googlesource.com/c/src/+/94773 https://webrtc-review.googlesource.com/c/src/+/96000 https://webrtc-review.googlesource.com/c/src/+/95949 Revert "Add Y4mFileReader" This reverts commit 404be7f302358e6be16aadeba8bc8f8aba348c0f. Revert "Remove SequencedTaskChecker from Y4mFileReader" This reverts commit 1b5e5db842971340eb9128985ddbaf0225a9d0b1. Revert "Add tool for aliging video files" This reverts commit b2c0e8f60fad10e2786e5e131136a0da1299d883. Revert "Reland "Update video_quality_analysis to align videos instead of using barcodes"" This reverts commit 9bb55fc09b6bfa00cba7779c37ad6c39b4206f7a. Revert "Fix a bug in barcode_decoder.py" This reverts commit 5c2de6b3ce079cff52c411a2c02ce6553a38dc79. TBR=magjed@webrtc.org, phoglund@webrtc.org, phensman@webrtc.org Bug: chromium:877968, webrtc:9642 Change-Id: I784d0598fd0370eec38d758b9fa0b38e4b3423be Reviewed-on: https://webrtc-review.googlesource.com/96320 Reviewed-by: Sami Kalliomäki <sakal@webrtc.org> Commit-Queue: Sami Kalliomäki <sakal@webrtc.org> Cr-Commit-Position: refs/heads/master@{#24458}
292 lines
10 KiB
Python
Executable File
292 lines
10 KiB
Python
Executable File
#!/usr/bin/env python
|
|
# Copyright (c) 2012 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 sys
|
|
|
|
if __name__ == '__main__':
|
|
# Make sure we always can import helper_functions.
|
|
sys.path.append(os.path.dirname(__file__))
|
|
|
|
import helper_functions
|
|
|
|
# Chrome browsertests will throw away stderr; avoid that output gets lost.
|
|
sys.stderr = sys.stdout
|
|
|
|
|
|
def ConvertYuvToPngFiles(yuv_file_name, yuv_frame_width, yuv_frame_height,
|
|
output_directory, ffmpeg_path):
|
|
"""Converts a YUV video file into PNG frames.
|
|
|
|
The function uses ffmpeg to convert the YUV file. The output of ffmpeg is in
|
|
the form frame_xxxx.png, where xxxx is the frame number, starting from 0001.
|
|
|
|
Args:
|
|
yuv_file_name(string): The name of the YUV file.
|
|
yuv_frame_width(int): The width of one YUV frame.
|
|
yuv_frame_height(int): The height of one YUV frame.
|
|
output_directory(string): The output directory where the PNG frames will be
|
|
stored.
|
|
ffmpeg_path(string): The path to the ffmpeg executable. If None, the PATH
|
|
will be searched for it.
|
|
|
|
Return:
|
|
(bool): True if the conversion was OK.
|
|
"""
|
|
size_string = str(yuv_frame_width) + 'x' + str(yuv_frame_height)
|
|
output_files_pattern = os.path.join(output_directory, 'frame_%04d.png')
|
|
if not ffmpeg_path:
|
|
ffmpeg_path = 'ffmpeg.exe' if sys.platform == 'win32' else 'ffmpeg'
|
|
command = [ffmpeg_path, '-s', '%s' % size_string, '-i', '%s'
|
|
% yuv_file_name, '-f', 'image2', '-vcodec', 'png',
|
|
'%s' % output_files_pattern]
|
|
try:
|
|
print 'Converting YUV file to PNG images (may take a while)...'
|
|
print ' '.join(command)
|
|
helper_functions.RunShellCommand(
|
|
command, fail_msg='Error during YUV to PNG conversion')
|
|
except helper_functions.HelperError, err:
|
|
print 'Error executing command: %s. Error: %s' % (command, err)
|
|
return False
|
|
except OSError:
|
|
print 'Did not find %s. Have you installed it?' % ffmpeg_path
|
|
return False
|
|
return True
|
|
|
|
|
|
def DecodeFrames(input_directory, zxing_path):
|
|
"""Decodes the barcodes overlaid in each frame.
|
|
|
|
The function uses the Zxing command-line tool from the Zxing C++ distribution
|
|
to decode the barcode in every PNG frame from the input directory. The frames
|
|
should be named frame_xxxx.png, where xxxx is the frame number. The frame
|
|
numbers should be consecutive and should start from 0001.
|
|
The decoding results in a frame_xxxx.txt file for every successfully decoded
|
|
barcode. This file contains the decoded barcode as 12-digit string (UPC-A
|
|
format: 11 digits content + one check digit).
|
|
|
|
Args:
|
|
input_directory(string): The input directory from where the PNG frames are
|
|
read.
|
|
zxing_path(string): The path to the zxing binary. If specified as None,
|
|
the PATH will be searched for it.
|
|
Return:
|
|
(bool): True if the decoding succeeded.
|
|
"""
|
|
if not zxing_path:
|
|
zxing_path = 'zxing.exe' if sys.platform == 'win32' else 'zxing'
|
|
print 'Decoding barcodes from PNG files with %s...' % zxing_path
|
|
return helper_functions.PerformActionOnAllFiles(
|
|
directory=input_directory, file_pattern='frame_',
|
|
file_extension='png', start_number=1, action=_DecodeBarcodeInFile,
|
|
command_line_decoder=zxing_path)
|
|
|
|
|
|
def _DecodeBarcodeInFile(file_name, command_line_decoder):
|
|
"""Decodes the barcode in the upper left corner of a PNG file.
|
|
|
|
Args:
|
|
file_name(string): File name of the PNG file.
|
|
command_line_decoder(string): The ZXing command-line decoding tool.
|
|
|
|
Return:
|
|
(bool): True upon success, False otherwise.
|
|
"""
|
|
command = [command_line_decoder, '--try-harder', '--dump-raw', file_name]
|
|
try:
|
|
out = helper_functions.RunShellCommand(
|
|
command, fail_msg='Error during decoding of %s' % file_name)
|
|
text_file = open('%s.txt' % file_name[:-4], 'w')
|
|
text_file.write(out)
|
|
text_file.close()
|
|
except helper_functions.HelperError, err:
|
|
print 'Barcode in %s cannot be decoded.' % file_name
|
|
print err
|
|
return False
|
|
except OSError:
|
|
print 'Did not find %s. Have you installed it?' % command_line_decoder
|
|
return False
|
|
return True
|
|
|
|
|
|
def _GenerateStatsFile(stats_file_name, input_directory='.'):
|
|
"""Generate statistics file.
|
|
|
|
The function generates a statistics file. The contents of the file are in the
|
|
format <frame_name> <barcode>, where frame name is the name of every frame
|
|
(effectively the frame number) and barcode is the decoded barcode. The frames
|
|
and the helper .txt files are removed after they have been used.
|
|
"""
|
|
file_prefix = os.path.join(input_directory, 'frame_')
|
|
stats_file = open(stats_file_name, 'w')
|
|
|
|
print 'Generating stats file: %s' % stats_file_name
|
|
for i in range(1, _CountFramesIn(input_directory=input_directory) + 1):
|
|
frame_number = helper_functions.ZeroPad(i)
|
|
barcode_file_name = file_prefix + frame_number + '.txt'
|
|
png_frame = file_prefix + frame_number + '.png'
|
|
entry_frame_number = helper_functions.ZeroPad(i-1)
|
|
entry = 'frame_' + entry_frame_number + ' '
|
|
|
|
if os.path.isfile(barcode_file_name):
|
|
barcode = _ReadBarcodeFromTextFile(barcode_file_name)
|
|
os.remove(barcode_file_name)
|
|
|
|
if _CheckBarcode(barcode):
|
|
entry += (helper_functions.ZeroPad(int(barcode[0:11])) + '\n')
|
|
else:
|
|
entry += 'Barcode error\n' # Barcode is wrongly detected.
|
|
else: # Barcode file doesn't exist.
|
|
entry += 'Barcode error\n'
|
|
|
|
stats_file.write(entry)
|
|
os.remove(png_frame)
|
|
|
|
stats_file.close()
|
|
|
|
|
|
def _ReadBarcodeFromTextFile(barcode_file_name):
|
|
"""Reads the decoded barcode for a .txt file.
|
|
|
|
Args:
|
|
barcode_file_name(string): The name of the .txt file.
|
|
Return:
|
|
(string): The decoded barcode.
|
|
"""
|
|
barcode_file = open(barcode_file_name, 'r')
|
|
barcode = barcode_file.read()
|
|
barcode_file.close()
|
|
return barcode
|
|
|
|
|
|
def _CheckBarcode(barcode):
|
|
"""Check weather the UPC-A barcode was decoded correctly.
|
|
|
|
This function calculates the check digit of the provided barcode and compares
|
|
it to the check digit that was decoded.
|
|
|
|
Args:
|
|
barcode(string): The barcode (12-digit).
|
|
Return:
|
|
(bool): True if the barcode was decoded correctly.
|
|
"""
|
|
if len(barcode) != 12:
|
|
return False
|
|
|
|
r1 = range(0, 11, 2) # Odd digits
|
|
r2 = range(1, 10, 2) # Even digits except last
|
|
dsum = 0
|
|
# Sum all the even digits
|
|
for i in r1:
|
|
dsum += int(barcode[i])
|
|
# Multiply the sum by 3
|
|
dsum *= 3
|
|
# Add all the even digits except the check digit (12th digit)
|
|
for i in r2:
|
|
dsum += int(barcode[i])
|
|
# Get the modulo 10
|
|
dsum = dsum % 10
|
|
# If not 0 substract from 10
|
|
if dsum != 0:
|
|
dsum = 10 - dsum
|
|
# Compare result and check digit
|
|
return dsum == int(barcode[11])
|
|
|
|
|
|
def _CountFramesIn(input_directory='.'):
|
|
"""Calculates the number of frames in the input directory.
|
|
|
|
The function calculates the number of frames in the input directory. The
|
|
frames should be named frame_xxxx.png, where xxxx is the number of the frame.
|
|
The numbers should start from 1 and should be consecutive.
|
|
|
|
Args:
|
|
input_directory(string): The input directory.
|
|
Return:
|
|
(int): The number of frames.
|
|
"""
|
|
file_prefix = os.path.join(input_directory, 'frame_')
|
|
file_exists = True
|
|
num = 1
|
|
|
|
while file_exists:
|
|
file_name = (file_prefix + helper_functions.ZeroPad(num) + '.png')
|
|
if os.path.isfile(file_name):
|
|
num += 1
|
|
else:
|
|
file_exists = False
|
|
return num - 1
|
|
|
|
|
|
def _ParseArgs():
|
|
"""Registers the command-line options."""
|
|
usage = "usage: %prog [options]"
|
|
parser = optparse.OptionParser(usage=usage)
|
|
|
|
parser.add_option('--zxing_path', type='string',
|
|
help=('The path to where the zxing executable is located. '
|
|
'If omitted, it will be assumed to be present in the '
|
|
'PATH with the name zxing[.exe].'))
|
|
parser.add_option('--ffmpeg_path', type='string',
|
|
help=('The path to where the ffmpeg executable is located. '
|
|
'If omitted, it will be assumed to be present in the '
|
|
'PATH with the name ffmpeg[.exe].'))
|
|
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('--yuv_file', type='string', default='output.yuv',
|
|
help='The YUV file to be decoded. Default: %default')
|
|
parser.add_option('--stats_file', type='string', default='stats.txt',
|
|
help='The output stats file. Default: %default')
|
|
parser.add_option('--png_working_dir', type='string', default='.',
|
|
help=('The directory for temporary PNG images to be stored '
|
|
'in when decoding from YUV before they\'re barcode '
|
|
'decoded. If using Windows and a Cygwin-compiled '
|
|
'zxing.exe, you should keep the default value to '
|
|
'avoid problems. Default: %default'))
|
|
options, _ = parser.parse_args()
|
|
return options
|
|
|
|
|
|
def main():
|
|
"""The main function.
|
|
|
|
A simple invocation is:
|
|
./webrtc/rtc_tools/barcode_tools/barcode_decoder.py
|
|
--yuv_file=<path_and_name_of_overlaid_yuv_video>
|
|
--yuv_frame_width=640 --yuv_frame_height=480
|
|
--stats_file=<path_and_name_to_stats_file>
|
|
"""
|
|
options = _ParseArgs()
|
|
|
|
# Convert the overlaid YUV video into a set of PNG frames.
|
|
if not ConvertYuvToPngFiles(options.yuv_file, options.yuv_frame_width,
|
|
options.yuv_frame_height,
|
|
output_directory=options.png_working_dir,
|
|
ffmpeg_path=options.ffmpeg_path):
|
|
print 'An error occurred converting from YUV to PNG frames.'
|
|
return -1
|
|
|
|
# Decode the barcodes from the PNG frames.
|
|
if not DecodeFrames(input_directory=options.png_working_dir,
|
|
zxing_path=options.zxing_path):
|
|
print 'An error occurred decoding barcodes from PNG frames.'
|
|
return -2
|
|
|
|
# Generate statistics file.
|
|
_GenerateStatsFile(options.stats_file,
|
|
input_directory=options.png_working_dir)
|
|
print 'Completed barcode decoding.'
|
|
return 0
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|