codec/context: make destructors safe

This commit is contained in:
meh 2015-09-17 17:33:31 +02:00
parent 19548810dd
commit 9736980b02
10 changed files with 166 additions and 134 deletions

View File

@ -1,4 +1,5 @@
use std::ptr;
use std::rc::Rc;
use libc::c_int;
use ffi::*;
@ -10,15 +11,14 @@ use super::encoder::Encoder;
pub struct Context {
ptr: *mut AVCodecContext,
_own: bool,
owner: Option<Rc<Drop>>,
}
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<Rc<Drop>>) -> 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 {
if self.owner.is_none() {
avcodec_free_context(&mut self.as_mut_ptr());
}
}

View File

@ -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<Video, Error> {
pub fn video(self) -> Result<video::Video, Error> {
if self.medium() == media::Type::Video {
Ok(Video(self))
Ok(video::Video(self))
}
else {
Err(Error::InvalidData)
}
}
pub fn audio(self) -> Result<Audio, Error> {
pub fn audio(self) -> Result<audio::Audio, Error> {
if self.medium() == media::Type::Audio {
Ok(Audio(self))
Ok(audio::Audio(self))
}
else {
Err(Error::InvalidData)
}
}
pub fn subtitle(self) -> Result<Subtitle, Error> {
pub fn subtitle(self) -> Result<subtitle::Subtitle, Error> {
if self.medium() == media::Type::Subtitle {
Ok(Subtitle(self))
Ok(subtitle::Subtitle(self))
}
else {
Err(Error::InvalidData)

View File

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

View File

@ -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,
dtor: Rc<Destructor>,
}
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<Destructor> {
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<Stream<'b>> 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<Stream<'b>> {
pub fn best<'b>(&self, kind: media::Type) -> Option<Stream<'b>> 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<<Self as Iterator>::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<usize>) {
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<<Self as Iterator>::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<usize>) {
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))
}
}
}

View File

@ -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),
}
}
}
}

View File

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

View File

@ -1,3 +1,6 @@
pub mod destructor;
pub use self::destructor::Destructor;
pub mod input;
pub use self::input::Input;

View File

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

View File

@ -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<<Self as Iterator>::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<usize>) {
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))
}
}
}

View File

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