forked from mirrors/gstreamer-rs
213 lines
5.9 KiB
Rust
213 lines
5.9 KiB
Rust
// Take a look at the license at the top of the repository in the LICENSE file.
|
|
|
|
use crate::utils::HasStreamLock;
|
|
use glib::translate::*;
|
|
use std::fmt;
|
|
use std::marker::PhantomData;
|
|
use std::ptr;
|
|
|
|
use crate::video_info::VideoInfo;
|
|
|
|
pub trait VideoCodecStateContext<'a> {
|
|
fn element(&self) -> Option<&'a dyn HasStreamLock>;
|
|
fn element_as_ptr(&self) -> *const gst::ffi::GstElement;
|
|
}
|
|
|
|
pub struct InNegotiation<'a> {
|
|
/* GstVideoCodecState API isn't safe so protect the state using the
|
|
* element (decoder or encoder) stream lock */
|
|
element: &'a dyn HasStreamLock,
|
|
}
|
|
pub struct Readable {}
|
|
|
|
impl<'a> VideoCodecStateContext<'a> for InNegotiation<'a> {
|
|
fn element(&self) -> Option<&'a dyn HasStreamLock> {
|
|
Some(self.element)
|
|
}
|
|
|
|
fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
|
|
self.element.element_as_ptr()
|
|
}
|
|
}
|
|
|
|
impl<'a> VideoCodecStateContext<'a> for Readable {
|
|
fn element(&self) -> Option<&'a dyn HasStreamLock> {
|
|
None
|
|
}
|
|
|
|
fn element_as_ptr(&self) -> *const gst::ffi::GstElement {
|
|
ptr::null()
|
|
}
|
|
}
|
|
|
|
pub struct VideoCodecState<'a, T: VideoCodecStateContext<'a>> {
|
|
state: *mut ffi::GstVideoCodecState,
|
|
pub(crate) context: T,
|
|
phantom: PhantomData<&'a T>,
|
|
}
|
|
|
|
impl<'a, T: VideoCodecStateContext<'a>> fmt::Debug for VideoCodecState<'a, T> {
|
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
f.debug_struct("VideoCodecState")
|
|
.field("info", &self.info())
|
|
.field("caps", &self.caps())
|
|
.field("codec_data", &self.codec_data())
|
|
.field("allocation_caps", &self.allocation_caps())
|
|
.finish()
|
|
}
|
|
}
|
|
|
|
impl<'a> VideoCodecState<'a, Readable> {
|
|
// Take ownership of @state
|
|
pub(crate) unsafe fn new(state: *mut ffi::GstVideoCodecState) -> Self {
|
|
skip_assert_initialized!();
|
|
Self {
|
|
state,
|
|
context: Readable {},
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> VideoCodecState<'a, InNegotiation<'a>> {
|
|
// Take ownership of @state
|
|
pub(crate) unsafe fn new<T: HasStreamLock>(
|
|
state: *mut ffi::GstVideoCodecState,
|
|
element: &'a T,
|
|
) -> Self {
|
|
skip_assert_initialized!();
|
|
let stream_lock = element.stream_lock();
|
|
glib::ffi::g_rec_mutex_lock(stream_lock);
|
|
Self {
|
|
state,
|
|
context: InNegotiation { element },
|
|
phantom: PhantomData,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a, T: VideoCodecStateContext<'a>> VideoCodecState<'a, T> {
|
|
pub fn info(&self) -> VideoInfo {
|
|
unsafe {
|
|
let ptr = &((*self.as_mut_ptr()).info) as *const _ as usize as *mut _;
|
|
VideoInfo::from_glib_none(ptr)
|
|
}
|
|
}
|
|
|
|
pub fn caps(&self) -> Option<&gst::CapsRef> {
|
|
unsafe {
|
|
let ptr = (*self.as_mut_ptr()).caps;
|
|
|
|
if ptr.is_null() {
|
|
None
|
|
} else {
|
|
Some(gst::CapsRef::from_ptr(ptr))
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn codec_data(&self) -> Option<&gst::BufferRef> {
|
|
unsafe {
|
|
let ptr = (*self.as_mut_ptr()).codec_data;
|
|
|
|
if ptr.is_null() {
|
|
None
|
|
} else {
|
|
Some(gst::BufferRef::from_ptr(ptr))
|
|
}
|
|
}
|
|
}
|
|
|
|
pub fn allocation_caps(&self) -> Option<&gst::CapsRef> {
|
|
unsafe {
|
|
let ptr = (*self.as_mut_ptr()).allocation_caps;
|
|
|
|
if ptr.is_null() {
|
|
None
|
|
} else {
|
|
Some(gst::CapsRef::from_ptr(ptr))
|
|
}
|
|
}
|
|
}
|
|
#[doc(hidden)]
|
|
pub fn as_mut_ptr(&self) -> *mut ffi::GstVideoCodecState {
|
|
self.state
|
|
}
|
|
}
|
|
|
|
impl<'a, T: VideoCodecStateContext<'a>> Drop for VideoCodecState<'a, T> {
|
|
fn drop(&mut self) {
|
|
unsafe {
|
|
if let Some(element) = self.context.element() {
|
|
let stream_lock = element.stream_lock();
|
|
glib::ffi::g_rec_mutex_unlock(stream_lock);
|
|
}
|
|
ffi::gst_video_codec_state_unref(self.state);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> VideoCodecState<'a, InNegotiation<'a>> {
|
|
pub fn set_info(&mut self, info: VideoInfo) {
|
|
unsafe {
|
|
ptr::write(&mut (*self.as_mut_ptr()).info, *(info.to_glib_none().0));
|
|
}
|
|
}
|
|
|
|
pub fn set_caps(&mut self, caps: &gst::Caps) {
|
|
unsafe {
|
|
let prev = (*self.as_mut_ptr()).caps;
|
|
|
|
if !prev.is_null() {
|
|
gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
|
|
}
|
|
|
|
ptr::write(
|
|
&mut (*self.as_mut_ptr()).caps,
|
|
gst::ffi::gst_mini_object_ref(caps.as_mut_ptr() as *mut _) as *mut _,
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn set_codec_data(&mut self, codec_data: &gst::Buffer) {
|
|
unsafe {
|
|
let prev = (*self.as_mut_ptr()).codec_data;
|
|
|
|
if !prev.is_null() {
|
|
gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
|
|
}
|
|
|
|
ptr::write(
|
|
&mut (*self.as_mut_ptr()).codec_data,
|
|
gst::ffi::gst_mini_object_ref(codec_data.as_mut_ptr() as *mut _) as *mut _,
|
|
);
|
|
}
|
|
}
|
|
|
|
pub fn set_allocation_caps(&mut self, allocation_caps: &gst::Caps) {
|
|
unsafe {
|
|
let prev = (*self.as_mut_ptr()).allocation_caps;
|
|
|
|
if !prev.is_null() {
|
|
gst::ffi::gst_mini_object_unref(prev as *mut gst::ffi::GstMiniObject)
|
|
}
|
|
|
|
ptr::write(
|
|
&mut (*self.as_mut_ptr()).allocation_caps,
|
|
gst::ffi::gst_mini_object_ref(allocation_caps.as_mut_ptr() as *mut _) as *mut _,
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<'a> Clone for VideoCodecState<'a, Readable> {
|
|
fn clone(&self) -> Self {
|
|
unsafe {
|
|
let state = ffi::gst_video_codec_state_ref(self.state);
|
|
Self::new(state)
|
|
}
|
|
}
|
|
}
|
|
|
|
unsafe impl<'a> Send for VideoCodecState<'a, Readable> {}
|
|
unsafe impl<'a> Sync for VideoCodecState<'a, Readable> {}
|