explicitly test ffmpeg library compatibility
Makes the problem in #11 more obvious.
This commit is contained in:
parent
99f10dfba6
commit
b9ebb74a58
|
@ -2,15 +2,15 @@
|
|||
name = "moonfire-ffmpeg"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"cc 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gcc"
|
||||
version = "0.3.51"
|
||||
name = "cc"
|
||||
version = "1.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
|
@ -29,7 +29,7 @@ version = "0.3.9"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum gcc 0.3.51 (registry+https://github.com/rust-lang/crates.io-index)" = "120d07f202dcc3f72859422563522b66fe6463a4c513df062874daad05f85f0a"
|
||||
"checksum cc 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ef4019bdb99c0c1ddd56c12c2f507c174d729c6915eca6bd9d27c42f3d93b0f4"
|
||||
"checksum libc 0.2.24 (registry+https://github.com/rust-lang/crates.io-index)" = "38f5c2b18a287cf78b4097db62e20f43cace381dc76ae5c0a3073067f78b7ddc"
|
||||
"checksum log 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "880f77541efa6e5cc74e76910c9884d9859683118839d6a1dc3b11e63512565b"
|
||||
"checksum pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "3a8b4c6b8165cd1a1cd4b9b120978131389f64bdaf456435caa41e630edba903"
|
||||
|
|
|
@ -33,7 +33,7 @@ extern crate libc;
|
|||
|
||||
use std::cell::{Ref, RefCell};
|
||||
use std::ffi::CStr;
|
||||
use std::fmt;
|
||||
use std::fmt::{self, Write};
|
||||
use std::marker::PhantomData;
|
||||
use std::ptr;
|
||||
use std::sync;
|
||||
|
@ -366,14 +366,47 @@ impl fmt::Display for Error {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct Version(libc::c_int);
|
||||
|
||||
impl Version {
|
||||
fn major(self) -> libc::c_int { (self.0 >> 16) & 0xFF }
|
||||
fn minor(self) -> libc::c_int { (self.0 >> 8) & 0xFF }
|
||||
}
|
||||
|
||||
impl fmt::Display for Version {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}.{}.{}", (self.0 >> 16) & 0xFF, (self.0 >> 8) & 0xFF, self.0 & 0xFF)
|
||||
}
|
||||
}
|
||||
|
||||
struct Library {
|
||||
name: &'static str,
|
||||
compiled: Version,
|
||||
running: Version,
|
||||
}
|
||||
|
||||
impl Library {
|
||||
fn new(name: &'static str, compiled: libc::c_int, running: libc::c_int) -> Self {
|
||||
Library {
|
||||
name,
|
||||
compiled: Version(compiled),
|
||||
running: Version(running),
|
||||
}
|
||||
}
|
||||
|
||||
fn is_compatible(&self) -> bool {
|
||||
self.running.major() == self.compiled.major() &&
|
||||
self.running.minor() >= self.compiled.minor()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Library {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(f, "{}: running={} compiled={}", self.name, self.running, self.compiled)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Dictionary(*mut AVDictionary);
|
||||
|
||||
impl Dictionary {
|
||||
|
@ -416,21 +449,38 @@ impl Drop for Dictionary {
|
|||
impl Ffmpeg {
|
||||
pub fn new() -> Ffmpeg {
|
||||
START.call_once(|| unsafe {
|
||||
let libs = &[
|
||||
Library::new("avutil", moonfire_ffmpeg_compiled_libavutil_version,
|
||||
avutil_version()),
|
||||
Library::new("avcodec", moonfire_ffmpeg_compiled_libavcodec_version,
|
||||
avcodec_version()),
|
||||
Library::new("avformat", moonfire_ffmpeg_compiled_libavformat_version,
|
||||
avformat_version()),
|
||||
];
|
||||
let mut msg = String::new();
|
||||
let mut compatible = true;
|
||||
for l in libs {
|
||||
write!(&mut msg, "\n{}", l).unwrap();
|
||||
if !l.is_compatible() {
|
||||
compatible = false;
|
||||
msg.push_str(" <- not ABI-compatible!");
|
||||
}
|
||||
}
|
||||
if !compatible {
|
||||
panic!("Incompatible ffmpeg versions:{}", msg);
|
||||
}
|
||||
for l in libs {
|
||||
if !l.is_compatible() {
|
||||
panic!("Library {}'s running version {} isn't ABI-compatible with \
|
||||
compiled version {}!", l.name, l.running, l.compiled);
|
||||
}
|
||||
}
|
||||
moonfire_ffmpeg_init();
|
||||
av_register_all();
|
||||
if avformat_network_init() < 0 {
|
||||
panic!("avformat_network_init failed");
|
||||
}
|
||||
info!("Initialized ffmpeg. Versions:\n\
|
||||
avcodec compiled={} running={}\n\
|
||||
avformat compiled={} running={}\n\
|
||||
avutil compiled={} running={}",
|
||||
Version(moonfire_ffmpeg_compiled_libavcodec_version),
|
||||
Version(avcodec_version()),
|
||||
Version(moonfire_ffmpeg_compiled_libavformat_version),
|
||||
Version(avformat_version()),
|
||||
Version(moonfire_ffmpeg_compiled_libavutil_version),
|
||||
Version(avutil_version()));
|
||||
info!("Initialized ffmpeg. Versions:{}", msg);
|
||||
});
|
||||
Ffmpeg{}
|
||||
}
|
||||
|
@ -441,6 +491,32 @@ mod tests {
|
|||
use std::ffi::CString;
|
||||
use super::Error;
|
||||
|
||||
/// Just tests that this doesn't crash with an ABI compatibility error.
|
||||
#[test]
|
||||
fn test_init() { super::Ffmpeg::new(); }
|
||||
|
||||
#[test]
|
||||
fn test_is_compatible() {
|
||||
// compiled major/minor/patch, running major/minor/patch, expected compatible
|
||||
use ::libc::c_int;
|
||||
struct Test(c_int, c_int, c_int, c_int, c_int, c_int, bool);
|
||||
|
||||
let tests = &[
|
||||
Test(55, 1, 2, 55, 1, 2, true), // same version, compatible
|
||||
Test(55, 1, 2, 55, 2, 1, true), // newer minor version, compatible
|
||||
Test(55, 1, 3, 55, 1, 2, true), // older patch version, compatible (but weird)
|
||||
Test(55, 2, 2, 55, 1, 2, false), // older minor version, incompatible
|
||||
Test(55, 1, 2, 56, 1, 2, false), // newer major version, incompatible
|
||||
Test(56, 1, 2, 55, 1, 2, false), // older major version, incompatible
|
||||
];
|
||||
|
||||
for t in tests {
|
||||
let l = super::Library::new(
|
||||
"avutil", (t.0 << 16) | (t.1 << 8) | t.2, (t.3 << 16) | (t.4 << 8) | t.5);
|
||||
assert!(l.is_compatible() == t.6, "{} expected={}", l, t.6);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_error() {
|
||||
let eof_formatted = format!("{}", Error::eof());
|
||||
|
|
Loading…
Reference in New Issue