diff --git a/src/codec/audio.rs b/src/codec/audio.rs index cb4bed8..71aefae 100644 --- a/src/codec/audio.rs +++ b/src/codec/audio.rs @@ -4,6 +4,7 @@ use {ChannelLayout, format}; use super::codec::Codec; use ffi::*; +#[derive(PartialEq, Eq, Copy, Clone)] pub struct Audio { codec: Codec, } diff --git a/src/codec/decoder/decoder.rs b/src/codec/decoder/decoder.rs new file mode 100644 index 0000000..fd2a257 --- /dev/null +++ b/src/codec/decoder/decoder.rs @@ -0,0 +1,130 @@ +use std::ptr; +use std::ops::{Deref, DerefMut}; + +use ffi::*; +use codec::{Context, traits}; +use super::{Opened, Video, Audio, Subtitle, Conceal, Check}; +use ::{Error, Discard, Rational, Dictionary}; + +pub struct Decoder(pub Context); + +impl Decoder { + pub fn open(mut self) -> Result { + unsafe { + match avcodec_open2(self.as_mut_ptr(), ptr::null(), ptr::null_mut()) { + 0 => Ok(Opened(self)), + e => Err(Error::from(e)) + } + } + } + + pub fn open_as(mut self, codec: D) -> Result { + unsafe { + if let Some(codec) = codec.decoder() { + match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), ptr::null_mut()) { + 0 => Ok(Opened(self)), + e => Err(Error::from(e)) + } + } + else { + Err(Error::DecoderNotFound) + } + } + } + + pub fn open_as_with(mut self, codec: D, options: Dictionary) -> Result { + unsafe { + if let Some(codec) = codec.decoder() { + let mut opts = options.disown(); + let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts); + + Dictionary::own(opts); + + match res { + 0 => Ok(Opened(self)), + e => Err(Error::from(e)) + } + } + else { + Err(Error::DecoderNotFound) + } + } + } + + pub fn video(self) -> Result { + if let Some(codec) = super::find(self.id()) { + self.open_as(codec).and_then(|o| o.video()) + } + else { + Err(Error::DecoderNotFound) + } + } + + pub fn audio(self) -> Result { + if let Some(codec) = super::find(self.id()) { + self.open_as(codec).and_then(|o| o.audio()) + } + else { + Err(Error::DecoderNotFound) + } + } + + pub fn subtitle(self) -> Result { + if let Some(codec) = super::find(self.id()) { + self.open_as(codec).and_then(|o| o.subtitle()) + } + else { + Err(Error::DecoderNotFound) + } + } + + pub fn conceal(&mut self, value: Conceal) { + unsafe { + (*self.as_mut_ptr()).error_concealment = value.bits(); + } + } + + pub fn check(&mut self, value: Check) { + unsafe { + (*self.as_mut_ptr()).err_recognition = value.bits(); + } + } + + pub fn skip_loop_filter(&mut self, value: Discard) { + unsafe { + (*self.as_mut_ptr()).skip_loop_filter = value.into(); + } + } + + pub fn skip_idct(&mut self, value: Discard) { + unsafe { + (*self.as_mut_ptr()).skip_idct = value.into(); + } + } + + pub fn skip_frame(&mut self, value: Discard) { + unsafe { + (*self.as_mut_ptr()).skip_frame = value.into(); + } + } + + pub fn time_base(&self) -> Rational { + unsafe { + Rational::from((*self.as_ptr()).time_base) + } + } +} + +impl Deref for Decoder { + type Target = Context; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +impl DerefMut for Decoder { + fn deref_mut(&mut self) -> &mut::Target { + &mut self.0 + } +} diff --git a/src/codec/decoder/mod.rs b/src/codec/decoder/mod.rs index 570e214..c3decba 100644 --- a/src/codec/decoder/mod.rs +++ b/src/codec/decoder/mod.rs @@ -1,3 +1,6 @@ +pub mod decoder; +pub use self::decoder::Decoder; + pub mod video; pub use self::video::Video; @@ -18,135 +21,15 @@ pub use self::check::Check; pub mod opened; pub use self::opened::Opened; -use std::ptr; use std::ffi::CString; -use std::ops::{Deref, DerefMut}; use ffi::*; -use super::{Id, Context}; -use ::{Codec, Error, Discard, Rational, Dictionary}; +use codec::Context; +use ::Codec; +use codec::Id; -pub struct Decoder(pub Context); - -impl Decoder { - pub fn open(mut self) -> Result { - unsafe { - match avcodec_open2(self.as_mut_ptr(), ptr::null(), ptr::null_mut()) { - 0 => Ok(Opened(self)), - e => Err(Error::from(e)) - } - } - } - - pub fn open_as(mut self, codec: &Codec) -> Result { - unsafe { - if codec.is_decoder() { - match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), ptr::null_mut()) { - 0 => Ok(Opened(self)), - e => Err(Error::from(e)) - } - } - else { - Err(Error::InvalidData) - } - } - } - - pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result { - unsafe { - if codec.is_decoder() { - let mut opts = options.disown(); - let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts); - - Dictionary::own(opts); - - match res { - 0 => Ok(Opened(self)), - e => Err(Error::from(e)) - } - } - else { - Err(Error::InvalidData) - } - } - } - - pub fn video(self) -> Result { - if let Some(ref codec) = find(self.id()) { - self.open_as(codec).and_then(|o| o.video()) - } - else { - Err(Error::DecoderNotFound) - } - } - - pub fn audio(self) -> Result { - if let Some(ref codec) = find(self.id()) { - self.open_as(codec).and_then(|o| o.audio()) - } - else { - Err(Error::DecoderNotFound) - } - } - - pub fn subtitle(self) -> Result { - if let Some(ref codec) = find(self.id()) { - self.open_as(codec).and_then(|o| o.subtitle()) - } - else { - Err(Error::DecoderNotFound) - } - } - - pub fn conceal(&mut self, value: Conceal) { - unsafe { - (*self.as_mut_ptr()).error_concealment = value.bits(); - } - } - - pub fn check(&mut self, value: Check) { - unsafe { - (*self.as_mut_ptr()).err_recognition = value.bits(); - } - } - - pub fn skip_loop_filter(&mut self, value: Discard) { - unsafe { - (*self.as_mut_ptr()).skip_loop_filter = value.into(); - } - } - - pub fn skip_idct(&mut self, value: Discard) { - unsafe { - (*self.as_mut_ptr()).skip_idct = value.into(); - } - } - - pub fn skip_frame(&mut self, value: Discard) { - unsafe { - (*self.as_mut_ptr()).skip_frame = value.into(); - } - } - - pub fn time_base(&self) -> Rational { - unsafe { - Rational::from((*self.as_ptr()).time_base) - } - } -} - -impl Deref for Decoder { - type Target = Context; - - fn deref(&self) -> &::Target { - &self.0 - } -} - -impl DerefMut for Decoder { - fn deref_mut(&mut self) -> &mut::Target { - &mut self.0 - } +pub fn new() -> Decoder { + Context::new().decoder() } pub fn find(id: Id) -> Option { diff --git a/src/codec/encoder/audio.rs b/src/codec/encoder/audio.rs index 28f3bd4..adf42a7 100644 --- a/src/codec/encoder/audio.rs +++ b/src/codec/encoder/audio.rs @@ -5,9 +5,9 @@ use libc::c_int; use ffi::*; use super::Encoder as Super; -use ::{Packet, Error, Dictionary, Codec, ChannelLayout}; -use ::frame; +use ::{Packet, Error, Dictionary, ChannelLayout, frame}; use ::util::format; +use codec::traits; pub struct Audio(pub Super); @@ -21,23 +21,23 @@ impl Audio { } } - pub fn open_as(mut self, codec: &Codec) -> Result { + pub fn open_as(mut self, codec: E) -> Result { unsafe { - if codec.is_encoder() { + if let Some(codec) = codec.encoder() { match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), ptr::null_mut()) { 0 => Ok(Encoder(self)), e => Err(Error::from(e)) } } else { - Err(Error::InvalidData) + Err(Error::EncoderNotFound) } } } - pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result { + pub fn open_as_with(mut self, codec: E, options: Dictionary) -> Result { unsafe { - if codec.is_encoder() { + if let Some(codec) = codec.encoder() { let mut opts = options.disown(); let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts); @@ -49,7 +49,7 @@ impl Audio { } } else { - Err(Error::InvalidData) + Err(Error::EncoderNotFound) } } } diff --git a/src/codec/encoder/encoder.rs b/src/codec/encoder/encoder.rs new file mode 100644 index 0000000..7011d56 --- /dev/null +++ b/src/codec/encoder/encoder.rs @@ -0,0 +1,104 @@ +use std::ops::{Deref, DerefMut}; + +use libc::c_int; +use codec::Context; +use ::{Error, Rational, media}; +use super::{video, audio, subtitle}; + +pub struct Encoder(pub Context); + +impl Encoder { + pub fn video(self) -> Result { + if self.medium() == media::Type::Video { + Ok(video::Video(self)) + } + else { + Err(Error::InvalidData) + } + } + + pub fn audio(self) -> Result { + if self.medium() == media::Type::Audio { + Ok(audio::Audio(self)) + } + else { + Err(Error::InvalidData) + } + } + + pub fn subtitle(self) -> Result { + if self.medium() == media::Type::Subtitle { + Ok(subtitle::Subtitle(self)) + } + else { + Err(Error::InvalidData) + } + } + + pub fn set_bit_rate(&mut self, value: usize) { + unsafe { + (*self.as_mut_ptr()).bit_rate = value as c_int; + } + } + + pub fn set_max_bit_rate(&mut self, value: usize) { + unsafe { + (*self.as_mut_ptr()).rc_max_rate = value as c_int; + } + } + + pub fn set_tolerance(&mut self, value: usize) { + unsafe { + (*self.as_mut_ptr()).bit_rate_tolerance = value as c_int; + } + } + + pub fn set_quality(&mut self, value: usize) { + unsafe { + (*self.as_mut_ptr()).global_quality = value as c_int; + } + } + + pub fn set_compression(&mut self, value: Option) { + unsafe { + if let Some(value) = value { + (*self.as_mut_ptr()).compression_level = value as c_int; + } + else { + (*self.as_mut_ptr()).compression_level = -1; + } + } + } + + pub fn set_time_base>(&mut self, value: R) { + unsafe { + (*self.as_mut_ptr()).time_base = value.into().into(); + } + } + + pub fn set_frame_rate>(&mut self, value: Option) { + unsafe { + if let Some(value) = value { + (*self.as_mut_ptr()).framerate = value.into().into(); + } + else { + (*self.as_mut_ptr()).framerate.num = 0; + (*self.as_mut_ptr()).framerate.den = 1; + } + } + } +} + +impl Deref for Encoder { + type Target = Context; + + fn deref(&self) -> &::Target { + &self.0 + } +} + +impl DerefMut for Encoder { + fn deref_mut(&mut self) -> &mut::Target { + &mut self.0 + } +} diff --git a/src/codec/encoder/mod.rs b/src/codec/encoder/mod.rs index ba5b595..b3178ff 100644 --- a/src/codec/encoder/mod.rs +++ b/src/codec/encoder/mod.rs @@ -1,3 +1,6 @@ +pub mod encoder; +pub use self::encoder::Encoder; + pub mod video; pub use self::video::Encoder as Video; @@ -20,110 +23,14 @@ pub mod decision; pub use self::decision::Decision; use std::ffi::CString; -use std::ops::{Deref, DerefMut}; -use libc::c_int; use ffi::*; -use super::{Id, Context}; -use ::{Codec, Error, Rational}; -use ::media; +use codec::Context; +use ::Codec; +use codec::Id; -pub struct Encoder(pub Context); - -impl Encoder { - pub fn video(self) -> Result { - if self.medium() == media::Type::Video { - Ok(video::Video(self)) - } - else { - Err(Error::InvalidData) - } - } - - pub fn audio(self) -> Result { - if self.medium() == media::Type::Audio { - Ok(audio::Audio(self)) - } - else { - Err(Error::InvalidData) - } - } - - pub fn subtitle(self) -> Result { - if self.medium() == media::Type::Subtitle { - Ok(subtitle::Subtitle(self)) - } - else { - Err(Error::InvalidData) - } - } - - pub fn set_bit_rate(&mut self, value: usize) { - unsafe { - (*self.as_mut_ptr()).bit_rate = value as c_int; - } - } - - pub fn set_max_bit_rate(&mut self, value: usize) { - unsafe { - (*self.as_mut_ptr()).rc_max_rate = value as c_int; - } - } - - pub fn set_tolerance(&mut self, value: usize) { - unsafe { - (*self.as_mut_ptr()).bit_rate_tolerance = value as c_int; - } - } - - pub fn set_quality(&mut self, value: usize) { - unsafe { - (*self.as_mut_ptr()).global_quality = value as c_int; - } - } - - pub fn set_compression(&mut self, value: Option) { - unsafe { - if let Some(value) = value { - (*self.as_mut_ptr()).compression_level = value as c_int; - } - else { - (*self.as_mut_ptr()).compression_level = -1; - } - } - } - - pub fn set_time_base>(&mut self, value: R) { - unsafe { - (*self.as_mut_ptr()).time_base = value.into().into(); - } - } - - pub fn set_frame_rate>(&mut self, value: Option) { - unsafe { - if let Some(value) = value { - (*self.as_mut_ptr()).framerate = value.into().into(); - } - else { - (*self.as_mut_ptr()).framerate.num = 0; - (*self.as_mut_ptr()).framerate.den = 1; - } - } - } -} - -impl Deref for Encoder { - type Target = Context; - - fn deref(&self) -> &::Target { - &self.0 - } -} - -impl DerefMut for Encoder { - fn deref_mut(&mut self) -> &mut::Target { - &mut self.0 - } +pub fn new() -> Encoder { + Context::new().encoder() } pub fn find(id: Id) -> Option { diff --git a/src/codec/encoder/subtitle.rs b/src/codec/encoder/subtitle.rs index 74cc57c..8a3fbaf 100644 --- a/src/codec/encoder/subtitle.rs +++ b/src/codec/encoder/subtitle.rs @@ -5,7 +5,8 @@ use libc::c_int; use ffi::*; use super::Encoder as Super; -use ::{Error, Dictionary, Codec}; +use ::{Error, Dictionary}; +use codec::traits; pub struct Subtitle(pub Super); @@ -19,23 +20,23 @@ impl Subtitle { } } - pub fn open_as(mut self, codec: &Codec) -> Result { + pub fn open_as(mut self, codec: E) -> Result { unsafe { - if codec.is_encoder() { + if let Some(codec) = codec.encoder() { match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), ptr::null_mut()) { 0 => Ok(Encoder(self)), e => Err(Error::from(e)) } } else { - Err(Error::InvalidData) + Err(Error::EncoderNotFound) } } } - pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result { + pub fn open_as_with(mut self, codec: E, options: Dictionary) -> Result { unsafe { - if codec.is_encoder() { + if let Some(codec) = codec.encoder() { let mut opts = options.disown(); let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts); @@ -47,7 +48,7 @@ impl Subtitle { } } else { - Err(Error::InvalidData) + Err(Error::EncoderNotFound) } } } diff --git a/src/codec/encoder/video.rs b/src/codec/encoder/video.rs index 291905f..6104e1b 100644 --- a/src/codec/encoder/video.rs +++ b/src/codec/encoder/video.rs @@ -6,9 +6,8 @@ use ffi::*; use super::Encoder as Super; use super::{MotionEstimation, Prediction, Comparison, Decision}; -use ::{Packet, Error, Rational, Dictionary, Codec}; -use ::frame; -use ::format; +use ::{Packet, Error, Rational, Dictionary, frame, format}; +use codec::traits; pub struct Video(pub Super); @@ -22,23 +21,23 @@ impl Video { } } - pub fn open_as(mut self, codec: &Codec) -> Result { + pub fn open_as(mut self, codec: E) -> Result { unsafe { - if codec.is_encoder() { + if let Some(codec) = codec.encoder() { match avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), ptr::null_mut()) { 0 => Ok(Encoder(self)), e => Err(Error::from(e)) } } else { - Err(Error::InvalidData) + Err(Error::EncoderNotFound) } } } - pub fn open_as_with(mut self, codec: &Codec, options: Dictionary) -> Result { + pub fn open_as_with(mut self, codec: E, options: Dictionary) -> Result { unsafe { - if codec.is_encoder() { + if let Some(codec) = codec.encoder() { let mut opts = options.disown(); let res = avcodec_open2(self.as_mut_ptr(), codec.as_ptr(), &mut opts); @@ -50,7 +49,7 @@ impl Video { } } else { - Err(Error::InvalidData) + Err(Error::EncoderNotFound) } } } diff --git a/src/codec/mod.rs b/src/codec/mod.rs index e3e9ac3..65821f0 100644 --- a/src/codec/mod.rs +++ b/src/codec/mod.rs @@ -42,6 +42,7 @@ pub mod threading; pub mod encoder; pub mod decoder; +pub mod traits; use std::ffi::CStr; use std::str::from_utf8_unchecked; diff --git a/src/codec/traits.rs b/src/codec/traits.rs new file mode 100644 index 0000000..b750cea --- /dev/null +++ b/src/codec/traits.rs @@ -0,0 +1,113 @@ +use ::Codec; +use codec::{Id, Audio, Video}; +use super::{decoder, encoder}; + +pub trait Decoder { + fn decoder(self) -> Option; +} + +impl<'a> Decoder for &'a str { + fn decoder(self) -> Option { + decoder::find_by_name(self) + } +} + +impl Decoder for Id { + fn decoder(self) -> Option { + decoder::find(self) + } +} + +impl Decoder for Codec { + fn decoder(self) -> Option { + if self.is_decoder() { + Some(self) + } + else { + None + } + } +} + +impl Decoder for Option { + fn decoder(self) -> Option { + self.and_then(|c| c.decoder()) + } +} + +impl Decoder for Audio { + fn decoder(self) -> Option { + if self.is_decoder() { + Some(*&*self) + } + else { + None + } + } +} + +impl Decoder for Video { + fn decoder(self) -> Option { + if self.is_decoder() { + Some(*&*self) + } + else { + None + } + } +} + +pub trait Encoder { + fn encoder(self) -> Option; +} + +impl<'a> Encoder for &'a str { + fn encoder(self) -> Option { + encoder::find_by_name(self) + } +} + +impl Encoder for Id { + fn encoder(self) -> Option { + encoder::find(self) + } +} + +impl Encoder for Codec { + fn encoder(self) -> Option { + if self.is_encoder() { + Some(self) + } + else { + None + } + } +} + +impl Encoder for Option { + fn encoder(self) -> Option { + self.and_then(|c| c.encoder()) + } +} + +impl Encoder for Audio { + fn encoder(self) -> Option { + if self.is_encoder() { + Some(*&*self) + } + else { + None + } + } +} + +impl Encoder for Video { + fn encoder(self) -> Option { + if self.is_encoder() { + Some(*&*self) + } + else { + None + } + } +} diff --git a/src/codec/video.rs b/src/codec/video.rs index 7a3a321..102d386 100644 --- a/src/codec/video.rs +++ b/src/codec/video.rs @@ -4,6 +4,7 @@ use {Rational, format}; use super::codec::Codec; use ffi::*; +#[derive(PartialEq, Eq, Copy, Clone)] pub struct Video { codec: Codec, } diff --git a/src/format/context/output.rs b/src/format/context/output.rs index 3a6ceed..dc1e4cc 100644 --- a/src/format/context/output.rs +++ b/src/format/context/output.rs @@ -3,9 +3,10 @@ use std::ptr; use std::ffi::CString; use ffi::*; -use ::{Error, Codec, StreamMut, Dictionary, format}; +use ::{Error, StreamMut, Dictionary, format}; use super::common::Context; use super::destructor; +use codec::traits; pub struct Output { ptr: *mut AVFormatContext, @@ -67,9 +68,10 @@ impl Output { } } - pub fn add_stream(&mut self, codec: &Codec) -> StreamMut { + pub fn add_stream(&mut self, codec: E) -> Result { unsafe { - let ptr = avformat_new_stream(self.as_mut_ptr(), codec.as_ptr()); + let codec = try!(codec.encoder().ok_or(Error::EncoderNotFound)); + let ptr = avformat_new_stream(self.as_mut_ptr(), codec.as_ptr()); if ptr.is_null() { panic!("out of memory"); @@ -77,7 +79,7 @@ impl Output { let index = (*self.ctx.as_ptr()).nb_streams - 1; - StreamMut::wrap(&mut self.ctx, index as usize) + Ok(StreamMut::wrap(&mut self.ctx, index as usize)) } }