video: Add pack/unpack func bindings

This commit is contained in:
Sebastian Dröge 2019-05-28 09:26:44 +02:00
parent 0147f03344
commit e5d0afee02
4 changed files with 242 additions and 1 deletions

View file

@ -38,6 +38,7 @@ generate = [
"GstVideo.VideoTimeCodeFlags", "GstVideo.VideoTimeCodeFlags",
"GstVideo.VideoCaptionType", "GstVideo.VideoCaptionType",
"GstVideo.VideoBufferPool", "GstVideo.VideoBufferPool",
"GstVideo.VideoPackFlags",
] ]
manual = [ manual = [

View file

@ -355,6 +355,55 @@ impl SetValue for VideoOverlayFormatFlags {
} }
} }
bitflags! {
pub struct VideoPackFlags: u32 {
const NONE = 0;
const TRUNCATE_RANGE = 1;
const INTERLACED = 2;
}
}
#[doc(hidden)]
impl ToGlib for VideoPackFlags {
type GlibType = gst_video_sys::GstVideoPackFlags;
fn to_glib(&self) -> gst_video_sys::GstVideoPackFlags {
self.bits()
}
}
#[doc(hidden)]
impl FromGlib<gst_video_sys::GstVideoPackFlags> for VideoPackFlags {
fn from_glib(value: gst_video_sys::GstVideoPackFlags) -> VideoPackFlags {
skip_assert_initialized!();
VideoPackFlags::from_bits_truncate(value)
}
}
impl StaticType for VideoPackFlags {
fn static_type() -> Type {
unsafe { from_glib(gst_video_sys::gst_video_pack_flags_get_type()) }
}
}
impl<'a> FromValueOptional<'a> for VideoPackFlags {
unsafe fn from_value_optional(value: &Value) -> Option<Self> {
Some(FromValue::from_value(value))
}
}
impl<'a> FromValue<'a> for VideoPackFlags {
unsafe fn from_value(value: &Value) -> Self {
from_glib(gobject_sys::g_value_get_flags(value.to_glib_none().0))
}
}
impl SetValue for VideoPackFlags {
unsafe fn set_value(value: &mut Value, this: &Self) {
gobject_sys::g_value_set_flags(value.to_glib_none_mut().0, this.to_glib())
}
}
#[cfg(any(feature = "v1_10", feature = "dox"))] #[cfg(any(feature = "v1_10", feature = "dox"))]
bitflags! { bitflags! {
pub struct VideoTimeCodeFlags: u32 { pub struct VideoTimeCodeFlags: u32 {

View file

@ -42,6 +42,7 @@ pub use self::flags::VideoFormatFlags;
pub use self::flags::VideoFrameFlags; pub use self::flags::VideoFrameFlags;
pub use self::flags::VideoMultiviewFlags; pub use self::flags::VideoMultiviewFlags;
pub use self::flags::VideoOverlayFormatFlags; pub use self::flags::VideoOverlayFormatFlags;
pub use self::flags::VideoPackFlags;
#[cfg(any(feature = "v1_10", feature = "dox"))] #[cfg(any(feature = "v1_10", feature = "dox"))]
pub use self::flags::VideoTimeCodeFlags; pub use self::flags::VideoTimeCodeFlags;

View file

@ -145,7 +145,157 @@ impl VideoFormatInfo {
(-((-(i64::from(height))) >> self.h_sub()[component as usize])) as u32 (-((-(i64::from(height))) >> self.h_sub()[component as usize])) as u32
} }
// TODO: pack/unpack pub fn unpack(
&self,
flags: ::VideoPackFlags,
dest: &mut [u8],
src: &[&[u8]],
stride: &[i32],
x: i32,
y: i32,
width: i32,
) {
let unpack_format = Self::from_format(self.unpack_format());
if unpack_format.pixel_stride()[0] == 0 || self.0.unpack_func.is_none() {
panic!("No unpack format for {:?}", self);
}
if src.len() != self.n_planes() as usize {
panic!(
"Wrong number of planes provided for format: {} != {}",
src.len(),
self.n_planes()
);
}
if stride.len() != self.n_planes() as usize {
panic!(
"Wrong number of strides provided for format: {} != {}",
stride.len(),
self.n_planes()
);
}
if dest.len() < unpack_format.pixel_stride()[0] as usize * width as usize {
panic!("Too small destination slice");
}
for plane in 0..(self.n_planes()) {
if stride[plane as usize]
< self.scale_width(plane as u8, width as u32) as i32
* self.pixel_stride()[plane as usize]
{
panic!("Too small source stride for plane {}", plane);
}
let plane_size = y * stride[plane as usize]
+ self.scale_width(plane as u8, (x + width) as u32) as i32
* self.pixel_stride()[plane as usize];
if src[plane as usize].len() < plane_size as usize {
panic!("Too small source plane size for plane {}", plane);
}
}
unsafe {
use std::ptr;
let mut src_ptr =
[ptr::null() as *const u8; gst_video_sys::GST_VIDEO_MAX_PLANES as usize];
for plane in 0..(self.n_planes()) {
src_ptr[plane as usize] = src[plane as usize].as_ptr();
}
(self.0.unpack_func.as_ref().unwrap())(
self.0,
flags.to_glib(),
dest.as_mut_ptr() as *mut _,
src_ptr.as_ptr() as *const _,
stride.as_ptr() as *const i32,
x,
y,
width,
);
}
}
pub fn pack(
&self,
flags: ::VideoPackFlags,
src: &[u8],
src_stride: i32,
dest: &mut [&mut [u8]],
dest_stride: &[i32],
chroma_site: ::VideoChromaSite,
y: i32,
width: i32,
) {
let unpack_format = Self::from_format(self.unpack_format());
if unpack_format.pixel_stride()[0] == 0 || self.0.unpack_func.is_none() {
panic!("No unpack format for {:?}", self);
}
if dest.len() != self.n_planes() as usize {
panic!(
"Wrong number of planes provided for format: {} != {}",
dest.len(),
self.n_planes()
);
}
if dest_stride.len() != self.n_planes() as usize {
panic!(
"Wrong number of strides provided for format: {} != {}",
dest_stride.len(),
self.n_planes()
);
}
if src.len() < unpack_format.pixel_stride()[0] as usize * width as usize {
panic!("Too small source slice");
}
for plane in 0..(self.n_planes()) {
if dest_stride[plane as usize]
< self.scale_width(plane as u8, width as u32) as i32
* self.pixel_stride()[plane as usize]
{
panic!("Too small destination stride for plane {}", plane);
}
let plane_size = y * dest_stride[plane as usize]
+ self.scale_width(plane as u8, width as u32) as i32
* self.pixel_stride()[plane as usize];
if dest[plane as usize].len() < plane_size as usize {
panic!("Too small destination plane size for plane {}", plane);
}
}
unsafe {
use std::ptr;
let mut dest_ptr =
[ptr::null_mut() as *mut u8; gst_video_sys::GST_VIDEO_MAX_PLANES as usize];
for plane in 0..(self.n_planes()) {
dest_ptr[plane as usize] = dest[plane as usize].as_mut_ptr();
}
(self.0.pack_func.as_ref().unwrap())(
self.0,
flags.to_glib(),
src.as_ptr() as *mut _,
src_stride,
dest_ptr.as_mut_ptr() as *mut _,
dest_stride.as_ptr() as *const i32,
chroma_site.to_glib(),
y,
width,
);
}
}
} }
unsafe impl Sync for VideoFormatInfo {} unsafe impl Sync for VideoFormatInfo {}
@ -237,4 +387,44 @@ mod tests {
assert_eq!(info.scale_width(1, 128), 64); assert_eq!(info.scale_width(1, 128), 64);
assert_eq!(info.scale_width(2, 128), 64); assert_eq!(info.scale_width(2, 128), 64);
} }
#[test]
fn test_unpack() {
gst::init().unwrap();
// One line black 320 pixel I420
let input = &[&[0; 320][..], &[128; 160][..], &[128; 160][..]];
// One line of AYUV
let intermediate = &mut [0; 320 * 4][..];
// One line of 320 pixel I420
let output = &mut [&mut [0; 320][..], &mut [0; 160][..], &mut [0; 160][..]];
let info = VideoFormatInfo::from_format(::VideoFormat::I420);
assert_eq!(info.unpack_format(), ::VideoFormat::Ayuv);
info.unpack(
::VideoPackFlags::empty(),
intermediate,
input,
&[320, 160, 160][..],
0,
0,
320,
);
for pixel in intermediate.chunks_exact(4) {
assert_eq!(&[255, 0, 128, 128][..], pixel);
}
info.pack(
::VideoPackFlags::empty(),
&intermediate[..(4 * 320)],
4 * 320,
output,
&[320, 160, 160][..],
::VideoChromaSite::NONE,
0,
320,
);
assert_eq!(input, output);
}
} }