codec: add magic traits to get codecs by name and id

This commit is contained in:
meh 2015-09-25 21:33:08 +02:00
parent bde17a8bae
commit 66284eb045
12 changed files with 396 additions and 254 deletions

View File

@ -4,6 +4,7 @@ use {ChannelLayout, format};
use super::codec::Codec;
use ffi::*;
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct Audio {
codec: Codec,
}

View File

@ -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<Opened, Error> {
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<D: traits::Decoder>(mut self, codec: D) -> Result<Opened, Error> {
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<D: traits::Decoder>(mut self, codec: D, options: Dictionary) -> Result<Opened, Error> {
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<Video, Error> {
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<Audio, Error> {
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<Subtitle, Error> {
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) -> &<Self as Deref>::Target {
&self.0
}
}
impl DerefMut for Decoder {
fn deref_mut(&mut self) -> &mut<Self as Deref>::Target {
&mut self.0
}
}

View File

@ -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<Opened, Error> {
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<Opened, Error> {
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<Opened, Error> {
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<Video, Error> {
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<Audio, Error> {
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<Subtitle, Error> {
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) -> &<Self as Deref>::Target {
&self.0
}
}
impl DerefMut for Decoder {
fn deref_mut(&mut self) -> &mut<Self as Deref>::Target {
&mut self.0
}
pub fn new() -> Decoder {
Context::new().decoder()
}
pub fn find(id: Id) -> Option<Codec> {

View File

@ -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<Encoder, Error> {
pub fn open_as<E: traits::Encoder>(mut self, codec: E) -> Result<Encoder, Error> {
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<Encoder, Error> {
pub fn open_as_with<E: traits::Encoder>(mut self, codec: E, options: Dictionary) -> Result<Encoder, Error> {
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)
}
}
}

View File

@ -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<video::Video, Error> {
if self.medium() == media::Type::Video {
Ok(video::Video(self))
}
else {
Err(Error::InvalidData)
}
}
pub fn audio(self) -> Result<audio::Audio, Error> {
if self.medium() == media::Type::Audio {
Ok(audio::Audio(self))
}
else {
Err(Error::InvalidData)
}
}
pub fn subtitle(self) -> Result<subtitle::Subtitle, Error> {
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<usize>) {
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<R: Into<Rational>>(&mut self, value: R) {
unsafe {
(*self.as_mut_ptr()).time_base = value.into().into();
}
}
pub fn set_frame_rate<R: Into<Rational>>(&mut self, value: Option<R>) {
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) -> &<Self as Deref>::Target {
&self.0
}
}
impl DerefMut for Encoder {
fn deref_mut(&mut self) -> &mut<Self as Deref>::Target {
&mut self.0
}
}

View File

@ -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<video::Video, Error> {
if self.medium() == media::Type::Video {
Ok(video::Video(self))
}
else {
Err(Error::InvalidData)
}
}
pub fn audio(self) -> Result<audio::Audio, Error> {
if self.medium() == media::Type::Audio {
Ok(audio::Audio(self))
}
else {
Err(Error::InvalidData)
}
}
pub fn subtitle(self) -> Result<subtitle::Subtitle, Error> {
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<usize>) {
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<R: Into<Rational>>(&mut self, value: R) {
unsafe {
(*self.as_mut_ptr()).time_base = value.into().into();
}
}
pub fn set_frame_rate<R: Into<Rational>>(&mut self, value: Option<R>) {
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) -> &<Self as Deref>::Target {
&self.0
}
}
impl DerefMut for Encoder {
fn deref_mut(&mut self) -> &mut<Self as Deref>::Target {
&mut self.0
}
pub fn new() -> Encoder {
Context::new().encoder()
}
pub fn find(id: Id) -> Option<Codec> {

View File

@ -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<Encoder, Error> {
pub fn open_as<E: traits::Encoder>(mut self, codec: E) -> Result<Encoder, Error> {
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<Encoder, Error> {
pub fn open_as_with<E: traits::Encoder>(mut self, codec: E, options: Dictionary) -> Result<Encoder, Error> {
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)
}
}
}

View File

@ -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<Encoder, Error> {
pub fn open_as<E: traits::Encoder>(mut self, codec: E) -> Result<Encoder, Error> {
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<Encoder, Error> {
pub fn open_as_with<E: traits::Encoder>(mut self, codec: E, options: Dictionary) -> Result<Encoder, Error> {
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)
}
}
}

View File

@ -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;

113
src/codec/traits.rs Normal file
View File

@ -0,0 +1,113 @@
use ::Codec;
use codec::{Id, Audio, Video};
use super::{decoder, encoder};
pub trait Decoder {
fn decoder(self) -> Option<Codec>;
}
impl<'a> Decoder for &'a str {
fn decoder(self) -> Option<Codec> {
decoder::find_by_name(self)
}
}
impl Decoder for Id {
fn decoder(self) -> Option<Codec> {
decoder::find(self)
}
}
impl Decoder for Codec {
fn decoder(self) -> Option<Codec> {
if self.is_decoder() {
Some(self)
}
else {
None
}
}
}
impl Decoder for Option<Codec> {
fn decoder(self) -> Option<Codec> {
self.and_then(|c| c.decoder())
}
}
impl Decoder for Audio {
fn decoder(self) -> Option<Codec> {
if self.is_decoder() {
Some(*&*self)
}
else {
None
}
}
}
impl Decoder for Video {
fn decoder(self) -> Option<Codec> {
if self.is_decoder() {
Some(*&*self)
}
else {
None
}
}
}
pub trait Encoder {
fn encoder(self) -> Option<Codec>;
}
impl<'a> Encoder for &'a str {
fn encoder(self) -> Option<Codec> {
encoder::find_by_name(self)
}
}
impl Encoder for Id {
fn encoder(self) -> Option<Codec> {
encoder::find(self)
}
}
impl Encoder for Codec {
fn encoder(self) -> Option<Codec> {
if self.is_encoder() {
Some(self)
}
else {
None
}
}
}
impl Encoder for Option<Codec> {
fn encoder(self) -> Option<Codec> {
self.and_then(|c| c.encoder())
}
}
impl Encoder for Audio {
fn encoder(self) -> Option<Codec> {
if self.is_encoder() {
Some(*&*self)
}
else {
None
}
}
}
impl Encoder for Video {
fn encoder(self) -> Option<Codec> {
if self.is_encoder() {
Some(*&*self)
}
else {
None
}
}
}

View File

@ -4,6 +4,7 @@ use {Rational, format};
use super::codec::Codec;
use ffi::*;
#[derive(PartialEq, Eq, Copy, Clone)]
pub struct Video {
codec: Codec,
}

View File

@ -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,8 +68,9 @@ impl Output {
}
}
pub fn add_stream(&mut self, codec: &Codec) -> StreamMut {
pub fn add_stream<E: traits::Encoder>(&mut self, codec: E) -> Result<StreamMut, Error> {
unsafe {
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() {
@ -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))
}
}