blob: 99c442b57295ddb8f9a64442d9d42483366f2caa [file] [log] [blame]
#!/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 %s' % '\n '.join(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', 58)),
os.path.join('libavformat', GetDsoName('avformat', 58)),
os.path.join('libavutil', GetDsoName('avutil', 56)),
]
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-debug',
'--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 automatically detected external libraries. This prevents
# automatic inclusion of things like hardware decoders. Each roll should
# audit new [autodetect] configure options and add any desired options to
# this file.
'--disable-autodetect',
# Common codecs.
'--enable-decoder=vorbis,flac',
'--enable-decoder=pcm_u8,pcm_s16le,pcm_s24le,pcm_s32le,pcm_f32le,mp3',
'--enable-decoder=pcm_s16be,pcm_s24be,pcm_mulaw,pcm_alaw',
'--enable-decoder=theora,vp8,sbc,aptx',
'--enable-demuxer=ogg,matroska,wav,flac,mp3,mov',
'--enable-parser=opus,vorbis,flac,mpegaudio',
'--enable-parser=vp3,vp8',
'--enable-encoder=sbc',
'--optflags="-O2"',
'--enable-pic',
# Force usage of yasm
'--x86asmexe=yasm',
])
configure_flags['Common'].extend([
'--enable-pic',
'--enable-lto',
'--cc=clang',
'--cxx=clang++',
'--ld=clang',
])
# 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, '..', '..', 'build', 'third_party', 'sysroot', 'linux-x64'),
])
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, '..', '..', 'build', 'third_party', 'sysroot', 'linux-arm64'),
'--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:]))