use crate::ffi;
use std::{
ffi::{c_uint, CStr},
fmt::Display,
};
#[derive(Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Clone, Copy)]
pub struct AvVersion {
pub major: u8,
pub minor: u8,
pub micro: u8,
}
impl AvVersion {
pub const fn new(major: u8, minor: u8, micro: u8) -> Self {
Self {
major,
minor,
micro,
}
}
pub const fn from_av_int(version: c_uint) -> Self {
let bytes = version.to_le_bytes();
Self {
major: bytes[2],
minor: bytes[1],
micro: bytes[0],
}
}
pub const fn to_av_int(self) -> c_uint {
let mut bytes = [0u8; std::mem::size_of::<c_uint>()];
bytes[2] = self.major;
bytes[1] = self.minor;
bytes[0] = self.micro;
c_uint::from_le_bytes(bytes)
}
}
impl Display for AvVersion {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}.{}.{}", self.major, self.minor, self.micro)
}
}
macro_rules! _impl_version {
($modname:ident) => {
paste::paste! {
#[doc = r" Descriptive semver version of the `lib" $modname r"` that ffi bindings were generated against."]
pub const VERSION: crate::avutil::AvVersion = crate::avutil::AvVersion::new(
crate::ffi::[< LIB $modname:upper _VERSION_MAJOR >] as u8,
crate::ffi::[< LIB $modname:upper _VERSION_MINOR >] as u8,
crate::ffi::[< LIB $modname:upper _VERSION_MICRO >] as u8,
);
#[doc = r" Returns the semver version of the `lib" $modname r"` that has been linked (whether static or dynamic)."]
#[doc = r" use rsmpeg::" $modname r";"]
#[doc = r" let version = " $modname "::version();"]
pub fn version() -> crate::avutil::AvVersion {
crate::avutil::AvVersion::from_av_int(unsafe { crate::ffi::[< $modname _version >]() })
}
#[doc = r" Returns the license of the `lib" $modname r"` that has been linked (whether static or dynamic)."]
#[doc = r" use rsmpeg::" $modname r";"]
#[doc = r" let license = " $modname "::license();"]
pub fn license() -> &'static core::ffi::CStr {
unsafe { core::ffi::CStr::from_ptr(crate::ffi::[< $modname _license >]()) }
}
#[doc = r" Returns the configuration of the `lib" $modname r"` that has been linked (whether static or dynamic)."]
#[doc = r" use rsmpeg::" $modname r";"]
#[doc = r" let configuration = " $modname "::configuration();"]
pub fn configuration() -> &'static core::ffi::CStr {
unsafe { core::ffi::CStr::from_ptr(crate::ffi::[< $modname _configuration >]()) }
}
}
}
}
pub(crate) use _impl_version as impl_version;
pub const FFMPEG_VERSION: &CStr = unsafe { CStr::from_ptr(ffi::FFMPEG_VERSION.as_ptr().cast()) };
pub fn version_info() -> &'static CStr {
unsafe { CStr::from_ptr(ffi::av_version_info()) }
}
#[cfg(test)]
mod tests {
use crate::avutil::AvVersion;
use core::ffi::c_uint;
#[test]
fn test_avversion_semver_order() {
let a = AvVersion {
major: 100,
minor: 100,
micro: 100,
};
assert!(
a < AvVersion {
major: 101,
minor: 0,
micro: 0
}
);
assert!(
a > AvVersion {
major: 99,
minor: 255,
micro: 255
}
);
assert!(
a < AvVersion {
major: 100,
minor: 101,
micro: 0
}
);
assert!(
a > AvVersion {
major: 100,
minor: 99,
micro: 255
}
);
assert!(
a < AvVersion {
major: 100,
minor: 100,
micro: 101
}
);
assert!(
a > AvVersion {
major: 100,
minor: 100,
micro: 99
}
);
}
#[test]
fn test_avversion_decode() {
let av_int: c_uint = 3999588;
let version = AvVersion::from_av_int(av_int);
assert_eq!(
version,
AvVersion {
major: 61,
minor: 7,
micro: 100
}
);
assert_eq!(version.to_av_int(), av_int);
}
}