Skip to content

Synchronize with meh/rust-ffmpeg-sys #16

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
sudo: required
language: rust
rust:
- stable
- beta
- nightly
os:
- linux
- osx
matrix:
allow_failures:
- rust: nightly
addons:
apt:
packages:
- build-essential
before_install:
# Without rustfmt, bindgen puts everything on one line and any warnings dump so many logs they break Travis
# See https://github.com/rust-lang/rust-bindgen/issues/1600
# optional, because nightlies may not have it
- rustup component add rustfmt || true
- if [[ $TRAVIS_OS_NAME == 'linux' ]]; then ./.travis/install_linux.sh; fi
- if [[ $TRAVIS_OS_NAME == 'osx' ]]; then brew update; fi
- if [[ $TRAVIS_OS_NAME == 'osx' ]]; then brew install yasm; fi

script: |
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then
# Current Travis Ubuntu version uses libav which doesn't come with libswresample
cargo build --verbose --no-default-features --features "avcodec avfilter avformat avresample swscale" &&
cargo test --verbose --no-default-features --features "avcodec avfilter avformat avresample swscale"
else
travis_wait cargo build --verbose --features "build"
cargo test --verbose --features "build"
fi

after_failure:
- find /usr -type f 2>/dev/null | grep -E 'lib(avcodec/version|avcodec/avcodec).h$' | xargs -I THEFILE -- sh -c 'echo "=== THEFILE ==="; cat THEFILE'
17 changes: 17 additions & 0 deletions .travis/install_linux.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash

sudo apt-get update -q
# From https://trac.ffmpeg.org/wiki/CompilationGuide/Ubuntu
sudo apt-get -y --force-yes install autoconf automake build-essential libass-dev libfreetype6-dev libsdl1.2-dev libtheora-dev libtool libva-dev libvdpau-dev libvorbis-dev libxcb1-dev libxcb-shm0-dev libxcb-xfixes0-dev pkg-config texinfo zlib1g-dev
sudo apt-get install yasm
pushd ~
git clone https://github.com/FFmpeg/FFmpeg.git
cd FFmpeg
git checkout release/3.2
mkdir ~/FFmpeg-build
cd ~/FFmpeg-build
../FFmpeg/configure --disable-ffprobe --disable-ffserver --disable-doc --enable-avresample
make -j
sudo make install
make distclean
popd
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
[package]
name = "ffmpeg-sys-next"
name = "ffmpeg-sys"
version = "4.3.5"
build = "build.rs"
links = "ffmpeg"

readme = "README.md"
authors = ["meh. <[email protected]>", "Zhiming Wang <[email protected]>"]
license = "WTFPL"

Expand All @@ -22,7 +23,7 @@ libc = "0.2"
num_cpus = "1.11"
cc = "1.0"
pkg-config = "0.3"
bindgen = { version = "0.54", default-features = false, features = ["runtime"] }
bindgen = { version = "0.56", default-features = false, features = ["runtime"] }

