gstreamer-rs/gstreamer-rtsp-server/src/subclass/rtsp_media.rs
Bilal Elmoussaoui 4ebec84f5e Adapt to no longer renamed ffi crates
Allows us to set all the crates in the main workspace file, so changing
their versions or branch is much simpler and reduce the amount of noise
in the diff

Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1450>
2024-06-02 11:20:55 +02:00

662 lines
20 KiB
Rust

// Take a look at the license at the top of the repository in the LICENSE file.
use std::ptr;
use glib::{prelude::*, subclass::prelude::*, translate::*};
use crate::{ffi, RTSPMedia, RTSPThread};
#[derive(Debug)]
pub struct SDPInfo(ptr::NonNull<ffi::GstSDPInfo>);
impl SDPInfo {
pub fn is_ipv6(&self) -> bool {
unsafe { from_glib(self.0.as_ref().is_ipv6) }
}
pub fn server_ip(&self) -> &str {
unsafe {
use std::ffi::CStr;
CStr::from_ptr(self.0.as_ref().server_ip).to_str().unwrap()
}
}
}
pub trait RTSPMediaImpl: RTSPMediaImplExt + ObjectImpl + Send + Sync {
fn handle_message(&self, message: &gst::MessageRef) -> bool {
self.parent_handle_message(message)
}
fn prepare(&self, thread: &RTSPThread) -> Result<(), gst::LoggableError> {
self.parent_prepare(thread)
}
fn unprepare(&self) -> Result<(), gst::LoggableError> {
self.parent_unprepare()
}
fn suspend(&self) -> Result<(), gst::LoggableError> {
self.parent_suspend()
}
fn unsuspend(&self) -> Result<(), gst::LoggableError> {
self.parent_unsuspend()
}
// TODO missing: convert_range
fn query_position(&self) -> Option<gst::ClockTime> {
self.parent_query_position()
}
fn query_stop(&self) -> Option<gst::ClockTime> {
self.parent_query_stop()
}
fn create_rtpbin(&self) -> Option<gst::Element> {
self.parent_create_rtpbin()
}
fn setup_rtpbin(&self, rtpbin: &gst::Element) -> Result<(), gst::LoggableError> {
self.parent_setup_rtpbin(rtpbin)
}
fn setup_sdp(
&self,
sdp: &mut gst_sdp::SDPMessageRef,
info: &SDPInfo,
) -> Result<(), gst::LoggableError> {
self.parent_setup_sdp(sdp, info)
}
fn new_stream(&self, stream: &crate::RTSPStream) {
self.parent_new_stream(stream);
}
fn removed_stream(&self, stream: &crate::RTSPStream) {
self.parent_removed_stream(stream);
}
fn prepared(&self) {
self.parent_prepared();
}
fn unprepared(&self) {
self.parent_unprepared();
}
fn target_state(&self, state: gst::State) {
self.parent_target_state(state);
}
fn new_state(&self, state: gst::State) {
self.parent_new_state(state);
}
fn handle_sdp(&self, sdp: &gst_sdp::SDPMessageRef) -> Result<(), gst::LoggableError> {
self.parent_handle_sdp(sdp)
}
}
mod sealed {
pub trait Sealed {}
impl<T: super::RTSPMediaImplExt> Sealed for T {}
}
pub trait RTSPMediaImplExt: sealed::Sealed + ObjectSubclass {
fn parent_handle_message(&self, message: &gst::MessageRef) -> bool {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).handle_message {
from_glib(f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
message.as_ptr() as *mut _,
))
} else {
false
}
}
}
fn parent_prepare(&self, thread: &RTSPThread) -> Result<(), gst::LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).prepare {
gst::result_from_gboolean!(
f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
thread.to_glib_none().0
),
gst::CAT_RUST,
"Parent function `prepare` failed"
)
} else {
Ok(())
}
}
}
fn parent_unprepare(&self) -> Result<(), gst::LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).unprepare {
gst::result_from_gboolean!(
f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0),
gst::CAT_RUST,
"Parent function `unprepare` failed"
)
} else {
Ok(())
}
}
}
fn parent_suspend(&self) -> Result<(), gst::LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).suspend {
gst::result_from_gboolean!(
f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0),
gst::CAT_RUST,
"Parent function `suspend` failed"
)
} else {
Ok(())
}
}
}
fn parent_unsuspend(&self) -> Result<(), gst::LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).unsuspend {
gst::result_from_gboolean!(
f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0),
gst::CAT_RUST,
"Parent function `unsuspend` failed"
)
} else {
Ok(())
}
}
}
// TODO missing: convert_range
fn parent_query_position(&self) -> Option<gst::ClockTime> {
unsafe {
use std::mem;
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).query_position {
let mut position = mem::MaybeUninit::uninit();
if f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
position.as_mut_ptr(),
) == glib::ffi::GFALSE
{
None
} else {
from_glib(position.assume_init() as u64)
}
} else {
None
}
}
}
fn parent_query_stop(&self) -> Option<gst::ClockTime> {
unsafe {
use std::mem;
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).query_stop {
let mut stop = mem::MaybeUninit::uninit();
if f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
stop.as_mut_ptr(),
) == glib::ffi::GFALSE
{
None
} else {
from_glib(stop.assume_init() as u64)
}
} else {
None
}
}
}
fn parent_create_rtpbin(&self) -> Option<gst::Element> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
let f = (*parent_class)
.create_rtpbin
.expect("No `create_rtpbin` virtual method implementation in parent class");
from_glib_none(f(self
.obj()
.unsafe_cast_ref::<RTSPMedia>()
.to_glib_none()
.0))
}
}
fn parent_setup_rtpbin(&self, rtpbin: &gst::Element) -> Result<(), gst::LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).setup_rtpbin {
let ptr = rtpbin.to_glib_none().0;
// The C code assumes to pass a floating reference around so let's make sure we do
glib::gobject_ffi::g_object_force_floating(ptr as *mut _);
let res = gst::result_from_gboolean!(
f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
ptr
),
gst::CAT_RUST,
"Parent function `setup_sdp` failed"
);
// If the code didn't accidentally sink it then we have to do that
// here now so that we don't have any floating reference on our side
// anymore
if glib::gobject_ffi::g_object_is_floating(ptr as *mut _) != glib::ffi::GFALSE {
glib::gobject_ffi::g_object_ref_sink(ptr as *mut _);
}
res
} else {
Ok(())
}
}
}
fn parent_setup_sdp(
&self,
sdp: &mut gst_sdp::SDPMessageRef,
info: &SDPInfo,
) -> Result<(), gst::LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
let f = (*parent_class)
.setup_sdp
.expect("No `setup_sdp` virtual method implementation in parent class");
gst::result_from_gboolean!(
f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
sdp as *mut _ as *mut gst_sdp::ffi::GstSDPMessage,
info.0.as_ptr()
),
gst::CAT_RUST,
"Parent function `setup_sdp` failed"
)
}
}
fn parent_new_stream(&self, stream: &crate::RTSPStream) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).new_stream {
f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
stream.to_glib_none().0,
);
}
}
}
fn parent_removed_stream(&self, stream: &crate::RTSPStream) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).removed_stream {
f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
stream.to_glib_none().0,
);
}
}
}
fn parent_prepared(&self) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).prepared {
f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0);
}
}
}
fn parent_unprepared(&self) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).unprepared {
f(self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0);
}
}
}
fn parent_target_state(&self, state: gst::State) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).target_state {
f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
state.into_glib(),
);
}
}
}
fn parent_new_state(&self, state: gst::State) {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
if let Some(f) = (*parent_class).new_state {
f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
state.into_glib(),
);
}
}
}
fn parent_handle_sdp(&self, sdp: &gst_sdp::SDPMessageRef) -> Result<(), gst::LoggableError> {
unsafe {
let data = Self::type_data();
let parent_class = data.as_ref().parent_class() as *mut ffi::GstRTSPMediaClass;
let f = (*parent_class)
.handle_sdp
.expect("No `handle_sdp` virtual method implementation in parent class");
gst::result_from_gboolean!(
f(
self.obj().unsafe_cast_ref::<RTSPMedia>().to_glib_none().0,
sdp as *const _ as *mut gst_sdp::ffi::GstSDPMessage
),
gst::CAT_RUST,
"Parent function `handle_sdp` failed"
)
}
}
}
impl<T: RTSPMediaImpl> RTSPMediaImplExt for T {}
unsafe impl<T: RTSPMediaImpl> IsSubclassable<T> for RTSPMedia {
fn class_init(klass: &mut glib::Class<Self>) {
Self::parent_class_init::<T>(klass);
let klass = klass.as_mut();
klass.handle_message = Some(media_handle_message::<T>);
klass.prepare = Some(media_prepare::<T>);
klass.unprepare = Some(media_unprepare::<T>);
klass.suspend = Some(media_suspend::<T>);
klass.unsuspend = Some(media_unsuspend::<T>);
klass.query_position = Some(media_query_position::<T>);
klass.query_stop = Some(media_query_stop::<T>);
klass.create_rtpbin = Some(media_create_rtpbin::<T>);
klass.setup_rtpbin = Some(media_setup_rtpbin::<T>);
klass.setup_sdp = Some(media_setup_sdp::<T>);
klass.new_stream = Some(media_new_stream::<T>);
klass.removed_stream = Some(media_removed_stream::<T>);
klass.prepared = Some(media_prepared::<T>);
klass.unprepared = Some(media_unprepared::<T>);
klass.target_state = Some(media_target_state::<T>);
klass.new_state = Some(media_new_state::<T>);
klass.handle_sdp = Some(media_handle_sdp::<T>);
}
}
unsafe extern "C" fn media_handle_message<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
message: *mut gst::ffi::GstMessage,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.handle_message(gst::MessageRef::from_ptr(message))
.into_glib()
}
unsafe extern "C" fn media_prepare<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
thread: *mut ffi::GstRTSPThread,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.prepare(&from_glib_borrow(thread)) {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
err.log_with_imp(imp);
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn media_unprepare<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.unprepare() {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
err.log_with_imp(imp);
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn media_suspend<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.suspend() {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
err.log_with_imp(imp);
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn media_unsuspend<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.unsuspend() {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
err.log_with_imp(imp);
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn media_query_position<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
position: *mut i64,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.query_position() {
Some(pos) => {
*position = pos.into_glib() as i64;
glib::ffi::GTRUE
}
None => glib::ffi::GFALSE,
}
}
unsafe extern "C" fn media_query_stop<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
stop: *mut i64,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.query_stop() {
Some(s) => {
*stop = s.into_glib() as i64;
glib::ffi::GTRUE
}
None => glib::ffi::GFALSE,
}
}
unsafe extern "C" fn media_create_rtpbin<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
) -> *mut gst::ffi::GstElement {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
let res: *mut gst::ffi::GstElement = imp.create_rtpbin().into_glib_ptr();
if !res.is_null() {
glib::gobject_ffi::g_object_force_floating(res as *mut _);
}
res
}
unsafe extern "C" fn media_setup_rtpbin<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
rtpbin: *mut gst::ffi::GstElement,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
// If the rtpbin was floating before make sure it is not anymore for now so
// we don't accidentally take ownership of it somewhere along the line
if glib::gobject_ffi::g_object_is_floating(rtpbin as *mut _) != glib::ffi::GFALSE {
glib::gobject_ffi::g_object_ref_sink(rtpbin as *mut _);
}
let res = match imp.setup_rtpbin(&from_glib_borrow(rtpbin)) {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
err.log_with_imp(imp);
glib::ffi::GFALSE
}
};
// Ensure that the rtpbin is still floating afterwards here
glib::gobject_ffi::g_object_force_floating(rtpbin as *mut _);
res
}
unsafe extern "C" fn media_setup_sdp<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
sdp: *mut gst_sdp::ffi::GstSDPMessage,
info: *mut ffi::GstSDPInfo,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.setup_sdp(
&mut *(sdp as *mut gst_sdp::SDPMessageRef),
&SDPInfo(ptr::NonNull::new(info).expect("NULL SDPInfo")),
) {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
err.log_with_imp(imp);
glib::ffi::GFALSE
}
}
}
unsafe extern "C" fn media_new_stream<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
stream: *mut ffi::GstRTSPStream,
) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.new_stream(&from_glib_borrow(stream));
}
unsafe extern "C" fn media_removed_stream<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
stream: *mut ffi::GstRTSPStream,
) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.removed_stream(&from_glib_borrow(stream));
}
unsafe extern "C" fn media_prepared<T: RTSPMediaImpl>(ptr: *mut ffi::GstRTSPMedia) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.prepared();
}
unsafe extern "C" fn media_unprepared<T: RTSPMediaImpl>(ptr: *mut ffi::GstRTSPMedia) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.unprepared();
}
unsafe extern "C" fn media_target_state<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
state: gst::ffi::GstState,
) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.target_state(from_glib(state));
}
unsafe extern "C" fn media_new_state<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
state: gst::ffi::GstState,
) {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
imp.new_state(from_glib(state));
}
unsafe extern "C" fn media_handle_sdp<T: RTSPMediaImpl>(
ptr: *mut ffi::GstRTSPMedia,
sdp: *mut gst_sdp::ffi::GstSDPMessage,
) -> glib::ffi::gboolean {
let instance = &*(ptr as *mut T::Instance);
let imp = instance.imp();
match imp.handle_sdp(&*(sdp as *const gst_sdp::SDPMessageRef)) {
Ok(()) => glib::ffi::GTRUE,
Err(err) => {
err.log_with_imp(imp);
glib::ffi::GFALSE
}
}
}