use libav_sys::ffi::{
avformat_open_input,
AVFormatContext, avformat_network_init, av_strerror, avformat_find_stream_info, av_dump_format
};
use std::{os::raw::c_char, error::Error};
fn main() -> Result<(), Box<dyn Error>> {
println!("Hello, world!");
// initialize and deinitialize libav
let _guard = InitGuard::new();
let url = r#"file:C:/Users/lucac/downloads/BigBuckBunny.mp4"#;
//let url = r#"http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"#;
let c_url = std::ffi::CString::new(url)?;
let mut format_context_ptr: *mut AVFormatContext = std::ptr::null_mut();
handle_result(unsafe {
avformat_open_input(
&mut format_context_ptr,
c_url.as_ptr(),
std::ptr::null_mut(),
std::ptr::null_mut()
)
}, "avformat_open_input failed")?;
println!("Input opened!");
println!("format_context_ptr: {:?}", format_context_ptr);
handle_result(unsafe {
avformat_find_stream_info(
format_context_ptr,
std::ptr::null_mut()
)
}, "failed to find stream info")?;
unsafe {
av_dump_format(
format_context_ptr,
0,
c_url.as_ptr() as *const c_char,
0
);
}
// Find the first video stream
let video_stream_index = {
let mut video_stream_index = -1;
for i in 0..unsafe { (*format_context_ptr).nb_streams } {
let stream = unsafe { *(*format_context_ptr).streams.offset(i as isize) };
if unsafe { (*(*stream).codecpar).codec_type } == libav_sys::ffi::AVMediaType_AVMEDIA_TYPE_VIDEO {
video_stream_index = i as i32;
break;
}
}
video_stream_index
};
if video_stream_index < 0 {
return Err("Could not find a video stream".into());
}
Ok(())
}
struct InitGuard;
impl InitGuard {
fn new() -> Self {
init();
InitGuard
}
}
impl Drop for InitGuard {
fn drop(&mut self) {
deinit();
}
}
fn init() {
// TODO ??? libav_sys::ffi::av_register_all();
let result = unsafe { avformat_network_init() };
if result != 0 {
panic!("avformat_network_init failed");
}
}
fn deinit() {
let result = unsafe { libav_sys::ffi::avformat_network_deinit() };
if result != 0 {
panic!("avformat_network_deinit failed");
}
}
fn av_error_to_string(error_code: std::os::raw::c_int) -> String {
// create a buffer for the error message
let mut error_buffer: Vec<std::os::raw::c_char> = vec![0; 1024];
// get the error message
let result = unsafe {
av_strerror(
error_code,
error_buffer.as_mut_ptr(),
error_buffer.len()
)
};
if result != 0 {
panic!("av_strerror failed");
}
// convert to rust string
error_buffer.iter().take_while(|c| **c != 0).map(|c| *c as u8 as char).collect()
}
fn handle_result(result: std::os::raw::c_int, error_message: &str) -> Result<(), Box<dyn Error>> {
if result < 0 {
return Err(format!("{}: {}", error_message, av_error_to_string(result)).into());
}
Ok(())
}
fn tmp() {
Drop
}