Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ rpi = []
[dependencies]
libc = "0.2"
bitflags = "1.2"
log = "0.4"
vsprintf = "2.0"

[dependencies.image]
version = "0.23"
Expand Down
10 changes: 10 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub extern crate ffmpeg_sys_next as sys;
#[cfg(feature = "image")]
extern crate image;
extern crate libc;
extern crate log as log_crate;

pub use sys as ffi;

Expand Down Expand Up @@ -99,6 +100,14 @@ fn init_filter() {
#[cfg(not(feature = "filter"))]
fn init_filter() {}

#[cfg(all(target_arch = "x86_64", any(target_family = "windows", target_family = "unix")))]
fn init_log() {
util::log::callback::set_logging_callback();
}

#[cfg(not(all(target_arch = "x86_64", any(target_family = "windows", target_family = "unix"))))]
fn init_log() {}

#[cfg_attr(
any(feature = "ffmpeg4", feature = "ffmpeg41", feature = "ffmpeg42"),
deprecated(
Expand All @@ -111,6 +120,7 @@ pub fn init() -> Result<(), Error> {
init_format();
init_device();
init_filter();
init_log();

Ok(())
}
111 changes: 111 additions & 0 deletions src/util/log/callback.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
use std::convert::TryInto;
use std::ffi::CStr;
use std::io::Error;

use libc::c_char;
use libc::c_int;
use log_crate::LevelFilter;

use util::log::Level;

// This is ugly, but va_list is not stabilized

#[cfg(all(target_arch = "x86_64", target_family = "windows"))]
pub type Args = sys::va_list;

#[cfg(all(target_arch = "x86_64", target_family = "unix"))]
pub type Args = *mut sys::__va_list_tag;

pub struct LogContext {
context: usize,
level: Level,
fmt: *const c_char,
args: Args,
}

impl LogContext {
/// Formats the message
#[inline]
pub fn to_message(&self) -> Result<String, Error> {
unsafe { vsprintf::vsprintf(self.fmt, self.args) }
}

/// The format string
#[inline]
pub fn format(&self) -> &CStr {
unsafe { CStr::from_ptr(self.fmt) }
}

/// The log level
#[inline]
pub fn level(&self) -> Level {
self.level
}

/// The log context. Mostly the address of whatever component called the log function.
#[inline]
pub fn context(&self) -> usize {
self.context
}

/// The log varargs.
///
/// **Platform dependant**, use with caution.
#[inline]
pub unsafe fn args(&self) -> Args {
self.args
}
}

pub trait Callback {
fn call(context: &LogContext);
}

unsafe extern "C" fn wrapped_callback<T: Callback>(context: *mut libc::c_void, level: c_int, fmt: *const c_char, args: Args) {
let context = LogContext {
context: context as usize,
level: level.try_into().unwrap_or(Level::Info),
fmt,
args,
};
T::call(&context);
}

/// Sets the log callback
pub fn set_callback<C: Callback>() {
unsafe {
sys::av_log_set_callback(Some(wrapped_callback::<C>));
}
}

/// Resets the log callback
pub fn reset_callback() {
unsafe {
sys::av_log_set_callback(None);
}
}

/// Sets the logging callback
///
/// Logs using the log crate to the target 'ffmpeg'
pub fn set_logging_callback() {
set_callback::<LoggingCallback>();
}

/// Logs using the log crate to the target 'ffmpeg'
pub struct LoggingCallback;

impl Callback for LoggingCallback {
fn call(context: &LogContext) {
if let Some(log_level) = LevelFilter::from(context.level()).to_level() {
// Don't format when level is disabled
if log::log_enabled!(log_level) {
match context.to_message() {
Ok(message) => log::log!(target: "ffmpeg", log_level, "{}", message.trim()),
Err(e) =>
log::warn!(target: "ffmpeg", "failed to format ffmpeg log message: {:?}", e),
}
}
}
}
}
15 changes: 15 additions & 0 deletions src/util/log/level.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ use std::convert::TryFrom;
use ffi::*;
use libc::c_int;

use log_crate::LevelFilter;

#[derive(Eq, PartialEq, Clone, Copy, Debug)]
pub enum Level {
Quiet,
Expand Down Expand Up @@ -52,3 +54,16 @@ impl From<Level> for c_int {
}
}
}

impl From<Level> for LevelFilter {
fn from(level: Level) -> LevelFilter {
match level {
Level::Quiet => LevelFilter::Off,
Level::Trace => LevelFilter::Trace,
Level::Debug | Level::Verbose => LevelFilter::Debug,
Level::Info => LevelFilter::Info,
Level::Warning => LevelFilter::Warn,
Level::Error | Level::Fatal | Level::Panic => LevelFilter::Error,
}
}
}
3 changes: 3 additions & 0 deletions src/util/log/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ pub use self::flag::Flags;
use ffi::*;
use std::convert::TryInto;

#[cfg(all(target_arch = "x86_64", any(target_family = "windows", target_family = "unix")))]
pub mod callback;

pub fn set_level(value: Level) {
unsafe { av_log_set_level(value.into()) }
}
Expand Down