diff --git a/src/codec/context.rs b/src/codec/context.rs index 536abee..549e264 100644 --- a/src/codec/context.rs +++ b/src/codec/context.rs @@ -1,4 +1,5 @@ use std::ptr; +use std::rc::Rc; use libc::c_int; use ffi::*; @@ -9,16 +10,15 @@ use super::decoder::Decoder; use super::encoder::Encoder; pub struct Context { - ptr: *mut AVCodecContext, - - _own: bool, + ptr: *mut AVCodecContext, + owner: Option>, } unsafe impl Send for Context { } impl Context { - pub unsafe fn wrap(ptr: *mut AVCodecContext) -> Self { - Context { ptr: ptr, _own: false } + pub unsafe fn wrap(ptr: *mut AVCodecContext, owner: Option>) -> Self { + Context { ptr: ptr, owner: owner } } pub unsafe fn as_ptr(&self) -> *const AVCodecContext { @@ -33,7 +33,7 @@ impl Context { impl Context { pub fn new() -> Self { unsafe { - Context { ptr: avcodec_alloc_context3(ptr::null()), _own: true } + Context { ptr: avcodec_alloc_context3(ptr::null()), owner: None } } } @@ -107,8 +107,8 @@ impl Context { impl Drop for Context { fn drop(&mut self) { - if self._own { - unsafe { + unsafe { + if self.owner.is_none() { avcodec_free_context(&mut self.as_mut_ptr()); } } diff --git a/src/codec/encoder/mod.rs b/src/codec/encoder/mod.rs index 5dd7a72..8fd32c3 100644 --- a/src/codec/encoder/mod.rs +++ b/src/codec/encoder/mod.rs @@ -1,11 +1,11 @@ pub mod video; -pub use self::video::Video; +pub use self::video::Encoder as Video; pub mod audio; -pub use self::audio::Audio; +pub use self::audio::Encoder as Audio; pub mod subtitle; -pub use self::subtitle::Subtitle; +pub use self::subtitle::Encoder as Subtitle; pub mod motion_estimation; pub use self::motion_estimation::MotionEstimation; @@ -31,27 +31,27 @@ use ::media; pub struct Encoder(pub Context); impl Encoder { - pub fn video(self) -> Result { + pub fn video(self) -> Result { if self.medium() == media::Type::Video { - Ok(Video(self)) + Ok(video::Video(self)) } else { Err(Error::InvalidData) } } - pub fn audio(self) -> Result { + pub fn audio(self) -> Result { if self.medium() == media::Type::Audio { - Ok(Audio(self)) + Ok(audio::Audio(self)) } else { Err(Error::InvalidData) } } - pub fn subtitle(self) -> Result { + pub fn subtitle(self) -> Result { if self.medium() == media::Type::Subtitle { - Ok(Subtitle(self)) + Ok(subtitle::Subtitle(self)) } else { Err(Error::InvalidData) diff --git a/src/codec/packet/side_data.rs b/src/codec/packet/side_data.rs index 4a2e898..1366de7 100644 --- a/src/codec/packet/side_data.rs +++ b/src/codec/packet/side_data.rs @@ -87,10 +87,6 @@ impl<'a> SideData<'a> { pub unsafe fn as_ptr(&self) -> *const AVPacketSideData { self.ptr as *const _ } - - pub unsafe fn as_mut_ptr(&mut self) -> *mut AVPacketSideData { - self.ptr - } } impl<'a> SideData<'a> { diff --git a/src/format/context/common.rs b/src/format/context/common.rs index 4d8baea..a306e0c 100644 --- a/src/format/context/common.rs +++ b/src/format/context/common.rs @@ -1,19 +1,22 @@ -use std::marker::PhantomData; +use std::rc::Rc; use std::ptr; +use std::mem; use ffi::*; use libc::{c_int, c_uint}; use ::{media, Stream, StreamMut, DictionaryRef}; +use super::destructor::{self, Destructor}; pub struct Context { - ptr: *mut AVFormatContext, + ptr: *mut AVFormatContext, + dtor: Rc, } unsafe impl Send for Context { } impl Context { - pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self { - Context { ptr: ptr } + pub unsafe fn wrap(ptr: *mut AVFormatContext, mode: destructor::Mode) -> Self { + Context { ptr: ptr, dtor: Rc::new(Destructor::new(ptr, mode)) } } pub unsafe fn as_ptr(&self) -> *const AVFormatContext { @@ -23,6 +26,10 @@ impl Context { pub unsafe fn as_mut_ptr(&mut self) -> *mut AVFormatContext { self.ptr } + + pub unsafe fn destructor(&self) -> Rc { + self.dtor.clone() + } } impl Context { @@ -32,7 +39,7 @@ impl Context { None } else { - Some(Stream::wrap(*(*self.as_ptr()).streams.offset(index as isize))) + Some(Stream::wrap(self, index)) } } } @@ -43,21 +50,17 @@ impl Context { None } else { - Some(StreamMut::wrap(*(*self.as_mut_ptr()).streams.offset(index as isize))) + Some(StreamMut::wrap(self, index)) } } } pub fn streams(&self) -> StreamIter { - unsafe { - StreamIter::new(self.as_ptr()) - } + StreamIter::new(self) } pub fn streams_mut(&mut self) -> StreamIterMut { - unsafe { - StreamIterMut::new(self.as_mut_ptr()) - } + StreamIterMut::new(self) } pub fn metadata(&self) -> DictionaryRef { @@ -68,23 +71,19 @@ impl Context { } pub struct Best<'a> { - ptr: *const AVFormatContext, + context: &'a Context, wanted: i32, related: i32, - - _marker: PhantomData<&'a ()>, } impl<'a> Best<'a> { - pub unsafe fn new<'b>(ptr: *const AVFormatContext) -> Best<'b> { + pub unsafe fn new<'b, 'c: 'b>(context: &'c Context) -> Best<'b> { Best { - ptr: ptr, + context: context, wanted: -1, related: -1, - - _marker: PhantomData, } } @@ -101,12 +100,12 @@ impl<'a> Best<'a> { 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, + let index = av_find_best_stream(self.context.as_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))) + Some(Stream::wrap(self.context, index as usize)) } else { None @@ -116,34 +115,32 @@ impl<'a> Best<'a> { } pub struct StreamIter<'a> { - ptr: *const AVFormatContext, - cur: c_uint, - - _marker: PhantomData<&'a ()>, + context: &'a Context, + current: c_uint, } impl<'a> StreamIter<'a> { - pub fn new(ptr: *const AVFormatContext) -> Self { - StreamIter { ptr: ptr, cur: 0, _marker: PhantomData } + pub fn new<'s, 'c: 's>(context: &'c Context) -> StreamIter<'s> { + StreamIter { context: context, current: 0 } } } impl<'a> StreamIter<'a> { - pub fn wanted<'b: 'a, 'c: 'a>(&'a self, stream: &'b Stream) -> Best<'a> { + pub fn wanted<'b, 'c>(&self, stream: &'b Stream) -> Best<'c> where 'a: 'b, 'a: 'c { unsafe { - Best::new(self.ptr).wanted(stream) + Best::new(self.context).wanted(stream) } } - pub fn related<'b: 'a>(&'a self, stream: &'b Stream) -> Best<'a> { + pub fn related<'b, 'c>(&self, stream: &'b Stream) -> Best<'c> where 'a: 'b, 'a: 'c { unsafe { - Best::new(self.ptr).related(stream) + Best::new(self.context).related(stream) } } - pub fn best<'b: 'a>(&'a self, kind: media::Type) -> Option> { + pub fn best<'b>(&self, kind: media::Type) -> Option> where 'a: 'b { unsafe { - Best::new(self.ptr).best(kind) + Best::new(self.context).best(kind) } } } @@ -153,19 +150,21 @@ impl<'a> Iterator for StreamIter<'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))) + if self.current >= (*self.context.as_ptr()).nb_streams { + return None; } + + self.current += 1; + + Some(Stream::wrap(self.context, (self.current - 1) as usize)) } } fn size_hint(&self) -> (usize, Option) { unsafe { - ((*self.ptr).nb_streams as usize, Some((*self.ptr).nb_streams as usize)) + let length = (*self.context.as_ptr()).nb_streams as usize; + + (length - self.current as usize, Some(length - self.current as usize)) } } } @@ -173,15 +172,13 @@ impl<'a> Iterator for StreamIter<'a> { impl<'a> ExactSizeIterator for StreamIter<'a> { } pub struct StreamIterMut<'a> { - ptr: *const AVFormatContext, - cur: c_uint, - - _marker: PhantomData<&'a ()>, + context: &'a mut Context, + current: c_uint, } impl<'a> StreamIterMut<'a> { - pub fn new(ptr: *mut AVFormatContext) -> Self { - StreamIterMut { ptr: ptr, cur: 0, _marker: PhantomData } + pub fn new<'s, 'c: 's>(context: &'c mut Context) -> StreamIterMut<'s> { + StreamIterMut { context: context, current: 0 } } } @@ -190,19 +187,21 @@ impl<'a> Iterator for StreamIterMut<'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))) + if self.current >= (*self.context.as_ptr()).nb_streams { + return None } + + self.current += 1; + + Some(StreamMut::wrap(mem::transmute_copy(&self.context), (self.current - 1) as usize)) } } fn size_hint(&self) -> (usize, Option) { unsafe { - ((*self.ptr).nb_streams as usize, Some((*self.ptr).nb_streams as usize)) + let length = (*self.context.as_ptr()).nb_streams as usize; + + (length - self.current as usize, Some(length - self.current as usize)) } } } diff --git a/src/format/context/destructor.rs b/src/format/context/destructor.rs new file mode 100644 index 0000000..7c90996 --- /dev/null +++ b/src/format/context/destructor.rs @@ -0,0 +1,35 @@ +use ffi::*; + +#[derive(Copy, Clone, Debug)] +pub enum Mode { + Input, + Output, +} + +pub struct Destructor { + ptr: *mut AVFormatContext, + mode: Mode, +} + +impl Destructor { + pub unsafe fn new(ptr: *mut AVFormatContext, mode: Mode) -> Self { + Destructor { + ptr: ptr, + mode: mode, + } + } +} + +impl Drop for Destructor { + fn drop(&mut self) { + unsafe { + match self.mode { + Mode::Input => + avformat_close_input(&mut self.ptr), + + Mode::Output => + avformat_free_context(self.ptr), + } + } + } +} diff --git a/src/format/context/input.rs b/src/format/context/input.rs index f87a69e..fba7c19 100644 --- a/src/format/context/input.rs +++ b/src/format/context/input.rs @@ -1,10 +1,12 @@ use std::ops::{Deref, DerefMut}; use std::ptr; +use std::mem; use std::ffi::CString; use ffi::*; use ::{Error, Codec, Stream, Packet, format}; use super::common::Context; +use super::destructor; pub struct Input { ptr: *mut AVFormatContext, @@ -15,7 +17,7 @@ unsafe impl Send for Input { } impl Input { pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self { - Input { ptr: ptr, ctx: Context::wrap(ptr) } + Input { ptr: ptr, ctx: Context::wrap(ptr, destructor::Mode::Input) } } pub unsafe fn as_ptr(&self) -> *const AVFormatContext { @@ -135,14 +137,6 @@ impl DerefMut for Input { } } -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, } @@ -161,10 +155,11 @@ impl<'a> Iterator for PacketIter<'a> { loop { match packet.read(self.context) { - Ok(..) => - return Some((unsafe { - Stream::wrap(*(*self.context.as_ptr()).streams.offset(packet.stream() as isize)) - }, packet)), + Ok(..) => unsafe { + return Some(( + Stream::wrap(mem::transmute_copy(&self.context), packet.stream()), + packet)); + }, Err(Error::Eof) => return None, diff --git a/src/format/context/mod.rs b/src/format/context/mod.rs index 8ae0257..512b1b0 100644 --- a/src/format/context/mod.rs +++ b/src/format/context/mod.rs @@ -1,3 +1,6 @@ +pub mod destructor; +pub use self::destructor::Destructor; + pub mod input; pub use self::input::Input; diff --git a/src/format/context/output.rs b/src/format/context/output.rs index b1f90ec..3a6ceed 100644 --- a/src/format/context/output.rs +++ b/src/format/context/output.rs @@ -5,6 +5,7 @@ use std::ffi::CString; use ffi::*; use ::{Error, Codec, StreamMut, Dictionary, format}; use super::common::Context; +use super::destructor; pub struct Output { ptr: *mut AVFormatContext, @@ -15,7 +16,7 @@ unsafe impl Send for Output { } impl Output { pub unsafe fn wrap(ptr: *mut AVFormatContext) -> Self { - Output { ptr: ptr, ctx: Context::wrap(ptr) } + Output { ptr: ptr, ctx: Context::wrap(ptr, destructor::Mode::Output) } } pub unsafe fn as_ptr(&self) -> *const AVFormatContext { @@ -74,7 +75,9 @@ impl Output { panic!("out of memory"); } - StreamMut::wrap(ptr) + let index = (*self.ctx.as_ptr()).nb_streams - 1; + + StreamMut::wrap(&mut self.ctx, index as usize) } } @@ -99,14 +102,6 @@ impl DerefMut for Output { } } -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()); diff --git a/src/format/stream/stream.rs b/src/format/stream/stream.rs index 7204ed1..596edb9 100644 --- a/src/format/stream/stream.rs +++ b/src/format/stream/stream.rs @@ -1,33 +1,29 @@ -use std::marker::PhantomData; - use libc::c_int; use ffi::*; -use ::format; use ::codec::{self, packet}; use ::{Rational, Discard}; use super::Disposition; +use format::context::common::Context; -#[derive(Eq, PartialEq)] pub struct Stream<'a> { - ptr: *mut AVStream, - - _marker: PhantomData<&'a format::Context>, + context: &'a Context, + index: usize, } impl<'a> Stream<'a> { - pub unsafe fn wrap(ptr: *mut AVStream) -> Self { - Stream { ptr: ptr, _marker: PhantomData } + pub unsafe fn wrap(context: &Context, index: usize) -> Stream { + Stream { context: context, index: index } } pub unsafe fn as_ptr(&self) -> *const AVStream { - self.ptr as *const _ + *(*self.context.as_ptr()).streams.offset(self.index as isize) } } impl<'a> Stream<'a> { pub fn codec(&self) -> codec::Context { unsafe { - codec::Context::wrap((*self.as_ptr()).codec) + codec::Context::wrap((*self.as_ptr()).codec, Some(self.context.destructor())) } } @@ -74,9 +70,7 @@ impl<'a> Stream<'a> { } pub fn side_data(&self) -> SideDataIter { - unsafe { - SideDataIter::new(self.as_ptr()) - } + SideDataIter::new(self) } pub fn frame_rate(&self) -> Rational { @@ -86,16 +80,24 @@ impl<'a> Stream<'a> { } } -pub struct SideDataIter<'a> { - ptr: *const AVStream, - cur: c_int, +impl<'a> PartialEq for Stream<'a> { + fn eq(&self, other: &Self) -> bool { + unsafe { + self.as_ptr() == other.as_ptr() + } + } +} - _marker: PhantomData<&'a Stream<'a>>, +impl<'a> Eq for Stream<'a> { } + +pub struct SideDataIter<'a> { + stream: &'a Stream<'a>, + current: c_int, } impl<'a> SideDataIter<'a> { - pub fn new(ptr: *const AVStream) -> Self { - SideDataIter { ptr: ptr, cur: 0, _marker: PhantomData } + pub fn new<'sd, 's: 'sd>(stream: &'s Stream) -> SideDataIter<'sd> { + SideDataIter { stream: stream, current: 0 } } } @@ -104,19 +106,22 @@ impl<'a> Iterator for SideDataIter<'a> { fn next(&mut self) -> Option<::Item> { unsafe { - if self.cur >= (*self.ptr).nb_side_data { - None - } - else { - self.cur += 1; - Some(packet::SideData::wrap((*self.ptr).side_data.offset((self.cur - 1) as isize))) + if self.current >= (*self.stream.as_ptr()).nb_side_data { + return None; } + + self.current += 1; + + Some(packet::SideData::wrap( + (*self.stream.as_ptr()).side_data.offset((self.current - 1) as isize))) } } fn size_hint(&self) -> (usize, Option) { unsafe { - ((*self.ptr).nb_side_data as usize, Some((*self.ptr).nb_side_data as usize)) + let length = (*self.stream.as_ptr()).nb_side_data as usize; + + (length - self.current as usize, Some(length - self.current as usize)) } } } diff --git a/src/format/stream/stream_mut.rs b/src/format/stream/stream_mut.rs index 65e773c..4c98c19 100644 --- a/src/format/stream/stream_mut.rs +++ b/src/format/stream/stream_mut.rs @@ -1,26 +1,30 @@ use std::ops::Deref; +use std::mem; use ffi::*; use ::Rational; use super::Stream; +use format::context::common::Context; -#[derive(Eq, PartialEq)] pub struct StreamMut<'a> { - ptr: *mut AVStream, - imm: Stream<'a>, + context: &'a mut Context, + index: usize, + + immutable: Stream<'a>, } impl<'a> StreamMut<'a> { - pub unsafe fn wrap(ptr: *mut AVStream) -> Self { - StreamMut { ptr: ptr, imm: Stream::wrap(ptr) } - } + pub unsafe fn wrap(context: &mut Context, index: usize) -> StreamMut { + StreamMut { + context: mem::transmute_copy(&context), + index: index, - pub unsafe fn as_ptr(&self) -> *const AVStream { - self.ptr as *const _ + immutable: Stream::wrap(mem::transmute_copy(&context), index) + } } pub unsafe fn as_mut_ptr(&mut self) -> *mut AVStream { - self.ptr + *(*self.context.as_mut_ptr()).streams.offset(self.index as isize) } } @@ -42,6 +46,6 @@ impl<'a> Deref for StreamMut<'a> { type Target = Stream<'a>; fn deref(&self) -> &Self::Target { - &self.imm + &self.immutable } }