From 66901497ab41c0800ce4236bb1cb010e5299afd1 Mon Sep 17 00:00:00 2001 From: meh Date: Tue, 12 May 2015 03:49:55 +0200 Subject: [PATCH] codec: add various Codec related stuff --- src/codec/codec.rs | 61 +++++++++++++ src/codec/context.rs | 198 +++++++++++++++++++++++++++++++++++++++++++ src/codec/decoder.rs | 39 +++++++++ src/codec/encoder.rs | 39 +++++++++ src/codec/mod.rs | 11 +++ src/lib.rs | 3 + 6 files changed, 351 insertions(+) create mode 100644 src/codec/codec.rs create mode 100644 src/codec/context.rs create mode 100644 src/codec/decoder.rs create mode 100644 src/codec/encoder.rs diff --git a/src/codec/codec.rs b/src/codec/codec.rs new file mode 100644 index 0000000..19ca225 --- /dev/null +++ b/src/codec/codec.rs @@ -0,0 +1,61 @@ +use std::marker::PhantomData; +use std::ffi::CStr; +use std::str::from_utf8_unchecked; + +use ffi::*; +use super::{Id, Context}; +use ::media; +use ::Error; +use ::codec::context::Opened; + +pub struct Codec<'a> { + pub ptr: *mut AVCodec, + + _marker: PhantomData<&'a i32>, +} + +impl<'a> Codec<'a> { + pub fn wrap(ptr: *mut AVCodec) -> Self { + Codec { ptr: ptr, _marker: PhantomData } + } + + pub fn open(&self) -> Result, Error> { + Context::new().open(self) + } + + pub fn is_encoder(&self) -> bool { + unsafe { + av_codec_is_encoder(self.ptr) != 0 + } + } + + pub fn is_decoder(&self) -> bool { + unsafe { + av_codec_is_decoder(self.ptr) != 0 + } + } + + pub fn name(&'a self) -> &'a str { + unsafe { + from_utf8_unchecked(CStr::from_ptr((*self.ptr).name).to_bytes()) + } + } + + pub fn description(&'a self) -> &'a str { + unsafe { + from_utf8_unchecked(CStr::from_ptr((*self.ptr).long_name).to_bytes()) + } + } + + pub fn kind(&self) -> media::Type { + unsafe { + media::Type::from((*self.ptr).kind) + } + } + + pub fn id(&self) -> Id { + unsafe { + Id::from((*self.ptr).id) + } + } +} diff --git a/src/codec/context.rs b/src/codec/context.rs new file mode 100644 index 0000000..6059c99 --- /dev/null +++ b/src/codec/context.rs @@ -0,0 +1,198 @@ +use std::marker::PhantomData; +use std::ops::Deref; +use std::ptr; +use libc::c_int; + +use ffi::*; +use ::media; +use ::{Error, Codec, Dictionary, Packet, Subtitle}; +use super::{Id, Encode, Decode}; +use ::frame; + +pub struct Context<'a> { + pub ptr: *mut AVCodecContext, + + own: bool, + _marker: PhantomData<&'a i32>, +} + +impl<'a> Context<'a> { + pub fn new() -> Self { + unsafe { + Context { ptr: avcodec_alloc_context3(ptr::null()), own: true, _marker: PhantomData } + } + } + + pub fn wrap(ptr: *mut AVCodecContext) -> Self { + Context { ptr: ptr, own: false, _marker: PhantomData } + } + + pub fn open(self, codec: &Codec) -> Result, Error> { + unsafe { + match avcodec_open2(self.ptr, codec.ptr, ptr::null_mut()) { + 0 => Ok(Opened(self)), + e => Err(Error::new(e)) + } + } + } + + pub fn open_with(self, codec: &Codec, mut options: Dictionary) -> Result, Error> { + unsafe { + match avcodec_open2(self.ptr, codec.ptr, &mut options.ptr) { + 0 => Ok(Opened(self)), + e => Err(Error::new(e)) + } + } + } + + pub fn kind(&self) -> media::Type { + unsafe { + media::Type::from((*self.ptr).codec_type) + } + } + + pub fn id(&self) -> Id { + unsafe { + Id::from((*self.ptr).codec_id) + } + } +} + +impl<'a> Drop for Context<'a> { + fn drop(&mut self) { + if self.own { + unsafe { + avcodec_free_context(&mut self.ptr); + } + } + } +} + +impl<'a> Clone for Context<'a> { + fn clone(&self) -> Self { + let mut ctx = Context::new(); + ctx.clone_from(self); + + ctx + } + + fn clone_from(&mut self, source: &Self) { + unsafe { + avcodec_copy_context(self.ptr, source.ptr); + } + } +} + +impl<'a> Decode for Context<'a> { + fn video(&self, packet: &Packet, out: &mut frame::Video) -> Result { + unsafe { + let mut got: c_int = 0; + + match avcodec_decode_video2(self.ptr, out.ptr, &mut got, &packet.val) { + e if e < 0 => Err(Error::new(e)), + _ => Ok(got != 0) + } + } + } + + fn audio(&self, packet: &Packet, out: &mut frame::Audio) -> Result { + unsafe { + let mut got: c_int = 0; + + match avcodec_decode_audio4(self.ptr, out.ptr, &mut got, &packet.val) { + e if e < 0 => Err(Error::new(e)), + _ => Ok(got != 0) + } + } + } + + fn subtitle(&self, packet: &Packet, out: &mut Subtitle) -> Result { + unsafe { + let mut got: c_int = 0; + + match avcodec_decode_subtitle2(self.ptr, &mut out.val, &mut got, &packet.val) { + e if e < 0 => Err(Error::new(e)), + _ => Ok(got != 0) + } + } + } +} + +impl<'a> Encode for Context<'a> { + fn video(&self, frame: &frame::Video, out: &mut Packet) -> Result { + unsafe { + let mut got: c_int = 0; + + match avcodec_encode_video2(self.ptr, &mut out.val, frame.ptr, &mut got) { + e if e < 0 => Err(Error::new(e)), + _ => Ok(got != 0) + } + } + } + + fn audio(&self, frame: &frame::Audio, out: &mut Packet) -> Result { + unsafe { + let mut got: c_int = 0; + + match avcodec_encode_audio2(self.ptr, &mut out.val, frame.ptr, &mut got) { + e if e < 0 => Err(Error::new(e)), + _ => Ok(got != 0) + } + } + } + + fn subtitle(&self, subtitle: &Subtitle, out: &mut [u8]) -> Result { + unsafe { + match avcodec_encode_subtitle(self.ptr, out.as_mut_ptr(), out.len() as c_int, &subtitle.val) { + e if e < 0 => Err(Error::new(e)), + _ => Ok(true) + } + } + } +} + +pub struct Opened<'a>(Context<'a>); + +impl<'a> Decode for Opened<'a> { + fn video(&self, packet: &Packet, out: &mut frame::Video) -> Result { + Decode::video(&self.0, packet, out) + } + + fn audio(&self, packet: &Packet, out: &mut frame::Audio) -> Result { + Decode::audio(&self.0, packet, out) + } + + fn subtitle(&self, packet: &Packet, out: &mut Subtitle) -> Result { + Decode::subtitle(&self.0, packet, out) + } +} + +impl<'a> Encode for Opened<'a> { + fn video(&self, frame: &frame::Video, out: &mut Packet) -> Result { + Encode::video(&self.0, frame, out) + } + + fn audio(&self, frame: &frame::Audio, out: &mut Packet) -> Result { + Encode::audio(&self.0, frame, out) + } + + fn subtitle(&self, subtitle: &Subtitle, out: &mut [u8]) -> Result { + Encode::subtitle(&self.0, subtitle, out) + } +} + +impl<'a> Drop for Opened<'a> { + fn drop(&mut self) { + unsafe { + avcodec_close(self.0.ptr); + } + } +} + +impl<'a> Deref for Opened<'a> { + type Target = Context<'a>; + + fn deref(&self) -> &Context<'a> { + &self.0 + } +} diff --git a/src/codec/decoder.rs b/src/codec/decoder.rs new file mode 100644 index 0000000..57d546b --- /dev/null +++ b/src/codec/decoder.rs @@ -0,0 +1,39 @@ +use std::ffi::CString; +use std::ptr; + +use ffi::*; +use ::codec::Id; +use ::{Codec, Packet, Subtitle, Error}; +use ::frame; + +pub trait Decode { + fn video(&self, packet: &Packet, out: &mut frame::Video) -> Result; + fn audio(&self, packet: &Packet, out: &mut frame::Audio) -> Result; + fn subtitle(&self, packet: &Packet, out: &mut Subtitle) -> Result; +} + +pub fn find(id: Id) -> Option> { + unsafe { + let ptr = avcodec_find_decoder(id.into()); + + if ptr == ptr::null_mut() { + None + } + else { + Some(Codec::wrap(ptr)) + } + } +} + +pub fn find_by_name(name: &str) -> Option> { + unsafe { + let ptr = avcodec_find_decoder_by_name(CString::new(name).unwrap().as_ptr()); + + if ptr == ptr::null_mut() { + None + } + else { + Some(Codec::wrap(ptr)) + } + } +} diff --git a/src/codec/encoder.rs b/src/codec/encoder.rs new file mode 100644 index 0000000..f889715 --- /dev/null +++ b/src/codec/encoder.rs @@ -0,0 +1,39 @@ +use std::ffi::CString; +use std::ptr; + +use ffi::*; +use ::codec::Id; +use ::{Codec, Packet, Subtitle, Error}; +use ::frame; + +pub trait Encode { + fn video(&self, frame: &frame::Video, out: &mut Packet) -> Result; + fn audio(&self, frame: &frame::Audio, out: &mut Packet) -> Result; + fn subtitle(&self, subtitle: &Subtitle, out: &mut [u8]) -> Result; +} + +pub fn find(id: Id) -> Option> { + unsafe { + let ptr = avcodec_find_encoder(id.into()); + + if ptr == ptr::null_mut() { + None + } + else { + Some(Codec::wrap(ptr)) + } + } +} + +pub fn find_by_name(name: &str) -> Option> { + unsafe { + let ptr = avcodec_find_encoder_by_name(CString::new(name).unwrap().as_ptr()); + + if ptr == ptr::null_mut() { + None + } + else { + Some(Codec::wrap(ptr)) + } + } +} diff --git a/src/codec/mod.rs b/src/codec/mod.rs index 85b1c91..d9d146a 100644 --- a/src/codec/mod.rs +++ b/src/codec/mod.rs @@ -7,6 +7,17 @@ pub mod subtitle; pub mod discard; +pub mod context; +pub use self::context::Context; + +pub mod codec; + +pub mod encoder; +pub use self::encoder::Encode; + +pub mod decoder; +pub use self::decoder::Decode; + use std::ffi::CStr; use std::str::from_utf8_unchecked; diff --git a/src/lib.rs b/src/lib.rs index fa2f7d8..0007dcb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,3 +18,6 @@ pub mod codec; pub use codec::packet::{self, Packet}; pub use codec::subtitle::Subtitle; pub use codec::discard::Discard; +pub use codec::codec::Codec; +pub use codec::encoder::{self, Encode}; +pub use codec::decoder::{self, Decode};