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"
|
name = "moonfire-ffmpeg"
|
||||||
version = "0.0.1"
|
version = "0.0.1"
|
||||||
dependencies = [
|
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)",
|
"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)",
|
"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)",
|
"pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "gcc"
|
name = "cc"
|
||||||
version = "0.3.51"
|
version = "1.0.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -29,7 +29,7 @@ version = "0.3.9"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
|
||||||
[metadata]
|
[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 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 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"
|
"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::cell::{Ref, RefCell};
|
||||||
use std::ffi::CStr;
|
use std::ffi::CStr;
|
||||||
use std::fmt;
|
use std::fmt::{self, Write};
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use std::sync;
|
use std::sync;
|
||||||
|
@ -366,14 +366,47 @@ impl fmt::Display for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
struct Version(libc::c_int);
|
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 {
|
impl fmt::Display for Version {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "{}.{}.{}", (self.0 >> 16) & 0xFF, (self.0 >> 8) & 0xFF, self.0 & 0xFF)
|
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);
|
pub struct Dictionary(*mut AVDictionary);
|
||||||
|
|
||||||
impl Dictionary {
|
impl Dictionary {
|
||||||
|
@ -416,21 +449,38 @@ impl Drop for Dictionary {
|
||||||
impl Ffmpeg {
|
impl Ffmpeg {
|
||||||
pub fn new() -> Ffmpeg {
|
pub fn new() -> Ffmpeg {
|
||||||
START.call_once(|| unsafe {
|
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();
|
moonfire_ffmpeg_init();
|
||||||
av_register_all();
|
av_register_all();
|
||||||
if avformat_network_init() < 0 {
|
if avformat_network_init() < 0 {
|
||||||
panic!("avformat_network_init failed");
|
panic!("avformat_network_init failed");
|
||||||
}
|
}
|
||||||
info!("Initialized ffmpeg. Versions:\n\
|
info!("Initialized ffmpeg. Versions:{}", msg);
|
||||||
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()));
|
|
||||||
});
|
});
|
||||||
Ffmpeg{}
|
Ffmpeg{}
|
||||||
}
|
}
|
||||||
|
@ -441,6 +491,32 @@ mod tests {
|
||||||
use std::ffi::CString;
|
use std::ffi::CString;
|
||||||
use super::Error;
|
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]
|
#[test]
|
||||||
fn test_error() {
|
fn test_error() {
|
||||||
let eof_formatted = format!("{}", Error::eof());
|
let eof_formatted = format!("{}", Error::eof());
|
||||||
|
|
Loading…
Reference in New Issue