| # Copyright (c) 2013 The Chromium OS Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| """Output the test video parameters for VDA tests. |
| |
| Output the test parameters of h264/vp8 videos for running VDA tests: |
| filename:width:height:frames:fragments:minFPSwithRender:minFPSnoRender:profile |
| (chromium content/common/gpu/media/video_decode_accelerator_unittest.cc) |
| |
| Executing this script with a single h264 or vp8 video: |
| 'output_test_video_params.py video.h264|video.vp8' will directly print the test |
| parameters for that video on screen. |
| |
| Executing this script with a directory containing h264/vp8 videos: |
| 'output_test_video_params.py video-dir/' will output |
| __test_video_list_[timestamp] file that contains a list of test parameters for |
| all h264/vp8 videos under video-dir. Only valid test parameters will be written |
| into the output file; unsupported videos/files under the video-dir will be |
| ignored. |
| """ |
| |
| import mmap |
| import os |
| import re |
| import struct |
| import subprocess |
| import sys |
| import time |
| |
| INVALID_PARAM = '##' |
| |
| def h264_fragments(path): |
| with open(path, "rb") as f: |
| mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) |
| |
| # Count NAL by searching for the 0x00000001 start code prefix. |
| pattern = '00000001'.decode('hex') |
| regex = re.compile(pattern, re.MULTILINE) |
| count = sum(1 for _ in regex.finditer(mm)) |
| mm.close() |
| |
| return str(count) |
| |
| def vp8_fragments(path): |
| # Read IVF 32-byte header and parse the frame number in the header. |
| # IVF header definition: http://wiki.multimedia.cx/index.php?title=IVF |
| with open(path, "rb") as f: |
| mm = mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) |
| |
| mm.seek(24, 0) |
| header_frame_num = struct.unpack('i', mm.read(4))[0] |
| mm.seek(32, 0) |
| |
| # Count the following frames and check if the count matches the frame number |
| # in the header. |
| count = 0 |
| size = mm.size() |
| while mm.tell() + 4 <= size: |
| (frame,) = struct.unpack('i', mm.read(4)) |
| offset = 8 + frame |
| if (mm.tell() + offset <= size): |
| mm.seek(offset, 1) |
| count = count + 1 |
| |
| mm.close() |
| if header_frame_num != count: |
| return INVALID_PARAM |
| |
| return str(count) |
| |
| def full_test_parameters(path): |
| try: |
| ffmpeg_cmd = ["ffmpeg", "-i", path, "-vcodec", "copy", "-an", "-f", |
| "null", "/dev/null"] |
| content = subprocess.check_output(ffmpeg_cmd, stderr=subprocess.STDOUT) |
| except subprocess.CalledProcessError as e: |
| content = e.output |
| |
| # Get video format, dimension, and frame number from the ffmpeg output. |
| # Sample of ffmpeg output: |
| # Input #0, h264, from 'video.h264': |
| # Stream #0.0: Video: h264 (High), yuv420p, 640x360, 25 fps, ... |
| # frame= 82 fps= 0 ... |
| results = re.findall('Input #0, (\S+),', content) |
| profile = INVALID_PARAM |
| frag = INVALID_PARAM |
| if (results): |
| video_format = results[0].lower() |
| if (video_format == 'h264'): |
| profile = '1' |
| frag = h264_fragments(path) |
| elif (video_format == 'ivf'): |
| profile = '11' |
| frag = vp8_fragments(path) |
| |
| dimen = [INVALID_PARAM, INVALID_PARAM] |
| fps = [INVALID_PARAM, INVALID_PARAM] |
| results = re.findall('Stream #0.*Video:.* (\d+)x(\d+)', content) |
| if (results): |
| dimen = results[0] |
| fps = ['30', '30'] |
| |
| results = re.findall('frame= *(\d+)', content) |
| frame = results[0] if results else INVALID_PARAM |
| |
| filename = os.path.basename(path) |
| return '%s:%s:%s:%s:%s:%s:%s:%s' % ( |
| filename, dimen[0], dimen[1], frame, frag, fps[0], fps[1], profile) |
| |
| def check_before_output(line): |
| if INVALID_PARAM in line: |
| print 'Warning: %s' % line |
| return False |
| return True |
| |
| def main(argv): |
| if len(argv) != 1: |
| print 'Please provide a h264/vp8 directory or file.' |
| sys.exit(1) |
| |
| if os.path.isdir(argv[0]): |
| name = '__test_video_list_%s' % time.strftime("%Y%m%d_%H%M%S") |
| with open(name, 'w') as output: |
| output.write('[\n') |
| for root, _, files in os.walk(argv[0]): |
| for f in files: |
| path = os.path.join(root, f) |
| line = full_test_parameters(path) |
| if check_before_output(line): |
| # Output in json format (no trailing comma in the list.) |
| sep = '' if f is files[-1] else ',' |
| output.write('\"%s\"%s\n' % (line, sep)) |
| |
| output.write(']\n') |
| elif os.path.isfile(argv[0]): |
| line = full_test_parameters(argv[0]) |
| if check_before_output(line): |
| print line |
| else: |
| print 'Invalid input.' |
| |
| main(sys.argv[1:]) |