Skip to content

Commit e26f70c

Browse files
committed
Support binding generation with system FFmpeg
1 parent 764b45b commit e26f70c

File tree

2 files changed

+144
-108
lines changed

2 files changed

+144
-108
lines changed

.github/workflows/ci.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,24 @@ jobs:
214214
- name: BindingBuild
215215
run: PKG_CONFIG_PATH="$HOME/ffmpeg_build/lib/pkgconfig" cargo build --verbose
216216

217+
build_with_system_ffmpeg:
218+
runs-on: ubuntu-latest
219+
steps:
220+
- uses: actions/checkout@v2
221+
222+
- name: Install latest nightly
223+
uses: actions-rs/toolchain@v1
224+
with:
225+
profile: minimal
226+
toolchain: nightly
227+
override: true
228+
229+
- name: Install System FFmpeg
230+
run: sudo apt-get install ffmpeg
231+
232+
- name: Binding Build
233+
run: cargo build --verbose
234+
217235
# Check if correct documentation can be generated by docs.rs
218236
docs_rs_check:
219237
runs-on: ubuntu-latest

build.rs

Lines changed: 126 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -115,13 +115,30 @@ impl callbacks::ParseCallbacks for FilterCargoCallbacks {
115115
}
116116
}
117117

118+
fn probe_system_ffmpeg() -> Result<(), String> {
119+
match (&*LIBS)
120+
.iter()
121+
.map(|name| "lib".to_owned() + name)
122+
.filter_map(|libname| {
123+
pkgconfig::Config::new()
124+
.statik(true)
125+
// Remove side effect
126+
.cargo_metadata(false)
127+
.probe(&libname)
128+
.is_err()
129+
}) {
130+
Some(libname) => Err(format!("{} not found!", libname)),
131+
None => Ok(()),
132+
}
133+
}
134+
118135
fn main() {
119136
// If it's a documentation generation from docs.rs, just copy the bindings
120137
// generated locally to `OUT_DIR`. We do this because the building
121138
// environment of docs.rs doesn't have an network connection, so we cannot
122139
// git clone the FFmpeg. And they also have a limitation on crate's size:
123-
// 10MB, which is not enough to fit in full FFmpeg source files. So the only
124-
// thing we can do is copy the locally generated binding files to the
140+
// 10MB, which is not enough to fit in FFmpeg source files. So the only
141+
// thing we can do is copying the locally generated binding files to the
125142
// `OUT_DIR`.
126143
if env::var("DOCS_RS").is_ok() {
127144
fs::copy("src/binding.rs", &*BINDING_FILE_PATH)
@@ -130,127 +147,128 @@ fn main() {
130147
}
131148

132149
if env::var("PKG_CONFIG_PATH").is_err() {
133-
// All outputs are stored in ./ffmpeg/build/{bin, lib, share, include}
134-
// If no prebuilt FFmpeg libraries provided, we custom build a FFmpeg.
135-
env::set_var(
136-
"PKG_CONFIG_PATH",
137-
format!("{}/build/lib/pkgconfig", *FFMPEG_DIR),
138-
);
139-
env::set_var("PATH", format!("{}/build/bin:{}", *FFMPEG_DIR, *PATH));
150+
match probe_system_ffmpeg() {
151+
// No system FFmpeg found, download and build one
152+
Err(msg) => {
153+
// All outputs are stored in ./ffmpeg/build/{bin, lib, share, include}
154+
// If no prebuilt FFmpeg libraries provided, we custom build a FFmpeg.
155+
env::set_var(
156+
"PKG_CONFIG_PATH",
157+
format!("{}/build/lib/pkgconfig", *FFMPEG_DIR),
158+
);
159+
env::set_var("PATH", format!("{}/build/bin:{}", *FFMPEG_DIR, *PATH));
140160

141-
// Check if submodule is not get cloned.
142-
if !path::PathBuf::from(format!("{}/fftools", &*FFMPEG_DIR)).is_dir() {
143-
Command::new("git")
144-
.current_dir(&*OUT_DIR)
145-
.args(["clone", "https://github.com/ffmpeg/ffmpeg", "--depth", "1"].iter())
146-
.spawn()
147-
.expect("FFmpeg submodule failed to clone.")
148-
.wait()
149-
.expect("FFmpeg submodule failed to clone.");
150-
}
161+
// Check if FFmpeg is not get cloned.
162+
if !path::PathBuf::from(format!("{}/fftools", &*FFMPEG_DIR)).is_dir() {
163+
Command::new("git")
164+
.current_dir(&*OUT_DIR)
165+
.args(["clone", "https://github.com/ffmpeg/ffmpeg", "--depth", "1"].iter())
166+
.spawn()
167+
.expect("FFmpeg submodule failed to clone.")
168+
.wait()
169+
.expect("FFmpeg submodule failed to clone.");
170+
}
151171

152-
// Corresponding to the shell script below:
153-
// ./configure \
154-
// --prefix="$PWD/build" \
155-
// --extra-cflags="-I$PWD/build/include" \
156-
// --extra-ldflags="-L$PWD/build/lib" \
157-
// --bindir="$PWD/build/bin" \
158-
// --pkg-config-flags="--static" \
159-
// --extra-libs="-lpthread -lm" \
160-
// --enable-gpl \
161-
// --enable-libass \
162-
// --enable-libfdk-aac \
163-
// --enable-libfreetype \
164-
// --enable-libmp3lame \
165-
// --enable-libopus \
166-
// --enable-libvorbis \
167-
// --enable-libvpx \
168-
// --enable-libx264 \
169-
// --enable-libx265 \
170-
// --enable-nonfree
171-
Command::new(format!("{}/configure", *FFMPEG_DIR))
172-
.current_dir(&*FFMPEG_DIR)
173-
.env(
174-
"PKG_CONFIG_PATH",
175-
format!("{}/build/lib/pkgconfig", *FFMPEG_DIR),
176-
)
177-
.args(
178-
[
179-
format!(r#"--prefix={}/build"#, *FFMPEG_DIR),
180-
format!(r#"--extra-cflags=-I{}/build/include"#, *FFMPEG_DIR),
181-
format!(r#"--extra-ldflags=-L{}/build/lib"#, *FFMPEG_DIR),
182-
format!(r#"--bindir={}/build/bin"#, *FFMPEG_DIR),
183-
]
184-
.iter(),
185-
)
186-
.args(
187-
[
188-
"--pkg-config-flags=--static",
189-
"--extra-libs=-lpthread -lm",
190-
"--enable-gpl",
191-
"--enable-libass",
192-
"--enable-libfdk-aac",
193-
"--enable-libfreetype",
194-
"--enable-libmp3lame",
195-
"--enable-libopus",
196-
"--enable-libvorbis",
197-
"--enable-libvpx",
198-
"--enable-libx264",
199-
"--enable-libx265",
200-
"--enable-nonfree",
201-
]
202-
.iter(),
203-
)
204-
.spawn()
205-
.expect("FFmpeg build process: configure failed!")
206-
.wait()
207-
.expect("FFmpeg build process: configure failed!");
172+
// Corresponding to the shell script below:
173+
// ./configure \
174+
// --prefix="$PWD/build" \
175+
// --extra-cflags="-I$PWD/build/include" \
176+
// --extra-ldflags="-L$PWD/build/lib" \
177+
// --bindir="$PWD/build/bin" \
178+
// --pkg-config-flags="--static" \
179+
// --extra-libs="-lpthread -lm" \
180+
// --enable-gpl \
181+
// --enable-libass \
182+
// --enable-libfdk-aac \
183+
// --enable-libfreetype \
184+
// --enable-libmp3lame \
185+
// --enable-libopus \
186+
// --enable-libvorbis \
187+
// --enable-libvpx \
188+
// --enable-libx264 \
189+
// --enable-libx265 \
190+
// --enable-nonfree
191+
Command::new(format!("{}/configure", *FFMPEG_DIR))
192+
.current_dir(&*FFMPEG_DIR)
193+
.env(
194+
"PKG_CONFIG_PATH",
195+
format!("{}/build/lib/pkgconfig", *FFMPEG_DIR),
196+
)
197+
.args(
198+
[
199+
format!(r#"--prefix={}/build"#, *FFMPEG_DIR),
200+
format!(r#"--extra-cflags=-I{}/build/include"#, *FFMPEG_DIR),
201+
format!(r#"--extra-ldflags=-L{}/build/lib"#, *FFMPEG_DIR),
202+
format!(r#"--bindir={}/build/bin"#, *FFMPEG_DIR),
203+
]
204+
.iter(),
205+
)
206+
.args(
207+
[
208+
"--pkg-config-flags=--static",
209+
"--extra-libs=-lpthread -lm",
210+
"--enable-gpl",
211+
"--enable-libass",
212+
"--enable-libfdk-aac",
213+
"--enable-libfreetype",
214+
"--enable-libmp3lame",
215+
"--enable-libopus",
216+
"--enable-libvorbis",
217+
"--enable-libvpx",
218+
"--enable-libx264",
219+
"--enable-libx265",
220+
"--enable-nonfree",
221+
]
222+
.iter(),
223+
)
224+
.spawn()
225+
.expect("FFmpeg build process: configure failed!")
226+
.wait()
227+
.expect("FFmpeg build process: configure failed!");
208228

209-
Command::new("make")
210-
.current_dir(&*FFMPEG_DIR)
211-
.arg(format!("-j{}", *NUM_CPUS))
212-
.spawn()
213-
.expect("FFmpeg build process: make compile failed!")
214-
.wait()
215-
.expect("FFmpeg build process: make compile failed!");
229+
Command::new("make")
230+
.current_dir(&*FFMPEG_DIR)
231+
.arg(format!("-j{}", *NUM_CPUS))
232+
.spawn()
233+
.expect("FFmpeg build process: make compile failed!")
234+
.wait()
235+
.expect("FFmpeg build process: make compile failed!");
216236

217-
Command::new("make")
218-
.current_dir(&*FFMPEG_DIR)
219-
.arg(format!("-j{}", *NUM_CPUS))
220-
.arg("install")
221-
.spawn()
222-
.expect("FFmpeg build process: make install failed!")
223-
.wait()
224-
.expect("FFmpeg build process: make install failed!");
237+
Command::new("make")
238+
.current_dir(&*FFMPEG_DIR)
239+
.arg(format!("-j{}", *NUM_CPUS))
240+
.arg("install")
241+
.spawn()
242+
.expect("FFmpeg build process: make install failed!")
243+
.wait()
244+
.expect("FFmpeg build process: make install failed!");
225245

226-
/* Commented because it's not needed, we are not using any specific shell.
227-
Command::new("hash")
228-
.current_dir(&*FFMPEG_DIR)
229-
.arg("-r")
230-
.spawn()
231-
.expect("FFmpeg build process: clear hash cache failed!")
232-
.wait()
233-
.expect("FFmpeg build process: clear hash cache failed!");
234-
*/
246+
/* Commented because it's not needed, we are not using any specific shell.
247+
Command::new("hash")
248+
.current_dir(&*FFMPEG_DIR)
249+
.arg("-r")
250+
.spawn()
251+
.expect("FFmpeg build process: clear hash cache failed!")
252+
.wait()
253+
.expect("FFmpeg build process: clear hash cache failed!");
254+
*/
255+
}
256+
257+
// System FFmpeg found.
258+
Ok(_) => {}
259+
}
235260
}
236261

237262
// We currently only support building with static libraries.
238-
239-
/* Thanks to pkg-config, we don't need this.
240-
// Output link libraries
241-
(&*LIBS)
242-
.iter()
243-
.for_each(|name| println!("cargo:rustc-link-lib={}={}", "static", name));
244-
*/
245-
246263
// Probe libraries
247-
// TODO if not enabled, we should not probe it
264+
// TODO if not enabled, we should not probe it. Should modify probe_system_ffmpeg() too.
248265
let include_paths = (&*LIBS)
249266
.iter()
250267
.map(|name| "lib".to_owned() + name)
251268
.map(|libname| {
252269
pkgconfig::Config::new()
253270
.statik(true)
271+
.cargo_metadata(true)
254272
.probe(&libname)
255273
.unwrap_or_else(|_| panic!(format!("{} not found!", libname)))
256274
.include_paths

0 commit comments

Comments
 (0)