Skip to content
Snippets Groups Projects
Commit 3ba228ad authored by Janne Mareike Koschinski's avatar Janne Mareike Koschinski
Browse files

make the code less bad

parent 5dea25aa
Branches
No related tags found
No related merge requests found
use ffmpeg_dev::sys as ffi;
use failure::bail;
use enum_primitive::*;
use std::marker::PhantomData;
use fraction::Fraction;
use crate::ffmpeg_api::enums::*;
// TODO: Use proper errors (with struct etc) for this
enum_from_primitive! {
#[derive(Debug, Copy, Clone, PartialEq)]
#[repr(i32)]
pub enum AVErrorKind {
Unknown = ffi::AVERROR_EXPERIMENTAL,
InputChanged = ffi::AVERROR_INPUT_CHANGED,
OutputChanged = ffi::AVERROR_OUTPUT_CHANGED
}
}
pub struct AVFormatContext {
base: *mut ffi::AVFormatContext,
}
impl<'a> AVFormatContext {
pub fn new() -> Result<Self, failure::Error> {
let base = unsafe { ffi::avformat_alloc_context() };
if base.is_null() {
bail!("avformat_alloc_context() failed");
}
Ok(AVFormatContext { base })
}
// TODO: Just for testing
pub unsafe fn raw(&self) -> *mut ffi::AVFormatContext {
self.base
}
pub fn open_input(&mut self, path: &str) -> Result<(), failure::Error> {
match unsafe {
ffi::avformat_open_input(
&mut self.base,
std::ffi::CString::new(path)
.map_err(|_| failure::format_err!("Could not convert path to c string"))?
.as_ptr(),
std::ptr::null_mut(),
std::ptr::null_mut(),
)
} {
0 => Ok(()),
_ => bail!("Could not open input")
}
}
pub fn streams(&self) -> Vec<AVStream> {
return unsafe {
std::slice::from_raw_parts(
(*self.base).streams,
(*self.base).nb_streams as usize,
)
}
.iter()
.map(|stream| {
AVStream::new(unsafe { (*stream).as_mut() }.expect("not null"), self)
})
.collect();
}
}
impl Drop for AVFormatContext {
fn drop(&mut self) {
unsafe { ffi::avformat_free_context(self.base) }
}
}
pub struct AVBuffer {
base: *mut u8,
size: usize,
}
impl AVBuffer {
pub fn new(size: usize) -> Result<Self, failure::Error> {
let base = unsafe { ffi::av_malloc(size) } as *mut u8;
if base.is_null() {
bail!("av_malloc() failed");
}
Ok(AVBuffer { base, size })
}
pub fn empty() -> Self {
AVBuffer { base: std::ptr::null_mut(), size: 0 }
}
pub fn data(&self) -> &[u8] {
unsafe {
std::slice::from_raw_parts(self.base, self.size)
}
}
pub fn data_mut(&mut self) -> &[u8] {
unsafe {
std::slice::from_raw_parts_mut(self.base, self.size)
}
}
}
pub struct AVFrame {
base: *mut ffi::AVFrame,
buffer: AVBuffer,
}
impl AVFrame {
pub fn new() -> Result<Self, failure::Error> {
let base = unsafe { ffi::av_frame_alloc() };
if base.is_null() {
bail!("avformat_alloc_frame() failed");
}
Ok(AVFrame { base, buffer: AVBuffer::empty() })
}
// TODO: Just for testing
pub unsafe fn as_mut(&mut self) -> &mut ffi::AVFrame {
self.base.as_mut().expect("not null")
}
pub fn init(&mut self, width: i32, height: i32, format: AVPixelFormat) -> Result<(), failure::Error>{
let mut base = unsafe { self.base.as_mut() }.expect("not null");
base.width = width;
base.height = height;
base.format = format as ffi::AVPixelFormat;
self.buffer = AVBuffer::new(self.size())?;
unsafe {
ffi::avpicture_fill(
self.base as *mut ffi::AVPicture,
self.buffer.base as *mut u8,
self.format() as ffi::AVPixelFormat,
self.width(),
self.height(),
)
};
Ok(())
}
pub fn width(&self) -> i32 {
let base = unsafe { self.base.as_ref() }.expect("not null");
base.width
}
pub fn height(&self) -> i32 {
let base = unsafe { self.base.as_ref() }.expect("not null");
base.height
}
pub fn format(&self) -> AVPixelFormat {
let base = unsafe { self.base.as_ref() }.expect("not null");
AVPixelFormat::from_i32(base.format)
.unwrap_or(AVPixelFormat::NONE)
}
pub fn size(&self) -> usize {
unsafe {
ffi::avpicture_get_size(self.format() as ffi::AVPixelFormat, self.width(), self.height()) as usize
}
}
pub fn key_frame(&self) -> bool {
let base = unsafe { self.base.as_ref() }.expect("not null");
base.key_frame != 0
}
pub fn pts(&self) -> i64 {
let base = unsafe { self.base.as_ref() }.expect("not null");
base.pts
}
pub fn coded_picture_number(&self) -> i32 {
let base = unsafe { self.base.as_ref() }.expect("not null");
base.coded_picture_number
}
pub fn display_picture_number(&self) -> i32 {
let base = unsafe { self.base.as_ref() }.expect("not null");
base.display_picture_number
}
pub fn linesize(&self) -> &[i32] {
let base = unsafe { self.base.as_ref() }.expect("not null");
&base.linesize
}
pub fn data_ptr(&self) -> *const *const u8 {
let base = unsafe { self.base.as_ref() }.expect("not null");
base.data.as_ptr() as *const *const u8
}
pub fn data_mut_ptr(&mut self) -> *mut *mut u8 {
let base = unsafe { self.base.as_mut() }.expect("not null");
base.data.as_mut_ptr() as *mut *mut u8
}
pub fn data(&self, index: usize) -> &[u8] {
let base = unsafe { self.base.as_ref() }.expect("not null");
unsafe {
std::slice::from_raw_parts(base.data[index], self.size())
}
}
pub fn data_mut(&mut self, index: usize) -> &mut [u8] {
let base = unsafe { self.base.as_mut() }.expect("not null");
unsafe {
std::slice::from_raw_parts_mut(base.data[index], self.size())
}
}
}
impl Drop for AVFrame {
fn drop(&mut self) {
unsafe { ffi::av_frame_free(&mut self.base) }
}
}
pub struct AVStream<'a> {
base: &'a mut ffi::AVStream,
phantom: PhantomData<&'a AVFormatContext>,
}
impl<'a> AVStream<'a> {
fn new(base: &'a mut ffi::AVStream, _: &'a AVFormatContext) -> Self {
return AVStream { base, phantom: PhantomData };
}
pub fn index(self: &AVStream<'a>) -> i32 {
self.base.index
}
pub fn time_base(self: &AVStream<'a>) -> Fraction {
Fraction::new(
self.base.time_base.num as u32,
self.base.time_base.den as u32,
)
}
pub fn timestamp(self: &AVStream<'a>, timestamp: i64) -> std::time::Duration {
std::time::Duration::from_millis(
1000 *
timestamp as u64 *
self.base.time_base.num as u64 /
self.base.time_base.den as u64
)
}
pub fn duration(self: &AVStream<'a>) -> std::time::Duration {
self.timestamp(self.base.duration)
}
pub fn frame_count(self: &AVStream<'a>) -> i64 {
self.base.nb_frames
}
pub fn discard(self: &AVStream<'a>) -> Option<AVDiscard> {
AVDiscard::from_i32(self.base.discard)
}
pub fn set_discard(self: &mut AVStream<'a>, value: AVDiscard) {
self.base.discard = value as ffi::AVDiscard;
}
pub fn sample_aspect_ratio(self: &AVStream<'a>) -> Fraction {
Fraction::new(
self.base.sample_aspect_ratio.num as u32,
self.base.sample_aspect_ratio.den as u32,
)
}
pub fn codec_parameters(self: &AVStream<'a>) -> AVCodecParameters {
AVCodecParameters::new(unsafe { self.base.codecpar.as_mut() }.expect("not null"), self)
}
}
pub struct AVCodecParameters<'a> {
base: &'a mut ffi::AVCodecParameters,
phantom: PhantomData<&'a AVStream<'a>>,
}
impl<'a> AVCodecParameters<'a> {
fn new(base: &'a mut ffi::AVCodecParameters, _: &'a AVStream) -> Self {
return AVCodecParameters { base, phantom: PhantomData };
}
// TODO: Just for testing
pub unsafe fn as_ref(&self) -> &ffi::AVCodecParameters {
self.base
}
pub fn codec_type(self: &AVCodecParameters<'a>) -> AVMediaType {
AVMediaType::from_i32(self.base.codec_type).unwrap_or(AVMediaType::Unknown)
}
pub fn codec_id(self: &AVCodecParameters<'a>) -> Option<AVCodecID> {
AVCodecID::from_u32(self.base.codec_id)
}
pub fn find_decoder(self: &AVCodecParameters<'a>) -> AVCodec {
AVCodec::new(
unsafe { ffi::avcodec_find_decoder(self.base.codec_id).as_mut() }.expect("Decoder not found"),
self,
)
}
}
pub struct AVCodec<'a> {
base: &'a mut ffi::AVCodec,
phantom: PhantomData<&'a AVCodecParameters<'a>>,
}
impl<'a> AVCodec<'a> {
fn new(base: &'a mut ffi::AVCodec, _: &'a AVCodecParameters) -> Self {
return AVCodec { base, phantom: PhantomData };
}
// TODO: Just for testing
pub unsafe fn as_ref(&self) -> &ffi::AVCodec {
self.base
}
pub fn name(self: &AVCodec<'a>) -> std::string::String {
String::from(unsafe { std::ffi::CStr::from_ptr(self.base.name) }.to_str().unwrap())
}
}
This diff is collapsed.
pub(crate) mod enums;
pub(crate) mod api;
use ffmpeg_dev::sys as ffi; use ffmpeg_dev::sys as ffi;
use enum_primitive::*;
use std::collections::HashMap;
mod ffmpeg_api; pub(crate) mod ffmpeg_api;
use ffmpeg_api::*; use crate::ffmpeg_api::enums::*;
use crate::ffmpeg_api::api::*;
fn main() -> Result<(), std::io::Error> { fn main() -> Result<(), std::io::Error> {
let mut before = std::time::SystemTime::now(); let mut before = std::time::SystemTime::now();
...@@ -31,36 +30,26 @@ fn main() -> Result<(), std::io::Error> { ...@@ -31,36 +30,26 @@ fn main() -> Result<(), std::io::Error> {
local_codec.name() local_codec.name()
); );
// TODO: HERE BE DRAGONS let mut output_frame = AVFrame::new().unwrap_or_else(|error| {
panic!("Could not create output frame: {:?}", error)
let output_frame = unsafe { });
ffi::av_frame_alloc().as_mut() output_frame.init(160, 90, AVPixelFormat::RGB24).unwrap_or_else(|error| {
}.expect("not null"); panic!("Could not init output frame: {:?}", error)
});
let num_bytes: usize = unsafe {
ffi::avpicture_get_size(ffi::AVPixelFormat_AV_PIX_FMT_RGB24, 160, 90) as usize
};
let output_frame_buffer = unsafe {
(ffi::av_malloc(num_bytes) as *mut u8).as_ref()
}.expect("not null");
unsafe {
ffi::avpicture_fill(
output_frame as *mut ffi::AVFrame as *mut ffi::AVPicture,
output_frame_buffer,
ffi::AVPixelFormat_AV_PIX_FMT_RGB24,
160,
90,
);
}
match codec_parameters.codec_type() { match codec_parameters.codec_type() {
AVMediaType::Video => { AVMediaType::Video => {
// TODO: HERE BE DRAGONS
let avc_ctx: &mut ffi::AVCodecContext = unsafe { let avc_ctx: &mut ffi::AVCodecContext = unsafe {
ffi::avcodec_alloc_context3(local_codec.as_ref()).as_mut() ffi::avcodec_alloc_context3(local_codec.as_ref()).as_mut()
}.expect("not null"); }.expect("not null");
avc_ctx.skip_loop_filter = ffi::AVDiscard_AVDISCARD_NONKEY;
avc_ctx.skip_idct = ffi::AVDiscard_AVDISCARD_NONKEY;
avc_ctx.skip_frame = ffi::AVDiscard_AVDISCARD_NONKEY;
unsafe { unsafe {
ffi::avcodec_parameters_to_context(avc_ctx, codec_parameters.as_ref()); ffi::avcodec_parameters_to_context(avc_ctx, codec_parameters.as_ref());
ffi::avcodec_open2(avc_ctx, local_codec.as_ref(), std::ptr::null_mut()); ffi::avcodec_open2(avc_ctx, local_codec.as_ref(), std::ptr::null_mut());
...@@ -70,49 +59,39 @@ fn main() -> Result<(), std::io::Error> { ...@@ -70,49 +59,39 @@ fn main() -> Result<(), std::io::Error> {
ffi::av_packet_alloc().as_mut() ffi::av_packet_alloc().as_mut()
}.expect("not null"); }.expect("not null");
let frame: &mut ffi::AVFrame = unsafe { let mut frame = AVFrame::new().unwrap_or_else(|error| {
ffi::av_frame_alloc().as_mut() panic!("Could not create input frame: {:?}", error)
}.expect("not null"); });
avc_ctx.skip_loop_filter = ffi::AVDiscard_AVDISCARD_NONKEY;
avc_ctx.skip_idct = ffi::AVDiscard_AVDISCARD_NONKEY;
avc_ctx.skip_frame = ffi::AVDiscard_AVDISCARD_NONKEY;
let mut i = 0; let mut i = 0;
println!("Time: {:#?}", before.elapsed().unwrap()); println!("Time: {:#?}", before.elapsed().unwrap());
before = std::time::SystemTime::now(); before = std::time::SystemTime::now();
let mut sws_context: *mut ffi::SwsContext = std::ptr::null_mut();
while unsafe { ffi::av_read_frame(avformat_context.raw(), packet) } >= 0 && i < 10 { while unsafe { ffi::av_read_frame(avformat_context.raw(), packet) } >= 0 && i < 10 {
if packet.stream_index == stream.index() { if packet.stream_index == stream.index() {
unsafe { unsafe {
ffi::avcodec_send_packet(avc_ctx, packet); ffi::avcodec_send_packet(avc_ctx, packet);
} }
while unsafe { ffi::avcodec_receive_frame(avc_ctx, frame) } >= 0 { while unsafe { ffi::avcodec_receive_frame(avc_ctx, frame.as_mut()) } >= 0 {
let key_frame = frame.key_frame != 0;
let frame_index = frame.coded_picture_number;
println!( println!(
"Frame {}: {:?} @ {}", "Frame {}: {:?} @ {}",
frame_index, frame.coded_picture_number(),
stream.timestamp(frame.pts as i64), stream.timestamp(frame.pts()),
key_frame frame.key_frame()
); );
println!("Reading Time: {:#?}", before.elapsed().unwrap()); println!("Reading Time: {:#?}", before.elapsed().unwrap());
before = std::time::SystemTime::now(); before = std::time::SystemTime::now();
if sws_context.is_null() {
/* sws_context = unsafe {
if frame.width == last_width && frame.height == last_height && (frame.format as AVPixelFormat) == last_format {
}
*/
let sws_context: &mut ffi::SwsContext = unsafe {
ffi::sws_getContext( ffi::sws_getContext(
frame.width, frame.width(),
frame.height, frame.height(),
frame.format as ffi::AVPixelFormat, frame.format() as ffi::AVPixelFormat,
160, 160,
90, 90,
ffi::AVPixelFormat_AV_PIX_FMT_RGB24, ffi::AVPixelFormat_AV_PIX_FMT_RGB24,
...@@ -122,31 +101,30 @@ fn main() -> Result<(), std::io::Error> { ...@@ -122,31 +101,30 @@ fn main() -> Result<(), std::io::Error> {
std::ptr::null(), std::ptr::null(),
).as_mut() ).as_mut()
}.expect("not null"); }.expect("not null");
}
let success = unsafe { let success = unsafe {
ffi::sws_scale( ffi::sws_scale(
sws_context, sws_context,
frame.data.as_ptr() as *const *const u8, frame.data_ptr(),
&frame.linesize[0], frame.linesize().as_ptr(),
0, 0,
frame.height, frame.height(),
&output_frame.data[0], output_frame.data_mut_ptr(),
&output_frame.linesize[0], output_frame.linesize().as_ptr(),
) )
}; };
println!("success: {}, size: {}", success, num_bytes); println!("success: {}", success);
println!("Processing Time: {:#?}", before.elapsed().unwrap()); println!("Processing Time: {:#?}", before.elapsed().unwrap());
before = std::time::SystemTime::now(); before = std::time::SystemTime::now();
if success > 0 { if success > 0 {
image::save_buffer( image::save_buffer(
format!("/home/janne/Workspace/justflix/data/test/image_{}.png", i), format!("/home/janne/Workspace/justflix/data/test/image_{}.png", i),
unsafe { output_frame.data(0),
std::slice::from_raw_parts(output_frame.data[0], num_bytes) output_frame.width() as u32,
}, output_frame.height() as u32,
160,
90,
image::ColorType::Rgb8, image::ColorType::Rgb8,
).unwrap(); ).unwrap();
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment