Commit 7a0bc766 authored by Sebastian Dröge's avatar Sebastian Dröge 🍵

video: Add VideoEncoder bindings

Fixes #160
parent 40968690
Pipeline #38649 passed with stages
in 10 minutes and 1 second
......@@ -43,7 +43,6 @@ generate = [
manual = [
"GLib.DateTime",
"GObject.Object",
"Gst.BufferPool",
"Gst.Object",
"Gst.Element",
"Gst.Buffer",
......@@ -65,6 +64,11 @@ manual = [
"GstVideo.VideoTimeCodeInterval",
]
[[object]]
name = "Gst.ClockTime"
status = "manual"
conversion_type = "scalar"
[[object]]
name = "Gst.Caps"
status = "manual"
......@@ -143,3 +147,52 @@ status = "generate"
[[object.function]]
name = "negotiate"
ignore = true
[[object]]
name = "GstVideo.VideoEncoder"
subclassing = true
status = "generate"
[[object.function]]
name = "allocate_output_frame"
ignore = true
[[object.function]]
name = "allocate_output_frame_with_params"
ignore = true
[[object.function]]
name = "finish_frame"
ignore = true
[[object.function]]
name = "set_latency"
ignore = true
[[object.function]]
name = "get_latency"
ignore = true
[[object.function]]
name = "get_frame"
ignore = true
[[object.function]]
name = "get_frames"
ignore = true
[[object.function]]
name = "get_oldest_frame"
ignore = true
[[object.function]]
name = "get_output_state"
ignore = true
[[object.function]]
name = "set_output_state"
ignore = true
[[object.function]]
name = "negotiate"
ignore = true
......@@ -2,12 +2,16 @@
// from gir-files (https://github.com/gtk-rs/gir-files)
// DO NOT EDIT
mod video_buffer_pool;
pub use self::video_buffer_pool::{VideoBufferPool, VideoBufferPoolClass, NONE_VIDEO_BUFFER_POOL};
mod video_decoder;
pub use self::video_decoder::{VideoDecoder, VideoDecoderClass, NONE_VIDEO_DECODER};
pub use self::video_decoder::VideoDecoderExt;
mod video_buffer_pool;
pub use self::video_buffer_pool::{VideoBufferPool, VideoBufferPoolClass, NONE_VIDEO_BUFFER_POOL};
mod video_encoder;
pub use self::video_encoder::{VideoEncoder, VideoEncoderClass, NONE_VIDEO_ENCODER};
pub use self::video_encoder::VideoEncoderExt;
mod video_filter;
pub use self::video_filter::{VideoFilter, VideoFilterClass, NONE_VIDEO_FILTER};
......@@ -44,5 +48,6 @@ pub use self::flags::VideoTimeCodeFlags;
#[doc(hidden)]
pub mod traits {
pub use super::VideoDecoderExt;
pub use super::VideoEncoderExt;
pub use super::VideoOverlayExt;
}
// This file was generated by gir (https://github.com/gtk-rs/gir)
// from gir-files (https://github.com/gtk-rs/gir-files)
// DO NOT EDIT
#[cfg(any(feature = "v1_14", feature = "dox"))]
use VideoCodecFrame;
use glib::StaticType;
use glib::Value;
use glib::object::Cast;
use glib::object::IsA;
use glib::signal::SignalHandlerId;
use glib::signal::connect_raw;
use glib::translate::*;
use glib_sys;
use gobject_sys;
use gst;
use gst_video_sys;
use std::boxed::Box as Box_;
use std::mem::transmute;
glib_wrapper! {
pub struct VideoEncoder(Object<gst_video_sys::GstVideoEncoder, gst_video_sys::GstVideoEncoderClass, VideoEncoderClass>) @extends gst::Element, gst::Object;
match fn {
get_type => || gst_video_sys::gst_video_encoder_get_type(),
}
}
unsafe impl Send for VideoEncoder {}
unsafe impl Sync for VideoEncoder {}
pub const NONE_VIDEO_ENCODER: Option<&VideoEncoder> = None;
pub trait VideoEncoderExt: 'static {
fn allocate_output_buffer(&self, size: usize) -> Option<gst::Buffer>;
//fn get_allocator(&self, allocator: /*Ignored*/gst::Allocator, params: /*Ignored*/gst::AllocationParams);
#[cfg(any(feature = "v1_14", feature = "dox"))]
fn get_max_encode_time(&self, frame: &VideoCodecFrame) -> gst::ClockTimeDiff;
#[cfg(any(feature = "v1_14", feature = "dox"))]
fn is_qos_enabled(&self) -> bool;
fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode);
fn proxy_getcaps(&self, caps: Option<&gst::Caps>, filter: Option<&gst::Caps>) -> Option<gst::Caps>;
fn set_headers(&self, headers: &[&gst::Buffer]);
fn set_min_pts(&self, min_pts: gst::ClockTime);
#[cfg(any(feature = "v1_14", feature = "dox"))]
fn set_qos_enabled(&self, enabled: bool);
fn get_property_qos(&self) -> bool;
fn set_property_qos(&self, qos: bool);
fn connect_property_qos_notify<F: Fn(&Self) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId;
}
impl<O: IsA<VideoEncoder>> VideoEncoderExt for O {
fn allocate_output_buffer(&self, size: usize) -> Option<gst::Buffer> {
unsafe {
from_glib_full(gst_video_sys::gst_video_encoder_allocate_output_buffer(self.as_ref().to_glib_none().0, size))
}
}
//fn get_allocator(&self, allocator: /*Ignored*/gst::Allocator, params: /*Ignored*/gst::AllocationParams) {
// unsafe { TODO: call gst_video_sys:gst_video_encoder_get_allocator() }
//}
#[cfg(any(feature = "v1_14", feature = "dox"))]
fn get_max_encode_time(&self, frame: &VideoCodecFrame) -> gst::ClockTimeDiff {
unsafe {
gst_video_sys::gst_video_encoder_get_max_encode_time(self.as_ref().to_glib_none().0, frame.to_glib_none().0)
}
}
#[cfg(any(feature = "v1_14", feature = "dox"))]
fn is_qos_enabled(&self) -> bool {
unsafe {
from_glib(gst_video_sys::gst_video_encoder_is_qos_enabled(self.as_ref().to_glib_none().0))
}
}
fn merge_tags(&self, tags: Option<&gst::TagList>, mode: gst::TagMergeMode) {
unsafe {
gst_video_sys::gst_video_encoder_merge_tags(self.as_ref().to_glib_none().0, tags.to_glib_none().0, mode.to_glib());
}
}
fn proxy_getcaps(&self, caps: Option<&gst::Caps>, filter: Option<&gst::Caps>) -> Option<gst::Caps> {
unsafe {
from_glib_full(gst_video_sys::gst_video_encoder_proxy_getcaps(self.as_ref().to_glib_none().0, caps.to_glib_none().0, filter.to_glib_none().0))
}
}
fn set_headers(&self, headers: &[&gst::Buffer]) {
unsafe {
gst_video_sys::gst_video_encoder_set_headers(self.as_ref().to_glib_none().0, headers.to_glib_full());
}
}
fn set_min_pts(&self, min_pts: gst::ClockTime) {
unsafe {
gst_video_sys::gst_video_encoder_set_min_pts(self.as_ref().to_glib_none().0, min_pts.to_glib());
}
}
#[cfg(any(feature = "v1_14", feature = "dox"))]
fn set_qos_enabled(&self, enabled: bool) {
unsafe {
gst_video_sys::gst_video_encoder_set_qos_enabled(self.as_ref().to_glib_none().0, enabled.to_glib());
}
}
fn get_property_qos(&self) -> bool {
unsafe {
let mut value = Value::from_type(<bool as StaticType>::static_type());
gobject_sys::g_object_get_property(self.to_glib_none().0 as *mut gobject_sys::GObject, b"qos\0".as_ptr() as *const _, value.to_glib_none_mut().0);
value.get().unwrap()
}
}
fn set_property_qos(&self, qos: bool) {
unsafe {
gobject_sys::g_object_set_property(self.to_glib_none().0 as *mut gobject_sys::GObject, b"qos\0".as_ptr() as *const _, Value::from(&qos).to_glib_none().0);
}
}
fn connect_property_qos_notify<F: Fn(&Self) + Send + Sync + 'static>(&self, f: F) -> SignalHandlerId {
unsafe {
let f: Box_<F> = Box_::new(f);
connect_raw(self.as_ptr() as *mut _, b"notify::qos\0".as_ptr() as *const _,
Some(transmute(notify_qos_trampoline::<Self, F> as usize)), Box_::into_raw(f))
}
}
}
unsafe extern "C" fn notify_qos_trampoline<P, F: Fn(&P) + Send + Sync + 'static>(this: *mut gst_video_sys::GstVideoEncoder, _param_spec: glib_sys::gpointer, f: glib_sys::gpointer)
where P: IsA<VideoEncoder> {
let f: &F = &*(f as *const F);
f(&VideoEncoder::from_glib_borrow(this).unsafe_cast())
}
......@@ -81,6 +81,7 @@ pub use video_buffer_pool::{
mod video_codec_frame;
mod video_decoder;
mod video_encoder;
pub use video_codec_frame::VideoCodecFrame;
pub mod video_codec_state;
pub use video_codec_state::VideoCodecState;
......@@ -95,6 +96,7 @@ pub mod prelude {
pub use auto::traits::*;
pub use video_buffer_pool::VideoBufferPoolConfig;
pub use video_decoder::VideoDecoderExtManual;
pub use video_encoder::VideoEncoderExtManual;
pub use video_overlay::VideoOverlayExtManual;
}
......
......@@ -8,7 +8,9 @@
#![cfg_attr(feature = "cargo-clippy", allow(cast_ptr_alignment))]
pub mod video_decoder;
pub mod video_encoder;
pub mod prelude {
pub use super::video_decoder::{VideoDecoderImpl, VideoDecoderImplExt};
pub use super::video_encoder::{VideoEncoderImpl, VideoEncoderImplExt};
}
This diff is collapsed.
// Copyright (C) 2019 Philippe Normand <philn@igalia.com>
// Copyright (C) 2019 Guillaume Desmottes <guillaume.desmottes@collabora.com>
// Copyright (C) 2019 Sebastian Dröge <sebastian@centricular.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use glib::object::IsA;
use glib::translate::*;
use gst;
use gst_video_sys;
use std::ptr;
use utils::HasStreamLock;
use video_codec_state::{InNegotiation, Readable, VideoCodecState, VideoCodecStateContext};
use VideoCodecFrame;
use VideoEncoder;
pub trait VideoEncoderExtManual: 'static {
#[cfg(any(feature = "v1_12", feature = "dox"))]
fn allocate_output_frame(
&self,
frame: &VideoCodecFrame,
size: usize,
) -> Result<gst::FlowSuccess, gst::FlowError>;
fn get_frame(&self, frame_number: i32) -> Option<VideoCodecFrame>;
fn get_frames(&self) -> Vec<VideoCodecFrame>;
fn get_oldest_frame(&self) -> Option<VideoCodecFrame>;
fn finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError>;
fn get_latency(&self) -> (gst::ClockTime, gst::ClockTime);
fn set_latency(&self, min_latency: gst::ClockTime, max_latency: gst::ClockTime);
fn get_output_state(&self) -> Option<VideoCodecState<Readable>>;
fn set_output_state(
&self,
caps: gst::Caps,
reference: Option<&VideoCodecState<Readable>>,
) -> Result<VideoCodecState<InNegotiation>, gst::FlowError>;
fn negotiate<'a>(
&'a self,
output_state: VideoCodecState<'a, InNegotiation<'a>>,
) -> Result<(), gst::FlowError>;
}
impl<O: IsA<VideoEncoder>> VideoEncoderExtManual for O {
#[cfg(any(feature = "v1_12", feature = "dox"))]
fn allocate_output_frame(
&self,
frame: &VideoCodecFrame,
size: usize,
) -> Result<gst::FlowSuccess, gst::FlowError> {
let ret: gst::FlowReturn = unsafe {
from_glib(gst_video_sys::gst_video_encoder_allocate_output_frame(
self.as_ref().to_glib_none().0,
frame.to_glib_none().0,
size,
))
};
ret.into_result()
}
fn finish_frame(&self, frame: VideoCodecFrame) -> Result<gst::FlowSuccess, gst::FlowError> {
let ret: gst::FlowReturn = unsafe {
from_glib(gst_video_sys::gst_video_encoder_finish_frame(
self.as_ref().to_glib_none().0,
frame.into_ptr(),
))
};
ret.into_result()
}
fn get_latency(&self) -> (gst::ClockTime, gst::ClockTime) {
let mut min_latency = gst_sys::GST_CLOCK_TIME_NONE;
let mut max_latency = gst_sys::GST_CLOCK_TIME_NONE;
unsafe {
gst_video_sys::gst_video_encoder_get_latency(
self.as_ref().to_glib_none().0,
&mut min_latency,
&mut max_latency,
);
(from_glib(min_latency), from_glib(max_latency))
}
}
fn set_latency(&self, min_latency: gst::ClockTime, max_latency: gst::ClockTime) {
unsafe {
gst_video_sys::gst_video_encoder_set_latency(
self.as_ref().to_glib_none().0,
min_latency.to_glib(),
max_latency.to_glib(),
);
}
}
fn get_frame(&self, frame_number: i32) -> Option<VideoCodecFrame> {
let frame = unsafe {
gst_video_sys::gst_video_encoder_get_frame(self.as_ref().to_glib_none().0, frame_number)
};
if frame.is_null() {
None
} else {
unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
}
}
fn get_frames(&self) -> Vec<VideoCodecFrame> {
unsafe {
let frames =
gst_video_sys::gst_video_encoder_get_frames(self.as_ref().to_glib_none().0);
let mut iter: *const glib_sys::GList = frames;
let mut vec = Vec::new();
while !iter.is_null() {
let frame_ptr = Ptr::from((*iter).data);
/* transfer ownership of the frame */
let frame = VideoCodecFrame::new(frame_ptr, self.as_ref());
vec.push(frame);
iter = (*iter).next;
}
glib_sys::g_list_free(frames);
vec
}
}
fn get_oldest_frame(&self) -> Option<VideoCodecFrame> {
let frame = unsafe {
gst_video_sys::gst_video_encoder_get_oldest_frame(self.as_ref().to_glib_none().0)
};
if frame.is_null() {
None
} else {
unsafe { Some(VideoCodecFrame::new(frame, self.as_ref())) }
}
}
fn get_output_state(&self) -> Option<VideoCodecState<Readable>> {
let state = unsafe {
gst_video_sys::gst_video_encoder_get_output_state(self.as_ref().to_glib_none().0)
};
if state.is_null() {
None
} else {
unsafe { Some(VideoCodecState::<Readable>::new(state)) }
}
}
fn set_output_state(
&self,
caps: gst::Caps,
reference: Option<&VideoCodecState<Readable>>,
) -> Result<VideoCodecState<InNegotiation>, gst::FlowError> {
let state = unsafe {
let reference = match reference {
Some(reference) => reference.as_mut_ptr(),
None => ptr::null_mut(),
};
gst_video_sys::gst_video_encoder_set_output_state(
self.as_ref().to_glib_none().0,
caps.into_ptr(),
reference,
)
};
if state.is_null() {
Err(gst::FlowError::Error)
} else {
unsafe { Ok(VideoCodecState::<InNegotiation>::new(state, self.as_ref())) }
}
}
fn negotiate<'a>(
&'a self,
output_state: VideoCodecState<'a, InNegotiation<'a>>,
) -> Result<(), gst::FlowError> {
// Consume output_state so user won't be able to modify it anymore
let self_ptr = self.to_glib_none().0 as *const gst_sys::GstElement;
assert_eq!(output_state.context.get_element_as_ptr(), self_ptr);
let ret = unsafe {
from_glib(gst_video_sys::gst_video_encoder_negotiate(
self.as_ref().to_glib_none().0,
))
};
if ret {
Ok(())
} else {
Err(gst::FlowError::NotNegotiated)
}
}
}
impl HasStreamLock for VideoEncoder {
fn get_stream_lock(&self) -> *mut glib_sys::GRecMutex {
let encoder_sys: *const gstreamer_video_sys::GstVideoEncoder = self.to_glib_none().0;
unsafe { &(*encoder_sys).stream_lock as *const _ as usize as *mut _ }
}
fn get_element_as_ptr(&self) -> *const gst_sys::GstElement {
let encoder_sys: *const gstreamer_video_sys::GstVideoEncoder = self.to_glib_none().0;
encoder_sys as *const gst_sys::GstElement
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment