forked from mirrors/gstreamer-rs
video: Add pack/unpack func bindings
This commit is contained in:
parent
0147f03344
commit
e5d0afee02
4 changed files with 242 additions and 1 deletions
|
@ -38,6 +38,7 @@ generate = [
|
|||
"GstVideo.VideoTimeCodeFlags",
|
||||
"GstVideo.VideoCaptionType",
|
||||
"GstVideo.VideoBufferPool",
|
||||
"GstVideo.VideoPackFlags",
|
||||
]
|
||||
|
||||
manual = [
|
||||
|
|
|
@ -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"))]
|
||||
bitflags! {
|
||||
pub struct VideoTimeCodeFlags: u32 {
|
||||
|
|
|
@ -42,6 +42,7 @@ pub use self::flags::VideoFormatFlags;
|
|||
pub use self::flags::VideoFrameFlags;
|
||||
pub use self::flags::VideoMultiviewFlags;
|
||||
pub use self::flags::VideoOverlayFormatFlags;
|
||||
pub use self::flags::VideoPackFlags;
|
||||
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||
pub use self::flags::VideoTimeCodeFlags;
|
||||
|
||||
|
|
|
@ -145,7 +145,157 @@ impl VideoFormatInfo {
|
|||
(-((-(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 {}
|
||||
|
@ -237,4 +387,44 @@ mod tests {
|
|||
assert_eq!(info.scale_width(1, 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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue