blob: c0400dfcccdc629db95699408e17d08c79362c4e [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
14import helper_functions
15
16_DEFAULT_BARCODE_WIDTH = 352
17_DEFAULT_BARCODES_FILE = 'barcodes.yuv'
18
19
kjellanderc88b5d52017-04-05 06:42:43 -070020def GenerateUpcaBarcodes(number_of_barcodes, barcode_width, barcode_height,
21 output_directory='.',
22 path_to_zxing='zxing-read-only'):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000023 """Generates UPC-A barcodes.
24
25 This function generates a number_of_barcodes UPC-A barcodes. The function
26 calls an example Java encoder from the Zxing library. The barcodes are
27 generated as PNG images. The width of the barcodes shouldn't be less than 102
28 pixels because otherwise Zxing can't properly generate the barcodes.
29
30 Args:
31 number_of_barcodes(int): The number of barcodes to generate.
32 barcode_width(int): Width of barcode in pixels.
33 barcode_height(int): Height of barcode in pixels.
34 output_directory(string): Output directory where to store generated
35 barcodes.
36 path_to_zxing(string): The path to Zxing.
37
38 Return:
39 (bool): True if the conversion is successful.
40 """
41 base_file_name = os.path.join(output_directory, "barcode_")
kjellanderc88b5d52017-04-05 06:42:43 -070042 jars = _FormJarsString(path_to_zxing)
phoglund@webrtc.org5d3713932013-03-07 09:59:43 +000043 command_line_encoder = 'com.google.zxing.client.j2se.CommandLineEncoder'
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000044 barcode_width = str(barcode_width)
45 barcode_height = str(barcode_height)
46
47 errors = False
48 for i in range(number_of_barcodes):
kjellanderc88b5d52017-04-05 06:42:43 -070049 suffix = helper_functions.ZeroPad(i)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000050 # Barcodes starting from 0
kjellanderc88b5d52017-04-05 06:42:43 -070051 content = helper_functions.ZeroPad(i, 11)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000052 output_file_name = base_file_name + suffix + ".png"
53
54 command = ["java", "-cp", jars, command_line_encoder,
55 "--barcode_format=UPC_A", "--height=%s" % barcode_height,
56 "--width=%s" % barcode_width,
57 "--output=%s" % (output_file_name), "%s" % (content)]
58 try:
kjellanderc88b5d52017-04-05 06:42:43 -070059 helper_functions.RunShellCommand(
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +000060 command, fail_msg=('Error during barcode %s generation' % content))
61 except helper_functions.HelperError as err:
kjellander@webrtc.orgccb52c22012-10-10 16:11:28 +000062 print >> sys.stderr, err
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000063 errors = True
64 return not errors
65
66
kjellanderc88b5d52017-04-05 06:42:43 -070067def ConvertPngToYuvBarcodes(input_directory='.', output_directory='.'):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000068 """Converts PNG barcodes to YUV barcode images.
69
70 This function reads all the PNG files from the input directory which are in
71 the format frame_xxxx.png, where xxxx is the number of the frame, starting
72 from 0000. The frames should be consecutive numbers. The output YUV file is
73 named frame_xxxx.yuv. The function uses ffmpeg to do the conversion.
74
75 Args:
76 input_directory(string): The input direcotry to read the PNG barcodes from.
77 output_directory(string): The putput directory to write the YUV files to.
78 Return:
79 (bool): True if the conversion was without errors.
80 """
kjellanderc88b5d52017-04-05 06:42:43 -070081 return helper_functions.PerformActionOnAllFiles(
82 input_directory, 'barcode_', 'png', 0, _ConvertToYuvAndDelete,
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000083 output_directory=output_directory, pattern='barcode_')
84
85
kjellanderc88b5d52017-04-05 06:42:43 -070086def _ConvertToYuvAndDelete(output_directory, file_name, pattern):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +000087 """Converts a PNG file to a YUV file and deletes the PNG file.
88
89 Args:
90 output_directory(string): The output directory for the YUV file.
91 file_name(string): The PNG file name.
92 pattern(string): The file pattern of the PNG/YUV file. The PNG/YUV files are
93 named patternxx..x.png/yuv, where xx..x are digits starting from 00..0.
94 Return:
95 (bool): True upon successful conversion, false otherwise.
96 """
97 # Pattern should be in file name
98 if not pattern in file_name:
99 return False
100 pattern_position = file_name.rfind(pattern)
101
102 # Strip the path to the PNG file and replace the png extension with yuv
103 yuv_file_name = file_name[pattern_position:-3] + 'yuv'
104 yuv_file_name = os.path.join(output_directory, yuv_file_name)
105
106 command = ['ffmpeg', '-i', '%s' % (file_name), '-pix_fmt', 'yuv420p',
107 '%s' % (yuv_file_name)]
108 try:
kjellanderc88b5d52017-04-05 06:42:43 -0700109 helper_functions.RunShellCommand(
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000110 command, fail_msg=('Error during PNG to YUV conversion of %s' %
111 file_name))
vspasova@webrtc.org1b0a02e2012-08-30 12:56:38 +0000112 os.remove(file_name)
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000113 except helper_functions.HelperError as err:
kjellander@webrtc.orgccb52c22012-10-10 16:11:28 +0000114 print >> sys.stderr, err
vspasova@webrtc.org1b0a02e2012-08-30 12:56:38 +0000115 return False
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000116 return True
117
118
kjellanderc88b5d52017-04-05 06:42:43 -0700119def CombineYuvFramesIntoOneFile(output_file_name, input_directory='.'):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000120 """Combines several YUV frames into one YUV video file.
121
122 The function combines the YUV frames from input_directory into one YUV video
123 file. The frames should be named in the format frame_xxxx.yuv where xxxx
124 stands for the frame number. The numbers have to be consecutive and start from
125 0000. The YUV frames are removed after they have been added to the video.
126
127 Args:
128 output_file_name(string): The name of the file to produce.
129 input_directory(string): The directory from which the YUV frames are read.
130 Return:
131 (bool): True if the frame stitching went OK.
132 """
133 output_file = open(output_file_name, "wb")
kjellanderc88b5d52017-04-05 06:42:43 -0700134 success = helper_functions.PerformActionOnAllFiles(
135 input_directory, 'barcode_', 'yuv', 0, _AddToFileAndDelete,
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000136 output_file=output_file)
137 output_file.close()
138 return success
139
kjellanderc88b5d52017-04-05 06:42:43 -0700140def _AddToFileAndDelete(output_file, file_name):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000141 """Adds the contents of a file to a previously opened file.
142
143 Args:
144 output_file(file): The ouput file, previously opened.
145 file_name(string): The file name of the file to add to the output file.
146
147 Return:
148 (bool): True if successful, False otherwise.
149 """
150 input_file = open(file_name, "rb")
151 input_file_contents = input_file.read()
152 output_file.write(input_file_contents)
153 input_file.close()
vspasova@webrtc.org1b0a02e2012-08-30 12:56:38 +0000154 try:
155 os.remove(file_name)
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000156 except OSError as e:
157 print >> sys.stderr, 'Error deleting file %s.\nError: %s' % (file_name, e)
vspasova@webrtc.org1b0a02e2012-08-30 12:56:38 +0000158 return False
159 return True
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000160
161
kjellanderc88b5d52017-04-05 06:42:43 -0700162def _OverlayBarcodeAndBaseFrames(barcodes_file, base_file, output_file,
163 barcodes_component_sizes,
164 base_component_sizes):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000165 """Overlays the next YUV frame from a file with a barcode.
166
167 Args:
168 barcodes_file(FileObject): The YUV file containing the barcodes (opened).
169 base_file(FileObject): The base YUV file (opened).
170 output_file(FileObject): The output overlaid file (opened).
171 barcodes_component_sizes(list of tuples): The width and height of each Y, U
172 and V plane of the barcodes YUV file.
173 base_component_sizes(list of tuples): The width and height of each Y, U and
174 V plane of the base YUV file.
175 Return:
176 (bool): True if there are more planes (i.e. frames) in the base file, false
177 otherwise.
178 """
179 # We will loop three times - once for the Y, U and V planes
180 for ((barcode_comp_width, barcode_comp_height),
181 (base_comp_width, base_comp_height)) in zip(barcodes_component_sizes,
182 base_component_sizes):
183 for base_row in range(base_comp_height):
184 barcode_plane_traversed = False
185 if (base_row < barcode_comp_height) and not barcode_plane_traversed:
186 barcode_plane = barcodes_file.read(barcode_comp_width)
187 if barcode_plane == "":
188 barcode_plane_traversed = True
189 else:
190 barcode_plane_traversed = True
191 base_plane = base_file.read(base_comp_width)
192
193 if base_plane == "":
194 return False
195
196 if not barcode_plane_traversed:
197 # Substitute part of the base component with the top component
198 output_file.write(barcode_plane)
199 base_plane = base_plane[barcode_comp_width:]
200 output_file.write(base_plane)
201 return True
202
203
kjellanderc88b5d52017-04-05 06:42:43 -0700204def OverlayYuvFiles(barcode_width, barcode_height, base_width, base_height,
205 barcodes_file_name, base_file_name, output_file_name):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000206 """Overlays two YUV files starting from the upper left corner of both.
207
208 Args:
209 barcode_width(int): The width of the barcode (to be overlaid).
210 barcode_height(int): The height of the barcode (to be overlaid).
211 base_width(int): The width of a frame of the base file.
212 base_height(int): The height of a frame of the base file.
213 barcodes_file_name(string): The name of the YUV file containing the YUV
214 barcodes.
215 base_file_name(string): The name of the base YUV file.
216 output_file_name(string): The name of the output file where the overlaid
217 video will be written.
218 """
219 # Component sizes = [Y_sizes, U_sizes, V_sizes]
220 barcodes_component_sizes = [(barcode_width, barcode_height),
221 (barcode_width/2, barcode_height/2),
222 (barcode_width/2, barcode_height/2)]
223 base_component_sizes = [(base_width, base_height),
224 (base_width/2, base_height/2),
225 (base_width/2, base_height/2)]
226
227 barcodes_file = open(barcodes_file_name, 'rb')
228 base_file = open(base_file_name, 'rb')
229 output_file = open(output_file_name, 'wb')
230
231 data_left = True
232 while data_left:
kjellanderc88b5d52017-04-05 06:42:43 -0700233 data_left = _OverlayBarcodeAndBaseFrames(barcodes_file, base_file,
234 output_file,
235 barcodes_component_sizes,
236 base_component_sizes)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000237
238 barcodes_file.close()
239 base_file.close()
240 output_file.close()
241
242
kjellanderc88b5d52017-04-05 06:42:43 -0700243def CalculateFramesNumberFromYuv(yuv_width, yuv_height, file_name):
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000244 """Calculates the number of frames of a YUV video.
245
246 Args:
247 yuv_width(int): Width of a frame of the yuv file.
248 yuv_height(int): Height of a frame of the YUV file.
249 file_name(string): The name of the YUV file.
250 Return:
251 (int): The number of frames in the YUV file.
252 """
253 file_size = os.path.getsize(file_name)
254
255 y_plane_size = yuv_width * yuv_height
256 u_plane_size = (yuv_width/2) * (yuv_height/2) # Equals to V plane size too
257 frame_size = y_plane_size + (2 * u_plane_size)
258 return int(file_size/frame_size) # Should be int anyway
259
260
kjellanderc88b5d52017-04-05 06:42:43 -0700261def _FormJarsString(path_to_zxing):
kjellander@webrtc.org38ebf982013-03-08 10:58:21 +0000262 """Forms the the Zxing core and javase jars argument.
263
264 Args:
265 path_to_zxing(string): The path to the Zxing checkout folder.
266 Return:
267 (string): The newly formed jars argument.
268 """
269 javase_jar = os.path.join(path_to_zxing, "javase", "javase.jar")
270 core_jar = os.path.join(path_to_zxing, "core", "core.jar")
271 delimiter = ':'
272 if os.name != 'posix':
273 delimiter = ';'
274 return javase_jar + delimiter + core_jar
275
kjellanderc88b5d52017-04-05 06:42:43 -0700276def _ParseArgs():
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000277 """Registers the command-line options."""
278 usage = "usage: %prog [options]"
279 parser = optparse.OptionParser(usage=usage)
280
281 parser.add_option('--barcode_width', type='int',
282 default=_DEFAULT_BARCODE_WIDTH,
283 help=('Width of the barcodes to be overlaid on top of the'
284 ' base file. Default: %default'))
285 parser.add_option('--barcode_height', type='int', default=32,
286 help=('Height of the barcodes to be overlaid on top of the'
287 ' base file. Default: %default'))
288 parser.add_option('--base_frame_width', type='int', default=352,
289 help=('Width of the base YUV file\'s frames. '
290 'Default: %default'))
291 parser.add_option('--base_frame_height', type='int', default=288,
292 help=('Height of the top YUV file\'s frames. '
293 'Default: %default'))
294 parser.add_option('--barcodes_yuv', type='string',
295 default=_DEFAULT_BARCODES_FILE,
296 help=('The YUV file with the barcodes in YUV. '
297 'Default: %default'))
298 parser.add_option('--base_yuv', type='string', default='base.yuv',
299 help=('The base YUV file to be overlaid. '
300 'Default: %default'))
301 parser.add_option('--output_yuv', type='string', default='output.yuv',
302 help=('The output YUV file containing the base overlaid'
303 ' with the barcodes. Default: %default'))
304 parser.add_option('--png_barcodes_output_dir', type='string', default='.',
305 help=('Output directory where the PNG barcodes will be '
306 'generated. Default: %default'))
307 parser.add_option('--png_barcodes_input_dir', type='string', default='.',
308 help=('Input directory from where the PNG barcodes will be '
309 'read. Default: %default'))
310 parser.add_option('--yuv_barcodes_output_dir', type='string', default='.',
311 help=('Output directory where the YUV barcodes will be '
312 'generated. Default: %default'))
313 parser.add_option('--yuv_frames_input_dir', type='string', default='.',
314 help=('Input directory from where the YUV will be '
315 'read before combination. Default: %default'))
316 parser.add_option('--zxing_dir', type='string', default='zxing',
317 help=('Path to the Zxing barcodes library. '
318 'Default: %default'))
319 options = parser.parse_args()[0]
320 return options
321
322
kjellanderc88b5d52017-04-05 06:42:43 -0700323def main():
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000324 """The main function.
325
326 A simple invocation will be:
kjellander@webrtc.orga6ff8452013-05-14 09:43:04 +0000327 ./webrtc/tools/barcode_tools/barcode_encoder.py --barcode_height=32
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000328 --base_frame_width=352 --base_frame_height=288
329 --base_yuv=<path_and_name_of_base_file>
330 --output_yuv=<path and name_of_output_file>
331 """
kjellanderc88b5d52017-04-05 06:42:43 -0700332 options = _ParseArgs()
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000333 # The barcodes with will be different than the base frame width only if
334 # explicitly specified at the command line.
335 if options.barcode_width == _DEFAULT_BARCODE_WIDTH:
336 options.barcode_width = options.base_frame_width
337 # If the user provides a value for the barcodes YUV video file, we will keep
338 # it. Otherwise we create a temp file which is removed after it has been used.
339 keep_barcodes_yuv_file = False
340 if options.barcodes_yuv != _DEFAULT_BARCODES_FILE:
341 keep_barcodes_yuv_file = True
342
343 # Calculate the number of barcodes - it is equal to the number of frames in
344 # the base file.
kjellanderc88b5d52017-04-05 06:42:43 -0700345 number_of_barcodes = CalculateFramesNumberFromYuv(
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000346 options.base_frame_width, options.base_frame_height, options.base_yuv)
347
348 script_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
vspasova@webrtc.org28655422012-08-15 14:35:40 +0000349 zxing_dir = os.path.join(script_dir, 'third_party', 'zxing')
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000350 # Generate barcodes - will generate them in PNG.
kjellanderc88b5d52017-04-05 06:42:43 -0700351 GenerateUpcaBarcodes(number_of_barcodes, options.barcode_width,
352 options.barcode_height,
353 output_directory=options.png_barcodes_output_dir,
354 path_to_zxing=zxing_dir)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000355 # Convert the PNG barcodes to to YUV format.
kjellanderc88b5d52017-04-05 06:42:43 -0700356 ConvertPngToYuvBarcodes(options.png_barcodes_input_dir,
357 options.yuv_barcodes_output_dir)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000358 # Combine the YUV barcodes into one YUV file.
kjellanderc88b5d52017-04-05 06:42:43 -0700359 CombineYuvFramesIntoOneFile(options.barcodes_yuv,
360 input_directory=options.yuv_frames_input_dir)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000361 # Overlay the barcodes over the base file.
kjellanderc88b5d52017-04-05 06:42:43 -0700362 OverlayYuvFiles(options.barcode_width, options.barcode_height,
363 options.base_frame_width, options.base_frame_height,
364 options.barcodes_yuv, options.base_yuv, options.output_yuv)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000365
366 if not keep_barcodes_yuv_file:
367 # Remove the temporary barcodes YUV file
vspasova@webrtc.org1b0a02e2012-08-30 12:56:38 +0000368 os.remove(options.barcodes_yuv)
vspasova@webrtc.org400e7da2012-08-15 10:25:12 +0000369
370
371if __name__ == '__main__':
kjellanderc88b5d52017-04-05 06:42:43 -0700372 sys.exit(main())