From 1f80007e5edccf4e92f83b3e9a9402c6b6b78fe1 Mon Sep 17 00:00:00 2001 From: meh Date: Fri, 4 Sep 2015 16:30:19 +0200 Subject: [PATCH] format: split input and output formats --- src/codec/packet/mod.rs | 6 +- src/device/extensions.rs | 2 +- src/format/context.rs | 419 ----------------------------------- src/format/context/common.rs | 210 ++++++++++++++++++ src/format/context/input.rs | 180 +++++++++++++++ src/format/context/mod.rs | 51 +++++ src/format/context/output.rs | 105 +++++++++ src/format/format.rs | 25 ++- src/format/mod.rs | 232 +++++++++---------- 9 files changed, 672 insertions(+), 558 deletions(-) delete mode 100644 src/format/context.rs create mode 100644 src/format/context/common.rs create mode 100644 src/format/context/input.rs create mode 100644 src/format/context/mod.rs create mode 100644 src/format/context/output.rs diff --git a/src/codec/packet/mod.rs b/src/codec/packet/mod.rs index 5e238e7..b5f81aa 100644 --- a/src/codec/packet/mod.rs +++ b/src/codec/packet/mod.rs @@ -123,7 +123,7 @@ impl Packet { SideDataIter::new(&self.0) } - pub fn read(&mut self, format: &mut format::Context) -> Result<(), Error> { + pub fn read(&mut self, format: &mut format::context::Input) -> Result<(), Error> { unsafe { match av_read_frame(format.as_mut_ptr(), self.as_mut_ptr()) { 0 => Ok(()), @@ -132,7 +132,7 @@ impl Packet { } } - pub fn write(&self, format: &mut format::Context) -> Result { + pub fn write(&self, format: &mut format::context::Output) -> Result { unsafe { match av_write_frame(format.as_mut_ptr(), self.as_ptr()) { 1 => Ok(true), @@ -142,7 +142,7 @@ impl Packet { } } - pub fn write_interleaved(&self, format: &mut format::Context) -> Result { + pub fn write_interleaved(&self, format: &mut format::context::Output) -> Result { unsafe { match av_interleaved_write_frame(format.as_mut_ptr(), self.as_ptr()) { 1 => Ok(true), diff --git a/src/device/extensions.rs b/src/device/extensions.rs index c518055..79ecc41 100644 --- a/src/device/extensions.rs +++ b/src/device/extensions.rs @@ -3,7 +3,7 @@ use std::marker::PhantomData; use ffi::*; use ::Error; -use ::format::Context; +use ::format::context::common::Context; use ::device; use libc::c_int; diff --git a/src/format/context.rs b/src/format/context.rs deleted file mode 100644 index fd9d9a9..0000000 --- a/src/format/context.rs +++ /dev/null @@ -1,419 +0,0 @@ -use std::marker::PhantomData; -use std::ptr; - -use libc::{c_int, c_uint}; -use ffi::*; -use ::{Error, Codec, Stream, StreamMut, Packet, Dictionary, media}; - -pub struct Context { - ptr: *mut AVFormatContext, - - _input: bool, -} - -unsafe impl Send for Context { } - -impl Context { - pub unsafe fn input(ptr: *mut AVFormatContext) -> Self { - Context { - ptr: ptr, - - _input: true, - } - } - - pub unsafe fn output(ptr: *mut AVFormatContext) -> Self { - Context { - ptr: ptr, - - _input: false, - } - } - - pub unsafe fn as_ptr(&self) -> *const AVFormatContext { - self.ptr as *const _ - } - - pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext { - self.ptr - } -} - -impl Context { - pub fn new() -> Self { - unsafe { - Context { - ptr: avformat_alloc_context(), - - _input: false, - } - } - } - - pub fn is_input(&self) -> bool { - self._input - } - - pub fn is_output(&self) -> bool { - !self._input - } - - pub fn write_header(&mut self) -> Result<(), Error> { - unsafe { - match avformat_write_header(self.as_mut_ptr(), ptr::null_mut()) { - 0 => Ok(()), - e => Err(Error::from(e)), - } - } - } - - pub fn write_header_with(&mut self, options: Dictionary) -> Result<(), Error> { - unsafe { - let mut opts = options.take(); - let status = avformat_write_header(self.as_mut_ptr(), &mut opts); - - Dictionary::own(opts); - - match status { - 0 => Ok(()), - e => Err(Error::from(e)), - } - } - } - - pub fn write_trailer(&mut self) -> Result<(), Error> { - unsafe { - match av_write_trailer(self.as_mut_ptr()) { - 0 => Ok(()), - e => Err(Error::from(e)), - } - } - } - - pub fn stream(&self, index: usize) -> Option { - unsafe { - if index >= (*self.as_ptr()).nb_streams as usize { - None - } - else { - Some(Stream::wrap(*(*self.ptr).streams.offset(index as isize))) - } - } - } - - pub fn stream_mut(&mut self, index: usize) -> Option { - unsafe { - if index >= (*self.as_ptr()).nb_streams as usize { - None - } - else { - Some(StreamMut::wrap(*(*self.ptr).streams.offset(index as isize))) - } - } - } - - pub fn streams(&self) -> StreamIter { - unsafe { - StreamIter::new(self.as_ptr()) - } - } - - pub fn streams_mut(&mut self) -> StreamIterMut { - unsafe { - StreamIterMut::new(self.as_mut_ptr()) - } - } - - pub fn new_stream(&mut self, codec: &Codec) -> Option { - unsafe { - let ptr = avformat_new_stream(self.as_mut_ptr(), codec.as_ptr()); - - if ptr.is_null() { - None - } - else { - Some(StreamMut::wrap(ptr)) - } - } - } - - pub fn metadata(&self) -> Dictionary { - unsafe { - Dictionary::wrap((*self.as_ptr()).metadata) - } - } - - pub fn probe_score(&self) -> i32 { - unsafe { - av_format_get_probe_score(self.as_ptr()) - } - } - - pub fn video_codec(&self) -> Option { - unsafe { - let ptr = av_format_get_video_codec(self.as_ptr()); - - if ptr.is_null() { - None - } - else { - Some(Codec::wrap(ptr)) - } - } - } - - pub fn set_video_codec(&mut self, mut value: Codec) { - unsafe { - av_format_set_video_codec(self.as_mut_ptr(), value.as_mut_ptr()); - } - } - - pub fn audio_codec(&self) -> Option { - unsafe { - let ptr = av_format_get_audio_codec(self.as_ptr()); - - if ptr.is_null() { - None - } - else { - Some(Codec::wrap(ptr)) - } - } - } - - pub fn set_audio_codec(&mut self, mut value: Codec) { - unsafe { - av_format_set_audio_codec(self.as_mut_ptr(), value.as_mut_ptr()); - } - } - - pub fn subtitle_codec(&self) -> Option { - unsafe { - let ptr = av_format_get_subtitle_codec(self.as_ptr()); - - if ptr.is_null() { - None - } - else { - Some(Codec::wrap(ptr)) - } - } - } - - pub fn set_subtitle_codec(&mut self, mut value: Codec) { - unsafe { - av_format_set_subtitle_codec(self.as_mut_ptr(), value.as_mut_ptr()); - } - } - - pub fn data_codec(&self) -> Option { - unsafe { - let ptr = av_format_get_data_codec(self.as_ptr()); - - if ptr.is_null() { - None - } - else { - Some(Codec::wrap(ptr)) - } - } - } - - pub fn set_data_codec(&mut self, mut value: Codec) { - unsafe { - av_format_set_data_codec(self.as_mut_ptr(), value.as_mut_ptr()); - } - } - - pub fn packets(&mut self) -> PacketIter { - PacketIter::new(self) - } -} - -impl Drop for Context { - fn drop(&mut self) { - unsafe { - if self._input { - avformat_close_input(&mut self.as_mut_ptr()); - } - else { - avformat_free_context(self.as_mut_ptr()); - } - } - } -} - -pub struct Best<'a> { - ptr: *const AVFormatContext, - - wanted: i32, - related: i32, - - _marker: PhantomData<&'a ()>, -} - -impl<'a> Best<'a> { - pub unsafe fn new<'b>(ptr: *const AVFormatContext) -> Best<'b> { - Best { - ptr: ptr, - - wanted: -1, - related: -1, - - _marker: PhantomData, - } - } - - pub fn wanted<'b: 'a>(mut self, stream: &'b Stream) -> Best<'a> { - self.wanted = stream.index() as i32; - self - } - - pub fn related<'b: 'a>(mut self, stream: &'b Stream) -> Best<'a> { - self.related = stream.index() as i32; - self - } - - pub fn best(self, kind: media::Type) -> Option> { - unsafe { - let mut decoder = ptr::null_mut(); - let index = av_find_best_stream(self.ptr, - kind.into(), self.wanted as c_int, self.related as c_int, - &mut decoder, 0); - - if index >= 0 && !decoder.is_null() { - Some(Stream::wrap(*(*self.ptr).streams.offset(index as isize))) - } - else { - None - } - } - } -} - -pub struct StreamIter<'a> { - ptr: *const AVFormatContext, - cur: c_uint, - - _marker: PhantomData<&'a Context>, -} - -impl<'a> StreamIter<'a> { - pub fn new(ptr: *const AVFormatContext) -> Self { - StreamIter { ptr: ptr, cur: 0, _marker: PhantomData } - } -} - -impl<'a> StreamIter<'a> { - pub fn wanted<'b: 'a>(&'a self, stream: &'b Stream) -> Best<'a> { - unsafe { - Best::new(self.ptr).wanted(stream) - } - } - - pub fn related<'b: 'a>(&'a self, stream: &'b Stream) -> Best<'a> { - unsafe { - Best::new(self.ptr).related(stream) - } - } - - pub fn best(&'a self, kind: media::Type) -> Option> { - unsafe { - Best::new(self.ptr).best(kind) - } - } -} - -impl<'a> Iterator for StreamIter<'a> { - type Item = Stream<'a>; - - fn next(&mut self) -> Option<::Item> { - unsafe { - if self.cur >= (*self.ptr).nb_streams { - None - } - else { - self.cur += 1; - Some(Stream::wrap(*(*self.ptr).streams.offset((self.cur - 1) as isize))) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - unsafe { - ((*self.ptr).nb_streams as usize, Some((*self.ptr).nb_streams as usize)) - } - } -} - -impl<'a> ExactSizeIterator for StreamIter<'a> { } - -pub struct StreamIterMut<'a> { - ptr: *const AVFormatContext, - cur: c_uint, - - _marker: PhantomData<&'a Context>, -} - -impl<'a> StreamIterMut<'a> { - pub fn new(ptr: *mut AVFormatContext) -> Self { - StreamIterMut { ptr: ptr, cur: 0, _marker: PhantomData } - } -} - -impl<'a> Iterator for StreamIterMut<'a> { - type Item = StreamMut<'a>; - - fn next(&mut self) -> Option<::Item> { - unsafe { - if self.cur >= (*self.ptr).nb_streams { - None - } - else { - self.cur += 1; - Some(StreamMut::wrap(*(*self.ptr).streams.offset((self.cur - 1) as isize))) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - unsafe { - ((*self.ptr).nb_streams as usize, Some((*self.ptr).nb_streams as usize)) - } - } -} - -impl<'a> ExactSizeIterator for StreamIterMut<'a> { } - -pub struct PacketIter<'a> { - context: &'a mut Context, -} - -impl<'a> PacketIter<'a> { - pub fn new(context: &mut Context) -> PacketIter { - PacketIter { context: context } - } -} - -impl<'a> Iterator for PacketIter<'a> { - type Item = (Stream<'a>, Packet); - - fn next(&mut self) -> Option<::Item> { - let mut packet = Packet::empty(); - - loop { - match packet.read(self.context) { - Ok(..) => - return Some((unsafe { - Stream::wrap(*(*self.context.as_ptr()).streams.offset(packet.stream() as isize)) - }, packet)), - - Err(Error::Eof) => - return None, - - Err(..) => - () - } - } - } -} diff --git a/src/format/context/common.rs b/src/format/context/common.rs new file mode 100644 index 0000000..5f94667 --- /dev/null +++ b/src/format/context/common.rs @@ -0,0 +1,210 @@ +use std::marker::PhantomData; +use std::ptr; + +use ffi::*; +use libc::{c_int, c_uint}; +use ::{media, Stream, StreamMut, Dictionary}; + +pub struct Context { + ptr: *mut AVFormatContext, +} + +unsafe impl Send for Context { } + +impl Context { + pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self { + Context { ptr: ptr } + } + + pub unsafe fn as_ptr(&self) -> *const AVFormatContext { + self.ptr as *const _ + } + + pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext { + self.ptr + } +} + +impl Context { + pub fn stream<'a, 'b>(&'a self, index: usize) -> Option> where 'a: 'b { + unsafe { + if index >= (*self.as_ptr()).nb_streams as usize { + None + } + else { + Some(Stream::wrap(*(*self.as_ptr()).streams.offset(index as isize))) + } + } + } + + pub fn stream_mut<'a, 'b>(&'a mut self, index: usize) -> Option> where 'a: 'b { + unsafe { + if index >= (*self.as_ptr()).nb_streams as usize { + None + } + else { + Some(StreamMut::wrap(*(*self.as_mut_ptr()).streams.offset(index as isize))) + } + } + } + + pub fn streams(&self) -> StreamIter { + unsafe { + StreamIter::new(self.as_ptr()) + } + } + + pub fn streams_mut(&mut self) -> StreamIterMut { + unsafe { + StreamIterMut::new(self.as_mut_ptr()) + } + } + + pub fn metadata(&self) -> Dictionary { + unsafe { + Dictionary::wrap((*self.as_ptr()).metadata) + } + } +} + +pub struct Best<'a> { + ptr: *const AVFormatContext, + + wanted: i32, + related: i32, + + _marker: PhantomData<&'a ()>, +} + +impl<'a> Best<'a> { + pub unsafe fn new<'b>(ptr: *const AVFormatContext) -> Best<'b> { + Best { + ptr: ptr, + + wanted: -1, + related: -1, + + _marker: PhantomData, + } + } + + pub fn wanted<'b>(mut self, stream: &'b Stream) -> Best<'a> where 'a: 'b { + self.wanted = stream.index() as i32; + self + } + + pub fn related<'b>(mut self, stream: &'b Stream) -> Best<'a> where 'a: 'b { + self.related = stream.index() as i32; + self + } + + pub fn best<'b>(self, kind: media::Type) -> Option> where 'a: 'b { + unsafe { + let mut decoder = ptr::null_mut(); + let index = av_find_best_stream(self.ptr, + kind.into(), self.wanted as c_int, self.related as c_int, + &mut decoder, 0); + + if index >= 0 && !decoder.is_null() { + Some(Stream::wrap(*(*self.ptr).streams.offset(index as isize))) + } + else { + None + } + } + } +} + +pub struct StreamIter<'a> { + ptr: *const AVFormatContext, + cur: c_uint, + + _marker: PhantomData<&'a ()>, +} + +impl<'a> StreamIter<'a> { + pub fn new(ptr: *const AVFormatContext) -> Self { + StreamIter { ptr: ptr, cur: 0, _marker: PhantomData } + } +} + +impl<'a> StreamIter<'a> { + pub fn wanted<'b: 'a, 'c: 'a>(&'a self, stream: &'b Stream) -> Best<'a> { + unsafe { + Best::new(self.ptr).wanted(stream) + } + } + + pub fn related<'b: 'a>(&'a self, stream: &'b Stream) -> Best<'a> { + unsafe { + Best::new(self.ptr).related(stream) + } + } + + pub fn best<'b: 'a>(&'a self, kind: media::Type) -> Option> { + unsafe { + Best::new(self.ptr).best(kind) + } + } +} + +impl<'a> Iterator for StreamIter<'a> { + type Item = Stream<'a>; + + fn next(&mut self) -> Option<::Item> { + unsafe { + if self.cur >= (*self.ptr).nb_streams { + None + } + else { + self.cur += 1; + Some(Stream::wrap(*(*self.ptr).streams.offset((self.cur - 1) as isize))) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + unsafe { + ((*self.ptr).nb_streams as usize, Some((*self.ptr).nb_streams as usize)) + } + } +} + +impl<'a> ExactSizeIterator for StreamIter<'a> { } + +pub struct StreamIterMut<'a> { + ptr: *const AVFormatContext, + cur: c_uint, + + _marker: PhantomData<&'a ()>, +} + +impl<'a> StreamIterMut<'a> { + pub fn new(ptr: *mut AVFormatContext) -> Self { + StreamIterMut { ptr: ptr, cur: 0, _marker: PhantomData } + } +} + +impl<'a> Iterator for StreamIterMut<'a> { + type Item = StreamMut<'a>; + + fn next(&mut self) -> Option<::Item> { + unsafe { + if self.cur >= (*self.ptr).nb_streams { + None + } + else { + self.cur += 1; + Some(StreamMut::wrap(*(*self.ptr).streams.offset((self.cur - 1) as isize))) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + unsafe { + ((*self.ptr).nb_streams as usize, Some((*self.ptr).nb_streams as usize)) + } + } +} + +impl<'a> ExactSizeIterator for StreamIterMut<'a> { } diff --git a/src/format/context/input.rs b/src/format/context/input.rs new file mode 100644 index 0000000..a8bd7b4 --- /dev/null +++ b/src/format/context/input.rs @@ -0,0 +1,180 @@ +use std::ops::{Deref, DerefMut}; +use std::ptr; +use std::ffi::CString; + +use ffi::*; +use ::{Error, Codec, Stream, Packet}; +use super::common::Context; + +pub struct Input { + ptr: *mut AVFormatContext, + ctx: Context, +} + +unsafe impl Send for Input { } + +impl Input { + pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self { + Input { ptr: ptr, ctx: Context::wrap(ptr) } + } + + pub unsafe fn as_ptr(&self) -> *const AVFormatContext { + self.ptr as *const _ + } + + pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext { + self.ptr + } +} + +impl Input { + pub fn video_codec(&self) -> Option { + unsafe { + let ptr = av_format_get_video_codec(self.as_ptr()); + + if ptr.is_null() { + None + } + else { + Some(Codec::wrap(ptr)) + } + } + } + + pub fn set_video_codec(&mut self, mut value: Codec) { + unsafe { + av_format_set_video_codec(self.as_mut_ptr(), value.as_mut_ptr()); + } + } + + pub fn audio_codec(&self) -> Option { + unsafe { + let ptr = av_format_get_audio_codec(self.as_ptr()); + + if ptr.is_null() { + None + } + else { + Some(Codec::wrap(ptr)) + } + } + } + + pub fn set_audio_codec(&mut self, mut value: Codec) { + unsafe { + av_format_set_audio_codec(self.as_mut_ptr(), value.as_mut_ptr()); + } + } + + pub fn subtitle_codec(&self) -> Option { + unsafe { + let ptr = av_format_get_subtitle_codec(self.as_ptr()); + + if ptr.is_null() { + None + } + else { + Some(Codec::wrap(ptr)) + } + } + } + + pub fn set_subtitle_codec(&mut self, mut value: Codec) { + unsafe { + av_format_set_subtitle_codec(self.as_mut_ptr(), value.as_mut_ptr()); + } + } + + pub fn data_codec(&self) -> Option { + unsafe { + let ptr = av_format_get_data_codec(self.as_ptr()); + + if ptr.is_null() { + None + } + else { + Some(Codec::wrap(ptr)) + } + } + } + + pub fn set_data_codec(&mut self, mut value: Codec) { + unsafe { + av_format_set_data_codec(self.as_mut_ptr(), value.as_mut_ptr()); + } + } + + pub fn probe_score(&self) -> i32 { + unsafe { + av_format_get_probe_score(self.as_ptr()) + } + } + + pub fn packets(&mut self) -> PacketIter { + PacketIter::new(self) + } +} + +impl Deref for Input { + type Target = Context; + + fn deref(&self) -> &Self::Target { + &self.ctx + } +} + +impl DerefMut for Input { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.ctx + } +} + +impl Drop for Input { + fn drop(&mut self) { + unsafe { + avformat_close_input(&mut self.as_mut_ptr()); + } + } +} + +pub struct PacketIter<'a> { + context: &'a mut Input, +} + +impl<'a> PacketIter<'a> { + pub fn new(context: &mut Input) -> PacketIter { + PacketIter { context: context } + } +} + +impl<'a> Iterator for PacketIter<'a> { + type Item = (Stream<'a>, Packet); + + fn next(&mut self) -> Option<::Item> { + let mut packet = Packet::empty(); + + loop { + match packet.read(self.context) { + Ok(..) => + return Some((unsafe { + Stream::wrap(*(*self.context.as_ptr()).streams.offset(packet.stream() as isize)) + }, packet)), + + Err(Error::Eof) => + return None, + + Err(..) => + () + } + } + } +} + +pub fn dump(ctx: &Input, index: i32, url: Option<&str>) { + let url = url.map(|u| CString::new(u).unwrap()); + + unsafe { + av_dump_format(ctx.as_ptr(), index, + url.map(|u| u.as_ptr()).unwrap_or(ptr::null()), 0); + } +} diff --git a/src/format/context/mod.rs b/src/format/context/mod.rs new file mode 100644 index 0000000..8ae0257 --- /dev/null +++ b/src/format/context/mod.rs @@ -0,0 +1,51 @@ +pub mod input; +pub use self::input::Input; + +pub mod output; +pub use self::output::Output; + +#[doc(hidden)] +pub mod common; + +pub enum Context { + Input(Input), + Output(Output), +} + +unsafe impl Send for Context { } + +impl Context { + pub fn is_input(&self) -> bool { + if let &Context::Input(..) = self { + true + } + else { + false + } + } + + pub fn input(self) -> Input { + if let Context::Input(context) = self { + return context; + } + + unreachable!(); + } + + pub fn is_output(&self) -> bool { + if let &Context::Output(..) = self { + true + } + else { + false + } + } + + pub fn output(self) -> Output { + if let Context::Output(context) = self { + return context; + } + + unreachable!(); + } +} diff --git a/src/format/context/output.rs b/src/format/context/output.rs new file mode 100644 index 0000000..8005796 --- /dev/null +++ b/src/format/context/output.rs @@ -0,0 +1,105 @@ +use std::ops::{Deref, DerefMut}; +use std::ptr; +use std::ffi::CString; + +use ffi::*; +use ::{Error, Codec, StreamMut, Dictionary}; +use super::common::Context; + +pub struct Output { + ptr: *mut AVFormatContext, + ctx: Context, +} + +unsafe impl Send for Output { } + +impl Output { + pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self { + Output { ptr: ptr, ctx: Context::wrap(ptr) } + } + + pub unsafe fn as_ptr(&self) -> *const AVFormatContext { + self.ptr as *const _ + } + + pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext { + self.ptr + } +} + +impl Output { + pub fn write_header(&mut self) -> Result<(), Error> { + unsafe { + match avformat_write_header(self.as_mut_ptr(), ptr::null_mut()) { + 0 => Ok(()), + e => Err(Error::from(e)), + } + } + } + + pub fn write_header_with(&mut self, options: Dictionary) -> Result<(), Error> { + unsafe { + let mut opts = options.take(); + let status = avformat_write_header(self.as_mut_ptr(), &mut opts); + + Dictionary::own(opts); + + match status { + 0 => Ok(()), + e => Err(Error::from(e)), + } + } + } + + pub fn write_trailer(&mut self) -> Result<(), Error> { + unsafe { + match av_write_trailer(self.as_mut_ptr()) { + 0 => Ok(()), + e => Err(Error::from(e)), + } + } + } + + pub fn add_stream(&mut self, codec: &Codec) -> StreamMut { + unsafe { + let ptr = avformat_new_stream(self.as_mut_ptr(), codec.as_ptr()); + + if ptr.is_null() { + panic!("out of memory"); + } + + StreamMut::wrap(ptr) + } + } +} + +impl Deref for Output { + type Target = Context; + + fn deref(&self) -> &Self::Target { + &self.ctx + } +} + +impl DerefMut for Output { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.ctx + } +} + +impl Drop for Output { + fn drop(&mut self) { + unsafe { + avformat_free_context(self.as_mut_ptr()); + } + } +} + +pub fn dump(ctx: &Output, index: i32, url: Option<&str>) { + let url = url.map(|u| CString::new(u).unwrap()); + + unsafe { + av_dump_format(ctx.as_ptr(), index, + url.map(|u| u.as_ptr()).unwrap_or(ptr::null()), 1); + } +} diff --git a/src/format/format.rs b/src/format/format.rs index ab42b4f..ceca921 100644 --- a/src/format/format.rs +++ b/src/format/format.rs @@ -162,12 +162,18 @@ pub fn list() -> FormatIter { pub struct FormatIter { input: *mut AVInputFormat, output: *mut AVOutputFormat, - step: usize, + step: Step, +} + +enum Step { + Input, + Output, + Done, } impl FormatIter { pub fn new() -> Self { - FormatIter { input: ptr::null_mut(), output: ptr::null_mut(), step: 0 } + FormatIter { input: ptr::null_mut(), output: ptr::null_mut(), step: Step::Input } } } @@ -177,11 +183,11 @@ impl Iterator for FormatIter { fn next(&mut self) -> Option<::Item> { unsafe { match self.step { - 0 => { + Step::Input => { let ptr = av_iformat_next(self.input); if ptr.is_null() && !self.input.is_null() { - self.step = 1; + self.step = Step::Output; self.next() } @@ -190,13 +196,13 @@ impl Iterator for FormatIter { Some(Format::Input(Input::wrap(ptr))) } - }, + } - 1 => { + Step::Output => { let ptr = av_oformat_next(self.output); if ptr.is_null() && !self.output.is_null() { - self.step = 2; + self.step = Step::Done; self.next() } @@ -205,9 +211,10 @@ impl Iterator for FormatIter { Some(Format::Output(Output::wrap(ptr))) } - }, + } - _ => None + Step::Done => + None } } } diff --git a/src/format/mod.rs b/src/format/mod.rs index a7c0fcb..0d3f92b 100644 --- a/src/format/mod.rs +++ b/src/format/mod.rs @@ -56,176 +56,156 @@ pub fn license() -> &'static str { } // XXX: use to_cstring when stable -fn from_path>(path: &T) -> CString { +fn from_path>(path: &P) -> CString { CString::new(path.as_ref().as_os_str().to_str().unwrap()).unwrap() } -pub fn open_input>(path: &T) -> Result { +// NOTE: this will be better with specialization or anonymous return types +pub fn open>(path: &P, format: &Format) -> Result { unsafe { - let mut ps = ptr::null_mut(); - let path = from_path(path); - let status = avformat_open_input(&mut ps, path.as_ptr(), ptr::null_mut(), ptr::null_mut()); + let mut ps = ptr::null_mut(); + let path = from_path(path); - match status { - 0 => { - let ctx = Context::input(ps); + match format { + &Format::Input(ref format) => { + match avformat_open_input(&mut ps, path.as_ptr(), format.as_ptr(), ptr::null_mut()) { + 0 => { + match avformat_find_stream_info(ps, ptr::null_mut()) { + 0 => Ok(Context::Input(context::Input::wrap(ps))), + e => Err(Error::from(e)), + } + } - match avformat_find_stream_info(ps, ptr::null_mut()) { - 0 => Ok(ctx), e => Err(Error::from(e)) } - }, + } + + &Format::Output(ref format) => { + match avformat_alloc_output_context2(&mut ps, format.as_ptr(), ptr::null(), path.as_ptr()) { + 0 => { + match avio_open(&mut (*ps).pb, path.as_ptr(), AVIO_FLAG_WRITE) { + 0 => Ok(Context::Output(context::Output::wrap(ps))), + e => Err(Error::from(e)), + } + } + + e => Err(Error::from(e)) + } + } + } + } +} + +pub fn open_with>(path: &P, format: &Format, options: Dictionary) -> Result { + unsafe { + let mut ps = ptr::null_mut(); + let path = from_path(path); + let mut opts = options.take(); + + match format { + &Format::Input(ref format) => { + match avformat_open_input(&mut ps, path.as_ptr(), format.as_ptr(), &mut opts) { + 0 => { + Dictionary::own(opts); + + match avformat_find_stream_info(ps, ptr::null_mut()) { + 0 => Ok(Context::Input(context::Input::wrap(ps))), + e => Err(Error::from(e)), + } + } + + e => Err(Error::from(e)) + } + } + + &Format::Output(ref format) => { + match avformat_alloc_output_context2(&mut ps, format.as_ptr(), ptr::null(), path.as_ptr()) { + 0 => { + match avio_open(&mut (*ps).pb, path.as_ptr(), AVIO_FLAG_WRITE) { + 0 => Ok(Context::Output(context::Output::wrap(ps))), + e => Err(Error::from(e)), + } + } + + e => Err(Error::from(e)) + } + } + } + } +} + +pub fn input>(path: &P) -> Result { + unsafe { + let mut ps = ptr::null_mut(); + let path = from_path(path); + + match avformat_open_input(&mut ps, path.as_ptr(), ptr::null_mut(), ptr::null_mut()) { + 0 => { + match avformat_find_stream_info(ps, ptr::null_mut()) { + 0 => Ok(context::Input::wrap(ps)), + e => Err(Error::from(e)) + } + } e => Err(Error::from(e)) } } } -pub fn open_input_with>(path: &T, options: Dictionary) -> Result { +pub fn input_with>(path: &P, options: Dictionary) -> Result { unsafe { - let mut ps = ptr::null_mut(); - let path = from_path(path); - let mut opts = options.take(); - let status = avformat_open_input(&mut ps, path.as_ptr(), ptr::null_mut(), &mut opts); + let mut ps = ptr::null_mut(); + let path = from_path(path); + let mut opts = options.take(); - Dictionary::own(opts); - - match status { + match avformat_open_input(&mut ps, path.as_ptr(), ptr::null_mut(), &mut opts) { 0 => { - let ctx = Context::input(ps); + Dictionary::own(opts); match avformat_find_stream_info(ps, ptr::null_mut()) { - 0 => Ok(ctx), + 0 => Ok(context::Input::wrap(ps)), e => Err(Error::from(e)) } - }, - + } + e => Err(Error::from(e)) } } } -pub fn open_input_as>(path: &T, format: &Format) -> Result { - if let &Format::Input(ref format) = format { - unsafe { - let mut ps = ptr::null_mut(); - let path = from_path(path); - let status = avformat_open_input(&mut ps, path.as_ptr(), format.as_ptr(), ptr::null_mut()); - - match status { - 0 => { - let ctx = Context::input(ps); - - match avformat_find_stream_info(ps, ptr::null_mut()) { - 0 => Ok(ctx), - e => Err(Error::from(e)) - } - }, - - e => Err(Error::from(e)) - } - } - } - else { - Err(Error::Bug) - } -} - -pub fn open_input_as_with>(path: &T, format: &Format, options: Dictionary) -> Result { - if let &Format::Input(ref format) = format { - unsafe { - let mut ps = ptr::null_mut(); - let path = from_path(path); - let mut opts = options.take(); - let status = avformat_open_input(&mut ps, path.as_ptr(), format.as_ptr(), &mut opts); - - Dictionary::own(opts); - - match status { - 0 => { - let ctx = Context::input(ps); - - match avformat_find_stream_info(ps, ptr::null_mut()) { - 0 => Ok(ctx), - e => Err(Error::from(e)) - } - }, - - e => Err(Error::from(e)) - } - } - } - else { - Err(Error::Bug) - } -} - -pub fn open_output>(path: &T) -> Result { +pub fn output>(path: &P) -> Result { unsafe { let mut ps = ptr::null_mut(); let path = from_path(path); - let status = avformat_alloc_output_context2(&mut ps, ptr::null_mut(), ptr::null(), path.as_ptr()); - match status { + match avformat_alloc_output_context2(&mut ps, ptr::null_mut(), ptr::null(), path.as_ptr()) { 0 => { match avio_open(&mut (*ps).pb, path.as_ptr(), AVIO_FLAG_WRITE) { - 0 => Ok(Context::output(ps)), - e => Err(Error::from(e)), + 0 => Ok(context::Output::wrap(ps)), + e => Err(Error::from(e)) } - }, + } + e => Err(Error::from(e)) } } } -pub fn open_output_as>(path: &T, format: &Format) -> Result { - if let &Format::Output(ref format) = format { - unsafe { - let mut ps = ptr::null_mut(); - let path = from_path(path); - let status = avformat_alloc_output_context2(&mut ps, format.as_ptr(), ptr::null(), path.as_ptr()); - - match status { - 0 => { - match avio_open(&mut (*ps).pb, path.as_ptr(), AVIO_FLAG_WRITE) { - 0 => Ok(Context::output(ps)), - e => Err(Error::from(e)), - } - }, - e => Err(Error::from(e)) - } - } - } - else { - Err(Error::Bug) - } -} - -pub fn open_output_as_string>(path: &T, format: &str) -> Result { +pub fn output_as>(path: &P, format: &str) -> Result { unsafe { let mut ps = ptr::null_mut(); let path = from_path(path); let format = CString::new(format).unwrap(); - let status = avformat_alloc_output_context2(&mut ps, ptr::null_mut(), format.as_ptr(), path.as_ptr()); - match status { - 0 => { - match avio_open(&mut (*ps).pb, path.as_ptr(), AVIO_FLAG_WRITE) { - 0 => Ok(Context::output(ps)), - e => Err(Error::from(e)), - } - }, + match avformat_alloc_output_context2(&mut ps, ptr::null_mut(), format.as_ptr(), path.as_ptr()) { + 0 => { + match avio_open(&mut (*ps).pb, path.as_ptr(), AVIO_FLAG_WRITE) { + 0 => Ok(context::Output::wrap(ps)), + e => Err(Error::from(e)) + } + } + e => Err(Error::from(e)) } } } - -pub fn dump(ctx: &Context, index: i32, url: Option<&str>) { - let url = url.map(|u| CString::new(u).unwrap()); - - unsafe { - av_dump_format(ctx.as_ptr(), index, - url.map(|u| u.as_ptr()).unwrap_or(ptr::null()), - if ctx.is_input() { 0 } else { 1 }); - } -}