diff --git a/gstreamer-video/Gir.toml b/gstreamer-video/Gir.toml index ecba6bff8..d7ddc8e64 100644 --- a/gstreamer-video/Gir.toml +++ b/gstreamer-video/Gir.toml @@ -20,6 +20,8 @@ generate = [ "GstVideo.ColorBalance", "GstVideo.ColorBalanceChannel", "GstVideo.ColorBalanceType", + "GstVideo.NavigationMessageType", + "GstVideo.NavigationQueryType", "GstVideo.VideoAFDSpec", "GstVideo.VideoAFDValue", "GstVideo.VideoAggregatorParallelConvertPad", @@ -84,6 +86,129 @@ name = "Gst.ClockTime" status = "manual" conversion_type = "Option" +[[object]] +name = "Gst.Event" +status = "manual" +ref_mode = "ref" + +[[object]] +name = "Gst.Query" +status = "manual" +ref_mode = "ref" + +[[object]] +name = "gst.Structure" +status = "manual" +ref_mode = "ref" + +[[object]] +name = "GstVideo.Navigation" +status = "generate" + [[object.function]] + name = "event_parse_key_event" + manual = true + + [[object.function]] + name = "send_event" + manual = true + + [[object.function]] + name = "event_parse_mouse_button_event" + manual = true + + [[object.function]] + name = "event_parse_mouse_move_event" + manual = true + + [[object.function]] + name = "event_parse_command" + manual = true + + [[object.function]] + name = "message_parse_event" + manual = true + + [[object.function]] + name = "message_get_type" + manual = true + + [[object.function]] + name = "message_new_event" + manual = true + + [[object.function]] + name = "event_parse_mouse_scroll_event" + manual = true + + [[object.function]] + name = "event_get_type" + manual = true + + + [[object.function]] + name = "message_new_commands_changed" + ignore = true + + [[object.function]] + name = "message_parse_angles_changed" + ignore = true + + [[object.function]] + name = "message_new_mouse_over" + ignore = true + + [[object.function]] + name = "message_parse_mouse_over" + ignore = true + + [[object.function]] + name = "message_new_angles_changed" + ignore = true + + [[object.function]] + name = "query_get_type" + ignore = true + + [[object.function]] + name = "query_new_angles" + ignore = true + + [[object.function]] + name = "query_new_commands" + ignore = true + + [[object.function]] + name = "query_parse_angles" + ignore = true + + [[object.function]] + name = "query_parse_commands_length" + ignore = true + + [[object.function]] + name = "query_parse_commands_nth" + ignore = true + + [[object.function]] + name = "query_set_angles" + ignore = true + +[[object]] +name = "GstVideo.NavigationCommand" +status = "generate" + [[object.derive]] + name = "serde::Serialize, serde::Deserialize" + cfg_condition = "feature = \"ser_de\"" + [[object.derive]] + name = "Debug, Eq, PartialEq, Ord, PartialOrd, Hash" + +[[object]] +name = "GstVideo.NavigationEventType" +status = "generate" + [[object.member]] + name = "mouse_scroll" + version = "1.18" + [[object]] name = "GstVideo.VideoBufferFlags" status = "generate" diff --git a/gstreamer-video/src/auto/enums.rs b/gstreamer-video/src/auto/enums.rs index 7a05ba005..5bdf64630 100644 --- a/gstreamer-video/src/auto/enums.rs +++ b/gstreamer-video/src/auto/enums.rs @@ -81,6 +81,382 @@ impl ToValue for ColorBalanceType { } } +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "GstNavigationCommand")] +pub enum NavigationCommand { + #[doc(alias = "GST_NAVIGATION_COMMAND_INVALID")] + Invalid, + #[doc(alias = "GST_NAVIGATION_COMMAND_MENU1")] + Menu1, + #[doc(alias = "GST_NAVIGATION_COMMAND_MENU2")] + Menu2, + #[doc(alias = "GST_NAVIGATION_COMMAND_MENU3")] + Menu3, + #[doc(alias = "GST_NAVIGATION_COMMAND_MENU4")] + Menu4, + #[doc(alias = "GST_NAVIGATION_COMMAND_MENU5")] + Menu5, + #[doc(alias = "GST_NAVIGATION_COMMAND_MENU6")] + Menu6, + #[doc(alias = "GST_NAVIGATION_COMMAND_MENU7")] + Menu7, + #[doc(alias = "GST_NAVIGATION_COMMAND_LEFT")] + Left, + #[doc(alias = "GST_NAVIGATION_COMMAND_RIGHT")] + Right, + #[doc(alias = "GST_NAVIGATION_COMMAND_UP")] + Up, + #[doc(alias = "GST_NAVIGATION_COMMAND_DOWN")] + Down, + #[doc(alias = "GST_NAVIGATION_COMMAND_ACTIVATE")] + Activate, + #[doc(alias = "GST_NAVIGATION_COMMAND_PREV_ANGLE")] + PrevAngle, + #[doc(alias = "GST_NAVIGATION_COMMAND_NEXT_ANGLE")] + NextAngle, + #[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl IntoGlib for NavigationCommand { + type GlibType = ffi::GstNavigationCommand; + + fn into_glib(self) -> ffi::GstNavigationCommand { + match self { + Self::Invalid => ffi::GST_NAVIGATION_COMMAND_INVALID, + Self::Menu1 => ffi::GST_NAVIGATION_COMMAND_MENU1, + Self::Menu2 => ffi::GST_NAVIGATION_COMMAND_MENU2, + Self::Menu3 => ffi::GST_NAVIGATION_COMMAND_MENU3, + Self::Menu4 => ffi::GST_NAVIGATION_COMMAND_MENU4, + Self::Menu5 => ffi::GST_NAVIGATION_COMMAND_MENU5, + Self::Menu6 => ffi::GST_NAVIGATION_COMMAND_MENU6, + Self::Menu7 => ffi::GST_NAVIGATION_COMMAND_MENU7, + Self::Left => ffi::GST_NAVIGATION_COMMAND_LEFT, + Self::Right => ffi::GST_NAVIGATION_COMMAND_RIGHT, + Self::Up => ffi::GST_NAVIGATION_COMMAND_UP, + Self::Down => ffi::GST_NAVIGATION_COMMAND_DOWN, + Self::Activate => ffi::GST_NAVIGATION_COMMAND_ACTIVATE, + Self::PrevAngle => ffi::GST_NAVIGATION_COMMAND_PREV_ANGLE, + Self::NextAngle => ffi::GST_NAVIGATION_COMMAND_NEXT_ANGLE, + Self::__Unknown(value) => value, + } + } +} + +#[doc(hidden)] +impl FromGlib for NavigationCommand { + unsafe fn from_glib(value: ffi::GstNavigationCommand) -> Self { + skip_assert_initialized!(); + match value { + ffi::GST_NAVIGATION_COMMAND_INVALID => Self::Invalid, + ffi::GST_NAVIGATION_COMMAND_MENU1 => Self::Menu1, + ffi::GST_NAVIGATION_COMMAND_MENU2 => Self::Menu2, + ffi::GST_NAVIGATION_COMMAND_MENU3 => Self::Menu3, + ffi::GST_NAVIGATION_COMMAND_MENU4 => Self::Menu4, + ffi::GST_NAVIGATION_COMMAND_MENU5 => Self::Menu5, + ffi::GST_NAVIGATION_COMMAND_MENU6 => Self::Menu6, + ffi::GST_NAVIGATION_COMMAND_MENU7 => Self::Menu7, + ffi::GST_NAVIGATION_COMMAND_LEFT => Self::Left, + ffi::GST_NAVIGATION_COMMAND_RIGHT => Self::Right, + ffi::GST_NAVIGATION_COMMAND_UP => Self::Up, + ffi::GST_NAVIGATION_COMMAND_DOWN => Self::Down, + ffi::GST_NAVIGATION_COMMAND_ACTIVATE => Self::Activate, + ffi::GST_NAVIGATION_COMMAND_PREV_ANGLE => Self::PrevAngle, + ffi::GST_NAVIGATION_COMMAND_NEXT_ANGLE => Self::NextAngle, + value => Self::__Unknown(value), + } + } +} + +impl StaticType for NavigationCommand { + fn static_type() -> Type { + unsafe { from_glib(ffi::gst_navigation_command_get_type()) } + } +} + +impl glib::value::ValueType for NavigationCommand { + type Type = Self; +} + +unsafe impl<'a> FromValue<'a> for NavigationCommand { + type Checker = glib::value::GenericValueTypeChecker; + + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) + } +} + +impl ToValue for NavigationCommand { + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "GstNavigationEventType")] +pub enum NavigationEventType { + #[doc(alias = "GST_NAVIGATION_EVENT_INVALID")] + Invalid, + #[doc(alias = "GST_NAVIGATION_EVENT_KEY_PRESS")] + KeyPress, + #[doc(alias = "GST_NAVIGATION_EVENT_KEY_RELEASE")] + KeyRelease, + #[doc(alias = "GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS")] + MouseButtonPress, + #[doc(alias = "GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE")] + MouseButtonRelease, + #[doc(alias = "GST_NAVIGATION_EVENT_MOUSE_MOVE")] + MouseMove, + #[doc(alias = "GST_NAVIGATION_EVENT_COMMAND")] + Command, + #[cfg(any(feature = "v1_18", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] + #[doc(alias = "GST_NAVIGATION_EVENT_MOUSE_SCROLL")] + MouseScroll, + #[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl IntoGlib for NavigationEventType { + type GlibType = ffi::GstNavigationEventType; + + fn into_glib(self) -> ffi::GstNavigationEventType { + match self { + Self::Invalid => ffi::GST_NAVIGATION_EVENT_INVALID, + Self::KeyPress => ffi::GST_NAVIGATION_EVENT_KEY_PRESS, + Self::KeyRelease => ffi::GST_NAVIGATION_EVENT_KEY_RELEASE, + Self::MouseButtonPress => ffi::GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS, + Self::MouseButtonRelease => ffi::GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE, + Self::MouseMove => ffi::GST_NAVIGATION_EVENT_MOUSE_MOVE, + Self::Command => ffi::GST_NAVIGATION_EVENT_COMMAND, + #[cfg(any(feature = "v1_18", feature = "dox"))] + Self::MouseScroll => ffi::GST_NAVIGATION_EVENT_MOUSE_SCROLL, + Self::__Unknown(value) => value, + } + } +} + +#[doc(hidden)] +impl FromGlib for NavigationEventType { + unsafe fn from_glib(value: ffi::GstNavigationEventType) -> Self { + skip_assert_initialized!(); + match value { + ffi::GST_NAVIGATION_EVENT_INVALID => Self::Invalid, + ffi::GST_NAVIGATION_EVENT_KEY_PRESS => Self::KeyPress, + ffi::GST_NAVIGATION_EVENT_KEY_RELEASE => Self::KeyRelease, + ffi::GST_NAVIGATION_EVENT_MOUSE_BUTTON_PRESS => Self::MouseButtonPress, + ffi::GST_NAVIGATION_EVENT_MOUSE_BUTTON_RELEASE => Self::MouseButtonRelease, + ffi::GST_NAVIGATION_EVENT_MOUSE_MOVE => Self::MouseMove, + ffi::GST_NAVIGATION_EVENT_COMMAND => Self::Command, + #[cfg(any(feature = "v1_18", feature = "dox"))] + ffi::GST_NAVIGATION_EVENT_MOUSE_SCROLL => Self::MouseScroll, + value => Self::__Unknown(value), + } + } +} + +impl StaticType for NavigationEventType { + fn static_type() -> Type { + unsafe { from_glib(ffi::gst_navigation_event_type_get_type()) } + } +} + +impl glib::value::ValueType for NavigationEventType { + type Type = Self; +} + +unsafe impl<'a> FromValue<'a> for NavigationEventType { + type Checker = glib::value::GenericValueTypeChecker; + + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) + } +} + +impl ToValue for NavigationEventType { + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "GstNavigationMessageType")] +pub enum NavigationMessageType { + #[doc(alias = "GST_NAVIGATION_MESSAGE_INVALID")] + Invalid, + #[doc(alias = "GST_NAVIGATION_MESSAGE_MOUSE_OVER")] + MouseOver, + #[doc(alias = "GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED")] + CommandsChanged, + #[doc(alias = "GST_NAVIGATION_MESSAGE_ANGLES_CHANGED")] + AnglesChanged, + #[doc(alias = "GST_NAVIGATION_MESSAGE_EVENT")] + Event, + #[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl IntoGlib for NavigationMessageType { + type GlibType = ffi::GstNavigationMessageType; + + fn into_glib(self) -> ffi::GstNavigationMessageType { + match self { + Self::Invalid => ffi::GST_NAVIGATION_MESSAGE_INVALID, + Self::MouseOver => ffi::GST_NAVIGATION_MESSAGE_MOUSE_OVER, + Self::CommandsChanged => ffi::GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED, + Self::AnglesChanged => ffi::GST_NAVIGATION_MESSAGE_ANGLES_CHANGED, + Self::Event => ffi::GST_NAVIGATION_MESSAGE_EVENT, + Self::__Unknown(value) => value, + } + } +} + +#[doc(hidden)] +impl FromGlib for NavigationMessageType { + unsafe fn from_glib(value: ffi::GstNavigationMessageType) -> Self { + skip_assert_initialized!(); + match value { + ffi::GST_NAVIGATION_MESSAGE_INVALID => Self::Invalid, + ffi::GST_NAVIGATION_MESSAGE_MOUSE_OVER => Self::MouseOver, + ffi::GST_NAVIGATION_MESSAGE_COMMANDS_CHANGED => Self::CommandsChanged, + ffi::GST_NAVIGATION_MESSAGE_ANGLES_CHANGED => Self::AnglesChanged, + ffi::GST_NAVIGATION_MESSAGE_EVENT => Self::Event, + value => Self::__Unknown(value), + } + } +} + +impl StaticType for NavigationMessageType { + fn static_type() -> Type { + unsafe { from_glib(ffi::gst_navigation_message_type_get_type()) } + } +} + +impl glib::value::ValueType for NavigationMessageType { + type Type = Self; +} + +unsafe impl<'a> FromValue<'a> for NavigationMessageType { + type Checker = glib::value::GenericValueTypeChecker; + + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) + } +} + +impl ToValue for NavigationMessageType { + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] +#[non_exhaustive] +#[doc(alias = "GstNavigationQueryType")] +pub enum NavigationQueryType { + #[doc(alias = "GST_NAVIGATION_QUERY_INVALID")] + Invalid, + #[doc(alias = "GST_NAVIGATION_QUERY_COMMANDS")] + Commands, + #[doc(alias = "GST_NAVIGATION_QUERY_ANGLES")] + Angles, + #[doc(hidden)] + __Unknown(i32), +} + +#[doc(hidden)] +impl IntoGlib for NavigationQueryType { + type GlibType = ffi::GstNavigationQueryType; + + fn into_glib(self) -> ffi::GstNavigationQueryType { + match self { + Self::Invalid => ffi::GST_NAVIGATION_QUERY_INVALID, + Self::Commands => ffi::GST_NAVIGATION_QUERY_COMMANDS, + Self::Angles => ffi::GST_NAVIGATION_QUERY_ANGLES, + Self::__Unknown(value) => value, + } + } +} + +#[doc(hidden)] +impl FromGlib for NavigationQueryType { + unsafe fn from_glib(value: ffi::GstNavigationQueryType) -> Self { + skip_assert_initialized!(); + match value { + ffi::GST_NAVIGATION_QUERY_INVALID => Self::Invalid, + ffi::GST_NAVIGATION_QUERY_COMMANDS => Self::Commands, + ffi::GST_NAVIGATION_QUERY_ANGLES => Self::Angles, + value => Self::__Unknown(value), + } + } +} + +impl StaticType for NavigationQueryType { + fn static_type() -> Type { + unsafe { from_glib(ffi::gst_navigation_query_type_get_type()) } + } +} + +impl glib::value::ValueType for NavigationQueryType { + type Type = Self; +} + +unsafe impl<'a> FromValue<'a> for NavigationQueryType { + type Checker = glib::value::GenericValueTypeChecker; + + unsafe fn from_value(value: &'a glib::Value) -> Self { + skip_assert_initialized!(); + from_glib(glib::gobject_ffi::g_value_get_enum(value.to_glib_none().0)) + } +} + +impl ToValue for NavigationQueryType { + fn to_value(&self) -> glib::Value { + let mut value = glib::Value::for_value_type::(); + unsafe { + glib::gobject_ffi::g_value_set_enum(value.to_glib_none_mut().0, self.into_glib()); + } + value + } + + fn value_type(&self) -> glib::Type { + Self::static_type() + } +} + #[cfg(any(feature = "v1_18", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] #[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone, Copy)] diff --git a/gstreamer-video/src/auto/mod.rs b/gstreamer-video/src/auto/mod.rs index ca2a10b66..793d6e747 100644 --- a/gstreamer-video/src/auto/mod.rs +++ b/gstreamer-video/src/auto/mod.rs @@ -9,6 +9,9 @@ pub use self::color_balance::ColorBalance; mod color_balance_channel; pub use self::color_balance_channel::ColorBalanceChannel; +mod navigation; +pub use self::navigation::Navigation; + #[cfg(any(feature = "v1_20", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_20")))] mod video_aggregator_parallel_convert_pad; @@ -39,6 +42,10 @@ pub use self::video_sink::VideoSink; mod enums; pub use self::enums::ColorBalanceType; +pub use self::enums::NavigationCommand; +pub use self::enums::NavigationEventType; +pub use self::enums::NavigationMessageType; +pub use self::enums::NavigationQueryType; #[cfg(any(feature = "v1_18", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] pub use self::enums::VideoAFDSpec; @@ -91,6 +98,7 @@ pub use self::flags::VideoTimeCodeFlags; pub mod traits { pub use super::color_balance::ColorBalanceExt; pub use super::color_balance_channel::ColorBalanceChannelExt; + pub use super::navigation::NavigationExt; pub use super::video_decoder::VideoDecoderExt; pub use super::video_encoder::VideoEncoderExt; pub use super::video_orientation::VideoOrientationExt; diff --git a/gstreamer-video/src/auto/navigation.rs b/gstreamer-video/src/auto/navigation.rs new file mode 100644 index 000000000..9eb56210b --- /dev/null +++ b/gstreamer-video/src/auto/navigation.rs @@ -0,0 +1,94 @@ +// This file was generated by gir (https://github.com/gtk-rs/gir) +// from gir-files (https://github.com/gtk-rs/gir-files) +// from gst-gir-files (https://gitlab.freedesktop.org/gstreamer/gir-files-rs.git) +// DO NOT EDIT + +use crate::NavigationCommand; +use glib::object::IsA; +use glib::translate::*; + +glib::wrapper! { + #[doc(alias = "GstNavigation")] + pub struct Navigation(Interface); + + match fn { + type_ => || ffi::gst_navigation_get_type(), + } +} + +impl Navigation { + pub const NONE: Option<&'static Navigation> = None; + + //#[doc(alias = "gst_navigation_query_set_commands")] + //pub fn query_set_commands(query: &gst::Query, n_cmds: i32, : /*Unknown conversion*//*Unimplemented*/Fundamental: VarArgs) { + // unsafe { TODO: call ffi:gst_navigation_query_set_commands() } + //} + + //#[doc(alias = "gst_navigation_query_set_commandsv")] + //pub fn query_set_commandsv(query: &gst::Query, cmds: /*Unimplemented*/&CArray TypeId { ns_id: 1, id: 6 }) { + // unsafe { TODO: call ffi:gst_navigation_query_set_commandsv() } + //} +} + +unsafe impl Send for Navigation {} +unsafe impl Sync for Navigation {} + +pub trait NavigationExt: 'static { + #[doc(alias = "gst_navigation_send_command")] + fn send_command(&self, command: NavigationCommand); + + #[doc(alias = "gst_navigation_send_key_event")] + fn send_key_event(&self, event: &str, key: &str); + + #[doc(alias = "gst_navigation_send_mouse_event")] + fn send_mouse_event(&self, event: &str, button: i32, x: f64, y: f64); + + #[cfg(any(feature = "v1_18", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] + #[doc(alias = "gst_navigation_send_mouse_scroll_event")] + fn send_mouse_scroll_event(&self, x: f64, y: f64, delta_x: f64, delta_y: f64); +} + +impl> NavigationExt for O { + fn send_command(&self, command: NavigationCommand) { + unsafe { + ffi::gst_navigation_send_command(self.as_ref().to_glib_none().0, command.into_glib()); + } + } + + fn send_key_event(&self, event: &str, key: &str) { + unsafe { + ffi::gst_navigation_send_key_event( + self.as_ref().to_glib_none().0, + event.to_glib_none().0, + key.to_glib_none().0, + ); + } + } + + fn send_mouse_event(&self, event: &str, button: i32, x: f64, y: f64) { + unsafe { + ffi::gst_navigation_send_mouse_event( + self.as_ref().to_glib_none().0, + event.to_glib_none().0, + button, + x, + y, + ); + } + } + + #[cfg(any(feature = "v1_18", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] + fn send_mouse_scroll_event(&self, x: f64, y: f64, delta_x: f64, delta_y: f64) { + unsafe { + ffi::gst_navigation_send_mouse_scroll_event( + self.as_ref().to_glib_none().0, + x, + y, + delta_x, + delta_y, + ); + } + } +} diff --git a/gstreamer-video/src/lib.rs b/gstreamer-video/src/lib.rs index 6cd578fd2..3dda050c5 100644 --- a/gstreamer-video/src/lib.rs +++ b/gstreamer-video/src/lib.rs @@ -30,6 +30,8 @@ macro_rules! skip_assert_initialized { mod auto; pub use crate::auto::*; +mod navigation; + mod caps_features; #[cfg(any(feature = "v1_16", feature = "dox"))] #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_16")))] @@ -54,10 +56,19 @@ pub mod video_frame; pub use crate::video_frame::{VideoFrame, VideoFrameRef}; mod video_overlay; pub use crate::video_overlay::is_video_overlay_prepare_window_handle_message; + pub mod video_event; +#[cfg(any(feature = "v1_18", feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] +pub use crate::video_event::MouseScrollEvent; pub use crate::video_event::{ - DownstreamForceKeyUnitEvent, ForceKeyUnitEvent, StillFrameEvent, UpstreamForceKeyUnitEvent, + CommandEvent, DownstreamForceKeyUnitEvent, ForceKeyUnitEvent, KeyEvent, MouseButtonEvent, + MouseMoveEvent, NavigationEvent, StillFrameEvent, UpstreamForceKeyUnitEvent, }; + +pub mod video_message; +pub use crate::video_message::{NavigationEventMessage, NavigationMessage}; + mod functions; pub use crate::functions::*; mod video_rectangle; @@ -126,6 +137,7 @@ pub mod prelude { pub use gst_base::prelude::*; pub use crate::auto::traits::*; + pub use crate::navigation::NavigationExtManual; pub use crate::video_buffer_pool::VideoBufferPoolConfig; pub use crate::video_decoder::VideoDecoderExtManual; pub use crate::video_encoder::VideoEncoderExtManual; diff --git a/gstreamer-video/src/navigation.rs b/gstreamer-video/src/navigation.rs new file mode 100644 index 000000000..95ff530d7 --- /dev/null +++ b/gstreamer-video/src/navigation.rs @@ -0,0 +1,16 @@ +use crate::auto::Navigation; +use glib::object::IsA; +use glib::translate::ToGlibPtr; + +pub trait NavigationExtManual: 'static { + #[doc(alias = "gst_navigation_send_event")] + fn send_event(&self, structure: gst::Structure); +} + +impl> NavigationExtManual for O { + fn send_event(&self, structure: gst::Structure) { + unsafe { + ffi::gst_navigation_send_event(self.as_ref().to_glib_none().0, structure.into_ptr()); + } + } +} diff --git a/gstreamer-video/src/subclass/mod.rs b/gstreamer-video/src/subclass/mod.rs index 3af535f67..52fba3b54 100644 --- a/gstreamer-video/src/subclass/mod.rs +++ b/gstreamer-video/src/subclass/mod.rs @@ -2,6 +2,7 @@ #![allow(clippy::cast_ptr_alignment)] +mod navigation; mod video_decoder; mod video_encoder; mod video_filter; @@ -11,6 +12,7 @@ pub mod prelude { #[doc(hidden)] pub use gst_base::subclass::prelude::*; + pub use super::navigation::NavigationImpl; pub use super::video_decoder::{VideoDecoderImpl, VideoDecoderImplExt}; pub use super::video_encoder::{VideoEncoderImpl, VideoEncoderImplExt}; pub use super::video_filter::{VideoFilterImpl, VideoFilterImplExt}; diff --git a/gstreamer-video/src/subclass/navigation.rs b/gstreamer-video/src/subclass/navigation.rs new file mode 100644 index 000000000..488f40bb6 --- /dev/null +++ b/gstreamer-video/src/subclass/navigation.rs @@ -0,0 +1,59 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use glib::prelude::*; +use glib::translate::*; + +use glib::subclass::prelude::*; + +use gst::ffi::GstStructure; + +use crate::Navigation; + +pub trait NavigationImpl: ObjectImpl { + fn send_event(&self, nav: &Self::Type, structure: gst::Structure); +} + +pub trait NavigationImplExt: ObjectSubclass { + fn parent_send_event(&self, nav: &Self::Type, structure: gst::Structure); +} + +impl NavigationImplExt for T { + fn parent_send_event(&self, nav: &Self::Type, structure: gst::Structure) { + unsafe { + let type_data = Self::type_data(); + let parent_iface = type_data.as_ref().parent_interface::() + as *const ffi::GstNavigationInterface; + + let func = match (*parent_iface).send_event { + Some(func) => func, + None => return, + }; + + func( + nav.unsafe_cast_ref::().to_glib_none().0, + structure.into_ptr(), + ); + } + } +} + +unsafe impl IsImplementable for Navigation { + fn interface_init(iface: &mut glib::Interface) { + let iface = iface.as_mut(); + + iface.send_event = Some(navigation_send_event::); + } +} + +unsafe extern "C" fn navigation_send_event( + nav: *mut ffi::GstNavigation, + structure: *mut GstStructure, +) { + let instance = &*(nav as *mut T::Instance); + let imp = instance.impl_(); + + imp.send_event( + from_glib_borrow::<_, Navigation>(nav).unsafe_cast_ref(), + from_glib_full(structure), + ); +} diff --git a/gstreamer-video/src/video_event.rs b/gstreamer-video/src/video_event.rs index 958db43ae..b2fc97fd0 100644 --- a/gstreamer-video/src/video_event.rs +++ b/gstreamer-video/src/video_event.rs @@ -1,8 +1,9 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use glib::translate::{from_glib, from_glib_full, IntoGlib}; +use crate::{NavigationCommand, NavigationEventType}; +use glib::translate::{from_glib, from_glib_none, from_glib_full, IntoGlib}; use glib::ToSendValue; -use std::mem; +use std::{mem, ptr}; // FIXME: Copy from gstreamer/src/event.rs macro_rules! event_builder_generic_impl { @@ -349,3 +350,213 @@ impl StillFrameEvent { } } } + +#[derive(Clone, PartialEq, Debug)] +pub struct KeyEvent { + pub key: String, +} + +impl KeyEvent { + #[doc(alias = "gst_navigation_event_parse_key_event")] + pub fn parse(event: &gst::EventRef) -> Result { + assert_initialized_main_thread!(); + unsafe { + let mut key = ptr::null(); + let ret = from_glib(ffi::gst_navigation_event_parse_key_event( + event.as_mut_ptr(), + &mut key, + )); + + if ret { + Ok(Self { + key: from_glib_none(key), + }) + } else { + Err(glib::bool_error!("Invalid key event")) + } + } + } +} + +#[derive(Clone, PartialEq, Debug)] +pub struct MouseButtonEvent { + pub button: i32, + pub x: f64, + pub y: f64, +} + +impl MouseButtonEvent { + #[doc(alias = "gst_navigation_event_parse_mouse_button_event")] + pub fn parse(event: &gst::EventRef) -> Result { + assert_initialized_main_thread!(); + unsafe { + let mut button = mem::MaybeUninit::uninit(); + let mut x = mem::MaybeUninit::uninit(); + let mut y = mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::gst_navigation_event_parse_mouse_button_event( + event.as_mut_ptr(), + button.as_mut_ptr(), + x.as_mut_ptr(), + y.as_mut_ptr(), + )); + let button = button.assume_init(); + let x = x.assume_init(); + let y = y.assume_init(); + if ret { + Ok(Self { button, x, y }) + } else { + Err(glib::bool_error!("Invalid mouse button event")) + } + } + } +} + +#[derive(Clone, PartialEq, Debug)] +pub struct MouseMoveEvent { + pub x: f64, + pub y: f64, +} + +impl MouseMoveEvent { + #[doc(alias = "gst_navigation_event_parse_mouse_move_event")] + pub fn parse(event: &gst::EventRef) -> Result { + assert_initialized_main_thread!(); + unsafe { + let mut x = mem::MaybeUninit::uninit(); + let mut y = mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::gst_navigation_event_parse_mouse_move_event( + event.as_mut_ptr(), + x.as_mut_ptr(), + y.as_mut_ptr(), + )); + let x = x.assume_init(); + let y = y.assume_init(); + if ret { + Ok(Self { x, y }) + } else { + Err(glib::bool_error!("Invalid mouse move event")) + } + } + } +} + +#[cfg(any(feature = "v1_18", feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] +#[derive(Clone, PartialEq, Debug)] +pub struct MouseScrollEvent { + pub x: f64, + pub y: f64, + pub delta_x: f64, + pub delta_y: f64, +} + +#[cfg(any(feature = "v1_18", feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] +impl MouseScrollEvent { + #[doc(alias = "gst_navigation_event_parse_mouse_scroll_event")] + pub fn parse(event: &gst::EventRef) -> Result { + assert_initialized_main_thread!(); + unsafe { + let mut x = mem::MaybeUninit::uninit(); + let mut y = mem::MaybeUninit::uninit(); + let mut delta_x = mem::MaybeUninit::uninit(); + let mut delta_y = mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::gst_navigation_event_parse_mouse_scroll_event( + event.as_mut_ptr(), + x.as_mut_ptr(), + y.as_mut_ptr(), + delta_x.as_mut_ptr(), + delta_y.as_mut_ptr(), + )); + let x = x.assume_init(); + let y = y.assume_init(); + let delta_x = delta_x.assume_init(); + let delta_y = delta_y.assume_init(); + if ret { + Ok(Self { + x, + y, + delta_x, + delta_y, + }) + } else { + Err(glib::bool_error!("Invalid mouse button event")) + } + } + } +} + +#[derive(Clone, PartialEq, Debug)] +pub struct CommandEvent { + cmd: NavigationCommand, +} + +impl CommandEvent { + #[doc(alias = "gst_navigation_event_parse_command")] + pub fn parse(event: &gst::EventRef) -> Result { + assert_initialized_main_thread!(); + unsafe { + let mut command = mem::MaybeUninit::uninit(); + let ret = from_glib(ffi::gst_navigation_event_parse_command( + event.as_mut_ptr(), + command.as_mut_ptr(), + )); + let command = command.assume_init(); + if ret { + Ok(Self { + cmd: from_glib(command), + }) + } else { + Err(glib::bool_error!("Invalid navigation command event")) + } + } + } +} + +#[derive(Clone, PartialEq, Debug)] +pub enum NavigationEvent { + KeyPress(KeyEvent), + KeyRelease(KeyEvent), + MouseMove(MouseMoveEvent), + MouseButtonPress(MouseButtonEvent), + MouseButtonRelease(MouseButtonEvent), + Command(CommandEvent), + #[cfg(any(feature = "v1_18", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] + MouseScroll(MouseScrollEvent), +} + +impl NavigationEvent { + #[doc(alias = "gst_navigation_event_get_type")] + pub fn type_(event: &gst::EventRef) -> NavigationEventType { + assert_initialized_main_thread!(); + unsafe { from_glib(ffi::gst_navigation_event_get_type(event.as_mut_ptr())) } + } + + pub fn parse(event: &gst::EventRef) -> Result { + skip_assert_initialized!(); + + let event_type: NavigationEventType = Self::type_(event); + + match event_type { + NavigationEventType::MouseMove => MouseMoveEvent::parse(event).map(Self::MouseMove), + NavigationEventType::KeyPress => KeyEvent::parse(event).map(Self::KeyPress), + NavigationEventType::KeyRelease => KeyEvent::parse(event).map(Self::KeyRelease), + #[cfg(any(feature = "v1_18", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_18")))] + NavigationEventType::MouseScroll => { + MouseScrollEvent::parse(event).map(Self::MouseScroll) + } + NavigationEventType::MouseButtonPress => { + MouseButtonEvent::parse(event).map(Self::MouseButtonPress) + } + NavigationEventType::MouseButtonRelease => { + MouseButtonEvent::parse(event).map(Self::MouseButtonRelease) + } + NavigationEventType::Command => CommandEvent::parse(event).map(Self::Command), + NavigationEventType::Invalid | NavigationEventType::__Unknown(_) => { + return Err(glib::bool_error!("Invalid navigation event")) + } + } + } +} diff --git a/gstreamer-video/src/video_message.rs b/gstreamer-video/src/video_message.rs new file mode 100644 index 000000000..0ebce8469 --- /dev/null +++ b/gstreamer-video/src/video_message.rs @@ -0,0 +1,215 @@ +// Take a look at the license at the top of the repository in the LICENSE file. + +use crate::NavigationMessageType; +use glib::translate::{from_glib, from_glib_full, IntoGlib, ToGlibPtr}; +#[cfg(any(feature = "v1_14", feature = "dox"))] +#[cfg_attr(feature = "dox", doc(cfg(feature = "v1_14")))] +use glib::ToSendValue; +use gst::ffi as gst_ffi; +use gst::{prelude::*, Message, Object, Seqnum}; +use std::ptr; + +macro_rules! message_builder_generic_impl { + ($new_fn:expr) => { + #[allow(clippy::needless_update)] + pub fn src + Cast + Clone>(self, src: &O) -> Self { + Self { + builder: self.builder.src(src), + ..self + } + } + + #[doc(alias = "gst_message_set_seqnum")] + #[allow(clippy::needless_update)] + pub fn seqnum(self, seqnum: Seqnum) -> Self { + Self { + builder: self.builder.seqnum(seqnum), + ..self + } + } + + #[cfg(any(feature = "v1_14", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_14")))] + #[allow(clippy::needless_update)] + pub fn other_fields( + self, + other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))], + ) -> Self { + Self { + builder: self.builder.other_fields(other_fields), + ..self + } + } + + #[must_use = "Building the message without using it has no effect"] + pub fn build(mut self) -> Message { + assert_initialized_main_thread!(); + unsafe { + let src = self.builder.src.to_glib_none().0; + let msg = $new_fn(&mut self, src); + if let Some(seqnum) = self.builder.seqnum { + gst_ffi::gst_message_set_seqnum(msg, seqnum.into_glib()); + } + + #[cfg(any(feature = "v1_14", feature = "dox"))] + if !self.builder.other_fields.is_empty() { + let structure = gst_ffi::gst_message_writable_structure(msg); + + if !structure.is_null() { + let structure = + gst::StructureRef::from_glib_borrow_mut(structure as *mut _); + + for (k, v) in self.builder.other_fields { + structure.set_value(k, v.to_send_value()); + } + } + } + + from_glib_full(msg) + } + } + }; +} + +struct MessageBuilder<'a> { + pub src: Option, + pub seqnum: Option, + #[allow(unused)] + pub other_fields: Vec<(&'a str, &'a (dyn ToSendValue + Sync))>, +} + +impl<'a> MessageBuilder<'a> { + pub fn new() -> Self { + assert_initialized_main_thread!(); + Self { + src: None, + seqnum: None, + other_fields: Vec::new(), + } + } + + pub fn src + Cast + Clone>(self, src: &O) -> Self { + Self { + src: Some(src.clone().upcast::()), + ..self + } + } + + pub fn seqnum(self, seqnum: Seqnum) -> Self { + Self { + seqnum: Some(seqnum), + ..self + } + } + + #[cfg(any(feature = "v1_14", feature = "dox"))] + #[cfg_attr(feature = "dox", doc(cfg(feature = "v1_14")))] + pub fn other_fields(self, other_fields: &[(&'a str, &'a (dyn ToSendValue + Sync))]) -> Self { + Self { + other_fields: self + .other_fields + .iter() + .cloned() + .chain(other_fields.iter().cloned()) + .collect(), + ..self + } + } +} + +#[must_use = "The builder must be built to be used"] +pub struct NavigationEventMessageBuilder<'a> { + builder: MessageBuilder<'a>, + event: gst::Event, +} + +impl<'a> NavigationEventMessageBuilder<'a> { + fn new(event: gst::Event) -> Self { + skip_assert_initialized!(); + Self { + builder: MessageBuilder::new(), + event, + } + } + + message_builder_generic_impl!(|s: &Self, src| ffi::gst_navigation_message_new_event( + src, + s.event.to_glib_none().0 + )); +} + +#[derive(Clone, Debug)] +pub struct NavigationEventMessage { + pub event: gst::Event, +} + +impl PartialEq for NavigationEventMessage { + fn eq(&self, other: &Self) -> bool { + unsafe { self.event.as_ptr() == other.event.as_ptr() } + } +} + +impl Eq for NavigationEventMessage {} + +impl NavigationEventMessage { + #[doc(alias = "gst_navigation_message_new_event")] + #[allow(clippy::new_ret_no_self)] + pub fn new(event: gst::Event) -> gst::Message { + assert_initialized_main_thread!(); + NavigationEventMessageBuilder::new(event).build() + } + + pub fn builder<'a>(event: gst::Event) -> NavigationEventMessageBuilder<'a> { + assert_initialized_main_thread!(); + NavigationEventMessageBuilder::new(event) + } + + #[doc(alias = "gst_navigation_message_parse_event")] + pub fn parse(msg: &gst::MessageRef) -> Result { + assert_initialized_main_thread!(); + unsafe { + let mut event = ptr::null_mut(); + let ret = from_glib(ffi::gst_navigation_message_parse_event( + msg.as_mut_ptr(), + &mut event, + )); + if ret { + Ok(Self { + event: from_glib_full(event), + }) + } else { + Err(glib::bool_error!("Invalid navigation event msg")) + } + } + } +} + +#[derive(Clone, PartialEq, Debug)] +pub enum NavigationMessage { + Event(NavigationEventMessage), +} + +impl NavigationMessage { + #[doc(alias = "gst_navigation_message_get_type")] + pub fn type_(msg: &gst::MessageRef) -> NavigationMessageType { + assert_initialized_main_thread!(); + unsafe { from_glib(ffi::gst_navigation_message_get_type(msg.as_mut_ptr())) } + } + + #[doc(alias = "gst_navigation_message_parse_event")] + pub fn parse(msg: &gst::MessageRef) -> Result { + skip_assert_initialized!(); + + let event_type: NavigationMessageType = Self::type_(msg); + + match event_type { + NavigationMessageType::Event => NavigationEventMessage::parse(msg).map(Self::Event), + _ => { + return Err(glib::bool_error!( + "Unsupported navigation msg {:?}", + event_type + )) + } + } + } +}