From a9e173a28ceb4fdd4288b3ee3a880f9acdb5895d Mon Sep 17 00:00:00 2001 From: meh Date: Tue, 9 Mar 2021 12:33:46 +0100 Subject: [PATCH] feat: add log integration --- Cargo.toml | 8 ++++++ src/lib.rs | 6 ++-- src/util/error.rs | 72 +++++++++++++++++++++++++++++------------------ src/util/log.rs | 53 ++++++++++++++++++++++++++++++++++ src/util/mod.rs | 3 ++ 5 files changed, 113 insertions(+), 29 deletions(-) create mode 100644 src/util/log.rs diff --git a/Cargo.toml b/Cargo.toml index b2d56c2..ed2cc76 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -101,6 +101,7 @@ ffmpeg_4_3 = ["ffmpeg_4_2"] libc = "0.2" bitflags = "1.0" thiserror = "1" +vsprintf = "2" [dependencies.serde] version = "1.0.0" @@ -114,3 +115,10 @@ optional = true [dependencies.ffmpeg-sys] version = "4.2" default-features = false + +[dependencies.log] +version = "0.4" +optional = true + +[dev-dependencies] +env_logger = "0.8" diff --git a/src/lib.rs b/src/lib.rs index 8d19196..ff1c344 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -64,8 +64,10 @@ pub use crate::filter::Filter; pub mod software; -fn init_error() { +fn init_util() { util::error::register_all(); + #[cfg(feature = "log")] + util::log::register(); } #[cfg(feature = "format")] @@ -93,7 +95,7 @@ fn init_filter() { fn init_filter() {} pub fn init() -> Result<(), Error> { - init_error(); + init_util(); init_format(); init_device(); init_filter(); diff --git a/src/util/error.rs b/src/util/error.rs index 26cedff..313774c 100644 --- a/src/util/error.rs +++ b/src/util/error.rs @@ -4,8 +4,8 @@ use libc::c_int; use crate::ffi::*; -#[derive(Copy, Clone)] pub enum Error { + Io(io::Error), Bug, Bug2, Unknown, @@ -68,15 +68,55 @@ impl From for Error { AVERROR_HTTP_NOT_FOUND => Error::HttpNotFound, AVERROR_HTTP_OTHER_4XX => Error::HttpOther4xx, AVERROR_HTTP_SERVER_ERROR => Error::HttpServerError, - - _ => Error::Unknown, + err => Error::Io(io::Error::from_raw_os_error(-err)), } } } impl Into for Error { fn into(self) -> c_int { + self.as_raw_error() + } +} + +impl From for io::Error { + fn from(value: Error) -> io::Error { + match value { + Error::Io(err) => + err, + + value => + io::Error::new(io::ErrorKind::Other, value) + } + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self { + Error::Io(err) => + err.fmt(f), + + err => f.write_str(unsafe { + from_utf8_unchecked(CStr::from_ptr(STRINGS[index(err)].as_ptr()).to_bytes()) + }) + } + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + f.write_str("ffmpeg::Error(")?; + f.write_str(&format!("{}: ", AVUNERROR(self.as_raw_error())))?; + fmt::Display::fmt(self, f)?; + f.write_str(")") + } +} + +impl Error { + pub fn as_raw_error(&self) -> c_int { + match self { + Error::Io(err) => err.raw_os_error().unwrap(), Error::BsfNotFound => AVERROR_BSF_NOT_FOUND, Error::Bug => AVERROR_BUG, Error::BufferTooSmall => AVERROR_BUFFER_TOO_SMALL, @@ -108,32 +148,10 @@ impl Into for Error { } } -impl From for io::Error { - fn from(value: Error) -> io::Error { - io::Error::new(io::ErrorKind::Other, value) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - f.write_str(unsafe { - from_utf8_unchecked(CStr::from_ptr(STRINGS[index(self)].as_ptr()).to_bytes()) - }) - } -} - -impl fmt::Debug for Error { - fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { - f.write_str("ffmpeg::Error(")?; - f.write_str(&format!("{}: ", AVUNERROR((*self).into())))?; - fmt::Display::fmt(self, f)?; - f.write_str(")") - } -} - #[inline(always)] fn index(error: &Error) -> usize { - match *error { + match error { + Error::Io(_) => unreachable!(), Error::BsfNotFound => 0, Error::Bug => 1, Error::BufferTooSmall => 2, diff --git a/src/util/log.rs b/src/util/log.rs new file mode 100644 index 0000000..5f059e1 --- /dev/null +++ b/src/util/log.rs @@ -0,0 +1,53 @@ +use libc::{c_void, c_int, c_char}; +use vsprintf::vsprintf; +use log; +use crate::ffi::*; + +pub fn set_level(level: log::Level) { + unsafe { + av_log_set_level(match level { + log::Level::Error => AV_LOG_ERROR, + log::Level::Warn => AV_LOG_WARNING, + log::Level::Info => AV_LOG_INFO, + log::Level::Debug => AV_LOG_DEBUG, + log::Level::Trace => AV_LOG_TRACE, + }); + } +} + +unsafe extern "C" fn callback(_ptr: *mut c_void, level: c_int, fmt: *const c_char, args: *mut __va_list_tag) { + let string = vsprintf(fmt, args).unwrap(); + let level = match level { + AV_LOG_PANIC | AV_LOG_FATAL | AV_LOG_ERROR => + log::LevelFilter::Error, + + AV_LOG_WARNING => + log::LevelFilter::Warn, + + AV_LOG_INFO => + log::LevelFilter::Info, + + AV_LOG_VERBOSE | AV_LOG_DEBUG => + log::LevelFilter::Debug, + + AV_LOG_TRACE => + log::LevelFilter::Trace, + + _ => + log::LevelFilter::Off, + }; + + if let Some(level) = level.to_level() { + log::log!(target: "ffmpeg", level, "{}", string.trim()); + } +} + +pub fn register() { + unsafe { + av_log_set_callback(Some(callback)); + } + + if let Some(level) = log::max_level().to_level() { + set_level(level); + } +} diff --git a/src/util/mod.rs b/src/util/mod.rs index 167dfb9..d32faab 100644 --- a/src/util/mod.rs +++ b/src/util/mod.rs @@ -15,6 +15,9 @@ pub mod range; pub mod rational; pub mod time; +#[cfg(feature = "log")] +pub mod log; + use std::{ffi::CStr, str::from_utf8_unchecked}; use crate::ffi::*;