use std::env;
use std::fs::{self, File};
use std::io::{self, Write};
use std::path::PathBuf;
use std::process::Command;
fn version() -> String {
let major: u8 = env::var("CARGO_PKG_VERSION_MAJOR").unwrap().parse().unwrap();
let minor: u8 = env::var("CARGO_PKG_VERSION_MINOR").unwrap().parse().unwrap();
let patch: u8 = env::var("CARGO_PKG_VERSION_PATCH").unwrap().parse().unwrap();
if patch == 0 {
format!("{}.{}", major, minor)
}
else {
format!("{}.{}.{}", major, minor, patch)
}
}
fn output() -> PathBuf {
PathBuf::from(env::var("OUT_DIR").unwrap())
}
fn source() -> PathBuf {
output().join(format!("ffmpeg-{}", version()))
}
fn search() -> PathBuf {
let mut absolute = env::current_dir().unwrap();
absolute.push(&output());
absolute.push("dist");
absolute
}
fn fetch() -> io::Result<()> {
let url = format!("http://ffmpeg.org/releases/ffmpeg-{}.tar.bz2", version());
let status = try!(if cfg!(target_os = "linux") {
Command::new("wget")
.current_dir(&output())
.arg(url)
.arg("-c")
.arg("-O")
.arg("ffmpeg.tar.bz2")
.status()
}
else {
unimplemented!();
});
if status.success() {
Ok(())
}
else {
Err(io::Error::new(io::ErrorKind::Other, "fetch failed"))
}
}
fn extract() -> io::Result<()> {
let status = try!(if cfg!(target_os = "linux") {
Command::new("tar")
.current_dir(&output())
.arg("xf")
.arg("ffmpeg.tar.bz2")
.status()
}
else {
unimplemented!();
});
if status.success() {
Ok(())
}
else {
Err(io::Error::new(io::ErrorKind::Other, "extract failed"))
}
}
fn build() -> io::Result<()> {
let mut configure = Command::new("./configure");
configure.current_dir(&source());
configure.arg(format!("--prefix={}", search().to_string_lossy()));
if env::var("TARGET").unwrap() != env::var("HOST").unwrap() {
configure.arg(format!("--cross-prefix={}-", env::var("TARGET").unwrap()));
}
if env::var("DEBUG").is_ok() {
configure.arg("--enable-debug");
configure.arg("--disable-stripping");
}
else {
configure.arg("--disable-debug");
configure.arg("--enable-stripping");
}
configure.arg("--enable-static");
configure.arg("--disable-shared");
configure.arg("--disable-programs");
macro_rules! switch {
($conf:expr, $feat:expr, $name:expr) => (
if env::var(concat!("CARGO_FEATURE_", $feat)).is_ok() {
$conf.arg(concat!("--enable-", $name));
}
else {
$conf.arg(concat!("--disable-", $name));
}
)
}
macro_rules! enable {
($conf:expr, $feat:expr, $name:expr) => (
if env::var(concat!("CARGO_FEATURE_", $feat)).is_ok() {
$conf.arg(concat!("--enable-", $name));
}
)
}
macro_rules! disable {
($conf:expr, $feat:expr, $name:expr) => (
if env::var(concat!("CARGO_FEATURE_", $feat)).is_err() {
$conf.arg(concat!("--disable-", $name));
}
)
}
switch!(configure, "BUILD_LICENSE_GPL", "gpl");
switch!(configure, "BUILD_LICENSE_VERSION3", "version3");
switch!(configure, "BUILD_LICENSE_NONFREE", "nonfree");
switch!(configure, "AVCODEC", "avcodec");
switch!(configure, "AVDEVICE", "avdevice");
switch!(configure, "AVFILTER", "avfilter");
switch!(configure, "AVFORMAT", "avformat");
switch!(configure, "AVRESAMPLE", "avresample");
switch!(configure, "POSTPROC", "postproc");
switch!(configure, "SWRESAMPLE", "swresample");
switch!(configure, "SWSCALE", "swscale");
enable!(configure, "BUILD_LIB_GNUTLS", "gnutls");
enable!(configure, "BUILD_LIB_OPENSSL", "openssl");
enable!(configure, "BUILD_LIB_FONTCONFIG", "fontconfig");
enable!(configure, "BUILD_LIB_FREI0R", "frei0r");
enable!(configure, "BUILD_LIB_LADSPA", "ladspa");
enable!(configure, "BUILD_LIB_ASS", "libass");
enable!(configure, "BUILD_LIB_FREETYPE", "libfreetype");
enable!(configure, "BUILD_LIB_FRIBIDI", "libfribidi");
enable!(configure, "BUILD_LIB_OPENCV", "libopencv");
enable!(configure, "BUILD_LIB_AACPLUS", "libaacplus");
enable!(configure, "BUILD_LIB_CELT", "libcelt");
enable!(configure, "BUILD_LIB_DCADEC", "libdcadec");
enable!(configure, "BUILD_LIB_FAAC", "libfaac");
enable!(configure, "BUILD_LIB_FDK_AAC", "libfdk-aac");
enable!(configure, "BUILD_LIB_GSM", "libgsm");
enable!(configure, "BUILD_LIB_ILBC", "libilbc");
enable!(configure, "BUILD_LIB_VAZAAR", "libvazaar");
enable!(configure, "BUILD_LIB_MP3LAME", "libmp3lame");
enable!(configure, "BUILD_LIB_OPENCORE_AMRNB", "libopencore-amrnb");
enable!(configure, "BUILD_LIB_OPENCORE_AMRWB", "libopencore-amrwrb");
enable!(configure, "BUILD_LIB_OPENH264", "libopenh264");
enable!(configure, "BUILD_LIB_OPENH265", "libopenh265");
enable!(configure, "BUILD_LIB_OPENJPEG", "libopenjpeg");
enable!(configure, "BUILD_LIB_OPUS", "libopus");
enable!(configure, "BUILD_LIB_SCHROEDINGER", "libschroedinger");
enable!(configure, "BUILD_LIB_SHINE", "libshine");
enable!(configure, "BUILD_LIB_SNAPPY", "libsnappy");
enable!(configure, "BUILD_LIB_SPEEX", "libspeex");
enable!(configure, "BUILD_LIB_STAGEFRIGHT_H264", "libstagefright-h264");
enable!(configure, "BUILD_LIB_THEORA", "libtheora");
enable!(configure, "BUILD_LIB_TWOLAME", "libtwolame");
enable!(configure, "BUILD_LIB_UTVIDEO", "libutvideo");
enable!(configure, "BUILD_LIB_VO_AACENC", "libvo-aacenc");
enable!(configure, "BUILD_LIB_VO_AMRWBENC", "libvo-amrwbenc");
enable!(configure, "BUILD_LIB_VORBIS", "libvorbis");
enable!(configure, "BUILD_LIB_VPX", "libvpx");
enable!(configure, "BUILD_LIB_WAVPACK", "libwavpack");
enable!(configure, "BUILD_LIB_WEBP", "libwebp");
enable!(configure, "BUILD_LIB_X264", "libx264");
enable!(configure, "BUILD_LIB_X265", "libx265");
enable!(configure, "BUILD_LIB_AVS", "libavs");
enable!(configure, "BUILD_LIB_XVID", "libxvid");
enable!(configure, "BUILD_LIB_SMBCLIENT", "libsmbclient");
enable!(configure, "BUILD_LIB_SSH", "libssh");
if !try!(configure.status()).success() {
return Err(io::Error::new(io::ErrorKind::Other, "configure failed"));
}
if !try!(Command::new("make").current_dir(&source()).status()).success() {
return Err(io::Error::new(io::ErrorKind::Other, "make failed"));
}
if !try!(Command::new("make").current_dir(&source()).arg("install").status()).success() {
return Err(io::Error::new(io::ErrorKind::Other, "make install failed"));
}
Ok(())
}
fn feature(header: &str, feature: Option<&str>, var: &str) -> io::Result<()> {
if let Some(feature) = feature {
if env::var(format!("CARGO_FEATURE_{}", feature.to_uppercase())).is_err() {
return Ok(());
}
}
try!(write!(try!(File::create(output().join("check.c"))), r#"
#include <stdio.h>
#include <{}>
int
main (int argc, char* argv[])
{{
printf("%d\n", {});
return 0;
}}
"#, header, var));
if Command::new("cc").current_dir(&output())
.arg("-I").arg(search().join("dist").join("include").to_string_lossy().into_owned())
.arg("-o").arg("check")
.arg("check.c")
.status().is_err()
{
return Ok(());
}
if try!(Command::new("./check").current_dir(&output()).output()).stdout[0] == b'1' {
println!(r#"cargo:rustc-cfg=feature="{}""#, var.to_lowercase());
println!(r#"cargo:{}=true"#, var.to_lowercase());
}
Ok(())
}
fn main() {
if env::var("CARGO_FEATURE_BUILD").is_ok() {
println!("cargo:rustc-link-search=native={}", search().join("lib").to_string_lossy());
if fs::metadata(&search().join("lib").join("libavutil.a")).is_ok() {
return;
}
fs::create_dir_all(&output()).ok().expect("failed to create build directory");
fetch().unwrap();
extract().unwrap();
build().unwrap();
}
feature("libavutil/avutil.h", None, "FF_API_OLD_AVOPTIONS").unwrap();
feature("libavutil/avutil.h", None, "FF_API_PIX_FMT").unwrap();
feature("libavutil/avutil.h", None, "FF_API_CONTEXT_SIZE").unwrap();
feature("libavutil/avutil.h", None, "FF_API_PIX_FMT_DESC").unwrap();
feature("libavutil/avutil.h", None, "FF_API_AV_REVERSE").unwrap();
feature("libavutil/avutil.h", None, "FF_API_AUDIOCONVERT").unwrap();
feature("libavutil/avutil.h", None, "FF_API_CPU_FLAG_MMX2").unwrap();
feature("libavutil/avutil.h", None, "FF_API_LLS_PRIVATE").unwrap();
feature("libavutil/avutil.h", None, "FF_API_AVFRAME_LAVC").unwrap();
feature("libavutil/avutil.h", None, "FF_API_VDPAU").unwrap();
feature("libavutil/avutil.h", None, "FF_API_GET_CHANNEL_LAYOUT_COMPAT").unwrap();
feature("libavutil/avutil.h", None, "FF_API_XVMC").unwrap();
feature("libavutil/avutil.h", None, "FF_API_OPT_TYPE_METADATA").unwrap();
feature("libavutil/avutil.h", None, "FF_API_DLOG").unwrap();
feature("libavutil/avutil.h", None, "FF_API_HMAC").unwrap();
feature("libavutil/avutil.h", None, "FF_API_VAAPI").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_VIMA_DECODER").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_REQUEST_CHANNELS").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_OLD_DECODE_AUDIO").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_OLD_ENCODE_AUDIO").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_OLD_ENCODE_VIDEO").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CODEC_ID").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AUDIO_CONVERT").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AVCODEC_RESAMPLE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_DEINTERLACE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_DESTRUCT_PACKET").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_GET_BUFFER").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MISSING_SAMPLE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_LOWRES").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CAP_VDPAU").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_BUFS_VDPAU").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_VOXWARE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_SET_DIMENSIONS").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_DEBUG_MV").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AC_VLC").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_OLD_MSMPEG4").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ASPECT_EXTENDED").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_THREAD_OPAQUE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CODEC_PKT").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ARCH_ALPHA").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_XVMC").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ERROR_RATE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_QSCALE_TYPE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MB_TYPE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MAX_BFRAMES").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_NEG_LINESIZES").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_EMU_EDGE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ARCH_SH4").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_ARCH_SPARC").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_UNUSED_MEMBERS").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_IDCT_XVIDMMX").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_INPUT_PRESERVED").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_NORMALIZE_AQP").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_GMC").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MV0").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CODEC_NAME").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AFD").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_VISMV").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_DV_FRAME_PROFILE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AUDIOENC_DELAY").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_VAAPI_CONTEXT").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_AVCTX_TIMEBASE").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MPV_OPT").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_STREAM_CODEC_TAG").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_QUANT_BIAS").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_RC_STRATEGY").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_CODED_FRAME").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_MOTION_EST").unwrap();
feature("libavcodec/avcodec.h", Some("avcodec"), "FF_API_WITHOUT_PREFIX").unwrap();
feature("libavformat/avformat.h", Some("avformat"), "FF_API_LAVF_BITEXACT").unwrap();
feature("libavformat/avformat.h", Some("avformat"), "FF_API_LAVF_FRAC").unwrap();
feature("libavformat/avformat.h", Some("avformat"), "FF_API_URL_FEOF").unwrap();
feature("libavformat/avformat.h", Some("avformat"), "FF_API_PROBESIZE_32").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_AVFILTERPAD_PUBLIC").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_FOO_COUNT").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_AVFILTERBUFFER").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_OLD_FILTER_OPTS").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_OLD_FILTER_OPTS_ERROR").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_AVFILTER_OPEN").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_OLD_FILTER_REGISTER").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_OLD_GRAPH_PARSE").unwrap();
feature("libavfilter/avfilter.h", Some("avfilter"), "FF_API_NOCONST_GET_NAME").unwrap();
feature("libavresample/avresample.h", Some("avresample"), "FF_API_RESAMPLE_CLOSE_OPEN").unwrap();
feature("libswscale/swscale.h", Some("swscale"), "FF_API_SWS_CPU_CAPS").unwrap();
feature("libswscale/swscale.h", Some("swscale"), "FF_API_ARCH_BFIN").unwrap();
}