[target.'cfg(target_env = "msvc")'.build-dependencies]
vcpkg = "0.2"
Expand Down Expand Up @@ -104,3 +105,4 @@ avresample = []
postproc = []
swresample = []
swscale = []
lib-drm = []
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
[![ffmpeg-sys-next on crates.io](https://img.shields.io/crates/v/ffmpeg-sys-next?cacheSeconds=3600)](https://crates.io/crates/ffmpeg-sys-next)
[![build](https://github.com/zmwangx/rust-ffmpeg-sys/workflows/build/badge.svg)](https://github.com/zmwangx/rust-ffmpeg-sys/actions)
# Rust FFI bindings for ffmpeg

This is a fork of the abandoned [ffmpeg-sys](https://github.com/meh/rust-ffmpeg-sys) crate. You can find this crate as [ffmpeg-sys-next](https://crates.io/crates/ffmpeg-sys-next) on crates.io.
Low-level bindings for ffmpeg autogenerated with bindgen. This crate supports cross-compilation automatically.

This crate contains low level bindings to FFmpeg. You're probably interested in the high level bindings instead: [ffmpeg-next](https://github.com/zmwangx/rust-ffmpeg).
For higher-level library, see [ffmpeg crate](https://lib.rs/ffmpeg).

## Building

By default, the crate will search for ffmpeg v4 installed on the system.

This crate can also download, build and statically link its own copy of ffmpeg if you enable `build` feature:

```toml
[dependencies]
ffmpeg-sys = { version = "4", features = ["build"] }
```

# Versioning

A word on versioning: major and minor versions track major and minor versions of FFmpeg, e.g. 4.2.x of this crate has been updated to support the 4.2.x series of FFmpeg. Patch level is reserved for bug fixes of this crate and does not track FFmpeg patch versions.

Expand All @@ -28,3 +40,10 @@ In addition to feature flags declared in `Cargo.toml`, this crate performs vario
- `ff_api_<feature>`, e.g. `ff_api_vaapi`, corresponding to whether their respective uppercase deprecation guards evaluate to true.

- `ff_api_<feature>_is_defined`, e.g. `ff_api_vappi_is_defined`, similar to above except these are enabled as long as the corresponding deprecation guards are defined.

See [Cargo features](https://github.com/meh/rust-ffmpeg/blob/HEAD/Cargo.toml) to control which codecs are included.

# Based On

This combines bits from [meh/rust-ffmpeg-sys](https://github.com/meh/rust-ffmpeg-sys) and [zmwangx/rust-ffmpeg-sys](https://github.com/zmwangx/rust-ffmpeg-sys) because
when you have two almost identical projects that aren't actively maintained what you _really_ need is a third!
111 changes: 87 additions & 24 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ extern crate pkg_config;
use std::env;
use std::fs::{self, File};
use std::io::{self, BufRead, BufReader, Write};
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;

Expand Down Expand Up @@ -225,6 +225,7 @@ fn build() -> io::Result<()> {
if env::var("DEBUG").is_ok() {
configure.arg("--enable-debug");
configure.arg("--disable-stripping");
configure.arg("--disable-optimizations");
} else {
configure.arg("--disable-debug");
configure.arg("--enable-stripping");
Expand Down Expand Up @@ -604,15 +605,6 @@ fn search_include(include_paths: &[PathBuf], header: &str) -> String {
format!("/usr/include/{}", header)
}

fn maybe_search_include(include_paths: &[PathBuf], header: &str) -> Option<String> {
let path = search_include(include_paths, header);
if fs::metadata(&path).is_ok() {
Some(path)
} else {
None
}
}

fn link_to_libraries(statik: bool) {
let ffmpeg_ty = if statik { "static" } else { "dylib" };
for lib in LIBRARIES {
Expand All @@ -627,6 +619,23 @@ fn link_to_libraries(statik: bool) {
}

fn main() {
// The long chain of `header` method calls for `bindgen::Builder` seems to be overflowing the default stack size on Windows.
// The main thread appears to have a hardcoded stack size which is unaffected by `RUST_MIN_STACK`. As a workaround, spawn a thread here with a stack size that works expermentally, and allow overriding it with `FFMPEG_SYS_BUILD_STACK_SIZE` just in case.
let stack_size = std::env::var("FFMPEG_SYS_BUILD_STACK_SIZE")
.map(|s| s.parse())
.unwrap_or(Ok(3 * 1024 * 1024));
eprintln!("Using stack size: {:?}", stack_size);

std::thread::Builder::new()
.name("ffmpg-sys-build".into())
.stack_size(stack_size.unwrap())
.spawn(thread_main)
.unwrap()
.join()
.unwrap();
}

fn thread_main() {
let statik = env::var("CARGO_FEATURE_STATIC").is_ok();

let include_paths: Vec<PathBuf> = if env::var("CARGO_FEATURE_BUILD").is_ok() {
Expand Down Expand Up @@ -694,10 +703,12 @@ fn main() {
}
// Fallback to pkg-config
else {
pkg_config::Config::new()
let mut libavutil = pkg_config::Config::new()
.cargo_metadata(false)
.statik(statik)
.probe("libavutil")
.unwrap();
print_pkg_config_libs(statik, &libavutil);

let libs = vec![
("libavformat", "AVFORMAT"),
Expand All @@ -710,18 +721,27 @@ fn main() {

for (lib_name, env_variable_name) in libs.iter() {
if env::var(format!("CARGO_FEATURE_{}", env_variable_name)).is_ok() {
pkg_config::Config::new()
.statik(statik)
.probe(lib_name)
.unwrap();
print_pkg_config_libs(
statik,
&pkg_config::Config::new()
.cargo_metadata(false)
.statik(statik)
.probe(lib_name)
.unwrap(),
);
}
}

pkg_config::Config::new()
let libavcodec = pkg_config::Config::new()
.cargo_metadata(false)
.statik(statik)
.probe("libavcodec")
.unwrap()
.include_paths
.unwrap();
print_pkg_config_libs(statik, &libavcodec);

let mut paths = libavcodec.include_paths;
paths.append(&mut libavutil.include_paths);
paths
};

if statik && cfg!(target_os = "macos") {
Expand Down Expand Up @@ -1208,7 +1228,6 @@ fn main() {
.header(search_include(&include_paths, "libavutil/frame.h"))
.header(search_include(&include_paths, "libavutil/hash.h"))
.header(search_include(&include_paths, "libavutil/hmac.h"))
.header(search_include(&include_paths, "libavutil/hwcontext.h"))
.header(search_include(&include_paths, "libavutil/imgutils.h"))
.header(search_include(&include_paths, "libavutil/lfg.h"))
.header(search_include(&include_paths, "libavutil/log.h"))
Expand Down Expand Up @@ -1237,7 +1256,8 @@ fn main() {
.header(search_include(&include_paths, "libavutil/timecode.h"))
.header(search_include(&include_paths, "libavutil/twofish.h"))
.header(search_include(&include_paths, "libavutil/avutil.h"))
.header(search_include(&include_paths, "libavutil/xtea.h"));
.header(search_include(&include_paths, "libavutil/xtea.h"))
.header(search_include(&include_paths, "libavutil/hwcontext.h"));

if env::var("CARGO_FEATURE_POSTPROC").is_ok() {
builder = builder.header(search_include(&include_paths, "libpostproc/postprocess.h"));
Expand All @@ -1251,10 +1271,8 @@ fn main() {
builder = builder.header(search_include(&include_paths, "libswscale/swscale.h"));
}

if let Some(hwcontext_drm_header) =
maybe_search_include(&include_paths, "libavutil/hwcontext_drm.h")
{
builder = builder.header(hwcontext_drm_header);
if env::var("CARGO_FEATURE_LIB_DRM").is_ok() {
builder = builder.header(search_include(&include_paths, "libavutil/hwcontext_drm.h"))
}

// Finish the builder and generate the bindings.
Expand All @@ -1268,3 +1286,48 @@ fn main() {
.write_to_file(output().join("bindings.rs"))
.expect("Couldn't write bindings!");
}

fn print_pkg_config_libs(statik: bool, lib: &pkg_config::Library) {
let target = env::var("TARGET").unwrap();
let is_msvc = target.contains("msvc");
let is_apple = target.contains("apple");

for val in &lib.link_paths {
println!("cargo:rustc-link-search=native={}", val.display());
}
for val in &lib.framework_paths {
println!("cargo:rustc-link-search=framework={}", val.display());
}
for val in &lib.frameworks {
println!("cargo:rustc-link=framework={}", val);
}

for val in &lib.libs {
if is_msvc && ["m", "c", "pthread"].contains(&val.as_str()) {
continue;
}
if is_apple && val == "stdc++" {
println!("cargo:rustc-link-lib=c++");
continue;
}

if statik && is_static_available(val, &lib.include_paths) {
println!("cargo:rustc-link-lib=static={}", val);
} else {
println!("cargo:rustc-link-lib={}", val);
}
}
}

fn is_static_available(lib: &str, dirs: &[PathBuf]) -> bool {
let libname = format!("lib{}.a", lib);
let has = dirs
.iter()
.map(|d| d.as_path())
.chain([Path::new("/usr/local/lib")].iter().copied())
.any(|dir| dir.join(&libname).exists());
if !has {
println!("cargo:warning=static {} not found", libname);
}
has
}
21 changes: 21 additions & 0 deletions shell.nix
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
let
mozilla = import (builtins.fetchTarball https://github.com/mozilla/nixpkgs-mozilla/archive/master.tar.gz);
in

with (import <nixpkgs> {
overlays = [mozilla];
});

mkShell {
name = "ffmpeg-sys";

buildInputs = [
# For building.
clang rustChannels.stable.rust pkg-config ffmpeg
];

RUST_BACKTRACE = 1;
RUSTFLAGS = "-C target-cpu=native";

LIBCLANG_PATH = "${llvmPackages.libclang}/lib";
}
2 changes: 1 addition & 1 deletion src/avutil/rational.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub unsafe fn av_cmp_q(a: AVRational, b: AVRational) -> c_int {
} else if b.den != 0 && a.den != 0 {
0
} else if a.num != 0 && b.num != 0 {
((i64::from(a.num) >> 31) - (i64::from(b.num) >> 31)) as c_int
(a.num >> 31) - (b.num >> 31)
} else {
c_int::min_value()
}
Expand Down