diff --git a/Cargo.toml b/Cargo.toml index 6a9cd05..7d18bb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -29,12 +29,10 @@ doctest = false [dependencies] once_cell = "1.4.0" +libc = "0.2.71" [build-dependencies] bindgen = "0.54.0" once_cell = "1.4.0" pkg-config = "0.3.17" num_cpus = "1.13.0" - -[dev-dependencies] -libc = "0.2.71" diff --git a/examples/slice/main.rs b/examples/slice/main.rs index b8bf7e7..98c99c3 100644 --- a/examples/slice/main.rs +++ b/examples/slice/main.rs @@ -1,9 +1,11 @@ //! Port from Original code: https://github.com/leandromoreira/ffmpeg-libav-tutorial/blob/master/0_hello_world.c //! Since this is a ported code, many warnings will emits. #![allow(non_snake_case, non_camel_case_types, non_upper_case_globals)] -use rusty_ffmpeg::ffi::*; +use rusty_ffmpeg::{ + avutil::error::{AVERROR, AVERROR_EOF}, + ffi, +}; -use libc::c_int; use std::{ ffi::{CStr, CString}, fs::File, @@ -13,46 +15,12 @@ use std::{ slice, }; -#[inline(always)] -pub fn AVERROR(e: c_int) -> c_int { - -e -} - -#[macro_export] -macro_rules! MKTAG { - ($a:expr, $b:expr, $c:expr, $d:expr) => { - ($a as isize) | (($b as isize) << 8) | (($c as isize) << 16) | (($d as isize) << 24) - }; -} - -macro_rules! FFERRTAG { - ($a:expr, $b:expr, $c:expr, $d:expr) => { - -MKTAG!($a, $b, $c, $d) as c_int - }; -} - -pub const AVERROR_BSF_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'B', b'S', b'F'); -pub const AVERROR_BUG: c_int = FFERRTAG!(b'B', b'U', b'G', b'!'); -pub const AVERROR_BUFFER_TOO_SMALL: c_int = FFERRTAG!(b'B', b'U', b'F', b'S'); -pub const AVERROR_DECODER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'D', b'E', b'C'); -pub const AVERROR_DEMUXER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'D', b'E', b'M'); -pub const AVERROR_ENCODER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'E', b'N', b'C'); -pub const AVERROR_EOF: c_int = FFERRTAG!(b'E', b'O', b'F', b' '); -pub const AVERROR_EXIT: c_int = FFERRTAG!(b'E', b'X', b'I', b'T'); -pub const AVERROR_EXTERNAL: c_int = FFERRTAG!(b'E', b'X', b'T', b' '); -pub const AVERROR_FILTER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'F', b'I', b'L'); -pub const AVERROR_INVALIDDATA: c_int = FFERRTAG!(b'I', b'N', b'D', b'A'); -pub const AVERROR_MUXER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'M', b'U', b'X'); -pub const AVERROR_OPTION_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'O', b'P', b'T'); -pub const AVERROR_PATCHWELCOME: c_int = FFERRTAG!(b'P', b'A', b'W', b'E'); -pub const AVERROR_PROTOCOL_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'P', b'R', b'O'); - fn main() { let filepath: CString = CString::new("./examples/slice/bear.mp4").unwrap(); println!("initializing all the containers, codecs and protocols."); - let pFormatContext = unsafe { avformat_alloc_context().as_mut() } + let pFormatContext = unsafe { ffi::avformat_alloc_context().as_mut() } .expect("ERROR could not allocate memory for Format Context"); println!( @@ -61,7 +29,7 @@ fn main() { ); let result = unsafe { - avformat_open_input( + ffi::avformat_open_input( &mut (pFormatContext as *mut _), filepath.as_ptr(), null_mut(), @@ -83,18 +51,18 @@ fn main() { println!("finding stream info from format"); - let result = unsafe { avformat_find_stream_info(pFormatContext, null_mut()) }; + let result = unsafe { ffi::avformat_find_stream_info(pFormatContext, null_mut()) }; if result < 0 { panic!("ERROR could not get the stream info"); } - let mut pCodec: *const AVCodec = null_mut(); - let mut pCodecParameters: *const AVCodecParameters = null_mut(); + let mut pCodec: *const ffi::AVCodec = null_mut(); + let mut pCodecParameters: *const ffi::AVCodecParameters = null_mut(); let mut video_stream_index = None; for i in 0..pFormatContext.nb_streams as i32 { let stream = unsafe { - slice::from_raw_parts(pFormatContext.streams, size_of::())[i as usize] + slice::from_raw_parts(pFormatContext.streams, size_of::())[i as usize] .as_ref() } .unwrap(); @@ -111,10 +79,11 @@ fn main() { println!("AVStream->duration {}", stream.duration); println!("finding the proper decoder (CODEC)"); - let pLocalCodec = unsafe { avcodec_find_decoder(pLocalCodecParameters.codec_id).as_ref() } - .expect("ERROR unsupported codec!"); + let pLocalCodec = + unsafe { ffi::avcodec_find_decoder(pLocalCodecParameters.codec_id).as_ref() } + .expect("ERROR unsupported codec!"); - if pLocalCodecParameters.codec_type == AVMediaType_AVMEDIA_TYPE_VIDEO { + if pLocalCodecParameters.codec_type == ffi::AVMediaType_AVMEDIA_TYPE_VIDEO { if video_stream_index.is_none() { video_stream_index = Some(i); pCodec = pLocalCodec; @@ -125,7 +94,7 @@ fn main() { "Video Codec: resolution {} x {}", pLocalCodecParameters.width, pLocalCodecParameters.height ); - } else if pLocalCodecParameters.codec_type == AVMediaType_AVMEDIA_TYPE_AUDIO { + } else if pLocalCodecParameters.codec_type == ffi::AVMediaType_AVMEDIA_TYPE_AUDIO { println!( "Audio Codec: {} channels, sample rate {}", pLocalCodecParameters.channels, pLocalCodecParameters.sample_rate @@ -141,27 +110,27 @@ fn main() { codec_name, pLocalCodec.id, pLocalCodecParameters.bit_rate ); } - let pCodecContext = unsafe { avcodec_alloc_context3(pCodec).as_mut() } + let pCodecContext = unsafe { ffi::avcodec_alloc_context3(pCodec).as_mut() } .expect("failed to allocated memory for AVCodecContext"); - let result = unsafe { avcodec_parameters_to_context(pCodecContext, pCodecParameters) }; + let result = unsafe { ffi::avcodec_parameters_to_context(pCodecContext, pCodecParameters) }; if result < 0 { panic!("failed to copy codec params to codec context"); } - let result = unsafe { avcodec_open2(pCodecContext, pCodec, null_mut()) }; + let result = unsafe { ffi::avcodec_open2(pCodecContext, pCodec, null_mut()) }; if result < 0 { panic!("failed to open codec through avcodec_open2"); } let pFrame = - unsafe { av_frame_alloc().as_mut() }.expect("failed to allocated memory for AVFrame"); - let pPacket = - unsafe { av_packet_alloc().as_mut() }.expect("failed to allocated memory for AVPacket"); + unsafe { ffi::av_frame_alloc().as_mut() }.expect("failed to allocated memory for AVFrame"); + let pPacket = unsafe { ffi::av_packet_alloc().as_mut() } + .expect("failed to allocated memory for AVPacket"); let mut how_many_packets_to_process = 8; - while unsafe { av_read_frame(pFormatContext, pPacket) } >= 0 { + while unsafe { ffi::av_read_frame(pFormatContext, pPacket) } >= 0 { if Some(pPacket.stream_index) == video_stream_index { println!("AVPacket->pts {}", pPacket.pts); if let Err(s) = decode_packet(pPacket, pCodecContext, pFrame) { @@ -172,33 +141,33 @@ fn main() { break; } } - unsafe { av_packet_unref(pPacket) }; + unsafe { ffi::av_packet_unref(pPacket) }; } println!("releasing all the resources"); unsafe { - avformat_close_input(&mut (pFormatContext as *mut _)); - av_packet_free(&mut (pPacket as *mut _)); - av_frame_free(&mut (pFrame as *mut _)); - avcodec_free_context(&mut (pCodecContext as *mut _)); + ffi::avformat_close_input(&mut (pFormatContext as *mut _)); + ffi::av_packet_free(&mut (pPacket as *mut _)); + ffi::av_frame_free(&mut (pFrame as *mut _)); + ffi::avcodec_free_context(&mut (pCodecContext as *mut _)); } } fn decode_packet( - pPacket: &AVPacket, - pCodecContext: &mut AVCodecContext, - pFrame: &mut AVFrame, + pPacket: &ffi::AVPacket, + pCodecContext: &mut ffi::AVCodecContext, + pFrame: &mut ffi::AVFrame, ) -> Result<(), String> { - let response = unsafe { avcodec_send_packet(pCodecContext, pPacket) }; + let response = unsafe { ffi::avcodec_send_packet(pCodecContext, pPacket) }; if response < 0 { return Err(String::from("Error while sending a packet to the decoder.")); } while response >= 0 { - let response = unsafe { avcodec_receive_frame(pCodecContext, pFrame) }; - if response == AVERROR(EAGAIN as i32) || response == AVERROR_EOF { + let response = unsafe { ffi::avcodec_receive_frame(pCodecContext, pFrame) }; + if response == AVERROR(ffi::EAGAIN as i32) || response == AVERROR_EOF { break; } else if response < 0 { return Err(String::from( @@ -210,7 +179,7 @@ fn decode_packet( println!( "Frame {} (type={}, size={} bytes) pts {} key_frame {} [DTS {}]", pCodecContext.frame_number, - unsafe { av_get_picture_type_char(pFrame.pict_type) }, + unsafe { ffi::av_get_picture_type_char(pFrame.pict_type) }, pFrame.pkt_size, pFrame.pts, pFrame.key_frame, diff --git a/src/avutil/avutils.rs b/src/avutil/avutils.rs new file mode 100644 index 0000000..c00462f --- /dev/null +++ b/src/avutil/avutils.rs @@ -0,0 +1 @@ +pub const AV_NOPTS_VALUE: i64 = 0x8000000000000000u64 as i64; diff --git a/src/avutil/common.rs b/src/avutil/common.rs new file mode 100644 index 0000000..75472e1 --- /dev/null +++ b/src/avutil/common.rs @@ -0,0 +1,9 @@ +#[allow(non_snake_case)] +pub const fn MKBETAG(a: u8, b: u8, c: u8, d: u8) -> u32 { + (d as u32) | ((c as u32) << 8) | ((b as u32) << 16) | ((a as u32) << 24) +} + +#[allow(non_snake_case)] +pub const fn MKTAG(a: u8, b: u8, c: u8, d: u8) -> u32 { + (a as u32) | ((b as u32) << 8) | ((c as u32) << 16) | ((d as u32) << 24) +} diff --git a/src/avutil/error.rs b/src/avutil/error.rs new file mode 100644 index 0000000..d6e0c55 --- /dev/null +++ b/src/avutil/error.rs @@ -0,0 +1,51 @@ +use libc::c_int; +use super::common::MKTAG; + +#[allow(non_snake_case)] +pub const fn AVERROR(e: c_int) -> c_int { + -e +} + +#[allow(non_snake_case)] +pub const fn AVUNERROR(e: c_int) -> c_int { + -e +} + +macro_rules! FFERRTAG { + ($a:expr, $b:expr, $c:expr, $d:expr) => + (-(MKTAG($a, $b, $c, $d) as c_int)) +} + +pub const AVERROR_BSF_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'B', b'S', b'F'); +pub const AVERROR_BUG: c_int = FFERRTAG!(b'B', b'U', b'G', b'!'); +pub const AVERROR_BUFFER_TOO_SMALL: c_int = FFERRTAG!(b'B', b'U', b'F', b'S'); +pub const AVERROR_DECODER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'D', b'E', b'C'); +pub const AVERROR_DEMUXER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'D', b'E', b'M'); +pub const AVERROR_ENCODER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'E', b'N', b'C'); +pub const AVERROR_EOF: c_int = FFERRTAG!(b'E', b'O', b'F', b' '); +pub const AVERROR_EXIT: c_int = FFERRTAG!(b'E', b'X', b'I', b'T'); +pub const AVERROR_EXTERNAL: c_int = FFERRTAG!(b'E', b'X', b'T', b' '); +pub const AVERROR_FILTER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'F', b'I', b'L'); +pub const AVERROR_INVALIDDATA: c_int = FFERRTAG!(b'I', b'N', b'D', b'A'); +pub const AVERROR_MUXER_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'M', b'U', b'X'); +pub const AVERROR_OPTION_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'O', b'P', b'T'); +pub const AVERROR_PATCHWELCOME: c_int = FFERRTAG!(b'P', b'A', b'W', b'E'); +pub const AVERROR_PROTOCOL_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'P', b'R', b'O'); + +pub const AVERROR_STREAM_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'S', b'T', b'R'); + +pub const AVERROR_BUG2: c_int = FFERRTAG!(b'B', b'U', b'G', b' '); +pub const AVERROR_UNKNOWN: c_int = FFERRTAG!(b'U', b'N', b'K', b'N'); +pub const AVERROR_EXPERIMENTAL: c_int = -0x2bb2afa8; ///< Requested feature is flagged experimental. Set strict_std_compliance if you really want to use it. +pub const AVERROR_INPUT_CHANGED: c_int = -0x636e6701; ///< Input changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_OUTPUT_CHANGED) +pub const AVERROR_OUTPUT_CHANGED: c_int = -0x636e6702; ///< Output changed between calls. Reconfiguration is required. (can be OR-ed with AVERROR_INPUT_CHANGED) + + +pub const AVERROR_HTTP_BAD_REQUEST: c_int = FFERRTAG!(0xF8, b'4', b'0', b'0'); +pub const AVERROR_HTTP_UNAUTHORIZED: c_int = FFERRTAG!(0xF8, b'4', b'0', b'1'); +pub const AVERROR_HTTP_FORBIDDEN: c_int = FFERRTAG!(0xF8, b'4', b'0', b'3'); +pub const AVERROR_HTTP_NOT_FOUND: c_int = FFERRTAG!(0xF8, b'4', b'0', b'4'); +pub const AVERROR_HTTP_OTHER_4XX: c_int = FFERRTAG!(0xF8, b'4', b'X', b'X'); +pub const AVERROR_HTTP_SERVER_ERROR: c_int = FFERRTAG!(0xF8, b'5', b'X', b'X'); + +pub const AV_ERROR_MAX_STRING_SIZE: c_int = 64; diff --git a/src/avutil/mod.rs b/src/avutil/mod.rs new file mode 100644 index 0000000..1978c19 --- /dev/null +++ b/src/avutil/mod.rs @@ -0,0 +1,6 @@ +pub mod common; + +#[rustfmt::skip] +pub mod error; + +pub mod avutils; diff --git a/src/lib.rs b/src/lib.rs index 2b0c4fb..c1fcdc4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,3 +8,5 @@ pub mod ffi { include!(concat!(env!("OUT_DIR"), "/binding.rs")); } + +pub mod avutil;