mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer-rs.git
synced 2024-12-18 22:26:32 +00:00
play: Improve API of PlayMessage
This is closer to the gst::Message API now, exposes all fields of the different message types and also allows for extensions with more fields later without breaking API. Because of https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/7754 the fields are read directly from the structure instead of going via the parsing functions. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer-rs/-/merge_requests/1577>
This commit is contained in:
parent
0b1be11789
commit
75095b03ec
3 changed files with 353 additions and 73 deletions
|
@ -24,12 +24,12 @@ fn main_loop(uri: &str) -> Result<(), Error> {
|
|||
let mut result = Ok(());
|
||||
for msg in play.message_bus().iter_timed(gst::ClockTime::NONE) {
|
||||
match PlayMessage::parse(&msg) {
|
||||
Ok(PlayMessage::EndOfStream) => {
|
||||
Ok(PlayMessage::EndOfStream(_)) => {
|
||||
play.stop();
|
||||
break;
|
||||
}
|
||||
Ok(PlayMessage::Error { error, details: _ }) => {
|
||||
result = Err(error);
|
||||
Ok(PlayMessage::Error(msg)) => {
|
||||
result = Err(msg.error().clone());
|
||||
play.stop();
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ macro_rules! assert_initialized_main_thread {
|
|||
}
|
||||
|
||||
#[allow(clippy::needless_borrow)]
|
||||
#[allow(unused)]
|
||||
mod auto;
|
||||
pub(crate) use crate::auto::PlayMessage as PlayMessageType;
|
||||
pub use crate::auto::*;
|
||||
|
@ -37,7 +38,7 @@ mod play_signal_adapter;
|
|||
mod play_video_overlay_video_renderer;
|
||||
mod play_visualization;
|
||||
|
||||
mod play_message;
|
||||
pub mod play_message;
|
||||
pub use crate::play_message::PlayMessage;
|
||||
|
||||
// Re-export all the traits in a prelude module, so that applications
|
||||
|
|
|
@ -1,47 +1,351 @@
|
|||
use crate::{PlayMediaInfo, PlayMessageType, PlayState};
|
||||
use crate::{Play, PlayMediaInfo, PlayMessageType, PlayState};
|
||||
|
||||
#[derive(Clone, PartialEq, Debug)]
|
||||
#[derive(Debug)]
|
||||
#[non_exhaustive]
|
||||
#[doc(alias = "GstPlayMessage")]
|
||||
pub enum PlayMessage {
|
||||
pub enum PlayMessage<'a> {
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_URI_LOADED")]
|
||||
UriLoaded,
|
||||
UriLoaded(&'a UriLoaded),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_POSITION_UPDATED")]
|
||||
PositionUpdated { position: Option<gst::ClockTime> },
|
||||
PositionUpdated(&'a PositionUpdated),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_DURATION_CHANGED")]
|
||||
DurationChanged { duration: Option<gst::ClockTime> },
|
||||
DurationChanged(&'a DurationChanged),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_STATE_CHANGED")]
|
||||
StateChanged { state: PlayState },
|
||||
StateChanged(&'a StateChanged),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_BUFFERING")]
|
||||
Buffering { percent: u32 },
|
||||
Buffering(&'a Buffering),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_END_OF_STREAM")]
|
||||
EndOfStream,
|
||||
EndOfStream(&'a EndOfStream),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_ERROR")]
|
||||
Error {
|
||||
error: glib::Error,
|
||||
details: Option<gst::Structure>,
|
||||
},
|
||||
Error(&'a Error),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_WARNING")]
|
||||
Warning {
|
||||
error: glib::Error,
|
||||
details: Option<gst::Structure>,
|
||||
},
|
||||
Warning(&'a Warning),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_VIDEO_DIMENSIONS_CHANGED")]
|
||||
VideoDimensionsChanged { width: u32, height: u32 },
|
||||
VideoDimensionsChanged(&'a VideoDimensionsChanged),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_MEDIA_INFO_UPDATED")]
|
||||
MediaInfoUpdated { info: PlayMediaInfo },
|
||||
MediaInfoUpdated(&'a MediaInfoUpdated),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_VOLUME_CHANGED")]
|
||||
VolumeChanged { volume: f64 },
|
||||
VolumeChanged(&'a VolumeChanged),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_MUTE_CHANGED")]
|
||||
MuteChanged { muted: bool },
|
||||
MuteChanged(&'a MuteChanged),
|
||||
#[doc(alias = "GST_PLAY_MESSAGE_SEEK_DONE")]
|
||||
SeekDone,
|
||||
SeekDone(&'a SeekDone),
|
||||
Other(&'a Other),
|
||||
}
|
||||
|
||||
impl PlayMessage {
|
||||
macro_rules! declare_concrete_message(
|
||||
($name:ident) => {
|
||||
#[repr(transparent)]
|
||||
pub struct $name<T = gst::MessageRef>(T);
|
||||
|
||||
impl $name {
|
||||
#[inline]
|
||||
pub fn message(&self) -> &gst::MessageRef {
|
||||
unsafe { &*(self as *const Self as *const gst::MessageRef) }
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn view(message: &gst::MessageRef) -> PlayMessage<'_> {
|
||||
let message = &*(message as *const gst::MessageRef as *const Self);
|
||||
PlayMessage::$name(message)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for $name {
|
||||
type Target = gst::MessageRef;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe {
|
||||
&*(self as *const Self as *const Self::Target)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToOwned for $name {
|
||||
type Owned = $name<gst::Message>;
|
||||
|
||||
#[inline]
|
||||
fn to_owned(&self) -> Self::Owned {
|
||||
$name::<gst::Message>(self.copy())
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for $name<gst::Message> {
|
||||
type Target = $name;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
unsafe { &*(self.0.as_ptr() as *const Self::Target) }
|
||||
}
|
||||
}
|
||||
|
||||
impl std::borrow::Borrow<$name> for $name<gst::Message> {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &$name {
|
||||
&*self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<$name<gst::Message>> for gst::Message {
|
||||
#[inline]
|
||||
fn from(concrete: $name<gst::Message>) -> Self {
|
||||
skip_assert_initialized!();
|
||||
concrete.0
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
declare_concrete_message!(UriLoaded);
|
||||
impl UriLoaded {
|
||||
pub fn uri(&self) -> &glib::GStr {
|
||||
self.message().structure().unwrap().get("uri").unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for UriLoaded {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("UriLoaded")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("uri", &self.uri())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(PositionUpdated);
|
||||
impl PositionUpdated {
|
||||
pub fn position(&self) -> Option<gst::ClockTime> {
|
||||
self.message().structure().unwrap().get("position").unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for PositionUpdated {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("PositionUpdated")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("position", &self.position())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(DurationChanged);
|
||||
impl DurationChanged {
|
||||
pub fn duration(&self) -> Option<gst::ClockTime> {
|
||||
self.message().structure().unwrap().get("duration").unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for DurationChanged {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("DurationChanged")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("duration", &self.duration())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(StateChanged);
|
||||
impl StateChanged {
|
||||
pub fn state(&self) -> PlayState {
|
||||
self.message()
|
||||
.structure()
|
||||
.unwrap()
|
||||
.get("play-state")
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for StateChanged {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("StateChanged")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("state", &self.state())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(Buffering);
|
||||
impl Buffering {
|
||||
pub fn percent(&self) -> u32 {
|
||||
self.message()
|
||||
.structure()
|
||||
.unwrap()
|
||||
// Typo in the library
|
||||
.get("bufferring-percent")
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for Buffering {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Buffering")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("percent", &self.percent())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(EndOfStream);
|
||||
impl std::fmt::Debug for EndOfStream {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("EndOfStream")
|
||||
.field("structure", &self.message().structure())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(Error);
|
||||
impl Error {
|
||||
pub fn error(&self) -> &glib::Error {
|
||||
self.message().structure().unwrap().get("error").unwrap()
|
||||
}
|
||||
|
||||
pub fn details(&self) -> Option<&gst::StructureRef> {
|
||||
self.message()
|
||||
.structure()
|
||||
.unwrap()
|
||||
.get_optional("error-details")
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Error")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("error", &self.error())
|
||||
.field("details", &self.details())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(Warning);
|
||||
impl Warning {
|
||||
pub fn error(&self) -> &glib::Error {
|
||||
self.message().structure().unwrap().get("warning").unwrap()
|
||||
}
|
||||
|
||||
pub fn details(&self) -> Option<&gst::StructureRef> {
|
||||
self.message()
|
||||
.structure()
|
||||
.unwrap()
|
||||
.get_optional("warning-details")
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for Warning {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Warning")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("error", &self.error())
|
||||
.field("details", &self.details())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(VideoDimensionsChanged);
|
||||
impl VideoDimensionsChanged {
|
||||
pub fn width(&self) -> u32 {
|
||||
self.message()
|
||||
.structure()
|
||||
.unwrap()
|
||||
.get("video-width")
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
pub fn height(&self) -> u32 {
|
||||
self.message()
|
||||
.structure()
|
||||
.unwrap()
|
||||
.get("video-height")
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for VideoDimensionsChanged {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("VideoDimensionsChanged")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("width", &self.width())
|
||||
.field("height", &self.height())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(MediaInfoUpdated);
|
||||
impl MediaInfoUpdated {
|
||||
pub fn media_info(&self) -> &PlayMediaInfo {
|
||||
self.message()
|
||||
.structure()
|
||||
.unwrap()
|
||||
.get("media-info")
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for MediaInfoUpdated {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("MediaInfoUpdated")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("media_info", &self.media_info())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(VolumeChanged);
|
||||
impl VolumeChanged {
|
||||
pub fn volume(&self) -> f64 {
|
||||
self.message().structure().unwrap().get("volume").unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for VolumeChanged {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("VolumeChanged")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("volume", &self.volume())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(MuteChanged);
|
||||
impl MuteChanged {
|
||||
pub fn is_muted(&self) -> bool {
|
||||
self.message().structure().unwrap().get("is-muted").unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for MuteChanged {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("MuteChanged")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("is_muted", &self.is_muted())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(SeekDone);
|
||||
impl SeekDone {
|
||||
pub fn position(&self) -> Option<gst::ClockTime> {
|
||||
self.message().structure().unwrap().get("position").unwrap()
|
||||
}
|
||||
}
|
||||
impl std::fmt::Debug for SeekDone {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SeekDone")
|
||||
.field("structure", &self.message().structure())
|
||||
.field("position", &self.position())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
declare_concrete_message!(Other);
|
||||
impl std::fmt::Debug for Other {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("Other")
|
||||
.field("structure", &self.message().structure())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PlayMessage<'a> {
|
||||
#[doc(alias = "gst_play_message_parse_uri_loaded")]
|
||||
#[doc(alias = "gst_play_message_parse_position_updated")]
|
||||
#[doc(alias = "gst_play_message_parse_duration_updated")]
|
||||
#[doc(alias = "gst_play_message_parse_duration_changed")]
|
||||
#[doc(alias = "gst_play_message_parse_state_changed")]
|
||||
#[doc(alias = "gst_play_message_parse_buffering")]
|
||||
#[doc(alias = "gst_play_message_parse_buffering_percent")]
|
||||
#[doc(alias = "gst_play_message_parse_error")]
|
||||
#[doc(alias = "gst_play_message_parse_warning")]
|
||||
|
@ -49,56 +353,31 @@ impl PlayMessage {
|
|||
#[doc(alias = "gst_play_message_parse_media_info_updated")]
|
||||
#[doc(alias = "gst_play_message_parse_muted_changed")]
|
||||
#[doc(alias = "gst_play_message_parse_volume_changed")]
|
||||
pub fn parse(msg: &gst::Message) -> Result<Self, glib::error::BoolError> {
|
||||
#[doc(alias = "gst_play_message_parse_seek_done")]
|
||||
pub fn parse(msg: &gst::Message) -> Result<PlayMessage, glib::error::BoolError> {
|
||||
skip_assert_initialized!();
|
||||
if msg.type_() != gst::MessageType::Application {
|
||||
|
||||
if !Play::is_play_message(msg) {
|
||||
return Err(glib::bool_error!("Invalid play message"));
|
||||
}
|
||||
match PlayMessageType::parse_type(msg) {
|
||||
PlayMessageType::UriLoaded => Ok(Self::UriLoaded),
|
||||
PlayMessageType::PositionUpdated => {
|
||||
let position = PlayMessageType::parse_position_updated(msg);
|
||||
Ok(Self::PositionUpdated { position })
|
||||
|
||||
unsafe {
|
||||
match PlayMessageType::parse_type(msg) {
|
||||
PlayMessageType::UriLoaded => Ok(UriLoaded::view(msg)),
|
||||
PlayMessageType::PositionUpdated => Ok(PositionUpdated::view(msg)),
|
||||
PlayMessageType::DurationChanged => Ok(DurationChanged::view(msg)),
|
||||
PlayMessageType::StateChanged => Ok(StateChanged::view(msg)),
|
||||
PlayMessageType::Buffering => Ok(Buffering::view(msg)),
|
||||
PlayMessageType::EndOfStream => Ok(EndOfStream::view(msg)),
|
||||
PlayMessageType::Error => Ok(Error::view(msg)),
|
||||
PlayMessageType::Warning => Ok(Warning::view(msg)),
|
||||
PlayMessageType::VideoDimensionsChanged => Ok(VideoDimensionsChanged::view(msg)),
|
||||
PlayMessageType::MediaInfoUpdated => Ok(MediaInfoUpdated::view(msg)),
|
||||
PlayMessageType::VolumeChanged => Ok(VolumeChanged::view(msg)),
|
||||
PlayMessageType::MuteChanged => Ok(MuteChanged::view(msg)),
|
||||
PlayMessageType::SeekDone => Ok(SeekDone::view(msg)),
|
||||
_ => Ok(Other::view(msg)),
|
||||
}
|
||||
PlayMessageType::DurationChanged => {
|
||||
let duration = PlayMessageType::parse_duration_updated(msg);
|
||||
Ok(Self::DurationChanged { duration })
|
||||
}
|
||||
PlayMessageType::StateChanged => {
|
||||
let state = PlayMessageType::parse_state_changed(msg);
|
||||
Ok(Self::StateChanged { state })
|
||||
}
|
||||
PlayMessageType::Buffering => {
|
||||
let percent = PlayMessageType::parse_buffering_percent(msg);
|
||||
Ok(Self::Buffering { percent })
|
||||
}
|
||||
PlayMessageType::EndOfStream => Ok(Self::EndOfStream),
|
||||
PlayMessageType::Error => {
|
||||
let (error, details) = PlayMessageType::parse_error(msg);
|
||||
Ok(Self::Error { error, details })
|
||||
}
|
||||
PlayMessageType::Warning => {
|
||||
let (error, details) = PlayMessageType::parse_warning(msg);
|
||||
Ok(Self::Warning { error, details })
|
||||
}
|
||||
PlayMessageType::VideoDimensionsChanged => {
|
||||
let (width, height) = PlayMessageType::parse_video_dimensions_changed(msg);
|
||||
Ok(Self::VideoDimensionsChanged { width, height })
|
||||
}
|
||||
PlayMessageType::MediaInfoUpdated => {
|
||||
let info = PlayMessageType::parse_media_info_updated(msg);
|
||||
Ok(Self::MediaInfoUpdated { info })
|
||||
}
|
||||
PlayMessageType::VolumeChanged => {
|
||||
let volume = PlayMessageType::parse_volume_changed(msg);
|
||||
Ok(Self::VolumeChanged { volume })
|
||||
}
|
||||
PlayMessageType::MuteChanged => {
|
||||
let muted = PlayMessageType::parse_muted_changed(msg);
|
||||
Ok(Self::MuteChanged { muted })
|
||||
}
|
||||
PlayMessageType::SeekDone => Ok(Self::SeekDone),
|
||||
_ => Err(glib::bool_error!("Invalid play message")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue