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.VideoTimeCodeFlags",
|
||||||
"GstVideo.VideoCaptionType",
|
"GstVideo.VideoCaptionType",
|
||||||
"GstVideo.VideoBufferPool",
|
"GstVideo.VideoBufferPool",
|
||||||
|
"GstVideo.VideoPackFlags",
|
||||||
]
|
]
|
||||||
|
|
||||||
manual = [
|
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"))]
|
#[cfg(any(feature = "v1_10", feature = "dox"))]
|
||||||
bitflags! {
|
bitflags! {
|
||||||
pub struct VideoTimeCodeFlags: u32 {
|
pub struct VideoTimeCodeFlags: u32 {
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue