Skip to content

Patch some of the FFmpeg specific error process macros #28

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 25, 2020
Merged
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
4 changes: 1 addition & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
99 changes: 34 additions & 65 deletions examples/slice/main.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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!(
Expand All @@ -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(),
Expand All @@ -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::<AVStream>())[i as usize]
slice::from_raw_parts(pFormatContext.streams, size_of::<ffi::AVStream>())[i as usize]
.as_ref()
}
.unwrap();
Expand All @@ -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;
Expand All @@ -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
Expand All @@ -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) {
Expand All @@ -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(
Expand All @@ -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,
Expand Down
1 change: 1 addition & 0 deletions src/avutil/avutils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub const AV_NOPTS_VALUE: i64 = 0x8000000000000000u64 as i64;
9 changes: 9 additions & 0 deletions src/avutil/common.rs
Original file line number Diff line number Diff line change
@@ -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)
}
51 changes: 51 additions & 0 deletions src/avutil/error.rs
Original file line number Diff line number Diff line change
@@ -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;
6 changes: 6 additions & 0 deletions src/avutil/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pub mod common;

#[rustfmt::skip]
pub mod error;

pub mod avutils;
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,5 @@
pub mod ffi {
include!(concat!(env!("OUT_DIR"), "/binding.rs"));
}

pub mod avutil;