#![allow(unused)]
use std::path::PathBuf;
use std::string::ToString;
use flate2::read::GzDecoder;
use tar::Archive;
fn is_release_mode() -> bool {
let value = std::env::var("PROFILE")
.expect("missing PROFILE")
.to_lowercase();
&value == "release"
}
fn is_debug_mode() -> bool {
let value = std::env::var("PROFILE")
.expect("missing PROFILE")
.to_lowercase();
&value == "debug"
}
fn get_vmaf_output_dir() -> PathBuf {
let vmaf_out_dir = std::env::var("OUT_DIR").expect("missing OUT_DIR");
let vmaf_out_dir = PathBuf::from(vmaf_out_dir).join("vmaf");
std::fs::create_dir_all(&vmaf_out_dir).expect("unable to add vmaf dir under OUT_DIR");
vmaf_out_dir
}
fn run_make(source_path: &PathBuf) {
let result = std::process::Command::new("make")
.arg("-C")
.arg(source_path)
.output()
.expect(&format!("make -C {:?} failed", source_path));
}
struct VmafModel {
main: PathBuf,
model: PathBuf,
}
struct VmafFiles {
release_dir: PathBuf,
lib_file: PathBuf,
model_def: VmafModel,
model_4k: VmafModel,
header_file: PathBuf,
}
fn download_and_build_vmaf() -> Result<VmafFiles, String> {
let out_dir = get_vmaf_output_dir();
let download_dir = out_dir.join("download");
let source_dir = out_dir.join("source");
let release_dir = out_dir.join("release");
let lib_file = release_dir.join("libvmaf.a");
let model_def = release_dir.join("vmaf_v0.6.1.pkl");
let model_def_other = release_dir.join("vmaf_v0.6.1.pkl.model");
let model_4k = release_dir.join("vmaf_4k_v0.6.1.pkl");
let model_4k_other = release_dir.join("vmaf_4k_v0.6.1.pkl.model");
let header_file = release_dir.join("libvmaf.h");
if is_debug_mode() {
let all_exists = lib_file.exists()
&& model_def.exists()
&& model_def_other.exists()
&& model_4k.exists()
&& model_4k_other.exists()
&& header_file.exists();
if all_exists {
return Ok(VmafFiles {
release_dir: release_dir.clone(),
lib_file,
model_def: VmafModel {
main: model_def,
model: model_def_other,
},
model_4k: VmafModel {
main: model_4k,
model: model_4k_other,
},
header_file,
});
}
}
std::fs::remove_dir_all(&out_dir).map_err(|x| x.to_string())?;
std::fs::create_dir_all(&download_dir).map_err(|x| x.to_string())?;
let url = "https://github.com/colbyn/vmaf/tarball/vmaf-sys--0.0.10";
let tar_reply = reqwest::get(url).expect("unable to get vmaf tar file from github");
let tar = GzDecoder::new(tar_reply);
let mut archive = Archive::new(tar);
let tmp_source_dir: Option<PathBuf> = {
archive
.unpack(&download_dir)
.map_err(|x| format!(
"failed to unpack vmaf tar payload from github to {:?}: {:?}",
download_dir,
x
))?;
let xs = std::fs::read_dir(&download_dir)
.expect(&format!("unable to read dir {:?}", download_dir))
.filter_map(Result::ok)
.filter(|file| {
file.file_type()
.map(|x| x.is_dir())
.unwrap_or(false)
})
.collect::<Vec<std::fs::DirEntry>>();
match &xs[..] {
[x] => Some(x.path()),
_ => None,
}
};
let tmp_source_dir = tmp_source_dir.expect("unexpected tar output from github");
std::fs::rename(&tmp_source_dir, &source_dir)
.map_err(|x| format!(
"unable to rename from {:?} to {:?}: {}",
tmp_source_dir,
source_dir,
x,
))?;
run_make(&source_dir);
std::fs::create_dir_all(&release_dir).map_err(|x| x.to_string())?;
let cpy = |src: PathBuf, dest: &PathBuf| {
std::fs::copy(&src, dest).expect(&format!(
"unable to cpy from {:?} to {:?}",
src,
dest,
));
};
cpy(source_dir.join("src/libvmaf/src/libvmaf.h"), &header_file);
cpy(source_dir.join("src/libvmaf/libvmaf.a"), &lib_file);
cpy(source_dir.join("model/vmaf_v0.6.1.pkl"), &model_def);
cpy(source_dir.join("model/vmaf_v0.6.1.pkl.model"), &model_def_other);
cpy(source_dir.join("model/vmaf_4k_v0.6.1.pkl"), &model_4k);
cpy(source_dir.join("model/vmaf_4k_v0.6.1.pkl.model"), &model_4k_other);
std::fs::remove_dir_all(&download_dir).map_err(|x| x.to_string())?;
std::fs::remove_dir_all(&source_dir).map_err(|x| x.to_string())?;
Ok(VmafFiles{
release_dir: release_dir.clone(),
lib_file,
model_def: VmafModel {
main: model_def,
model: model_def_other,
},
model_4k: VmafModel {
main: model_4k,
model: model_4k_other,
},
header_file,
})
}
fn build_all() {
let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
let target = std::env::var("TARGET").expect("missing TARGET");
if target.contains("apple") {
println!("cargo:rustc-link-lib=dylib=c++");
} else if target.contains("linux") {
println!("cargo:rustc-link-lib=dylib=stdc++");
} else {
println!("cargo:rustc-link-lib=dylib=stdc++");
}
let vmaf_files = match download_and_build_vmaf() {
Ok(x) => x,
Err(x) => panic!("{}", x),
};
println!("cargo:rustc-link-search=native={}", {
vmaf_files.release_dir
.to_str()
.expect("unable to get str")
});
println!("cargo:rustc-link-lib=static=vmaf");
bindgen::Builder::default()
.header({
vmaf_files.header_file
.to_str()
.expect("vmaf_files.header_file.to_str() failed")
})
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
fn build_docs_only() {
let out_path = PathBuf::from(std::env::var("OUT_DIR").unwrap());
bindgen::Builder::default()
.header("include/libvmaf.h")
.generate()
.expect("Unable to generate bindings")
.write_to_file(out_path.join("bindings.rs"))
.expect("Couldn't write bindings!");
}
fn main() {
#[cfg(feature="buildtype-docs-only")]
build_docs_only();
#[cfg(not(feature="buildtype-docs-only"))]
build_all();
}