From 306b9c6698978db56daf11987db169d1021e48dd Mon Sep 17 00:00:00 2001 From: meh Date: Thu, 8 Oct 2015 17:54:09 +0200 Subject: [PATCH] codec/packet: refactoring to allow zero-copy packet creation --- src/codec/decoder/audio.rs | 4 +- src/codec/decoder/subtitle.rs | 4 +- src/codec/decoder/video.rs | 4 +- src/codec/encoder/audio.rs | 6 +- src/codec/encoder/video.rs | 6 +- src/codec/packet/borrow.rs | 55 +++++++ src/codec/packet/mod.rs | 292 ++-------------------------------- src/codec/packet/packet.rs | 290 +++++++++++++++++++++++++++++++++ src/codec/packet/traits.rs | 9 ++ 9 files changed, 375 insertions(+), 295 deletions(-) create mode 100644 src/codec/packet/borrow.rs create mode 100644 src/codec/packet/packet.rs create mode 100644 src/codec/packet/traits.rs diff --git a/src/codec/decoder/audio.rs b/src/codec/decoder/audio.rs index 66872be..6a1c04d 100644 --- a/src/codec/decoder/audio.rs +++ b/src/codec/decoder/audio.rs @@ -4,14 +4,14 @@ use libc::c_int; use ffi::*; use super::Opened; -use ::{Packet, Error, AudioService, ChannelLayout}; +use ::{packet, Error, AudioService, ChannelLayout}; use ::frame; use ::util::format; pub struct Audio(pub Opened); impl Audio { - pub fn decode(&mut self, packet: &Packet, out: &mut frame::Audio) -> Result { + pub fn decode(&mut self, packet: &P, out: &mut frame::Audio) -> Result { unsafe { let mut got: c_int = 0; diff --git a/src/codec/decoder/subtitle.rs b/src/codec/decoder/subtitle.rs index db378d9..6052b26 100644 --- a/src/codec/decoder/subtitle.rs +++ b/src/codec/decoder/subtitle.rs @@ -4,12 +4,12 @@ use libc::c_int; use ffi::*; use super::Opened; -use ::{Packet, Error}; +use ::{packet, Error}; pub struct Subtitle(pub Opened); impl Subtitle { - pub fn decode(&mut self, packet: &Packet, out: &mut ::Subtitle) -> Result { + pub fn decode(&mut self, packet: &P, out: &mut ::Subtitle) -> Result { unsafe { let mut got: c_int = 0; diff --git a/src/codec/decoder/video.rs b/src/codec/decoder/video.rs index e075534..f24b008 100644 --- a/src/codec/decoder/video.rs +++ b/src/codec/decoder/video.rs @@ -4,7 +4,7 @@ use libc::c_int; use ffi::*; use super::{Opened, slice}; -use ::{Packet, Error, Rational, FieldOrder}; +use ::{packet, Error, Rational, FieldOrder}; use ::frame; use ::util::format; use ::util::chroma; @@ -13,7 +13,7 @@ use ::color; pub struct Video(pub Opened); impl Video { - pub fn decode(&mut self, packet: &Packet, out: &mut frame::Video) -> Result { + pub fn decode(&mut self, packet: &P, out: &mut frame::Video) -> Result { unsafe { let mut got: c_int = 0; diff --git a/src/codec/encoder/audio.rs b/src/codec/encoder/audio.rs index 1e2f417..25045bb 100644 --- a/src/codec/encoder/audio.rs +++ b/src/codec/encoder/audio.rs @@ -5,7 +5,7 @@ use libc::c_int; use ffi::*; use super::Encoder as Super; -use ::{Packet, Error, Dictionary, ChannelLayout, frame}; +use ::{packet, Error, Dictionary, ChannelLayout, frame}; use ::util::format; use codec::traits; @@ -120,7 +120,7 @@ impl DerefMut for Audio { pub struct Encoder(pub Audio); impl Encoder { - pub fn encode(&mut self, frame: &frame::Audio, out: &mut Packet) -> Result { + pub fn encode(&mut self, frame: &frame::Audio, out: &mut P) -> Result { unsafe { if self.format() != frame.format() { return Err(Error::InvalidData); @@ -135,7 +135,7 @@ impl Encoder { } } - pub fn flush(&mut self, out: &mut Packet) -> Result { + pub fn flush(&mut self, out: &mut P) -> Result { unsafe { let mut got: c_int = 0; diff --git a/src/codec/encoder/video.rs b/src/codec/encoder/video.rs index 6fcd0cb..1f75e0d 100644 --- a/src/codec/encoder/video.rs +++ b/src/codec/encoder/video.rs @@ -6,7 +6,7 @@ use ffi::*; use super::Encoder as Super; use super::{MotionEstimation, Prediction, Comparison, Decision}; -use ::{Packet, Error, Rational, Dictionary, frame, format}; +use ::{packet, Error, Rational, Dictionary, frame, format}; use codec::traits; pub struct Video(pub Super); @@ -368,7 +368,7 @@ pub struct Encoder(pub Video); impl Encoder { #[inline] - pub fn encode(&mut self, frame: &frame::Video, out: &mut Packet) -> Result { + pub fn encode(&mut self, frame: &frame::Video, out: &mut P) -> Result { unsafe { if self.format() != frame.format() || self.width() != frame.width() || self.height() != frame.height() { return Err(Error::InvalidData); @@ -384,7 +384,7 @@ impl Encoder { } #[inline] - pub fn flush(&mut self, out: &mut Packet) -> Result { + pub fn flush(&mut self, out: &mut P) -> Result { unsafe { let mut got: c_int = 0; diff --git a/src/codec/packet/borrow.rs b/src/codec/packet/borrow.rs new file mode 100644 index 0000000..11190c7 --- /dev/null +++ b/src/codec/packet/borrow.rs @@ -0,0 +1,55 @@ +use std::mem; +use std::ptr; + +use libc::c_int; +use ffi::*; +use ::{Error, Rational, format}; +use super::{flag, Flags, Ref}; + +pub struct Borrow<'a> { + packet: AVPacket, + data: &'a [u8], +} + +impl<'a> Borrow<'a> { + pub fn new(data: &[u8]) -> Borrow { + unsafe { + let mut packet: AVPacket = mem::zeroed(); + + packet.data = data.as_ptr() as *mut _; + packet.size = data.len() as c_int; + + Borrow { + packet: packet, + data: data, + } + } + } + + #[inline] + pub fn size(&self) -> usize { + self.packet.size as usize + } + + #[inline] + pub fn data(&self) -> Option<&[u8]> { + Some(self.data) + } +} + +impl<'a> Ref for Borrow<'a> { + fn as_ptr(&self) -> *const AVPacket { + &self.packet + } +} + +impl<'a> Drop for Borrow<'a> { + fn drop(&mut self) { + unsafe { + self.packet.data = ptr::null_mut(); + self.packet.size = 0; + + av_free_packet(&mut self.packet); + } + } +} diff --git a/src/codec/packet/mod.rs b/src/codec/packet/mod.rs index 31473c2..4e1ce3b 100644 --- a/src/codec/packet/mod.rs +++ b/src/codec/packet/mod.rs @@ -1,288 +1,14 @@ +pub mod traits; +pub use self::traits::{Ref, Mut}; + +pub mod packet; +pub use self::packet::Packet; + +pub mod borrow; +pub use self::borrow::Borrow; + pub mod side_data; pub use self::side_data::SideData; pub mod flag; pub use self::flag::Flags; - -use std::marker::PhantomData; -use std::mem; -use std::slice; - -use libc::c_int; -use ffi::*; -use ::{Error, Rational, format}; - -pub struct Packet(AVPacket); - -unsafe impl Send for Packet { } -unsafe impl Sync for Packet { } - -impl Packet { - #[inline(always)] - pub unsafe fn as_ptr(&self) -> *const AVPacket { - &self.0 - } - - #[inline(always)] - pub unsafe fn as_mut_ptr(&mut self) -> *mut AVPacket { - &mut self.0 - } - - #[inline(always)] - pub unsafe fn is_empty(&self) -> bool { - self.0.size == 0 - } -} - -impl Packet { - #[inline] - pub fn empty() -> Self { - unsafe { - let mut pkt: AVPacket = mem::zeroed(); - - av_init_packet(&mut pkt); - - Packet(pkt) - } - } - - #[inline] - pub fn new(size: usize) -> Self { - unsafe { - let mut pkt: AVPacket = mem::zeroed(); - - av_init_packet(&mut pkt); - av_new_packet(&mut pkt, size as c_int); - - Packet(pkt) - } - } - - #[inline] - pub fn copy(data: &[u8]) -> Self { - use std::io::Write; - - let mut packet = Packet::new(data.len()); - packet.data_mut().unwrap().write(data).unwrap(); - - packet - } - - #[inline] - pub fn shrink(&mut self, size: usize) { - unsafe { - av_shrink_packet(&mut self.0, size as c_int); - } - } - - #[inline] - pub fn grow(&mut self, size: usize) { - unsafe { - av_grow_packet(&mut self.0, size as c_int); - } - } - - #[inline] - pub fn rescale_ts(&mut self, source: S, destination: D) - where S: Into, - D: Into - { - unsafe { - av_packet_rescale_ts(self.as_mut_ptr(), source.into().into(), destination.into().into()); - } - } - - #[inline] - pub fn flags(&self) -> Flags { - Flags::from_bits_truncate(self.0.flags) - } - - #[inline] - pub fn set_flags(&mut self, value: Flags) { - self.0.flags = value.bits(); - } - - #[inline] - pub fn is_key(&self) -> bool { - self.flags().contains(flag::KEY) - } - - #[inline] - pub fn is_corrupt(&self) -> bool { - self.flags().contains(flag::CORRUPT) - } - - #[inline] - pub fn stream(&self) -> usize { - self.0.stream_index as usize - } - - #[inline] - pub fn set_stream(&mut self, index: usize) { - self.0.stream_index = index as c_int; - } - - #[inline] - pub fn pts(&self) -> Option { - match self.0.pts { - AV_NOPTS_VALUE => None, - pts => Some(pts as i64), - } - } - - #[inline] - pub fn dts(&self) -> i64 { - self.0.dts as i64 - } - - #[inline] - pub fn size(&self) -> usize { - self.0.size as usize - } - - #[inline] - pub fn duration(&self) -> usize { - self.0.duration as usize - } - - #[inline] - pub fn position(&self) -> isize { - self.0.pos as isize - } - - #[inline] - pub fn convergence(&self) -> isize { - self.0.convergence_duration as isize - } - - #[inline] - pub fn side_data(&self) -> SideDataIter { - SideDataIter::new(&self.0) - } - - #[inline] - pub fn data(&self) -> Option<&[u8]> { - unsafe { - if self.0.data.is_null() { - None - } - else { - Some(slice::from_raw_parts(self.0.data, self.0.size as usize)) - } - } - } - - #[inline] - pub fn data_mut(&mut self) -> Option<&mut [u8]> { - unsafe { - if self.0.data.is_null() { - None - } - else { - Some(slice::from_raw_parts_mut(self.0.data, self.0.size as usize)) - } - } - } - - #[inline] - 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(()), - e => Err(Error::from(e)) - } - } - } - - #[inline] - pub fn write(&self, format: &mut format::context::Output) -> Result { - unsafe { - if self.is_empty() { - return Err(Error::InvalidData); - } - - match av_write_frame(format.as_mut_ptr(), self.as_ptr()) { - 1 => Ok(true), - 0 => Ok(false), - e => Err(Error::from(e)) - } - } - } - - #[inline] - pub fn write_interleaved(&self, format: &mut format::context::Output) -> Result { - unsafe { - if self.is_empty() { - return Err(Error::InvalidData); - } - - match av_interleaved_write_frame(format.as_mut_ptr(), self.as_ptr()) { - 1 => Ok(true), - 0 => Ok(false), - e => Err(Error::from(e)) - } - } - } -} - -impl Clone for Packet { - #[inline] - fn clone(&self) -> Self { - let mut pkt = Packet::empty(); - pkt.clone_from(self); - - pkt - } - - #[inline] - fn clone_from(&mut self, source: &Self) { - unsafe { - av_copy_packet(&mut self.0, &source.0); - } - } -} - -impl Drop for Packet { - fn drop(&mut self) { - unsafe { - av_free_packet(&mut self.0); - } - } -} - -pub struct SideDataIter<'a> { - ptr: *const AVPacket, - cur: c_int, - - _marker: PhantomData<&'a Packet>, -} - -impl<'a> SideDataIter<'a> { - pub fn new(ptr: *const AVPacket) -> Self { - SideDataIter { ptr: ptr, cur: 0, _marker: PhantomData } - } -} - -impl<'a> Iterator for SideDataIter<'a> { - type Item = SideData<'a>; - - fn next(&mut self) -> Option<::Item> { - unsafe { - if self.cur >= (*self.ptr).side_data_elems { - None - } - else { - self.cur += 1; - Some(SideData::wrap((*self.ptr).side_data.offset((self.cur - 1) as isize))) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - unsafe { - ((*self.ptr).side_data_elems as usize, Some((*self.ptr).side_data_elems as usize)) - } - } -} - -impl<'a> ExactSizeIterator for SideDataIter<'a> { } diff --git a/src/codec/packet/packet.rs b/src/codec/packet/packet.rs new file mode 100644 index 0000000..39f68be --- /dev/null +++ b/src/codec/packet/packet.rs @@ -0,0 +1,290 @@ +use std::marker::PhantomData; +use std::mem; +use std::slice; + +use libc::c_int; +use ffi::*; +use ::{Error, Rational, format}; +use super::{flag, Flags, SideData, Ref, Mut, Borrow}; + +pub struct Packet(AVPacket); + +unsafe impl Send for Packet { } +unsafe impl Sync for Packet { } + +impl Packet { + #[inline(always)] + pub unsafe fn is_empty(&self) -> bool { + self.0.size == 0 + } +} + +impl Packet { + #[inline] + pub fn empty() -> Self { + unsafe { + let mut pkt: AVPacket = mem::zeroed(); + + av_init_packet(&mut pkt); + + Packet(pkt) + } + } + + #[inline] + pub fn new(size: usize) -> Self { + unsafe { + let mut pkt: AVPacket = mem::zeroed(); + + av_init_packet(&mut pkt); + av_new_packet(&mut pkt, size as c_int); + + Packet(pkt) + } + } + + #[inline] + pub fn copy(data: &[u8]) -> Self { + use std::io::Write; + + let mut packet = Packet::new(data.len()); + packet.data_mut().unwrap().write(data).unwrap(); + + packet + } + + #[inline] + pub fn borrow(data: &[u8]) -> Borrow { + Borrow::new(data) + } + + #[inline] + pub fn shrink(&mut self, size: usize) { + unsafe { + av_shrink_packet(&mut self.0, size as c_int); + } + } + + #[inline] + pub fn grow(&mut self, size: usize) { + unsafe { + av_grow_packet(&mut self.0, size as c_int); + } + } + + #[inline] + pub fn rescale_ts(&mut self, source: S, destination: D) + where S: Into, + D: Into + { + unsafe { + av_packet_rescale_ts(self.as_mut_ptr(), source.into().into(), destination.into().into()); + } + } + + #[inline] + pub fn flags(&self) -> Flags { + Flags::from_bits_truncate(self.0.flags) + } + + #[inline] + pub fn set_flags(&mut self, value: Flags) { + self.0.flags = value.bits(); + } + + #[inline] + pub fn is_key(&self) -> bool { + self.flags().contains(flag::KEY) + } + + #[inline] + pub fn is_corrupt(&self) -> bool { + self.flags().contains(flag::CORRUPT) + } + + #[inline] + pub fn stream(&self) -> usize { + self.0.stream_index as usize + } + + #[inline] + pub fn set_stream(&mut self, index: usize) { + self.0.stream_index = index as c_int; + } + + #[inline] + pub fn pts(&self) -> Option { + match self.0.pts { + AV_NOPTS_VALUE => None, + pts => Some(pts as i64), + } + } + + #[inline] + pub fn dts(&self) -> i64 { + self.0.dts as i64 + } + + #[inline] + pub fn size(&self) -> usize { + self.0.size as usize + } + + #[inline] + pub fn duration(&self) -> usize { + self.0.duration as usize + } + + #[inline] + pub fn position(&self) -> isize { + self.0.pos as isize + } + + #[inline] + pub fn convergence(&self) -> isize { + self.0.convergence_duration as isize + } + + #[inline] + pub fn side_data(&self) -> SideDataIter { + SideDataIter::new(&self.0) + } + + #[inline] + pub fn data(&self) -> Option<&[u8]> { + unsafe { + if self.0.data.is_null() { + None + } + else { + Some(slice::from_raw_parts(self.0.data, self.0.size as usize)) + } + } + } + + #[inline] + pub fn data_mut(&mut self) -> Option<&mut [u8]> { + unsafe { + if self.0.data.is_null() { + None + } + else { + Some(slice::from_raw_parts_mut(self.0.data, self.0.size as usize)) + } + } + } + + #[inline] + 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(()), + e => Err(Error::from(e)) + } + } + } + + #[inline] + pub fn write(&self, format: &mut format::context::Output) -> Result { + unsafe { + if self.is_empty() { + return Err(Error::InvalidData); + } + + match av_write_frame(format.as_mut_ptr(), self.as_ptr()) { + 1 => Ok(true), + 0 => Ok(false), + e => Err(Error::from(e)) + } + } + } + + #[inline] + pub fn write_interleaved(&self, format: &mut format::context::Output) -> Result { + unsafe { + if self.is_empty() { + return Err(Error::InvalidData); + } + + match av_interleaved_write_frame(format.as_mut_ptr(), self.as_ptr()) { + 1 => Ok(true), + 0 => Ok(false), + e => Err(Error::from(e)) + } + } + } +} + +impl Ref for Packet { + fn as_ptr(&self) -> *const AVPacket { + &self.0 + } +} + +impl Mut for Packet { + fn as_mut_ptr(&mut self) -> *mut AVPacket { + &mut self.0 + } +} + +impl Clone for Packet { + #[inline] + fn clone(&self) -> Self { + let mut pkt = Packet::empty(); + pkt.clone_from(self); + + pkt + } + + #[inline] + fn clone_from(&mut self, source: &Self) { + unsafe { + av_copy_packet(&mut self.0, &source.0); + } + } +} + +impl Drop for Packet { + fn drop(&mut self) { + unsafe { + av_free_packet(&mut self.0); + } + } +} + +pub struct SideDataIter<'a> { + ptr: *const AVPacket, + cur: c_int, + + _marker: PhantomData<&'a Packet>, +} + +impl<'a> SideDataIter<'a> { + pub fn new(ptr: *const AVPacket) -> Self { + SideDataIter { ptr: ptr, cur: 0, _marker: PhantomData } + } +} + +impl<'a> Iterator for SideDataIter<'a> { + type Item = SideData<'a>; + + fn next(&mut self) -> Option<::Item> { + unsafe { + if self.cur >= (*self.ptr).side_data_elems { + None + } + else { + self.cur += 1; + Some(SideData::wrap((*self.ptr).side_data.offset((self.cur - 1) as isize))) + } + } + } + + fn size_hint(&self) -> (usize, Option) { + unsafe { + ((*self.ptr).side_data_elems as usize, Some((*self.ptr).side_data_elems as usize)) + } + } +} + +impl<'a> ExactSizeIterator for SideDataIter<'a> { } diff --git a/src/codec/packet/traits.rs b/src/codec/packet/traits.rs new file mode 100644 index 0000000..affe3bc --- /dev/null +++ b/src/codec/packet/traits.rs @@ -0,0 +1,9 @@ +use ffi::*; + +pub trait Ref { + fn as_ptr(&self) -> *const AVPacket; +} + +pub trait Mut { + fn as_mut_ptr(&mut self) -> *mut AVPacket; +}