gstreamer-rs/gstreamer-rtsp-server/src/subclass/rtsp_media.rs

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::{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
}
}
}