2024-10-24 12:26:52 +01:00
|
|
|
use anyhow::Error;
|
2024-11-06 13:41:42 +00:00
|
|
|
use ffmpeg_sys_the_third::{
|
|
|
|
av_dict_set, av_frame_alloc, av_frame_copy_props, av_frame_free, av_hwframe_transfer_data,
|
|
|
|
av_make_error_string, av_opt_next, av_opt_set, AVDictionary, AVFrame, AVOption,
|
|
|
|
AV_OPT_SEARCH_CHILDREN,
|
|
|
|
};
|
2024-10-24 12:26:52 +01:00
|
|
|
use std::collections::HashMap;
|
|
|
|
use std::ptr;
|
2024-10-23 14:48:03 +01:00
|
|
|
|
|
|
|
mod decode;
|
|
|
|
mod demux;
|
2024-11-08 14:28:38 +00:00
|
|
|
mod encode;
|
2024-11-06 09:34:37 +00:00
|
|
|
mod filter;
|
2024-11-13 13:32:46 +00:00
|
|
|
mod mux;
|
2024-10-23 14:48:03 +01:00
|
|
|
mod resample;
|
|
|
|
mod scale;
|
2024-10-24 12:26:52 +01:00
|
|
|
mod stream_info;
|
2024-11-09 15:47:03 +00:00
|
|
|
mod transcode;
|
2024-10-23 14:48:03 +01:00
|
|
|
|
2024-10-23 21:56:53 +01:00
|
|
|
#[macro_export]
|
2024-11-09 15:47:03 +00:00
|
|
|
macro_rules! bail_ffmpeg {
|
2024-10-23 14:48:03 +01:00
|
|
|
($x:expr) => {
|
|
|
|
if $x < 0 {
|
2024-11-09 15:47:03 +00:00
|
|
|
anyhow::bail!($crate::get_ffmpeg_error_msg($x))
|
2024-11-05 10:59:12 +00:00
|
|
|
}
|
|
|
|
};
|
|
|
|
($x:expr,$msg:expr) => {
|
|
|
|
if $x < 0 {
|
2024-11-09 15:47:03 +00:00
|
|
|
anyhow::bail!(format!("{}: {}", $msg, $crate::get_ffmpeg_error_msg($x)))
|
2024-10-23 14:48:03 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-11-06 09:34:37 +00:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! cstr {
|
|
|
|
($str:expr) => {
|
2024-11-13 13:32:46 +00:00
|
|
|
std::ffi::CString::new($str).unwrap().into_raw()
|
2024-11-06 09:34:37 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-11-06 14:12:45 +00:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! rstr {
|
|
|
|
($str:expr) => {
|
2024-11-08 11:48:49 +00:00
|
|
|
if !$str.is_null() {
|
|
|
|
core::ffi::CStr::from_ptr($str).to_str().unwrap()
|
|
|
|
} else {
|
|
|
|
""
|
|
|
|
}
|
2024-11-06 14:12:45 +00:00
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2024-11-13 15:39:13 +00:00
|
|
|
pub(crate) const AVIO_BUFFER_SIZE: usize = 4096;
|
|
|
|
|
2024-10-23 14:48:03 +01:00
|
|
|
fn get_ffmpeg_error_msg(ret: libc::c_int) -> String {
|
|
|
|
unsafe {
|
|
|
|
const BUF_SIZE: usize = 512;
|
|
|
|
let mut buf: [libc::c_char; BUF_SIZE] = [0; BUF_SIZE];
|
|
|
|
av_make_error_string(buf.as_mut_ptr(), BUF_SIZE, ret);
|
2024-11-06 14:12:45 +00:00
|
|
|
rstr!(buf.as_ptr()).to_string()
|
2024-10-23 14:48:03 +01:00
|
|
|
}
|
|
|
|
}
|
2024-10-23 19:28:13 +01:00
|
|
|
|
2024-10-24 12:26:52 +01:00
|
|
|
unsafe fn options_to_dict(options: HashMap<String, String>) -> Result<*mut AVDictionary, Error> {
|
|
|
|
let mut dict = ptr::null_mut();
|
|
|
|
for (key, value) in options {
|
2024-11-06 14:12:45 +00:00
|
|
|
let ret = av_dict_set(&mut dict, cstr!(key), cstr!(value), 0);
|
2024-11-09 15:47:03 +00:00
|
|
|
bail_ffmpeg!(ret);
|
2024-10-24 12:26:52 +01:00
|
|
|
}
|
|
|
|
Ok(dict)
|
|
|
|
}
|
|
|
|
|
2024-11-05 13:57:13 +00:00
|
|
|
/// Format seconds value into human-readable string
|
|
|
|
pub fn format_time(secs: f32) -> String {
|
|
|
|
const MIN: f32 = 60.0;
|
|
|
|
const HR: f32 = MIN * 60.0;
|
|
|
|
|
|
|
|
if secs >= HR {
|
|
|
|
format!(
|
|
|
|
"{:0>2.0}h {:0>2.0}m {:0>2.0}s",
|
|
|
|
(secs / HR).floor(),
|
|
|
|
((secs % HR) / MIN).floor(),
|
|
|
|
(secs % MIN).floor()
|
|
|
|
)
|
|
|
|
} else if secs >= MIN {
|
|
|
|
format!(
|
|
|
|
"{:0>2.0}m {:0>2.0}s",
|
|
|
|
(secs / MIN).floor(),
|
|
|
|
(secs % MIN).floor()
|
|
|
|
)
|
|
|
|
} else {
|
|
|
|
format!("{:0>2.2}s", secs)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-10-24 12:26:52 +01:00
|
|
|
fn list_opts(ctx: *mut libc::c_void) -> Result<Vec<String>, Error> {
|
|
|
|
let mut opt_ptr: *const AVOption = ptr::null_mut();
|
|
|
|
|
|
|
|
let mut ret = vec![];
|
|
|
|
unsafe {
|
|
|
|
loop {
|
|
|
|
opt_ptr = av_opt_next(ctx, opt_ptr);
|
|
|
|
if opt_ptr.is_null() {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-11-06 14:12:45 +00:00
|
|
|
ret.push(rstr!((*opt_ptr).name).to_string());
|
2024-10-24 12:26:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(ret)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn set_opts(ctx: *mut libc::c_void, options: HashMap<String, String>) -> Result<(), Error> {
|
|
|
|
unsafe {
|
|
|
|
for (key, value) in options {
|
2024-11-06 14:12:45 +00:00
|
|
|
let ret = av_opt_set(ctx, cstr!(key), cstr!(value), AV_OPT_SEARCH_CHILDREN);
|
2024-11-09 15:47:03 +00:00
|
|
|
bail_ffmpeg!(ret);
|
2024-10-24 12:26:52 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-11-06 10:07:28 +00:00
|
|
|
/// Get the frame as CPU frame
|
|
|
|
pub unsafe fn get_frame_from_hw(mut frame: *mut AVFrame) -> Result<*mut AVFrame, Error> {
|
|
|
|
if (*frame).hw_frames_ctx.is_null() {
|
|
|
|
Ok(frame)
|
|
|
|
} else {
|
|
|
|
let new_frame = av_frame_alloc();
|
|
|
|
let ret = av_hwframe_transfer_data(new_frame, frame, 0);
|
2024-11-09 15:47:03 +00:00
|
|
|
bail_ffmpeg!(ret);
|
2024-11-06 10:36:47 +00:00
|
|
|
av_frame_copy_props(new_frame, frame);
|
2024-11-06 10:07:28 +00:00
|
|
|
av_frame_free(&mut frame);
|
|
|
|
Ok(new_frame)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-11-08 14:28:38 +00:00
|
|
|
#[cfg(test)]
|
|
|
|
pub unsafe fn generate_test_frame() -> *mut AVFrame {
|
|
|
|
use ffmpeg_sys_the_third::{av_frame_get_buffer, AVPixelFormat};
|
|
|
|
use std::mem::transmute;
|
|
|
|
|
|
|
|
let frame = av_frame_alloc();
|
2024-11-09 15:47:03 +00:00
|
|
|
(*frame).width = 1024;
|
|
|
|
(*frame).height = 1024;
|
2024-11-08 14:28:38 +00:00
|
|
|
(*frame).format = transmute(AVPixelFormat::AV_PIX_FMT_RGB24);
|
|
|
|
av_frame_get_buffer(frame, 0);
|
|
|
|
|
|
|
|
let mut lx = 0;
|
|
|
|
for line in 0..(*frame).height {
|
|
|
|
let c = lx % 3;
|
|
|
|
for y in 0..(*frame).width as usize {
|
|
|
|
let ptr = (*frame).data[0];
|
|
|
|
let offset = (line * (*frame).linesize[0]) as usize + (y * 3);
|
|
|
|
match c {
|
|
|
|
0 => *ptr.add(offset) = 0xff,
|
|
|
|
1 => *ptr.add(offset + 1) = 0xff,
|
|
|
|
2 => *ptr.add(offset + 2) = 0xff,
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
lx += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
frame
|
|
|
|
}
|
|
|
|
|
2024-10-23 19:28:13 +01:00
|
|
|
pub use decode::*;
|
|
|
|
pub use demux::*;
|
2024-11-09 15:47:03 +00:00
|
|
|
pub use encode::*;
|
2024-10-23 19:34:57 +01:00
|
|
|
pub use ffmpeg_sys_the_third;
|
2024-11-06 09:34:37 +00:00
|
|
|
pub use filter::*;
|
2024-11-13 13:32:46 +00:00
|
|
|
pub use mux::*;
|
2024-10-23 19:28:13 +01:00
|
|
|
pub use resample::*;
|
|
|
|
pub use scale::*;
|
2024-10-24 12:26:52 +01:00
|
|
|
pub use stream_info::*;
|
2024-11-09 15:47:03 +00:00
|
|
|
pub use transcode::*;
|