blob: 7a366686a40d43d959bb84c6082c4dd8702ee4f6 [file] [log] [blame]
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +00001#!/usr/bin/env python
2# Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3#
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
6# tree. An additional intellectual property rights grant can be found
7# in the file PATENTS. All contributing project authors may
8# be found in the AUTHORS file in the root of the source tree.
9
10import optparse
11import os
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000012import sys
13
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000014if __name__ == '__main__':
15 # Make sure we always can import helper_functions.
16 sys.path.append(os.path.dirname(__file__))
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000017
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000018import helper_functions
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000019
phoglund@webrtc.org84002462013-07-29 11:01:03 +000020# Chrome browsertests will throw away stderr; avoid that output gets lost.
21sys.stderr = sys.stdout
22
23
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000024def convert_yuv_to_png_files(yuv_file_name, yuv_frame_width, yuv_frame_height,
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000025 output_directory, ffmpeg_path):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000026 """Converts a YUV video file into PNG frames.
27
28 The function uses ffmpeg to convert the YUV file. The output of ffmpeg is in
29 the form frame_xxxx.png, where xxxx is the frame number, starting from 0001.
30
31 Args:
32 yuv_file_name(string): The name of the YUV file.
33 yuv_frame_width(int): The width of one YUV frame.
34 yuv_frame_height(int): The height of one YUV frame.
35 output_directory(string): The output directory where the PNG frames will be
36 stored.
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000037 ffmpeg_path(string): The path to the ffmpeg executable. If None, the PATH
38 will be searched for it.
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000039
40 Return:
41 (bool): True if the conversion was OK.
42 """
43 size_string = str(yuv_frame_width) + 'x' + str(yuv_frame_height)
44 output_files_pattern = os.path.join(output_directory, 'frame_%04d.png')
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000045 if not ffmpeg_path:
46 ffmpeg_path = 'ffmpeg.exe' if sys.platform == 'win32' else 'ffmpeg'
47 command = [ffmpeg_path, '-s', '%s' % size_string, '-i', '%s'
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000048 % yuv_file_name, '-f', 'image2', '-vcodec', 'png',
49 '%s' % output_files_pattern]
50 try:
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +000051 print 'Converting YUV file to PNG images (may take a while)...'
52 print ' '.join(command)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000053 helper_functions.run_shell_command(
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +000054 command, fail_msg='Error during YUV to PNG conversion')
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000055 except helper_functions.HelperError, err:
phoglund@webrtc.org84002462013-07-29 11:01:03 +000056 print 'Error executing command: %s. Error: %s' % (command, err)
57 return False
58 except OSError:
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000059 print ('Did not find %s. Have you installed it?' % ffmpeg_path)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000060 return False
61 return True
62
63
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000064def decode_frames(input_directory, zxing_path):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000065 """Decodes the barcodes overlaid in each frame.
66
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +000067 The function uses the Zxing command-line tool from the Zxing C++ distribution
68 to decode the barcode in every PNG frame from the input directory. The frames
69 should be named frame_xxxx.png, where xxxx is the frame number. The frame
70 numbers should be consecutive and should start from 0001.
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000071 The decoding results in a frame_xxxx.txt file for every successfully decoded
72 barcode. This file contains the decoded barcode as 12-digit string (UPC-A
73 format: 11 digits content + one check digit).
74
75 Args:
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000076 input_directory(string): The input directory from where the PNG frames are
77 read.
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000078 zxing_path(string): The path to the zxing binary. If specified as None,
79 the PATH will be searched for it.
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000080 Return:
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000081 (bool): True if the decoding succeeded.
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000082 """
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000083 if not zxing_path:
84 zxing_path = 'zxing.exe' if sys.platform == 'win32' else 'zxing'
85 print 'Decoding barcodes from PNG files with %s...' % zxing_path
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000086 return helper_functions.perform_action_on_all_files(
87 directory=input_directory, file_pattern='frame_',
88 file_extension='png', start_number=1, action=_decode_barcode_in_file,
phoglund@webrtc.org3260f102013-11-25 14:10:20 +000089 command_line_decoder=zxing_path)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000090
91
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +000092def _decode_barcode_in_file(file_name, command_line_decoder):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000093 """Decodes the barcode in the upper left corner of a PNG file.
94
95 Args:
96 file_name(string): File name of the PNG file.
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000097 command_line_decoder(string): The ZXing command-line decoding tool.
98
99 Return:
100 (bool): True upon success, False otherwise.
101 """
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000102 command = [command_line_decoder, '--try-harder', '--dump-raw', file_name]
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000103 try:
104 out = helper_functions.run_shell_command(
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000105 command, fail_msg='Error during decoding of %s' % file_name)
106 print 'Image %s : decoded barcode: %s' % (file_name, out)
107 text_file = open('%s.txt' % file_name[:-4], 'w')
108 text_file.write(out)
109 text_file.close()
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000110 except helper_functions.HelperError, err:
phoglund@webrtc.org84002462013-07-29 11:01:03 +0000111 print 'Barcode in %s cannot be decoded.' % file_name
112 print err
113 return False
114 except OSError:
115 print ('Did not find %s. Have you installed it?' % command_line_decoder)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000116 return False
117 return True
118
119
120def _generate_stats_file(stats_file_name, input_directory='.'):
121 """Generate statistics file.
122
123 The function generates a statistics file. The contents of the file are in the
124 format <frame_name> <barcode>, where frame name is the name of every frame
125 (effectively the frame number) and barcode is the decoded barcode. The frames
126 and the helper .txt files are removed after they have been used.
127 """
128 file_prefix = os.path.join(input_directory, 'frame_')
129 stats_file = open(stats_file_name, 'w')
130
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000131 print 'Generating stats file: %s' % stats_file_name
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000132 for i in range(1, _count_frames_in(input_directory=input_directory) + 1):
133 frame_number = helper_functions.zero_pad(i)
134 barcode_file_name = file_prefix + frame_number + '.txt'
135 png_frame = file_prefix + frame_number + '.png'
136 entry_frame_number = helper_functions.zero_pad(i-1)
137 entry = 'frame_' + entry_frame_number + ' '
138
139 if os.path.isfile(barcode_file_name):
140 barcode = _read_barcode_from_text_file(barcode_file_name)
vspasova@webrtc.org1b0a02e2012-08-30 12:56:38 +0000141 os.remove(barcode_file_name)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000142
143 if _check_barcode(barcode):
144 entry += (helper_functions.zero_pad(int(barcode[0:11])) + '\n')
145 else:
146 entry += 'Barcode error\n' # Barcode is wrongly detected.
147 else: # Barcode file doesn't exist.
148 entry += 'Barcode error\n'
149
150 stats_file.write(entry)
vspasova@webrtc.org1b0a02e2012-08-30 12:56:38 +0000151 os.remove(png_frame)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000152
153 stats_file.close()
154
155
156def _read_barcode_from_text_file(barcode_file_name):
157 """Reads the decoded barcode for a .txt file.
158
159 Args:
160 barcode_file_name(string): The name of the .txt file.
161 Return:
162 (string): The decoded barcode.
163 """
164 barcode_file = open(barcode_file_name, 'r')
165 barcode = barcode_file.read()
166 barcode_file.close()
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000167 return barcode
168
169
170def _check_barcode(barcode):
171 """Check weather the UPC-A barcode was decoded correctly.
172
173 This function calculates the check digit of the provided barcode and compares
174 it to the check digit that was decoded.
175
176 Args:
177 barcode(string): The barcode (12-digit).
178 Return:
179 (bool): True if the barcode was decoded correctly.
180 """
181 if len(barcode) != 12:
182 return False
183
184 r1 = range(0, 11, 2) # Odd digits
185 r2 = range(1, 10, 2) # Even digits except last
186 dsum = 0
187 # Sum all the even digits
188 for i in r1:
189 dsum += int(barcode[i])
190 # Multiply the sum by 3
191 dsum *= 3
192 # Add all the even digits except the check digit (12th digit)
193 for i in r2:
194 dsum += int(barcode[i])
195 # Get the modulo 10
196 dsum = dsum % 10
197 # If not 0 substract from 10
198 if dsum != 0:
199 dsum = 10 - dsum
200 # Compare result and check digit
201 return dsum == int(barcode[11])
202
203
204def _count_frames_in(input_directory = '.'):
205 """Calculates the number of frames in the input directory.
206
207 The function calculates the number of frames in the input directory. The
208 frames should be named frame_xxxx.png, where xxxx is the number of the frame.
209 The numbers should start from 1 and should be consecutive.
210
211 Args:
212 input_directory(string): The input directory.
213 Return:
214 (int): The number of frames.
215 """
216 file_prefix = os.path.join(input_directory, 'frame_')
217 file_exists = True
218 num = 1
219
220 while file_exists:
221 file_name = (file_prefix + helper_functions.zero_pad(num) + '.png')
222 if os.path.isfile(file_name):
223 num += 1
224 else:
225 file_exists = False
226 return num - 1
227
228
229def _parse_args():
230 """Registers the command-line options."""
231 usage = "usage: %prog [options]"
232 parser = optparse.OptionParser(usage=usage)
233
phoglund@webrtc.org3260f102013-11-25 14:10:20 +0000234 parser.add_option('--zxing_path', type='string',
235 help=('The path to where the zxing executable is located. '
236 'If omitted, it will be assumed to be present in the '
237 'PATH with the name zxing[.exe].'))
238 parser.add_option('--ffmpeg_path', type='string',
239 help=('The path to where the ffmpeg executable is located. '
240 'If omitted, it will be assumed to be present in the '
241 'PATH with the name ffmpeg[.exe].'))
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000242 parser.add_option('--yuv_frame_width', type='int', default=640,
243 help='Width of the YUV file\'s frames. Default: %default')
244 parser.add_option('--yuv_frame_height', type='int', default=480,
245 help='Height of the YUV file\'s frames. Default: %default')
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000246 parser.add_option('--yuv_file', type='string', default='output.yuv',
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000247 help='The YUV file to be decoded. Default: %default')
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000248 parser.add_option('--stats_file', type='string', default='stats.txt',
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000249 help='The output stats file. Default: %default')
250 parser.add_option('--png_working_dir', type='string', default='.',
251 help=('The directory for temporary PNG images to be stored '
252 'in when decoding from YUV before they\'re barcode '
253 'decoded. If using Windows and a Cygwin-compiled '
254 'zxing.exe, you should keep the default value to '
255 'avoid problems. Default: %default'))
256 options, _args = parser.parse_args()
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000257 return options
258
259
260def _main():
261 """The main function.
262
263 A simple invocation is:
kjellander@webrtc.orga6ff8452013-05-14 09:43:04 +0000264 ./webrtc/tools/barcode_tools/barcode_decoder.py
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000265 --yuv_file=<path_and_name_of_overlaid_yuv_video>
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000266 --yuv_frame_width=640 --yuv_frame_height=480
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000267 --stats_file=<path_and_name_to_stats_file>
268 """
269 options = _parse_args()
270
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000271 # Convert the overlaid YUV video into a set of PNG frames.
kjellander@webrtc.orgccb52c22012-10-10 16:11:28 +0000272 if not convert_yuv_to_png_files(options.yuv_file, options.yuv_frame_width,
273 options.yuv_frame_height,
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000274 output_directory=options.png_working_dir,
phoglund@webrtc.org3260f102013-11-25 14:10:20 +0000275 ffmpeg_path=options.ffmpeg_path):
phoglund@webrtc.org84002462013-07-29 11:01:03 +0000276 print 'An error occurred converting from YUV to PNG frames.'
kjellander@webrtc.orgccb52c22012-10-10 16:11:28 +0000277 return -1
278
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000279 # Decode the barcodes from the PNG frames.
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000280 if not decode_frames(input_directory=options.png_working_dir,
phoglund@webrtc.org3260f102013-11-25 14:10:20 +0000281 zxing_path=options.zxing_path):
phoglund@webrtc.org84002462013-07-29 11:01:03 +0000282 print 'An error occurred decoding barcodes from PNG frames.'
kjellander@webrtc.orgccb52c22012-10-10 16:11:28 +0000283 return -2
284
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000285 # Generate statistics file.
286 _generate_stats_file(options.stats_file,
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000287 input_directory=options.png_working_dir)
288 print 'Completed barcode decoding.'
kjellander@webrtc.orgccb52c22012-10-10 16:11:28 +0000289 return 0
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000290
291if __name__ == '__main__':
292 sys.exit(_main())