From 609098570733beef84faa4bb03bbe60aceead94d Mon Sep 17 00:00:00 2001 From: meh Date: Sat, 16 May 2015 14:45:21 +0200 Subject: [PATCH] codec: refactor API --- src/codec/codec.rs | 2 +- src/codec/context.rs | 175 +++++++++++++++++-------------------------- src/codec/decoder.rs | 118 +++++++++++++++++++++++++++-- src/codec/encoder.rs | 116 ++++++++++++++++++++++++++-- src/codec/mod.rs | 3 - src/lib.rs | 4 - 6 files changed, 292 insertions(+), 126 deletions(-) diff --git a/src/codec/codec.rs b/src/codec/codec.rs index be82d15..fe3dd9f 100644 --- a/src/codec/codec.rs +++ b/src/codec/codec.rs @@ -19,7 +19,7 @@ impl<'a> Codec<'a> { Codec { ptr: ptr, _marker: PhantomData } } - pub fn open(&self) -> Result, Error> { + pub fn open(&self) -> Result { Context::new().open(self) } diff --git a/src/codec/context.rs b/src/codec/context.rs index bb00abe..b5c6c36 100644 --- a/src/codec/context.rs +++ b/src/codec/context.rs @@ -1,33 +1,31 @@ -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; +use ::{Error, Codec, Dictionary}; +use super::Id; +use super::decoder::Decoder; +use super::encoder::Encoder; -pub struct Context<'a> { +pub struct Context { pub ptr: *mut AVCodecContext, - _own: bool, - _marker: PhantomData<&'a ()>, + _own: bool, } -impl<'a> Context<'a> { +impl Context { pub fn new() -> Self { unsafe { - Context { ptr: avcodec_alloc_context3(ptr::null()), _own: true, _marker: PhantomData } + Context { ptr: avcodec_alloc_context3(ptr::null()), _own: true } } } pub fn wrap(ptr: *mut AVCodecContext) -> Self { - Context { ptr: ptr, _own: false, _marker: PhantomData } + Context { ptr: ptr, _own: false } } - pub fn open(self, codec: &Codec) -> Result, Error> { + pub fn open(self, codec: &Codec) -> Result { unsafe { match avcodec_open2(self.ptr, codec.ptr, ptr::null_mut()) { 0 => Ok(Opened(self)), @@ -36,7 +34,7 @@ impl<'a> Context<'a> { } } - pub fn open_with(self, codec: &Codec, mut options: Dictionary) -> Result, Error> { + pub fn open_with(self, codec: &Codec, mut options: Dictionary) -> Result { unsafe { match avcodec_open2(self.ptr, codec.ptr, &mut options.ptr) { 0 => Ok(Opened(self)), @@ -45,6 +43,35 @@ impl<'a> Context<'a> { } } + pub fn decoder(&self) -> Result { + if let Some(ref codec) = super::decoder::find(self.id()) { + self.clone().open(codec).and_then(|c| c.decoder()) + } + else { + Err(Error::from(AVERROR_DECODER_NOT_FOUND)) + } + } + + pub fn encoder(&self) -> Result { + if let Some(ref codec) = super::encoder::find(self.id()) { + self.clone().open(codec).and_then(|c| c.encoder()) + } + else { + Err(Error::from(AVERROR_ENCODER_NOT_FOUND)) + } + } + + pub fn codec(&self) -> Option { + unsafe { + if (*self.ptr).codec == ptr::null() { + None + } + else { + Some(Codec::wrap((*self.ptr).codec as *mut _)) + } + } + } + pub fn medium(&self) -> media::Type { unsafe { media::Type::from((*self.ptr).codec_type) @@ -58,7 +85,7 @@ impl<'a> Context<'a> { } } -impl<'a> Drop for Context<'a> { +impl Drop for Context { fn drop(&mut self) { if self._own { unsafe { @@ -68,7 +95,7 @@ impl<'a> Drop for Context<'a> { } } -impl<'a> Clone for Context<'a> { +impl Clone for Context { fn clone(&self) -> Self { let mut ctx = Context::new(); ctx.clone_from(self); @@ -83,105 +110,41 @@ impl<'a> Clone for Context<'a> { } } -impl<'a> Decode for Context<'a> { - fn video(&self, packet: &Packet, out: &mut frame::Video) -> Result { - unsafe { - let mut got: c_int = 0; +pub struct Opened(pub Context); - match avcodec_decode_video2(self.ptr, out.ptr, &mut got, &packet.val) { - e if e < 0 => Err(Error::new(e)), - _ => Ok(got != 0) - } +impl Opened { + pub fn decoder(self) -> Result { + let mut valid = false; + + if let Some(codec) = self.codec() { + valid = codec.is_decoder(); + } + + if valid { + Ok(Decoder(self)) + } + else { + Err(Error::from(AVERROR_INVALIDDATA)) } } - fn audio(&self, packet: &Packet, out: &mut frame::Audio) -> Result { - unsafe { - let mut got: c_int = 0; + pub fn encoder(self) -> Result { + let mut valid = false; - match avcodec_decode_audio4(self.ptr, out.ptr, &mut got, &packet.val) { - e if e < 0 => Err(Error::new(e)), - _ => Ok(got != 0) - } + if let Some(codec) = self.codec() { + valid = codec.is_encoder(); } - } - 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) - } + if valid { + Ok(Encoder(self)) + } + else { + Err(Error::from(AVERROR_INVALIDDATA)) } } } -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> { +impl Drop for Opened { fn drop(&mut self) { unsafe { avcodec_close(self.0.ptr); @@ -189,10 +152,10 @@ impl<'a> Drop for Opened<'a> { } } -impl<'a> Deref for Opened<'a> { - type Target = Context<'a>; +impl Deref for Opened { + type Target = Context; - fn deref(&self) -> &Context<'a> { + fn deref(&self) -> &::Target { &self.0 } } diff --git a/src/codec/decoder.rs b/src/codec/decoder.rs index 57d546b..fc9bed0 100644 --- a/src/codec/decoder.rs +++ b/src/codec/decoder.rs @@ -1,15 +1,121 @@ use std::ffi::CString; use std::ptr; +use std::ops::Deref; +use libc::c_int; use ffi::*; -use ::codec::Id; -use ::{Codec, Packet, Subtitle, Error}; +use super::Id; +use super::context::Opened; +use ::{Codec, Packet, Error}; use ::frame; +use ::media; -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 struct Decoder(pub Opened); + +impl Decoder { + pub fn video(self) -> Result { + if self.medium() == media::Type::Video { + Ok(Video(self)) + } + else { + Err(Error::from(AVERROR_INVALIDDATA)) + } + } + + pub fn audio(self) -> Result { + if self.medium() == media::Type::Audio { + Ok(Audio(self)) + } + else { + Err(Error::from(AVERROR_INVALIDDATA)) + } + } + + pub fn subtitle(self) -> Result { + if self.medium() == media::Type::Subtitle { + Ok(Subtitle(self)) + } + else { + Err(Error::from(AVERROR_INVALIDDATA)) + } + } +} + +impl Deref for Decoder { + type Target = Opened; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +pub struct Video(pub Decoder); + +impl Video { + pub fn decode(&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) + } + } + } +} + +impl Deref for Video { + type Target = Decoder; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +pub struct Audio(pub Decoder); + +impl Audio { + pub fn decode(&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) + } + } + } +} + +impl Deref for Audio { + type Target = Decoder; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +pub struct Subtitle(pub Decoder); + +impl Subtitle { + pub fn decode(&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 Deref for Subtitle { + type Target = Decoder; + + fn deref(&self) -> &::Target { + &self.0 + } } pub fn find(id: Id) -> Option> { diff --git a/src/codec/encoder.rs b/src/codec/encoder.rs index f889715..8bab6bf 100644 --- a/src/codec/encoder.rs +++ b/src/codec/encoder.rs @@ -1,15 +1,119 @@ use std::ffi::CString; use std::ptr; +use std::ops::Deref; +use libc::c_int; use ffi::*; -use ::codec::Id; -use ::{Codec, Packet, Subtitle, Error}; +use super::Id; +use super::context::Opened; +use ::{Codec, Packet, Error}; use ::frame; +use ::media; -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 struct Encoder(pub Opened); + +impl Encoder { + pub fn video(self) -> Result { + if self.medium() == media::Type::Video { + Ok(Video(self)) + } + else { + Err(Error::from(AVERROR_INVALIDDATA)) + } + } + + pub fn audio(self) -> Result { + if self.medium() == media::Type::Audio { + Ok(Audio(self)) + } + else { + Err(Error::from(AVERROR_INVALIDDATA)) + } + } + + pub fn subtitle(self) -> Result { + if self.medium() == media::Type::Subtitle { + Ok(Subtitle(self)) + } + else { + Err(Error::from(AVERROR_INVALIDDATA)) + } + } +} + +impl Deref for Encoder { + type Target = Opened; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +pub struct Video(pub Encoder); + +impl Video { + pub fn encode(&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) + } + } + } +} + +impl Deref for Video { + type Target = Encoder; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +pub struct Audio(pub Encoder); + +impl Audio { + pub fn encode(&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) + } + } + } +} + +impl Deref for Audio { + type Target = Encoder; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +pub struct Subtitle(pub Encoder); + +impl Subtitle { + pub fn encode(&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) + } + } + } +} + +impl Deref for Subtitle { + type Target = Encoder; + + fn deref(&self) -> &::Target { + &self.0 + } } pub fn find(id: Id) -> Option> { diff --git a/src/codec/mod.rs b/src/codec/mod.rs index c7ffdbd..781a01e 100644 --- a/src/codec/mod.rs +++ b/src/codec/mod.rs @@ -15,10 +15,7 @@ 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 fa30851..03f02cb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,10 +34,6 @@ pub use codec::picture::Picture; pub use codec::discard::Discard; #[cfg(feature = "codec")] pub use codec::codec::Codec; -#[cfg(feature = "codec")] -pub use codec::encoder::{self, Encode}; -#[cfg(feature = "codec")] -pub use codec::decoder::{self, Decode}; #[cfg(feature = "device")] pub mod device;