| #!/usr/bin/env python |
| # |
| # Copyright 2017 The Fuchsia Authors. All rights reserved. |
| # Use of this source code is governed by a BSD-style license that can be |
| # found in the LICENSE file. |
| |
| from __future__ import print_function |
| |
| import collections |
| import multiprocessing |
| import optparse |
| import os |
| import platform |
| import re |
| import shutil |
| import subprocess |
| import sys |
| |
| |
| SCRIPTS_DIR = os.path.abspath(os.path.dirname(__file__)) |
| FFMPEG_DIR = os.path.abspath(os.path.join(SCRIPTS_DIR, '..', '..')) |
| |
| |
| # These profiles select different levels of format support. The 'default' |
| # profile includes only a few unencumbered formats, essentially those supported |
| # by Chromium. The 'max' profile includes most of the formats that ffmpeg |
| # supports. Some formats (e.g. Opus) aren't included, because more development |
| # is required to support them. |
| PROFILES = [ |
| 'default', |
| 'max', |
| ] |
| |
| |
| USAGE = """Usage: %prog [x64|arm64] [options] -- [configure_args] |
| |
| Resulting binaries will be placed in: |
| build.[x64|arm64]/default/out/ |
| build.[x64|arm64]/max/out/ |
| """ |
| |
| |
| def PrintAndCheckCall(argv, *args, **kwargs): |
| print('Running %r' % argv) |
| subprocess.check_call(argv, *args, **kwargs) |
| |
| |
| def GetDsoName(dso_name, dso_version): |
| return 'lib%s.so.%s' % (dso_name, dso_version) |
| |
| |
| def RewriteFile(path, search, replace): |
| with open(path) as f: |
| contents = f.read() |
| with open(path, 'w') as f: |
| f.write(re.sub(search, replace, contents)) |
| |
| |
| def BuildFFmpeg(target_arch, parallel_jobs, config_only, profile, |
| configure_flags): |
| config_dir = 'build.%s/%s' % (target_arch, profile) |
| shutil.rmtree(config_dir, ignore_errors=True) |
| os.makedirs(os.path.join(config_dir, 'out')) |
| |
| PrintAndCheckCall( |
| [os.path.join(FFMPEG_DIR, 'configure')] + configure_flags, cwd=config_dir) |
| |
| RewriteFile( |
| os.path.join(config_dir, 'config.h'), |
| r'(#define HAVE_SYSCTL [01])', |
| (r'#define HAVE_SYSCTL 0')) |
| |
| RewriteFile( |
| os.path.join(config_dir, 'config.h'), |
| r'(#define HAVE_AS_FUNC [01])', |
| (r'#define HAVE_AS_FUNC 0')) |
| |
| RewriteFile( |
| os.path.join(config_dir, 'config.h'), |
| r'(#define HAVE_VALGRIND_VALGRIND_H [01])', |
| (r'#define HAVE_VALGRIND_VALGRIND_H 0')) |
| |
| if config_only: |
| print('Skipping build step as requested.') |
| else: |
| libraries = [ |
| os.path.join('libavcodec', GetDsoName('avcodec', 55)), |
| os.path.join('libavformat', GetDsoName('avformat', 55)), |
| os.path.join('libavutil', GetDsoName('avutil', 55)), |
| ] |
| PrintAndCheckCall( |
| ['make', '-j%d' % parallel_jobs] + libraries, cwd=config_dir) |
| for lib in libraries: |
| shutil.copy(os.path.join(config_dir, lib), |
| os.path.join(config_dir, 'out')) |
| |
| if target_arch in ('arm64'): |
| RewriteFile( |
| os.path.join(config_dir, 'config.h'), |
| r'(#define HAVE_VFP_ARGS [01])', |
| (r'/* \1 -- softfp/hardfp selection is done by the fuchsia build */')) |
| |
| |
| def main(argv): |
| parser = optparse.OptionParser(usage=USAGE) |
| parser.add_option('--profile', action='append', dest='profiles', |
| choices=PROFILES, |
| help='Profile to build; determines e.g. supported codecs') |
| parser.add_option('--config-only', action='store_true', |
| help='Skip the build step.') |
| options, args = parser.parse_args(argv) |
| |
| if len(args) == 0: |
| parser.print_help() |
| return 1 |
| |
| target_arch = args[0] |
| configure_args = args[1:] |
| |
| parallel_jobs = multiprocessing.cpu_count() |
| |
| print('System information:\n' |
| 'Target arch : %s\n' |
| 'Parallel jobs : %d\n' % (target_arch, parallel_jobs)) |
| |
| configure_flags = collections.defaultdict(list) |
| |
| # Common configuration. Note: --disable-everything does not in fact disable |
| # everything, just non-library components such as decoders and demuxers. |
| #TODO(dalesat): Consider --enable-libopus, --enable-decoder=libopus |
| configure_flags['Common'].extend([ |
| '--disable-everything', |
| '--disable-all', |
| '--disable-doc', |
| '--disable-htmlpages', |
| '--disable-manpages', |
| '--disable-podpages', |
| '--disable-txtpages', |
| '--disable-static', |
| '--enable-avcodec', |
| '--enable-avformat', |
| '--enable-avutil', |
| '--enable-fft', |
| '--enable-rdft', |
| '--enable-static', |
| |
| # Disable features. |
| '--disable-bzlib', |
| '--disable-iconv', |
| '--disable-lzo', |
| '--disable-network', |
| '--disable-schannel', |
| '--disable-sdl2', |
| '--disable-symver', |
| '--disable-xlib', |
| '--disable-zlib', |
| '--disable-securetransport', |
| '--disable-faan', |
| '--disable-alsa', |
| |
| # Disable hardware decoding options which will sometimes turn on |
| # via autodetect. |
| '--disable-d3d11va', |
| '--disable-dxva2', |
| '--disable-vaapi', |
| '--disable-vdpau', |
| '--disable-videotoolbox', |
| '--disable-nvenc', |
| '--disable-cuda', |
| '--disable-cuvid', |
| '--disable-v4l2_m2m', |
| |
| # Common codecs. |
| '--enable-decoder=vorbis,flac', |
| '--enable-decoder=pcm_u8,pcm_s16le,pcm_s24le,pcm_s32le,pcm_f32le', |
| '--enable-decoder=pcm_s16be,pcm_s24be,pcm_mulaw,pcm_alaw', |
| '--enable-decoder=theora,vp8', |
| '--enable-demuxer=ogg,matroska,wav,flac', |
| '--enable-parser=opus,vorbis,flac', |
| '--enable-parser=vp3,vp8', |
| |
| '--optflags="-O2"', |
| '--enable-pic' |
| ]) |
| |
| configure_flags['Common'].extend([ |
| '--enable-pic', |
| '--enable-lto', |
| '--cc=clang', |
| '--cxx=clang++', |
| '--ld=clang', |
| '--extra-ldflags=-fuse-ld=lld', |
| ]) |
| |
| # TODO(dalesat): determine if we can use --enable-lto in x64 |
| # TODO(dalesat): enable vp9 on arm64 |
| |
| if target_arch == 'x64': |
| configure_flags['Common'].extend([ |
| '--enable-decoder=vp9', |
| '--enable-parser=vp9', |
| '--sysroot=' + os.path.join( |
| FFMPEG_DIR, '..', '..', 'buildtools', 'linux-x64', 'sysroot'), |
| ]) |
| elif target_arch == 'arm64': |
| configure_flags['Common'].extend([ |
| '--enable-cross-compile', |
| '--cross-prefix=/usr/bin/aarch64-linux-gnu-', |
| '--target-os=linux', |
| '--arch=aarch64', |
| '--enable-armv8', |
| '--extra-cflags=-march=armv8-a', |
| '--sysroot=' + os.path.join( |
| FFMPEG_DIR, '..', '..', 'buildtools', 'linux-arm64', 'sysroot'), |
| '--extra-cflags=--target=aarch64-linux-gnu', |
| '--extra-ldflags=--target=aarch64-linux-gnu', |
| '--disable-linux-perf', |
| ]) |
| else: |
| print('Error: Unknown target arch %r!' % (target_arch), file=sys.stderr) |
| return 1 |
| |
| configure_flags['default'].extend([ |
| # max enables MPEG4 which requires error resilience :( |
| '--disable-error-resilience', |
| ]) |
| |
| configure_flags['max'].extend([ |
| '--enable-decoder=aac,h264,mp3', |
| '--enable-demuxer=aac,mp3,mov', |
| '--enable-parser=aac,h264,mpegaudio', |
| # Enable playing avi files. |
| '--enable-decoder=mpeg4', |
| '--enable-parser=h263,mpeg4video', |
| '--enable-demuxer=avi', |
| # Enable playing Android 3gp files. |
| '--enable-demuxer=amr', |
| '--enable-decoder=amrnb,amrwb', |
| # Wav files for playing phone messages. |
| '--enable-decoder=gsm_ms', |
| '--enable-demuxer=gsm', |
| '--enable-parser=gsm', |
| ]) |
| |
| def do_build_ffmpeg(profile, configure_flags): |
| if options.profiles and profile not in options.profiles: |
| print('%s skipped' % profile) |
| return |
| |
| print('%s configure/build:' % profile) |
| BuildFFmpeg(target_arch, parallel_jobs, |
| options.config_only, profile, configure_flags) |
| |
| do_build_ffmpeg('default', |
| configure_flags['Common'] + |
| configure_flags['default'] + |
| configure_args) |
| do_build_ffmpeg('max', |
| configure_flags['Common'] + |
| configure_flags['max'] + |
| configure_args) |
| |
| print('Done. If desired you may copy config.h/config.asm into the ' |
| 'source/config tree using copy_config.sh.') |
| return 0 |
| |
| |
| if __name__ == '__main__': |
| sys.exit(main(sys.argv[1:])) |