diff --git a/gstreamer-allocators/Gir.toml b/gstreamer-allocators/Gir.toml index ea9d9644d..1a1f504b5 100644 --- a/gstreamer-allocators/Gir.toml +++ b/gstreamer-allocators/Gir.toml @@ -52,6 +52,15 @@ status = "generate" [[object.function]] name = "phys_memory_get_phys_addr" manual = true + [[object.function]] + name = "is_drm_dumb_memory" + manual = true + [[object.function]] + name = "drm_dumb_memory_get_handle" + manual = true + [[object.function]] + name = "drm_dumb_memory_export_dmabuf" + manual = true [[object]] name = "GstAllocators.DmaBufAllocator" @@ -64,6 +73,21 @@ cfg_condition = "target_os = \"linux\"" name = "alloc_with_flags" manual = true +[[object]] +name = "GstAllocators.DRMDumbAllocator" +status = "generate" +cfg_condition = "target_os = \"linux\"" + [[object.function]] + name = "alloc" + manual = true + [[object.function]] + name = "new_with_fd" + manual = true + [[object.function]] + name = "new_with_device_path" + [object.function.return] + nullable_return_is_error = "Failed to create allocator" + [[object]] name = "GstAllocators.FdAllocator" status = "generate" diff --git a/gstreamer-allocators/src/drm_dumb_allocator.rs b/gstreamer-allocators/src/drm_dumb_allocator.rs new file mode 100644 index 000000000..eaf30be5f --- /dev/null +++ b/gstreamer-allocators/src/drm_dumb_allocator.rs @@ -0,0 +1,81 @@ +use std::{fmt, mem, os::unix::prelude::IntoRawFd}; + +use glib::{translate::*, Cast}; +use gst::{Memory, MemoryRef}; + +use crate::{DRMDumbAllocator, DmaBufMemory}; + +gst::memory_object_wrapper!( + DRMDumbMemory, + DRMDumbMemoryRef, + gst::ffi::GstMemory, + |mem: &gst::MemoryRef| { unsafe { from_glib(ffi::gst_is_drm_dumb_memory(mem.as_mut_ptr())) } }, + Memory, + MemoryRef +); + +impl fmt::Debug for DRMDumbMemory { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + DRMDumbMemoryRef::fmt(self, f) + } +} + +impl fmt::Debug for DRMDumbMemoryRef { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + MemoryRef::fmt(self, f) + } +} + +impl DRMDumbMemoryRef { + #[doc(alias = "gst_drm_dumb_memory_get_handle")] + pub fn fd(&self) -> u32 { + skip_assert_initialized!(); + unsafe { ffi::gst_drm_dumb_memory_get_handle(self.as_mut_ptr()) } + } + + #[doc(alias = "gst_drm_dumb_memory_export_dmabuf")] + pub fn export_dmabuf(&self) -> Result { + skip_assert_initialized!(); + unsafe { + Option::::from_glib_full(ffi::gst_drm_dumb_memory_export_dmabuf( + self.as_mut_ptr(), + )) + .ok_or_else(|| glib::bool_error!("Failed to export as dmabuf")) + } + } +} + +impl DRMDumbAllocator { + #[doc(alias = "gst_drm_dumb_allocator_new_with_fd")] + #[doc(alias = "new_with_fd")] + pub fn with_fd(drm_fd: A) -> Result { + assert_initialized_main_thread!(); + unsafe { + Option::::from_glib_full(ffi::gst_drm_dumb_allocator_new_with_fd( + drm_fd.into_raw_fd(), + )) + .map(|o| o.unsafe_cast()) + .ok_or_else(|| glib::bool_error!("Failed to create allocator")) + } + } + + #[doc(alias = "gst_drm_dumb_allocator_alloc")] + pub unsafe fn alloc( + &self, + drm_fourcc: u32, + width: u32, + height: u32, + ) -> Result<(gst::Memory, u32), glib::BoolError> { + skip_assert_initialized!(); + let mut out_pitch = mem::MaybeUninit::uninit(); + Option::<_>::from_glib_full(ffi::gst_drm_dumb_allocator_alloc( + self.to_glib_none().0, + drm_fourcc, + width, + height, + out_pitch.as_mut_ptr(), + )) + .ok_or_else(|| glib::bool_error!("Failed to allocate memory")) + .map(|mem| (mem, unsafe { out_pitch.assume_init() })) + } +} diff --git a/gstreamer-allocators/src/lib.rs b/gstreamer-allocators/src/lib.rs index 7eac5250a..9e0ee34f4 100644 --- a/gstreamer-allocators/src/lib.rs +++ b/gstreamer-allocators/src/lib.rs @@ -37,6 +37,13 @@ mod dma_buf_allocator; #[cfg_attr(feature = "dox", doc(cfg(target_os = "linux")))] pub use dma_buf_allocator::*; +#[cfg(any(all(feature = "v1_24", target_os = "linux"), feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(all(feature = "v1_24", target_os = "linux"))))] +mod drm_dumb_allocator; +#[cfg(any(all(feature = "v1_24", target_os = "linux"), feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(all(feature = "v1_24", target_os = "linux"))))] +pub use drm_dumb_allocator::*; + mod phys_memory; pub use phys_memory::*; diff --git a/gstreamer-app/Gir.toml b/gstreamer-app/Gir.toml index a80119daf..7bb4aca60 100644 --- a/gstreamer-app/Gir.toml +++ b/gstreamer-app/Gir.toml @@ -104,6 +104,11 @@ final_type = true # Action signal ignore = true + [[object.signal]] + name = "propose-allocation" + # Action signal + ignore = true + [[object.property]] name = "emit-signals" # Use callbacks instead diff --git a/gstreamer-app/src/app_sink.rs b/gstreamer-app/src/app_sink.rs index 572fcf5f1..8dba1d936 100644 --- a/gstreamer-app/src/app_sink.rs +++ b/gstreamer-app/src/app_sink.rs @@ -26,6 +26,8 @@ pub struct AppSinkCallbacks { Box Result + Send + 'static>, >, new_event: Option bool + Send + 'static>>, + propose_allocation: + Option bool + Send + 'static>>, panicked: AtomicBool, callbacks: ffi::GstAppSinkCallbacks, } @@ -41,6 +43,7 @@ impl AppSinkCallbacks { new_preroll: None, new_sample: None, new_event: None, + propose_allocation: None, } } } @@ -56,6 +59,8 @@ pub struct AppSinkCallbacksBuilder { Box Result + Send + 'static>, >, new_event: Option bool + Send + 'static>>, + propose_allocation: + Option bool + Send + 'static>>, } impl AppSinkCallbacksBuilder { @@ -90,6 +95,18 @@ impl AppSinkCallbacksBuilder { } } + pub fn new_propose_allocation< + F: FnMut(&AppSink) -> Result + Send + 'static, + >( + self, + new_sample: F, + ) -> Self { + Self { + new_sample: Some(Box::new(new_sample)), + ..self + } + } + #[cfg(any(feature = "v1_20", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))] pub fn new_event bool + Send + 'static>(self, new_event: F) -> Self { @@ -99,18 +116,34 @@ impl AppSinkCallbacksBuilder { } } + #[cfg(any(feature = "v1_24", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_24")))] + pub fn propose_allocation< + F: FnMut(&AppSink, &mut gst::query::Allocation) -> bool + Send + 'static, + >( + self, + propose_allocation: F, + ) -> Self { + Self { + propose_allocation: Some(Box::new(propose_allocation)), + ..self + } + } + #[must_use = "Building the callbacks without using them has no effect"] pub fn build(self) -> AppSinkCallbacks { let have_eos = self.eos.is_some(); let have_new_preroll = self.new_preroll.is_some(); let have_new_sample = self.new_sample.is_some(); let have_new_event = self.new_event.is_some(); + let have_propose_allocation = self.propose_allocation.is_some(); AppSinkCallbacks { eos: self.eos, new_preroll: self.new_preroll, new_sample: self.new_sample, new_event: self.new_event, + propose_allocation: self.propose_allocation, panicked: AtomicBool::new(false), callbacks: ffi::GstAppSinkCallbacks { eos: if have_eos { Some(trampoline_eos) } else { None }, @@ -129,7 +162,12 @@ impl AppSinkCallbacksBuilder { } else { None }, - _gst_reserved: [ptr::null_mut(), ptr::null_mut(), ptr::null_mut()], + propose_allocation: if have_propose_allocation { + Some(trampoline_propose_allocation) + } else { + None + }, + _gst_reserved: [ptr::null_mut(), ptr::null_mut()], }, } } @@ -266,6 +304,48 @@ unsafe extern "C" fn trampoline_new_event( ret.into_glib() } +unsafe extern "C" fn trampoline_propose_allocation( + appsink: *mut ffi::GstAppSink, + query: *mut gst::ffi::GstQuery, + callbacks: gpointer, +) -> glib::ffi::gboolean { + let callbacks = callbacks as *mut AppSinkCallbacks; + let element: Borrowed = from_glib_borrow(appsink); + + if (*callbacks).panicked.load(Ordering::Relaxed) { + let element: Borrowed = from_glib_borrow(appsink); + gst::subclass::post_panic_error_message(element.upcast_ref(), element.upcast_ref(), None); + return false.into_glib(); + } + + let ret = if let Some(ref mut propose_allocation) = (*callbacks).propose_allocation { + let query = match gst::QueryRef::from_mut_ptr(query).view_mut() { + gst::QueryViewMut::Allocation(allocation) => allocation, + _ => unreachable!(), + }; + let result = panic::catch_unwind(panic::AssertUnwindSafe(|| { + propose_allocation(&element, query) + })); + match result { + Ok(result) => result, + Err(err) => { + (*callbacks).panicked.store(true, Ordering::Relaxed); + gst::subclass::post_panic_error_message( + element.upcast_ref(), + element.upcast_ref(), + Some(err), + ); + + false + } + } + } else { + false + }; + + ret.into_glib() +} + unsafe extern "C" fn destroy_callbacks(ptr: gpointer) { let _ = Box::::from_raw(ptr as *mut _); } diff --git a/gstreamer-base/Gir.toml b/gstreamer-base/Gir.toml index 657c82d89..73a930179 100644 --- a/gstreamer-base/Gir.toml +++ b/gstreamer-base/Gir.toml @@ -385,8 +385,8 @@ manual_traits = ["BaseSrcExtManual"] [[object.function]] name = "new_segment" - # Segment parameter - manual = true + [object.function.return] + bool_return_is_error = "Failed to update segment" [[object]] name = "GstBase.BaseTransform" diff --git a/gstreamer-base/src/base_src.rs b/gstreamer-base/src/base_src.rs index db08665ac..5cc3fe549 100644 --- a/gstreamer-base/src/base_src.rs +++ b/gstreamer-base/src/base_src.rs @@ -20,11 +20,6 @@ pub trait BaseSrcExtManual: 'static { &self, ) -> Result<(bool, Option, Option), glib::BoolError>; - #[cfg(any(feature = "v1_18", feature = "dox"))] - #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] - #[doc(alias = "gst_base_src_new_segment")] - fn new_segment(&self, segment: &gst::Segment) -> Result<(), glib::BoolError>; - fn src_pad(&self) -> &gst::Pad; } @@ -78,23 +73,6 @@ impl> BaseSrcExtManual for O { } } - #[cfg(any(feature = "v1_18", feature = "dox"))] - #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] - fn new_segment(&self, segment: &gst::Segment) -> Result<(), glib::BoolError> { - unsafe { - let ret = from_glib(ffi::gst_base_src_new_segment( - self.as_ref().to_glib_none().0, - segment.to_glib_none().0, - )); - - if ret { - Ok(()) - } else { - Err(glib::bool_error!("Failed to configure new segment")) - } - } - } - fn src_pad(&self) -> &gst::Pad { unsafe { let elt = &*(self.as_ptr() as *const ffi::GstBaseSrc); diff --git a/gstreamer-gl/Gir.toml b/gstreamer-gl/Gir.toml index 5793ab748..327bed9c5 100644 --- a/gstreamer-gl/Gir.toml +++ b/gstreamer-gl/Gir.toml @@ -366,6 +366,11 @@ status = "generate" [object.function.return] nullable_return_is_error = "Failed to create window" + [[object.function]] + name = "ensure_context" + # inout parameter + manual = true + [[object]] name = "GstGL.GLDisplayType" status = "generate" diff --git a/gstreamer-gl/src/gl_display.rs b/gstreamer-gl/src/gl_display.rs index d1755153c..43b2a2f58 100644 --- a/gstreamer-gl/src/gl_display.rs +++ b/gstreamer-gl/src/gl_display.rs @@ -3,6 +3,46 @@ use crate::{GLContext, GLDisplay}; use glib::prelude::*; use glib::translate::*; +pub trait GLDisplayExtManual: 'static { + #[cfg(any(feature = "v1_24", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_24")))] + #[doc(alias = "gst_gl_display_ensure_context")] + fn ensure_context( + &self, + other_context: Option<&impl IsA>, + context: &mut Option, + ) -> Result<(), glib::Error>; +} + +impl> GLDisplayExtManual for O { + #[cfg(any(feature = "v1_24", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_24")))] + fn ensure_context( + &self, + other_context: Option<&impl IsA>, + context: &mut Option, + ) -> Result<(), glib::Error> { + unsafe { + let mut err = std::ptr::null_mut(); + let res = ffi::gst_gl_display_ensure_context( + self.as_ref().to_glib_none().0, + other_context.map(AsRef::as_ref).to_glib_none().0, + context as *mut Option as *mut Option<*mut ffi::GstGLContext> + as *mut *mut ffi::GstGLContext, + &mut err, + ); + + if res == glib::ffi::GFALSE { + *context = None; + Err(from_glib_full(err)) + } else { + debug_assert!(err.is_null()); + Ok(()) + } + } + } +} + impl GLDisplay { #[doc(alias = "gst_gl_display_get_gl_context_for_thread")] pub fn get_gl_context_for_current_thread( diff --git a/gstreamer-gl/src/lib.rs b/gstreamer-gl/src/lib.rs index 25b91e036..a75a0effd 100644 --- a/gstreamer-gl/src/lib.rs +++ b/gstreamer-gl/src/lib.rs @@ -53,7 +53,7 @@ pub mod prelude { pub use crate::{ auto::traits::*, context::ContextGLExt, gl_context::GLContextExtManual, - gl_video_frame::VideoFrameGLExt, + gl_display::GLDisplayExtManual, gl_video_frame::VideoFrameGLExt, }; } diff --git a/gstreamer-video/Gir.toml b/gstreamer-video/Gir.toml index a4f21fa78..2e0d7494e 100644 --- a/gstreamer-video/Gir.toml +++ b/gstreamer-video/Gir.toml @@ -73,6 +73,7 @@ manual = [ "GstVideo.VideoColorRange", "GstVideo.VideoFormatInfo", "GstVideo.VideoInfo", + "GstVideo.VideoInfoDmaDrm", "GstVideo.VideoMeta", "GstVideo.VideoTimeCode", "GstVideo.VideoTimeCodeInterval", diff --git a/gstreamer-video/src/lib.rs b/gstreamer-video/src/lib.rs index 6ce135e1d..809d5bb69 100644 --- a/gstreamer-video/src/lib.rs +++ b/gstreamer-video/src/lib.rs @@ -53,6 +53,12 @@ mod video_format_info; pub use crate::video_format_info::*; mod video_info; pub use crate::video_info::*; +#[cfg(any(feature = "v1_24", feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_24")))] +mod video_info_dma_drm; +#[cfg(any(feature = "v1_24", feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_24")))] +pub use crate::video_info_dma_drm::*; pub mod video_frame; pub use crate::video_frame::{VideoFrame, VideoFrameRef}; mod video_overlay; diff --git a/gstreamer-video/src/video_info_dma_drm.rs b/gstreamer-video/src/video_info_dma_drm.rs new file mode 100644 index 000000000..6a8ddf214 --- /dev/null +++ b/gstreamer-video/src/video_info_dma_drm.rs @@ -0,0 +1,277 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use std::{fmt, marker::PhantomData, mem, ops, ptr, str}; + +use glib::translate::*; +use gst::prelude::*; + +use crate::{VideoFormat, VideoInfo}; + +#[doc(alias = "gst_video_dma_drm_fourcc_from_format")] +pub fn dma_drm_fourcc_from_format(v: VideoFormat) -> Result { + skip_assert_initialized!(); + unsafe { + let res = ffi::gst_video_dma_drm_fourcc_from_format(v.into_glib()); + if res == 0 { + Err(glib::bool_error!("Unsupported video format")) + } else { + Ok(res) + } + } +} + +#[doc(alias = "gst_video_dma_drm_fourcc_to_format")] +pub fn dma_drm_fourcc_to_format(v: u32) -> Result { + skip_assert_initialized!(); + unsafe { + let res = ffi::gst_video_dma_drm_fourcc_to_format(v); + if res == ffi::GST_VIDEO_FORMAT_UNKNOWN { + Err(glib::bool_error!("Unsupported fourcc")) + } else { + Ok(from_glib(res)) + } + } +} + +#[doc(alias = "gst_video_dma_drm_fourcc_to_string")] +pub fn dma_drm_fourcc_to_string(fourcc: u32, modifier: u64) -> glib::GString { + skip_assert_initialized!(); + unsafe { + glib::GString::from_glib_full(ffi::gst_video_dma_drm_fourcc_to_string(fourcc, modifier)) + } +} + +#[doc(alias = "gst_video_dma_drm_fourcc_from_string")] +pub fn dma_drm_fourcc_from_str(v: &str) -> Result<(u32, u64), glib::BoolError> { + skip_assert_initialized!(); + unsafe { + let mut modifier = mem::MaybeUninit::uninit(); + let res = + ffi::gst_video_dma_drm_fourcc_from_string(v.to_glib_none().0, modifier.as_mut_ptr()); + if res == 0 { + Err(glib::bool_error!("Can't parse fourcc string")) + } else { + Ok((res, modifier.assume_init())) + } + } +} + +#[doc(alias = "GstVideoInfoDmaDrm")] +#[derive(Clone)] +#[repr(transparent)] +pub struct VideoInfoDmaDrm(pub(crate) ffi::GstVideoInfoDmaDrm); + +impl ops::Deref for VideoInfoDmaDrm { + type Target = VideoInfo; + + fn deref(&self) -> &Self::Target { + unsafe { &*(&self.0.vinfo as *const ffi::GstVideoInfo as *const VideoInfo) } + } +} + +impl fmt::Debug for VideoInfoDmaDrm { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("VideoInfoDmaDrm") + .field("info", &**self) + .field("drm_fourcc", &self.0.drm_fourcc) + .field("drm_modifier", &self.0.drm_modifier) + .finish() + } +} + +impl VideoInfoDmaDrm { + pub fn new(info: VideoInfo, fourcc: u32, modifier: u64) -> VideoInfoDmaDrm { + assert_initialized_main_thread!(); + + VideoInfoDmaDrm(ffi::GstVideoInfoDmaDrm { + vinfo: info.0, + drm_fourcc: fourcc, + drm_modifier: modifier, + _gst_reserved: [0; 20], + }) + } + + #[inline] + pub fn is_valid(&self) -> bool { + !self.0.vinfo.finfo.is_null() + && self.0.vinfo.width > 0 + && self.0.vinfo.height > 0 + && self.0.vinfo.size > 0 + } + + #[doc(alias = "gst_video_info_dma_drm_from_caps")] + pub fn from_caps(caps: &gst::CapsRef) -> Result { + skip_assert_initialized!(); + + unsafe { + let mut info = mem::MaybeUninit::uninit(); + if from_glib(ffi::gst_video_info_dma_drm_from_caps( + info.as_mut_ptr(), + caps.as_ptr(), + )) { + Ok(Self(info.assume_init())) + } else { + Err(glib::bool_error!( + "Failed to create VideoInfoDmaDrm from caps" + )) + } + } + } + + #[doc(alias = "gst_video_info_dma_drm_to_caps")] + pub fn to_caps(&self) -> Result { + unsafe { + let result = from_glib_full(ffi::gst_video_info_dma_drm_to_caps( + &self.0 as *const _ as *mut _, + )); + match result { + Some(c) => Ok(c), + None => Err(glib::bool_error!( + "Failed to create caps from VideoInfoDmaDrm" + )), + } + } + } + + #[inline] + pub fn fourcc(&self) -> u32 { + self.0.drm_fourcc + } + + #[inline] + pub fn modifier(&self) -> u64 { + self.0.drm_modifier + } +} + +impl PartialEq for VideoInfoDmaDrm { + #[doc(alias = "gst_video_info_is_equal")] + fn eq(&self, other: &Self) -> bool { + unsafe { + from_glib(ffi::gst_video_info_is_equal(&self.0.vinfo, &other.0.vinfo)) + && self.0.drm_fourcc == other.0.drm_fourcc + && self.0.drm_modifier == other.0.drm_modifier + } + } +} + +impl Eq for VideoInfoDmaDrm {} + +unsafe impl Send for VideoInfoDmaDrm {} +unsafe impl Sync for VideoInfoDmaDrm {} + +impl glib::types::StaticType for VideoInfoDmaDrm { + #[inline] + fn static_type() -> glib::types::Type { + unsafe { glib::translate::from_glib(ffi::gst_video_info_dma_drm_get_type()) } + } +} + +impl glib::value::ValueType for VideoInfoDmaDrm { + type Type = Self; +} + +#[doc(hidden)] +unsafe impl<'a> glib::value::FromValue<'a> for VideoInfoDmaDrm { + type Checker = glib::value::GenericValueTypeOrNoneChecker; + + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib_none(glib::gobject_ffi::g_value_get_boxed(value.to_glib_none().0) + as *mut ffi::GstVideoInfoDmaDrm) + } +} + +#[doc(hidden)] +impl glib::value::ToValue for VideoInfoDmaDrm { + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_boxed( + value.to_glib_none_mut().0, + self.to_glib_none().0 as *mut _, + ) + } + value + } + + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +#[doc(hidden)] +impl glib::value::ToValueOptional for VideoInfoDmaDrm { + fn to_value_optional(s: Option<&Self>) -> glib::Value { + skip_assert_initialized!(); + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_boxed( + value.to_glib_none_mut().0, + s.to_glib_none().0 as *mut _, + ) + } + value + } +} + +#[doc(hidden)] +impl From for glib::Value { + fn from(v: VideoInfoDmaDrm) -> glib::Value { + skip_assert_initialized!(); + glib::value::ToValue::to_value(&v) + } +} + +#[doc(hidden)] +impl glib::translate::Uninitialized for VideoInfoDmaDrm { + #[inline] + unsafe fn uninitialized() -> Self { + mem::zeroed() + } +} + +#[doc(hidden)] +impl glib::translate::GlibPtrDefault for VideoInfoDmaDrm { + type GlibType = *mut ffi::GstVideoInfoDmaDrm; +} + +#[doc(hidden)] +impl<'a> glib::translate::ToGlibPtr<'a, *const ffi::GstVideoInfoDmaDrm> for VideoInfoDmaDrm { + type Storage = PhantomData<&'a Self>; + + #[inline] + fn to_glib_none(&'a self) -> glib::translate::Stash<'a, *const ffi::GstVideoInfoDmaDrm, Self> { + glib::translate::Stash(&self.0, PhantomData) + } + + fn to_glib_full(&self) -> *const ffi::GstVideoInfoDmaDrm { + unimplemented!() + } +} + +#[doc(hidden)] +impl glib::translate::FromGlibPtrNone<*const ffi::GstVideoInfoDmaDrm> for VideoInfoDmaDrm { + #[inline] + unsafe fn from_glib_none(ptr: *const ffi::GstVideoInfoDmaDrm) -> Self { + Self(ptr::read(ptr)) + } +} + +#[doc(hidden)] +impl glib::translate::FromGlibPtrNone<*mut ffi::GstVideoInfoDmaDrm> for VideoInfoDmaDrm { + #[inline] + unsafe fn from_glib_none(ptr: *mut ffi::GstVideoInfoDmaDrm) -> Self { + Self(ptr::read(ptr)) + } +} + +#[doc(hidden)] +impl glib::translate::FromGlibPtrFull<*mut ffi::GstVideoInfoDmaDrm> for VideoInfoDmaDrm { + #[inline] + unsafe fn from_glib_full(ptr: *mut ffi::GstVideoInfoDmaDrm) -> Self { + let info = from_glib_none(ptr); + glib::ffi::g_free(ptr as *mut _); + info + } +} diff --git a/gstreamer-webrtc/Gir.toml b/gstreamer-webrtc/Gir.toml index 4509c6a84..bd30a87b2 100644 --- a/gstreamer-webrtc/Gir.toml +++ b/gstreamer-webrtc/Gir.toml @@ -24,7 +24,6 @@ generate = [ "GstWebRTC.WebRTCDTLSTransportState", "GstWebRTC.WebRTCError", "GstWebRTC.WebRTCFECType", - "GstWebRTC.WebRTCICE", "GstWebRTC.WebRTCICECandidateStats", "GstWebRTC.WebRTCICEComponent", "GstWebRTC.WebRTCICEConnectionState", @@ -66,6 +65,14 @@ name = "GstWebRTC.WebRTCDTLSTransport" status = "generate" final_type = true +[[object]] +name = "GstWebRTC.WebRTCICE" +status = "generate" + [[object.function]] + name = "add_candidate" + # ABI breakage in 1.24 needs working around + manual = true + [[object]] name = "GstWebRTC.WebRTCICETransport" status = "generate" diff --git a/gstreamer-webrtc/src/lib.rs b/gstreamer-webrtc/src/lib.rs index ce94232d8..792271e7c 100644 --- a/gstreamer-webrtc/src/lib.rs +++ b/gstreamer-webrtc/src/lib.rs @@ -22,6 +22,9 @@ pub use crate::auto::*; #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_22")))] mod web_rtc_ice_candidate_stats; mod web_rtc_session_description; +#[cfg(any(feature = "v1_22", feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_22")))] +mod web_rtcice; // Re-export all the traits in a prelude module, so that applications // can always "use gst_webrtc::prelude::*" without getting conflicts diff --git a/gstreamer-webrtc/src/web_rtcice.rs b/gstreamer-webrtc/src/web_rtcice.rs new file mode 100644 index 000000000..70d393b31 --- /dev/null +++ b/gstreamer-webrtc/src/web_rtcice.rs @@ -0,0 +1,79 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use glib::{prelude::*, translate::*}; + +use crate::{WebRTCICE, WebRTCICEStream}; + +pub trait WebRTCICEExtManual: 'static { + #[doc(alias = "gst_webrtc_ice_add_candidate")] + fn add_candidate(&self, stream: &impl IsA, candidate: &str); + + #[cfg(any(feature = "v1_24", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_24")))] + #[doc(alias = "gst_webrtc_ice_add_candidate")] + fn add_candidate_full( + &self, + stream: &impl IsA, + candidate: &str, + promise: Option<&gst::Promise>, + ); +} + +impl> WebRTCICEExtManual for O { + fn add_candidate(&self, stream: &impl IsA, candidate: &str) { + #[cfg(not(feature = "v1_24"))] + unsafe { + use std::{mem, ptr}; + + if gst::version() < (1, 23, 0, 0) { + let func = mem::transmute::< + unsafe extern "C" fn( + *mut ffi::GstWebRTCICE, + *mut ffi::GstWebRTCICEStream, + *const std::os::raw::c_char, + *mut gst::ffi::GstPromise, + ), + unsafe extern "C" fn( + *mut ffi::GstWebRTCICE, + *mut ffi::GstWebRTCICEStream, + *const std::os::raw::c_char, + ), + >(ffi::gst_webrtc_ice_add_candidate); + func( + self.as_ref().to_glib_none().0, + stream.as_ref().to_glib_none().0, + candidate.to_glib_none().0, + ); + } else { + ffi::gst_webrtc_ice_add_candidate( + self.as_ref().to_glib_none().0, + stream.as_ref().to_glib_none().0, + candidate.to_glib_none().0, + ptr::null_mut(), + ); + } + } + #[cfg(feature = "v1_24")] + { + self.add_candidate_full(stream, candidate, None); + } + } + + #[cfg(any(feature = "v1_24", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_24")))] + fn add_candidate_full( + &self, + stream: &impl IsA, + candidate: &str, + promise: Option<&gst::Promise>, + ) { + unsafe { + ffi::gst_webrtc_ice_add_candidate( + self.as_ref().to_glib_none().0, + stream.as_ref().to_glib_none().0, + candidate.to_glib_none().0, + promise.to_glib_none().0, + ); + } + } +} diff --git a/gstreamer/Gir.toml b/gstreamer/Gir.toml index 2423fe6c3..a35795252 100644 --- a/gstreamer/Gir.toml +++ b/gstreamer/Gir.toml @@ -1238,6 +1238,15 @@ manual_traits = ["ElementExtManual"] # Needs integration into subclassing infrastructure ignore = true + [[object.function]] + name = "decorate_stream_id_printf" + # Varargs + ignore = true + [[object.function]] + name = "decorate_stream_id_printf_valist" + # Varargs + ignore = true + [[object]] name = "Gst.ElementFactory" status = "generate" diff --git a/gstreamer/src/element_factory_type.rs b/gstreamer/src/element_factory_type.rs index 23473e1bc..cb0c9cc47 100644 --- a/gstreamer/src/element_factory_type.rs +++ b/gstreamer/src/element_factory_type.rs @@ -32,6 +32,8 @@ bitflags! { const ENCRYPTOR = ffi::GST_ELEMENT_FACTORY_TYPE_ENCRYPTOR; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_HARDWARE")] const HARDWARE = ffi::GST_ELEMENT_FACTORY_TYPE_HARDWARE; + #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_TIMESTAMPER")] + const TIMESTAMPER = ffi::GST_ELEMENT_FACTORY_TYPE_TIMESTAMPER; #[doc(alias = "GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO")] const MEDIA_VIDEO = ffi::GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO;