From c39c0c7264a1867450c82eeb6dc6b5df30b35b26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Sat, 11 Nov 2017 11:21:55 +0100 Subject: [PATCH] Implement ClockTime as ClockTime(Option) And also implement a FormatValue type that holds a value together with its format to make usage of the positions/durations/seek positions/etc more convenient and safe. Fixes https://github.com/sdroege/gstreamer-rs/issues/3 --- Gir_Gst.toml | 31 +- Gir_GstApp.toml | 6 +- Gir_GstBase.toml | 6 +- Gir_GstPlayer.toml | 6 +- examples/src/bin/gtksink.rs | 25 +- examples/src/bin/gtkvideooverlay.rs | 25 +- examples/src/bin/queries.rs | 28 +- gstreamer-app/src/auto/app_sink.rs | 4 +- gstreamer-app/src/auto/app_src.rs | 4 +- gstreamer-audio/src/audio_info.rs | 18 +- gstreamer-base/src/auto/adapter.rs | 12 +- gstreamer-base/src/auto/base_sink.rs | 12 +- gstreamer-base/src/auto/base_src.rs | 2 +- gstreamer-base/src/auto/base_transform.rs | 2 +- gstreamer-player/src/auto/player.rs | 6 +- .../src/auto/player_media_info.rs | 2 +- gstreamer-video/src/video_info.rs | 15 +- gstreamer/Cargo.toml | 1 + gstreamer/src/auto/alias.rs | 1 - gstreamer/src/auto/bus.rs | 2 +- gstreamer/src/auto/clock.rs | 32 +- gstreamer/src/auto/element.rs | 59 +--- gstreamer/src/auto/functions.rs | 2 +- gstreamer/src/auto/mod.rs | 1 - gstreamer/src/auto/object.rs | 8 +- gstreamer/src/auto/pad.rs | 61 ---- gstreamer/src/auto/pipeline.rs | 8 +- gstreamer/src/buffer.rs | 34 +- gstreamer/src/clock.rs | 26 +- gstreamer/src/clock_time.rs | 334 ++++++++++++++++++ gstreamer/src/element.rs | 129 +++++++ gstreamer/src/event.rs | 99 +++--- gstreamer/src/format.rs | 169 +++++++++ gstreamer/src/lib.rs | 21 +- gstreamer/src/message.rs | 42 ++- gstreamer/src/pad.rs | 127 +++++++ gstreamer/src/query.rs | 173 ++++++--- tutorials/src/bin/basic-tutorial-4.rs | 11 +- tutorials/src/bin/basic-tutorial-5.rs | 16 +- 39 files changed, 1174 insertions(+), 386 deletions(-) create mode 100644 gstreamer/src/clock_time.rs create mode 100644 gstreamer/src/format.rs diff --git a/Gir_Gst.toml b/Gir_Gst.toml index c2f7bc7be..e9fd1aa83 100644 --- a/Gir_Gst.toml +++ b/Gir_Gst.toml @@ -14,7 +14,6 @@ external_libraries = [ ] generate = [ - "Gst.ClockTime", "Gst.ClockTimeDiff", "Gst.Pipeline", "Gst.State", @@ -83,6 +82,11 @@ manual = [ "Gst.StaticPadTemplate", ] +[[object]] +name = "Gst.ClockTime" +status = "manual" +conversion_type = "scalar" + [[object]] name = "Gst.Bin" status = "generate" @@ -312,6 +316,31 @@ status = "generate" # ulong ignore = true + [[object.function]] + name = "query_duration" + # formatted value + ignore = true + + [[object.function]] + name = "query_position" + # formatted value + ignore = true + + [[object.function]] + name = "query_convert" + # formatted value + ignore = true + + [[object.function]] + name = "seek" + # formatted value + ignore = true + + [[object.function]] + name = "seek_simple" + # formatted value + ignore = true + [[object]] name = "Gst.ElementFactory" status = "generate" diff --git a/Gir_GstApp.toml b/Gir_GstApp.toml index dbc889c33..69bf3f53a 100644 --- a/Gir_GstApp.toml +++ b/Gir_GstApp.toml @@ -24,7 +24,6 @@ manual = [ "Gst.Object", "Gst.Element", "Gst.URIHandler", - "Gst.ClockTime", "Gst.FlowReturn", "Gst.Format", "GstBase.BaseSrc", @@ -100,3 +99,8 @@ ref_mode = "ref" name = "Gst.Sample" status = "manual" ref_mode = "ref" + +[[object]] +name = "Gst.ClockTime" +status = "manual" +conversion_type = "scalar" diff --git a/Gir_GstBase.toml b/Gir_GstBase.toml index 1dbef3678..359f06d3b 100644 --- a/Gir_GstBase.toml +++ b/Gir_GstBase.toml @@ -26,7 +26,6 @@ manual = [ "GLib.Bytes", "Gst.Object", "Gst.Element", - "Gst.ClockTime", "Gst.ClockTimeDiff", "Gst.ClockReturn", "Gst.FlowReturn", @@ -96,3 +95,8 @@ ref_mode = "ref" name = "Gst.Sample" status = "manual" ref_mode = "ref" + +[[object]] +name = "Gst.ClockTime" +status = "manual" +conversion_type = "scalar" diff --git a/Gir_GstPlayer.toml b/Gir_GstPlayer.toml index 2d94f9a68..3a0fa0a59 100644 --- a/Gir_GstPlayer.toml +++ b/Gir_GstPlayer.toml @@ -28,7 +28,6 @@ manual = [ "GLib.Error", "GLib.MainContext", "GObject.Object", - "Gst.ClockTime", "Gst.Element", ] @@ -158,3 +157,8 @@ trait = false name = "new" # Wrong return value ignore = true + +[[object]] +name = "Gst.ClockTime" +status = "manual" +conversion_type = "scalar" diff --git a/examples/src/bin/gtksink.rs b/examples/src/bin/gtksink.rs index 598c84504..c277d04ba 100644 --- a/examples/src/bin/gtksink.rs +++ b/examples/src/bin/gtksink.rs @@ -59,25 +59,14 @@ fn create_ui(app: >k::Application) { let pipeline_clone = pipeline.clone(); gtk::timeout_add(500, move || { let pipeline = &pipeline_clone; - let position = pipeline.query_position(gst::Format::Time); - - if let Some(position) = position { - let mut seconds = (position as gst::ClockTime) / gst::SECOND; - let mut minutes = seconds / 60; - let hours = minutes / 60; - - seconds %= 60; - minutes %= 60; - - label.set_text(&format!( - "Position: {:02}:{:02}:{:02}", - hours, - minutes, - seconds - )); + let position = if let Some(gst::FormatValue::Time(position)) = + pipeline.query_position(gst::Format::Time) + { + position } else { - label.set_text("Position: 00:00:00"); - } + 0.into() + }; + label.set_text(&format!("Position: {:.0}", position)); glib::Continue(true) }); diff --git a/examples/src/bin/gtkvideooverlay.rs b/examples/src/bin/gtkvideooverlay.rs index b53fedfed..aa136b4b9 100644 --- a/examples/src/bin/gtkvideooverlay.rs +++ b/examples/src/bin/gtkvideooverlay.rs @@ -129,25 +129,14 @@ fn create_ui(app: >k::Application) { let pipeline_clone = pipeline.clone(); gtk::timeout_add(500, move || { let pipeline = &pipeline_clone; - let position = pipeline.query_position(gst::Format::Time); - - if let Some(position) = position { - let mut seconds = (position as gst::ClockTime) / gst::SECOND; - let mut minutes = seconds / 60; - let hours = minutes / 60; - - seconds %= 60; - minutes %= 60; - - label.set_text(&format!( - "Position: {:02}:{:02}:{:02}", - hours, - minutes, - seconds - )); + let position = if let Some(gst::FormatValue::Time(position)) = + pipeline.query_position(gst::Format::Time) + { + position } else { - label.set_text("Position: 00:00:00"); - } + 0.into() + }; + label.set_text(&format!("Position: {:.0}", position)); glib::Continue(true) }); diff --git a/examples/src/bin/queries.rs b/examples/src/bin/queries.rs index 43f88c7d1..cfcbab298 100644 --- a/examples/src/bin/queries.rs +++ b/examples/src/bin/queries.rs @@ -30,21 +30,29 @@ fn main() { //let dur = pipeline.query_duration(gst::Format::Time).unwrap_or(-1); let pos = { let mut q = gst::Query::new_position(gst::Format::Time); - pipeline.query(q.get_mut().unwrap()); - match q.view() { - QueryView::Position(ref p) => p.get().1, - _ => unreachable!(), + if pipeline.query(q.get_mut().unwrap()) { + match q.view() { + QueryView::Position(ref p) => Some(p.get()), + _ => None, + } + } else { + None } - }; + }.and_then(|pos| pos.try_to_time()) + .unwrap(); let dur = { let mut q = gst::Query::new_duration(gst::Format::Time); - pipeline.query(q.get_mut().unwrap()); - match q.view() { - QueryView::Duration(ref p) => p.get().1, - _ => unreachable!(), + if pipeline.query(q.get_mut().unwrap()) { + match q.view() { + QueryView::Duration(ref p) => Some(p.get()), + _ => None, + } + } else { + None } - }; + }.and_then(|dur| dur.try_to_time()) + .unwrap(); println!("{} / {}", pos, dur); diff --git a/gstreamer-app/src/auto/app_sink.rs b/gstreamer-app/src/auto/app_sink.rs index 39344b2c0..e29a9cede 100644 --- a/gstreamer-app/src/auto/app_sink.rs +++ b/gstreamer-app/src/auto/app_sink.rs @@ -130,14 +130,14 @@ impl AppSink { #[cfg(any(feature = "v1_10", feature = "dox"))] pub fn try_pull_preroll(&self, timeout: gst::ClockTime) -> Option { unsafe { - from_glib_full(ffi::gst_app_sink_try_pull_preroll(self.to_glib_none().0, timeout)) + from_glib_full(ffi::gst_app_sink_try_pull_preroll(self.to_glib_none().0, timeout.to_glib())) } } #[cfg(any(feature = "v1_10", feature = "dox"))] pub fn try_pull_sample(&self, timeout: gst::ClockTime) -> Option { unsafe { - from_glib_full(ffi::gst_app_sink_try_pull_sample(self.to_glib_none().0, timeout)) + from_glib_full(ffi::gst_app_sink_try_pull_sample(self.to_glib_none().0, timeout.to_glib())) } } diff --git a/gstreamer-app/src/auto/app_src.rs b/gstreamer-app/src/auto/app_src.rs index 49b22a7b3..bb0e3e955 100644 --- a/gstreamer-app/src/auto/app_src.rs +++ b/gstreamer-app/src/auto/app_src.rs @@ -54,7 +54,7 @@ impl AppSrc { #[cfg(any(feature = "v1_10", feature = "dox"))] pub fn get_duration(&self) -> gst::ClockTime { unsafe { - ffi::gst_app_src_get_duration(self.to_glib_none().0) + from_glib(ffi::gst_app_src_get_duration(self.to_glib_none().0)) } } @@ -110,7 +110,7 @@ impl AppSrc { #[cfg(any(feature = "v1_10", feature = "dox"))] pub fn set_duration(&self, duration: gst::ClockTime) { unsafe { - ffi::gst_app_src_set_duration(self.to_glib_none().0, duration); + ffi::gst_app_src_set_duration(self.to_glib_none().0, duration.to_glib()); } } diff --git a/gstreamer-audio/src/audio_info.rs b/gstreamer-audio/src/audio_info.rs index 23078e5be..270f20b75 100644 --- a/gstreamer-audio/src/audio_info.rs +++ b/gstreamer-audio/src/audio_info.rs @@ -42,12 +42,13 @@ impl<'a> AudioInfoBuilder<'a> { return None; } - let positions: [ffi::GstAudioChannelPosition; 64] = - array_init::array_init_copy(|i| if i >= self.channels as usize { + let positions: [ffi::GstAudioChannelPosition; 64] = array_init::array_init_copy( + |i| if i >= self.channels as usize { ffi::GST_AUDIO_CHANNEL_POSITION_INVALID } else { p[i].to_glib() - }); + }, + ); let valid: bool = from_glib(ffi::gst_audio_check_valid_channel_positions( positions.as_ptr() as *mut _, @@ -156,22 +157,21 @@ impl AudioInfo { pub fn convert( &self, - src_fmt: gst::Format, - src_val: i64, + src_val: gst::FormatValue, dest_fmt: gst::Format, - ) -> Option { + ) -> Option { assert_initialized_main_thread!(); unsafe { let mut dest_val = mem::uninitialized(); if from_glib(ffi::gst_audio_info_convert( &self.0, - src_fmt.to_glib(), - src_val, + src_val.to_format().to_glib(), + src_val.to_value(), dest_fmt.to_glib(), &mut dest_val, )) { - Some(dest_val) + Some(gst::FormatValue::new(dest_fmt, dest_val)) } else { None } diff --git a/gstreamer-base/src/auto/adapter.rs b/gstreamer-base/src/auto/adapter.rs index d3bf609c9..5f796e6b3 100644 --- a/gstreamer-base/src/auto/adapter.rs +++ b/gstreamer-base/src/auto/adapter.rs @@ -59,7 +59,7 @@ impl Adapter { #[cfg(any(feature = "v1_10", feature = "dox"))] pub fn dts_at_discont(&self) -> gst::ClockTime { unsafe { - ffi::gst_adapter_dts_at_discont(self.to_glib_none().0) + from_glib(ffi::gst_adapter_dts_at_discont(self.to_glib_none().0)) } } @@ -117,7 +117,7 @@ impl Adapter { pub fn prev_dts(&self) -> (gst::ClockTime, u64) { unsafe { let mut distance = mem::uninitialized(); - let ret = ffi::gst_adapter_prev_dts(self.to_glib_none().0, &mut distance); + let ret = from_glib(ffi::gst_adapter_prev_dts(self.to_glib_none().0, &mut distance)); (ret, distance) } } @@ -125,7 +125,7 @@ impl Adapter { pub fn prev_dts_at_offset(&self, offset: usize) -> (gst::ClockTime, u64) { unsafe { let mut distance = mem::uninitialized(); - let ret = ffi::gst_adapter_prev_dts_at_offset(self.to_glib_none().0, offset, &mut distance); + let ret = from_glib(ffi::gst_adapter_prev_dts_at_offset(self.to_glib_none().0, offset, &mut distance)); (ret, distance) } } @@ -142,7 +142,7 @@ impl Adapter { pub fn prev_pts(&self) -> (gst::ClockTime, u64) { unsafe { let mut distance = mem::uninitialized(); - let ret = ffi::gst_adapter_prev_pts(self.to_glib_none().0, &mut distance); + let ret = from_glib(ffi::gst_adapter_prev_pts(self.to_glib_none().0, &mut distance)); (ret, distance) } } @@ -150,7 +150,7 @@ impl Adapter { pub fn prev_pts_at_offset(&self, offset: usize) -> (gst::ClockTime, u64) { unsafe { let mut distance = mem::uninitialized(); - let ret = ffi::gst_adapter_prev_pts_at_offset(self.to_glib_none().0, offset, &mut distance); + let ret = from_glib(ffi::gst_adapter_prev_pts_at_offset(self.to_glib_none().0, offset, &mut distance)); (ret, distance) } } @@ -158,7 +158,7 @@ impl Adapter { #[cfg(any(feature = "v1_10", feature = "dox"))] pub fn pts_at_discont(&self) -> gst::ClockTime { unsafe { - ffi::gst_adapter_pts_at_discont(self.to_glib_none().0) + from_glib(ffi::gst_adapter_pts_at_discont(self.to_glib_none().0)) } } diff --git a/gstreamer-base/src/auto/base_sink.rs b/gstreamer-base/src/auto/base_sink.rs index 5efedfc69..63319d3e4 100644 --- a/gstreamer-base/src/auto/base_sink.rs +++ b/gstreamer-base/src/auto/base_sink.rs @@ -154,7 +154,7 @@ impl + IsA> BaseSinkExt for O { fn get_latency(&self) -> gst::ClockTime { unsafe { - ffi::gst_base_sink_get_latency(self.to_glib_none().0) + from_glib(ffi::gst_base_sink_get_latency(self.to_glib_none().0)) } } @@ -172,7 +172,7 @@ impl + IsA> BaseSinkExt for O { fn get_render_delay(&self) -> gst::ClockTime { unsafe { - ffi::gst_base_sink_get_render_delay(self.to_glib_none().0) + from_glib(ffi::gst_base_sink_get_render_delay(self.to_glib_none().0)) } } @@ -219,7 +219,7 @@ impl + IsA> BaseSinkExt for O { let mut min_latency = mem::uninitialized(); let mut max_latency = mem::uninitialized(); let ret = from_glib(ffi::gst_base_sink_query_latency(self.to_glib_none().0, &mut live, &mut upstream_live, &mut min_latency, &mut max_latency)); - if ret { Some((from_glib(live), from_glib(upstream_live), min_latency, max_latency)) } else { None } + if ret { Some((from_glib(live), from_glib(upstream_live), from_glib(min_latency), from_glib(max_latency))) } else { None } } } @@ -268,7 +268,7 @@ impl + IsA> BaseSinkExt for O { fn set_render_delay(&self, delay: gst::ClockTime) { unsafe { - ffi::gst_base_sink_set_render_delay(self.to_glib_none().0, delay); + ffi::gst_base_sink_set_render_delay(self.to_glib_none().0, delay.to_glib()); } } @@ -293,7 +293,7 @@ impl + IsA> BaseSinkExt for O { fn wait(&self, time: gst::ClockTime) -> (gst::FlowReturn, gst::ClockTimeDiff) { unsafe { let mut jitter = mem::uninitialized(); - let ret = from_glib(ffi::gst_base_sink_wait(self.to_glib_none().0, time, &mut jitter)); + let ret = from_glib(ffi::gst_base_sink_wait(self.to_glib_none().0, time.to_glib(), &mut jitter)); (ret, jitter) } } @@ -301,7 +301,7 @@ impl + IsA> BaseSinkExt for O { fn wait_clock(&self, time: gst::ClockTime) -> (gst::ClockReturn, gst::ClockTimeDiff) { unsafe { let mut jitter = mem::uninitialized(); - let ret = from_glib(ffi::gst_base_sink_wait_clock(self.to_glib_none().0, time, &mut jitter)); + let ret = from_glib(ffi::gst_base_sink_wait_clock(self.to_glib_none().0, time.to_glib(), &mut jitter)); (ret, jitter) } } diff --git a/gstreamer-base/src/auto/base_src.rs b/gstreamer-base/src/auto/base_src.rs index 79da99853..2bab85ea8 100644 --- a/gstreamer-base/src/auto/base_src.rs +++ b/gstreamer-base/src/auto/base_src.rs @@ -133,7 +133,7 @@ impl + IsA> BaseSrcExt for O { let mut min_latency = mem::uninitialized(); let mut max_latency = mem::uninitialized(); let ret = from_glib(ffi::gst_base_src_query_latency(self.to_glib_none().0, &mut live, &mut min_latency, &mut max_latency)); - if ret { Some((from_glib(live), min_latency, max_latency)) } else { None } + if ret { Some((from_glib(live), from_glib(min_latency), from_glib(max_latency))) } else { None } } } diff --git a/gstreamer-base/src/auto/base_transform.rs b/gstreamer-base/src/auto/base_transform.rs index a6e550293..0cbf16eb9 100644 --- a/gstreamer-base/src/auto/base_transform.rs +++ b/gstreamer-base/src/auto/base_transform.rs @@ -139,7 +139,7 @@ impl + IsA> BaseTransformExt for O { fn update_qos(&self, proportion: f64, diff: gst::ClockTimeDiff, timestamp: gst::ClockTime) { unsafe { - ffi::gst_base_transform_update_qos(self.to_glib_none().0, proportion, diff, timestamp); + ffi::gst_base_transform_update_qos(self.to_glib_none().0, proportion, diff, timestamp.to_glib()); } } diff --git a/gstreamer-player/src/auto/player.rs b/gstreamer-player/src/auto/player.rs index 20be88984..d056b9a96 100644 --- a/gstreamer-player/src/auto/player.rs +++ b/gstreamer-player/src/auto/player.rs @@ -83,7 +83,7 @@ impl Player { pub fn get_duration(&self) -> gst::ClockTime { unsafe { - ffi::gst_player_get_duration(self.to_glib_none().0) + from_glib(ffi::gst_player_get_duration(self.to_glib_none().0)) } } @@ -115,7 +115,7 @@ impl Player { pub fn get_position(&self) -> gst::ClockTime { unsafe { - ffi::gst_player_get_position(self.to_glib_none().0) + from_glib(ffi::gst_player_get_position(self.to_glib_none().0)) } } @@ -171,7 +171,7 @@ impl Player { pub fn seek(&self, position: gst::ClockTime) { unsafe { - ffi::gst_player_seek(self.to_glib_none().0, position); + ffi::gst_player_seek(self.to_glib_none().0, position.to_glib()); } } diff --git a/gstreamer-player/src/auto/player_media_info.rs b/gstreamer-player/src/auto/player_media_info.rs index 4edfed676..cb8bca13e 100644 --- a/gstreamer-player/src/auto/player_media_info.rs +++ b/gstreamer-player/src/auto/player_media_info.rs @@ -36,7 +36,7 @@ impl PlayerMediaInfo { pub fn get_duration(&self) -> gst::ClockTime { unsafe { - ffi::gst_player_media_info_get_duration(self.to_glib_none().0) + from_glib(ffi::gst_player_media_info_get_duration(self.to_glib_none().0)) } } diff --git a/gstreamer-video/src/video_info.rs b/gstreamer-video/src/video_info.rs index 6fc13fa67..3384d6b07 100644 --- a/gstreamer-video/src/video_info.rs +++ b/gstreamer-video/src/video_info.rs @@ -545,24 +545,25 @@ impl VideoInfo { self.format_info().n_components() } - pub fn convert( + pub fn convert>( &self, - src_fmt: gst::Format, - src_val: i64, + src_val: V, dest_fmt: gst::Format, - ) -> Option { + ) -> Option { skip_assert_initialized!(); + let src_val = src_val.into(); + unsafe { let mut dest_val = mem::uninitialized(); if from_glib(ffi::gst_video_info_convert( &self.0 as *const _ as *mut _, - src_fmt.to_glib(), - src_val, + src_val.to_format().to_glib(), + src_val.to_value(), dest_fmt.to_glib(), &mut dest_val, )) { - Some(dest_val) + Some(gst::FormatValue::new(dest_fmt, dest_val)) } else { None } diff --git a/gstreamer/Cargo.toml b/gstreamer/Cargo.toml index 044f8e071..9039918f6 100644 --- a/gstreamer/Cargo.toml +++ b/gstreamer/Cargo.toml @@ -22,6 +22,7 @@ glib = { git = "https://github.com/gtk-rs/glib" } num-rational = { version = "0.1.38", default-features = false, features = [] } lazy_static = "0.2" futures = { version = "0.1", optional = true } +muldiv = "0.1.1" [build-dependencies.rustdoc-stripper] version = "0.1" diff --git a/gstreamer/src/auto/alias.rs b/gstreamer/src/auto/alias.rs index aea6e6d87..f00994038 100644 --- a/gstreamer/src/auto/alias.rs +++ b/gstreamer/src/auto/alias.rs @@ -4,6 +4,5 @@ #[allow(unused_imports)] use auto::*; -pub type ClockTime = u64; pub type ClockTimeDiff = i64; pub type ElementFactoryListType = u64; diff --git a/gstreamer/src/auto/bus.rs b/gstreamer/src/auto/bus.rs index 0d8b529e0..712b0164d 100644 --- a/gstreamer/src/auto/bus.rs +++ b/gstreamer/src/auto/bus.rs @@ -113,7 +113,7 @@ impl Bus { pub fn timed_pop(&self, timeout: ClockTime) -> Option { unsafe { - from_glib_full(ffi::gst_bus_timed_pop(self.to_glib_none().0, timeout)) + from_glib_full(ffi::gst_bus_timed_pop(self.to_glib_none().0, timeout.to_glib())) } } diff --git a/gstreamer/src/auto/clock.rs b/gstreamer/src/auto/clock.rs index 879f03f85..4c7d724c8 100644 --- a/gstreamer/src/auto/clock.rs +++ b/gstreamer/src/auto/clock.rs @@ -127,7 +127,7 @@ impl + IsA> ClockExt for O { fn add_observation(&self, slave: ClockTime, master: ClockTime) -> Option { unsafe { let mut r_squared = mem::uninitialized(); - let ret = from_glib(ffi::gst_clock_add_observation(self.to_glib_none().0, slave, master, &mut r_squared)); + let ret = from_glib(ffi::gst_clock_add_observation(self.to_glib_none().0, slave.to_glib(), master.to_glib(), &mut r_squared)); if ret { Some(r_squared) } else { None } } } @@ -139,20 +139,20 @@ impl + IsA> ClockExt for O { let mut external = mem::uninitialized(); let mut rate_num = mem::uninitialized(); let mut rate_denom = mem::uninitialized(); - let ret = from_glib(ffi::gst_clock_add_observation_unapplied(self.to_glib_none().0, slave, master, &mut r_squared, &mut internal, &mut external, &mut rate_num, &mut rate_denom)); - if ret { Some((r_squared, internal, external, rate_num, rate_denom)) } else { None } + let ret = from_glib(ffi::gst_clock_add_observation_unapplied(self.to_glib_none().0, slave.to_glib(), master.to_glib(), &mut r_squared, &mut internal, &mut external, &mut rate_num, &mut rate_denom)); + if ret { Some((r_squared, from_glib(internal), from_glib(external), from_glib(rate_num), from_glib(rate_denom))) } else { None } } } fn adjust_unlocked(&self, internal: ClockTime) -> ClockTime { unsafe { - ffi::gst_clock_adjust_unlocked(self.to_glib_none().0, internal) + from_glib(ffi::gst_clock_adjust_unlocked(self.to_glib_none().0, internal.to_glib())) } } fn adjust_with_calibration(&self, internal_target: ClockTime, cinternal: ClockTime, cexternal: ClockTime, cnum: ClockTime, cdenom: ClockTime) -> ClockTime { unsafe { - ffi::gst_clock_adjust_with_calibration(self.to_glib_none().0, internal_target, cinternal, cexternal, cnum, cdenom) + from_glib(ffi::gst_clock_adjust_with_calibration(self.to_glib_none().0, internal_target.to_glib(), cinternal.to_glib(), cexternal.to_glib(), cnum.to_glib(), cdenom.to_glib())) } } @@ -163,13 +163,13 @@ impl + IsA> ClockExt for O { let mut rate_num = mem::uninitialized(); let mut rate_denom = mem::uninitialized(); ffi::gst_clock_get_calibration(self.to_glib_none().0, &mut internal, &mut external, &mut rate_num, &mut rate_denom); - (internal, external, rate_num, rate_denom) + (from_glib(internal), from_glib(external), from_glib(rate_num), from_glib(rate_denom)) } } fn get_internal_time(&self) -> ClockTime { unsafe { - ffi::gst_clock_get_internal_time(self.to_glib_none().0) + from_glib(ffi::gst_clock_get_internal_time(self.to_glib_none().0)) } } @@ -181,19 +181,19 @@ impl + IsA> ClockExt for O { fn get_resolution(&self) -> ClockTime { unsafe { - ffi::gst_clock_get_resolution(self.to_glib_none().0) + from_glib(ffi::gst_clock_get_resolution(self.to_glib_none().0)) } } fn get_time(&self) -> ClockTime { unsafe { - ffi::gst_clock_get_time(self.to_glib_none().0) + from_glib(ffi::gst_clock_get_time(self.to_glib_none().0)) } } fn get_timeout(&self) -> ClockTime { unsafe { - ffi::gst_clock_get_timeout(self.to_glib_none().0) + from_glib(ffi::gst_clock_get_timeout(self.to_glib_none().0)) } } @@ -217,7 +217,7 @@ impl + IsA> ClockExt for O { fn set_calibration(&self, internal: ClockTime, external: ClockTime, rate_num: ClockTime, rate_denom: ClockTime) { unsafe { - ffi::gst_clock_set_calibration(self.to_glib_none().0, internal, external, rate_num, rate_denom); + ffi::gst_clock_set_calibration(self.to_glib_none().0, internal.to_glib(), external.to_glib(), rate_num.to_glib(), rate_denom.to_glib()); } } @@ -231,7 +231,7 @@ impl + IsA> ClockExt for O { fn set_resolution(&self, resolution: ClockTime) -> ClockTime { unsafe { - ffi::gst_clock_set_resolution(self.to_glib_none().0, resolution) + from_glib(ffi::gst_clock_set_resolution(self.to_glib_none().0, resolution.to_glib())) } } @@ -243,7 +243,7 @@ impl + IsA> ClockExt for O { fn set_timeout(&self, timeout: ClockTime) { unsafe { - ffi::gst_clock_set_timeout(self.to_glib_none().0, timeout); + ffi::gst_clock_set_timeout(self.to_glib_none().0, timeout.to_glib()); } } @@ -253,19 +253,19 @@ impl + IsA> ClockExt for O { fn unadjust_unlocked(&self, external: ClockTime) -> ClockTime { unsafe { - ffi::gst_clock_unadjust_unlocked(self.to_glib_none().0, external) + from_glib(ffi::gst_clock_unadjust_unlocked(self.to_glib_none().0, external.to_glib())) } } fn unadjust_with_calibration(&self, external_target: ClockTime, cinternal: ClockTime, cexternal: ClockTime, cnum: ClockTime, cdenom: ClockTime) -> ClockTime { unsafe { - ffi::gst_clock_unadjust_with_calibration(self.to_glib_none().0, external_target, cinternal, cexternal, cnum, cdenom) + from_glib(ffi::gst_clock_unadjust_with_calibration(self.to_glib_none().0, external_target.to_glib(), cinternal.to_glib(), cexternal.to_glib(), cnum.to_glib(), cdenom.to_glib())) } } fn wait_for_sync(&self, timeout: ClockTime) -> Result<(), glib::error::BoolError> { unsafe { - glib::error::BoolError::from_glib(ffi::gst_clock_wait_for_sync(self.to_glib_none().0, timeout), "Timed out waiting for sync") + glib::error::BoolError::from_glib(ffi::gst_clock_wait_for_sync(self.to_glib_none().0, timeout.to_glib()), "Timed out waiting for sync") } } diff --git a/gstreamer/src/auto/element.rs b/gstreamer/src/auto/element.rs index 3c49d190e..e0fc580f4 100644 --- a/gstreamer/src/auto/element.rs +++ b/gstreamer/src/auto/element.rs @@ -8,15 +8,12 @@ use ClockTime; use Context; use ElementFactory; use Error; -use Format; use Message; use Object; use Pad; use PadLinkCheck; use PadTemplate; use Plugin; -use SeekFlags; -use SeekType; use State; use StateChange; use StateChangeReturn; @@ -153,22 +150,12 @@ pub trait ElementExt { fn provide_clock(&self) -> Option; - fn query_convert(&self, src_format: Format, src_val: i64, dest_format: Format) -> Option; - - fn query_duration(&self, format: Format) -> Option; - - fn query_position(&self, format: Format) -> Option; - fn release_request_pad>(&self, pad: &P); fn remove_pad>(&self, pad: &P) -> Result<(), glib::error::BoolError>; fn request_pad<'a, 'b, P: Into>, Q: Into>>(&self, templ: &PadTemplate, name: P, caps: Q) -> Option; - fn seek(&self, rate: f64, format: Format, flags: SeekFlags, start_type: SeekType, start: i64, stop_type: SeekType, stop: i64) -> Result<(), glib::error::BoolError>; - - fn seek_simple(&self, format: Format, seek_flags: SeekFlags, seek_pos: i64) -> Result<(), glib::error::BoolError>; - fn set_base_time(&self, time: ClockTime); fn set_bus(&self, bus: &Bus); @@ -236,7 +223,7 @@ impl + IsA> ElementExt for O { fn get_base_time(&self) -> ClockTime { unsafe { - ffi::gst_element_get_base_time(self.to_glib_none().0) + from_glib(ffi::gst_element_get_base_time(self.to_glib_none().0)) } } @@ -292,7 +279,7 @@ impl + IsA> ElementExt for O { fn get_start_time(&self) -> ClockTime { unsafe { - ffi::gst_element_get_start_time(self.to_glib_none().0) + from_glib(ffi::gst_element_get_start_time(self.to_glib_none().0)) } } @@ -300,7 +287,7 @@ impl + IsA> ElementExt for O { unsafe { let mut state = mem::uninitialized(); let mut pending = mem::uninitialized(); - let ret = from_glib(ffi::gst_element_get_state(self.to_glib_none().0, &mut state, &mut pending, timeout)); + let ret = from_glib(ffi::gst_element_get_state(self.to_glib_none().0, &mut state, &mut pending, timeout.to_glib())); (ret, from_glib(state), from_glib(pending)) } } @@ -412,30 +399,6 @@ impl + IsA> ElementExt for O { } } - fn query_convert(&self, src_format: Format, src_val: i64, dest_format: Format) -> Option { - unsafe { - let mut dest_val = mem::uninitialized(); - let ret = from_glib(ffi::gst_element_query_convert(self.to_glib_none().0, src_format.to_glib(), src_val, dest_format.to_glib(), &mut dest_val)); - if ret { Some(dest_val) } else { None } - } - } - - fn query_duration(&self, format: Format) -> Option { - unsafe { - let mut duration = mem::uninitialized(); - let ret = from_glib(ffi::gst_element_query_duration(self.to_glib_none().0, format.to_glib(), &mut duration)); - if ret { Some(duration) } else { None } - } - } - - fn query_position(&self, format: Format) -> Option { - unsafe { - let mut cur = mem::uninitialized(); - let ret = from_glib(ffi::gst_element_query_position(self.to_glib_none().0, format.to_glib(), &mut cur)); - if ret { Some(cur) } else { None } - } - } - fn release_request_pad>(&self, pad: &P) { unsafe { ffi::gst_element_release_request_pad(self.to_glib_none().0, pad.to_glib_none().0); @@ -458,21 +421,9 @@ impl + IsA> ElementExt for O { } } - fn seek(&self, rate: f64, format: Format, flags: SeekFlags, start_type: SeekType, start: i64, stop_type: SeekType, stop: i64) -> Result<(), glib::error::BoolError> { - unsafe { - glib::error::BoolError::from_glib(ffi::gst_element_seek(self.to_glib_none().0, rate, format.to_glib(), flags.to_glib(), start_type.to_glib(), start, stop_type.to_glib(), stop), "Failed to seek") - } - } - - fn seek_simple(&self, format: Format, seek_flags: SeekFlags, seek_pos: i64) -> Result<(), glib::error::BoolError> { - unsafe { - glib::error::BoolError::from_glib(ffi::gst_element_seek_simple(self.to_glib_none().0, format.to_glib(), seek_flags.to_glib(), seek_pos), "Failed to seek") - } - } - fn set_base_time(&self, time: ClockTime) { unsafe { - ffi::gst_element_set_base_time(self.to_glib_none().0, time); + ffi::gst_element_set_base_time(self.to_glib_none().0, time.to_glib()); } } @@ -502,7 +453,7 @@ impl + IsA> ElementExt for O { fn set_start_time(&self, time: ClockTime) { unsafe { - ffi::gst_element_set_start_time(self.to_glib_none().0, time); + ffi::gst_element_set_start_time(self.to_glib_none().0, time.to_glib()); } } diff --git a/gstreamer/src/auto/functions.rs b/gstreamer/src/auto/functions.rs index ecef50170..eaa3fd113 100644 --- a/gstreamer/src/auto/functions.rs +++ b/gstreamer/src/auto/functions.rs @@ -153,7 +153,7 @@ pub fn update_registry() -> Result<(), glib::error::BoolError> { pub fn util_get_timestamp() -> ClockTime { assert_initialized_main_thread!(); unsafe { - ffi::gst_util_get_timestamp() + from_glib(ffi::gst_util_get_timestamp()) } } diff --git a/gstreamer/src/auto/mod.rs b/gstreamer/src/auto/mod.rs index 643c7b265..d8b6f6117 100644 --- a/gstreamer/src/auto/mod.rs +++ b/gstreamer/src/auto/mod.rs @@ -152,7 +152,6 @@ pub use self::flags::StreamFlags; pub use self::flags::StreamType; mod alias; -pub use self::alias::ClockTime; pub use self::alias::ClockTimeDiff; pub use self::alias::ElementFactoryListType; diff --git a/gstreamer/src/auto/object.rs b/gstreamer/src/auto/object.rs index b7129b892..5fcd91392 100644 --- a/gstreamer/src/auto/object.rs +++ b/gstreamer/src/auto/object.rs @@ -122,7 +122,7 @@ impl + IsA> GstObjectExt for O { fn get_control_rate(&self) -> ClockTime { unsafe { - ffi::gst_object_get_control_rate(self.to_glib_none().0) + from_glib(ffi::gst_object_get_control_rate(self.to_glib_none().0)) } } @@ -198,7 +198,7 @@ impl + IsA> GstObjectExt for O { fn set_control_rate(&self, control_rate: ClockTime) { unsafe { - ffi::gst_object_set_control_rate(self.to_glib_none().0, control_rate); + ffi::gst_object_set_control_rate(self.to_glib_none().0, control_rate.to_glib()); } } @@ -218,13 +218,13 @@ impl + IsA> GstObjectExt for O { fn suggest_next_sync(&self) -> ClockTime { unsafe { - ffi::gst_object_suggest_next_sync(self.to_glib_none().0) + from_glib(ffi::gst_object_suggest_next_sync(self.to_glib_none().0)) } } fn sync_values(&self, timestamp: ClockTime) -> Result<(), glib::error::BoolError> { unsafe { - glib::error::BoolError::from_glib(ffi::gst_object_sync_values(self.to_glib_none().0, timestamp), "Failed to sync values") + glib::error::BoolError::from_glib(ffi::gst_object_sync_values(self.to_glib_none().0, timestamp.to_glib()), "Failed to sync values") } } diff --git a/gstreamer/src/auto/pad.rs b/gstreamer/src/auto/pad.rs index 3f67feefe..e80472b19 100644 --- a/gstreamer/src/auto/pad.rs +++ b/gstreamer/src/auto/pad.rs @@ -6,7 +6,6 @@ use Element; use Event; use EventType; use FlowReturn; -use Format; use Object; use PadDirection; use PadLinkCheck; @@ -151,22 +150,10 @@ pub trait PadExt { fn peer_query_caps<'a, P: Into>>(&self, filter: P) -> Option; - fn peer_query_convert(&self, src_format: Format, src_val: i64, dest_format: Format) -> Option; - - fn peer_query_duration(&self, format: Format) -> Option; - - fn peer_query_position(&self, format: Format) -> Option; - fn query_accept_caps(&self, caps: &Caps) -> bool; fn query_caps<'a, P: Into>>(&self, filter: P) -> Option; - fn query_convert(&self, src_format: Format, src_val: i64, dest_format: Format) -> Option; - - fn query_duration(&self, format: Format) -> Option; - - fn query_position(&self, format: Format) -> Option; - //fn set_activate_function_full>>(&self, activate: /*Unknown conversion*//*Unimplemented*/PadActivateFunction, user_data: P, notify: /*Unknown conversion*//*Unimplemented*/DestroyNotify); //fn set_activatemode_function_full>>(&self, activatemode: /*Unknown conversion*//*Unimplemented*/PadActivateModeFunction, user_data: P, notify: /*Unknown conversion*//*Unimplemented*/DestroyNotify); @@ -449,30 +436,6 @@ impl + IsA> PadExt for O { } } - fn peer_query_convert(&self, src_format: Format, src_val: i64, dest_format: Format) -> Option { - unsafe { - let mut dest_val = mem::uninitialized(); - let ret = from_glib(ffi::gst_pad_peer_query_convert(self.to_glib_none().0, src_format.to_glib(), src_val, dest_format.to_glib(), &mut dest_val)); - if ret { Some(dest_val) } else { None } - } - } - - fn peer_query_duration(&self, format: Format) -> Option { - unsafe { - let mut duration = mem::uninitialized(); - let ret = from_glib(ffi::gst_pad_peer_query_duration(self.to_glib_none().0, format.to_glib(), &mut duration)); - if ret { Some(duration) } else { None } - } - } - - fn peer_query_position(&self, format: Format) -> Option { - unsafe { - let mut cur = mem::uninitialized(); - let ret = from_glib(ffi::gst_pad_peer_query_position(self.to_glib_none().0, format.to_glib(), &mut cur)); - if ret { Some(cur) } else { None } - } - } - fn query_accept_caps(&self, caps: &Caps) -> bool { unsafe { from_glib(ffi::gst_pad_query_accept_caps(self.to_glib_none().0, caps.to_glib_none().0)) @@ -487,30 +450,6 @@ impl + IsA> PadExt for O { } } - fn query_convert(&self, src_format: Format, src_val: i64, dest_format: Format) -> Option { - unsafe { - let mut dest_val = mem::uninitialized(); - let ret = from_glib(ffi::gst_pad_query_convert(self.to_glib_none().0, src_format.to_glib(), src_val, dest_format.to_glib(), &mut dest_val)); - if ret { Some(dest_val) } else { None } - } - } - - fn query_duration(&self, format: Format) -> Option { - unsafe { - let mut duration = mem::uninitialized(); - let ret = from_glib(ffi::gst_pad_query_duration(self.to_glib_none().0, format.to_glib(), &mut duration)); - if ret { Some(duration) } else { None } - } - } - - fn query_position(&self, format: Format) -> Option { - unsafe { - let mut cur = mem::uninitialized(); - let ret = from_glib(ffi::gst_pad_query_position(self.to_glib_none().0, format.to_glib(), &mut cur)); - if ret { Some(cur) } else { None } - } - } - //fn set_activate_function_full>>(&self, activate: /*Unknown conversion*//*Unimplemented*/PadActivateFunction, user_data: P, notify: /*Unknown conversion*//*Unimplemented*/DestroyNotify) { // unsafe { TODO: call ffi::gst_pad_set_activate_function_full() } //} diff --git a/gstreamer/src/auto/pipeline.rs b/gstreamer/src/auto/pipeline.rs index e42abe2b6..fcbc35b80 100644 --- a/gstreamer/src/auto/pipeline.rs +++ b/gstreamer/src/auto/pipeline.rs @@ -84,13 +84,13 @@ impl + IsA> PipelineExt for O { fn get_delay(&self) -> ClockTime { unsafe { - ffi::gst_pipeline_get_delay(self.to_glib_none().0) + from_glib(ffi::gst_pipeline_get_delay(self.to_glib_none().0)) } } fn get_latency(&self) -> ClockTime { unsafe { - ffi::gst_pipeline_get_latency(self.to_glib_none().0) + from_glib(ffi::gst_pipeline_get_latency(self.to_glib_none().0)) } } @@ -108,13 +108,13 @@ impl + IsA> PipelineExt for O { fn set_delay(&self, delay: ClockTime) { unsafe { - ffi::gst_pipeline_set_delay(self.to_glib_none().0, delay); + ffi::gst_pipeline_set_delay(self.to_glib_none().0, delay.to_glib()); } } fn set_latency(&self, latency: ClockTime) { unsafe { - ffi::gst_pipeline_set_latency(self.to_glib_none().0, latency); + ffi::gst_pipeline_set_latency(self.to_glib_none().0, latency.to_glib()); } } diff --git a/gstreamer/src/buffer.rs b/gstreamer/src/buffer.rs index 1748391e0..5c6256ffc 100644 --- a/gstreamer/src/buffer.rs +++ b/gstreamer/src/buffer.rs @@ -21,7 +21,7 @@ use ClockTime; use glib; use glib_ffi; use ffi; -use glib::translate::{from_glib, from_glib_full}; +use glib::translate::{from_glib, from_glib_full, ToGlib}; pub struct Readable; pub struct Writable; @@ -317,27 +317,27 @@ impl BufferRef { } pub fn get_pts(&self) -> ClockTime { - self.0.pts + from_glib(self.0.pts) } pub fn set_pts(&mut self, pts: ClockTime) { - self.0.pts = pts; + self.0.pts = pts.to_glib(); } pub fn get_dts(&self) -> ClockTime { - self.0.dts + from_glib(self.0.dts) } pub fn set_dts(&mut self, dts: ClockTime) { - self.0.dts = dts; + self.0.dts = dts.to_glib(); } pub fn get_duration(&self) -> ClockTime { - self.0.duration + from_glib(self.0.duration) } pub fn set_duration(&mut self, duration: ClockTime) { - self.0.duration = duration; + self.0.duration = duration.to_glib(); } pub fn get_flags(&self) -> BufferFlags { @@ -474,17 +474,17 @@ mod tests { { let buffer = buffer.get_mut().unwrap(); - buffer.set_pts(1); - buffer.set_dts(2); + buffer.set_pts(1.into()); + buffer.set_dts(2.into()); buffer.set_offset(3); buffer.set_offset_end(4); - buffer.set_duration(5); + buffer.set_duration(5.into()); } - assert_eq!(buffer.get_pts(), 1); - assert_eq!(buffer.get_dts(), 2); + assert_eq!(buffer.get_pts(), 1.into()); + assert_eq!(buffer.get_dts(), 2.into()); assert_eq!(buffer.get_offset(), 3); assert_eq!(buffer.get_offset_end(), 4); - assert_eq!(buffer.get_duration(), 5); + assert_eq!(buffer.get_duration(), 5.into()); } #[test] @@ -499,7 +499,7 @@ mod tests { assert_ne!(buffer.get_mut(), None); { let buffer = buffer.get_mut().unwrap(); - buffer.set_pts(1); + buffer.set_pts(1.into()); } let mut buffer2 = buffer.clone(); @@ -515,15 +515,15 @@ mod tests { assert_ne!(buffer2.as_ptr(), buffer.as_ptr()); } - buffer2.set_pts(2); + buffer2.set_pts(2.into()); let mut data = buffer2.map_writable().unwrap(); assert_eq!(data.as_slice(), vec![1, 2, 3, 4].as_slice()); data.as_mut_slice()[0] = 0; } - assert_eq!(buffer.get_pts(), 1); - assert_eq!(buffer2.get_pts(), 2); + assert_eq!(buffer.get_pts(), 1.into()); + assert_eq!(buffer2.get_pts(), 2.into()); { let data = buffer.map_readable().unwrap(); diff --git a/gstreamer/src/clock.rs b/gstreamer/src/clock.rs index bd9ff82d1..202494690 100644 --- a/gstreamer/src/clock.rs +++ b/gstreamer/src/clock.rs @@ -34,14 +34,18 @@ glib_wrapper! { unsafe extern "C" fn trampoline_wait_async( clock: *mut ffi::GstClock, - time: ClockTime, + time: ffi::GstClockTime, id: gpointer, func: gpointer, ) -> gboolean { let _guard = CallbackGuard::new(); #[cfg_attr(feature = "cargo-clippy", allow(transmute_ptr_to_ref))] let f: &&(Fn(&Clock, ClockTime, &ClockId) -> bool + Send + 'static) = transmute(func); - f(&from_glib_borrow(clock), time, &from_glib_borrow(id)).to_glib() + f( + &from_glib_borrow(clock), + from_glib(time), + &from_glib_borrow(id), + ).to_glib() } unsafe extern "C" fn destroy_closure_wait_async(ptr: gpointer) { @@ -60,7 +64,7 @@ fn into_raw_wait_async bool + Send + 'stat impl ClockId { pub fn get_time(&self) -> ClockTime { - unsafe { ffi::gst_clock_id_get_time(self.to_glib_none().0) } + unsafe { from_glib(ffi::gst_clock_id_get_time(self.to_glib_none().0)) } } pub fn unschedule(&self) { @@ -142,8 +146,8 @@ impl + IsA> ClockExtManual for O { unsafe { from_glib_full(ffi::gst_clock_new_periodic_id( self.to_glib_none().0, - start_time, - interval, + start_time.to_glib(), + interval.to_glib(), )) } } @@ -159,8 +163,8 @@ impl + IsA> ClockExtManual for O { let res: bool = from_glib(ffi::gst_clock_periodic_id_reinit( self.to_glib_none().0, id.to_glib_none().0, - start_time, - interval, + start_time.to_glib(), + interval.to_glib(), )); if res { Ok(()) @@ -174,7 +178,7 @@ impl + IsA> ClockExtManual for O { unsafe { from_glib_full(ffi::gst_clock_new_single_shot_id( self.to_glib_none().0, - time, + time.to_glib(), )) } } @@ -184,7 +188,7 @@ impl + IsA> ClockExtManual for O { let res: bool = from_glib(ffi::gst_clock_single_shot_id_reinit( self.to_glib_none().0, id.to_glib_none().0, - time, + time.to_glib(), )); if res { Ok(()) @@ -207,7 +211,7 @@ mod tests { let clock = SystemClock::obtain(); let now = clock.get_time(); - let id = clock.new_single_shot_id(now + 20_000_000).unwrap(); + let id = clock.new_single_shot_id(now + 20 * ::MSECOND).unwrap(); let (res, _) = id.wait(); assert!(res == ClockReturn::Ok || res == ClockReturn::Early); @@ -221,7 +225,7 @@ mod tests { let clock = SystemClock::obtain(); let now = clock.get_time(); - let id = clock.new_single_shot_id(now + 20_000_000).unwrap(); + let id = clock.new_single_shot_id(now + 20 * ::MSECOND).unwrap(); let res = id.wait_async(move |_, _, _| { sender.send(()).unwrap(); diff --git a/gstreamer/src/clock_time.rs b/gstreamer/src/clock_time.rs new file mode 100644 index 000000000..526a8f21a --- /dev/null +++ b/gstreamer/src/clock_time.rs @@ -0,0 +1,334 @@ +// Copyright (C) 2017 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::ops; +use ffi; +use glib::translate::*; +use std::{cmp, fmt}; +use muldiv::MulDiv; + +#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Copy, Debug, Default)] +pub struct ClockTime(pub Option); + +impl ClockTime { + pub fn hours(&self) -> Option { + (*self / ::SECOND / 60 / 60).0 + } + + pub fn minutes(&self) -> Option { + (*self / ::SECOND / 60).0 + } + + pub fn seconds(&self) -> Option { + (*self / ::SECOND).0 + } + + pub fn nanoseconds(&self) -> Option { + self.0 + } + + pub fn from_seconds(seconds: u64) -> ClockTime { + seconds * ::SECOND + } + + pub fn new(nanoseconds: u64) -> ClockTime { + ClockTime(Some(nanoseconds)) + } + + pub fn none() -> ClockTime { + ClockTime(None) + } +} + +impl From for ClockTime { + fn from(v: u64) -> ClockTime { + from_glib(v) + } +} + +impl From> for ClockTime { + fn from(v: Option) -> ClockTime { + ClockTime(v) + } +} + +impl Into for ClockTime { + fn into(self) -> u64 { + self.to_glib() + } +} + +impl Into> for ClockTime { + fn into(self) -> Option { + self.0 + } +} + +impl ops::Deref for ClockTime { + type Target = Option; + + fn deref(&self) -> &Option { + &self.0 + } +} + +impl ops::DerefMut for ClockTime { + fn deref_mut(&mut self) -> &mut Option { + &mut self.0 + } +} + +impl AsRef> for ClockTime { + fn as_ref(&self) -> &Option { + &self.0 + } +} + +impl AsMut> for ClockTime { + fn as_mut(&mut self) -> &mut Option { + &mut self.0 + } +} + +impl fmt::Display for ClockTime { + fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { + let precision = f.precision().unwrap_or(9); + // TODO: Could also check width and pad the hours as needed + + let (h, m, s, ns) = match self.0 { + Some(v) => { + let mut s = v / 1_000_000_000; + let mut m = s / 60; + let h = m / 60; + s %= 60; + m %= 60; + let ns = v % 1_000_000_000; + + (h, m, s, ns) + } + None => (99, 99, 99, 999_999_999), + }; + + if precision == 0 { + f.write_fmt(format_args!("{:02}:{:02}:{:02}", h, m, s)) + } else { + let mut divisor = 1; + let precision = cmp::max(precision, 9); + for _ in 0..(9 - precision) { + divisor *= 10; + } + + f.write_fmt(format_args!( + "{:02}:{:02}:{:02}.{:0width$}", + h, + m, + s, + ns / divisor, + width = precision + )) + } + } +} + +macro_rules! impl_op_same( + ($op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident, $e:expr) => { + impl ops::$op for ClockTime { + type Output = ClockTime; + + fn $op_name(self, other: ClockTime) -> ClockTime { + match (self.0, other.0) { + (Some(a), Some(b)) => ClockTime(Some($e(a, b))), + _ => ClockTime(None), + } + } + } + + impl<'a> ops::$op<&'a ClockTime> for ClockTime { + type Output = ClockTime; + + fn $op_name(self, other: &'a ClockTime) -> ClockTime { + self.$op_name(*other) + } + } + + impl ops::$op_assign for ClockTime { + fn $op_assign_name(&mut self, other: ClockTime) { + match (self.0, other.0) { + (Some(a), Some(b)) => self.0 = Some($e(a, b)), + _ => self.0 = None, + } + } + } + + impl<'a> ops::$op_assign<&'a ClockTime> for ClockTime { + fn $op_assign_name(&mut self, other: &'a ClockTime) { + self.$op_assign_name(*other) + } + } + }; +); + +impl_op_same!(Add, add, AddAssign, add_assign, |a, b| a + b); +impl_op_same!(Sub, sub, SubAssign, sub_assign, |a, b| a - b); +impl_op_same!(Mul, mul, MulAssign, mul_assign, |a, b| a * b); +impl_op_same!(Div, div, DivAssign, div_assign, |a, b| a / b); +impl_op_same!(Rem, rem, RemAssign, rem_assign, |a, b| a % b); + +macro_rules! impl_op_u64( + ($op:ident, $op_name:ident, $op_assign:ident, $op_assign_name:ident, $e:expr) => { + impl ops::$op for ClockTime { + type Output = ClockTime; + + fn $op_name(self, other: u64) -> ClockTime { + match self.0 { + Some(a) => ClockTime(Some($e(a, other))), + _ => ClockTime(None), + } + } + } + + impl<'a> ops::$op<&'a u64> for ClockTime { + type Output = ClockTime; + + fn $op_name(self, other: &'a u64) -> ClockTime { + self.$op_name(*other) + } + } + + impl ops::$op_assign for ClockTime { + fn $op_assign_name(&mut self, other: u64) { + match self.0 { + Some(a) => self.0 = Some($e(a, other)), + _ => self.0 = None, + } + } + } + + impl<'a> ops::$op_assign<&'a u64> for ClockTime { + fn $op_assign_name(&mut self, other: &'a u64) { + self.$op_assign_name(*other) + } + } + }; +); + +impl_op_u64!(Mul, mul, MulAssign, mul_assign, |a, b| a * b); +impl_op_u64!(Div, div, DivAssign, div_assign, |a, b| a / b); +impl_op_u64!(Rem, rem, RemAssign, rem_assign, |a, b| a % b); + +impl ops::Mul for u64 { + type Output = ClockTime; + + fn mul(self, other: ClockTime) -> ClockTime { + other.mul(self) + } +} + +impl<'a> ops::Mul<&'a ClockTime> for u64 { + type Output = ClockTime; + + fn mul(self, other: &'a ClockTime) -> ClockTime { + other.mul(self) + } +} + +#[doc(hidden)] +impl ToGlib for ClockTime { + type GlibType = ffi::GstClockTime; + + fn to_glib(&self) -> ffi::GstClockTime { + match self.0 { + None => ffi::GST_CLOCK_TIME_NONE, + Some(v) => v, + } + } +} + +#[doc(hidden)] +impl FromGlib for ClockTime { + fn from_glib(value: ffi::GstClockTime) -> Self { + skip_assert_initialized!(); + match value { + ffi::GST_CLOCK_TIME_NONE => ClockTime(None), + value => ClockTime(Some(value)), + } + } +} + +impl MulDiv for ClockTime { + type Output = ClockTime; + + fn mul_div_floor(self, num: ClockTime, denom: ClockTime) -> Option { + match (self.0, num.0, denom.0) { + (Some(s), Some(n), Some(d)) => s.mul_div_floor(n, d).map(ClockTime::new), + _ => Some(ClockTime(None)), + } + } + + fn mul_div_round(self, num: ClockTime, denom: ClockTime) -> Option { + match (self.0, num.0, denom.0) { + (Some(s), Some(n), Some(d)) => s.mul_div_round(n, d).map(ClockTime::new), + _ => Some(ClockTime(None)), + } + } + + fn mul_div_ceil(self, num: ClockTime, denom: ClockTime) -> Option { + match (self.0, num.0, denom.0) { + (Some(s), Some(n), Some(d)) => s.mul_div_ceil(n, d).map(ClockTime::new), + _ => Some(ClockTime(None)), + } + } +} + +impl<'a> MulDiv<&'a ClockTime> for ClockTime { + type Output = ClockTime; + + fn mul_div_floor(self, num: &ClockTime, denom: &ClockTime) -> Option { + self.mul_div_floor(*num, *denom) + } + + fn mul_div_round(self, num: &ClockTime, denom: &ClockTime) -> Option { + self.mul_div_round(*num, *denom) + } + + fn mul_div_ceil(self, num: &ClockTime, denom: &ClockTime) -> Option { + self.mul_div_ceil(*num, *denom) + } +} + +impl<'a> MulDiv for ClockTime { + type Output = ClockTime; + + fn mul_div_floor(self, num: u64, denom: u64) -> Option { + self.mul_div_floor(ClockTime::from(num), ClockTime::from(denom)) + } + + fn mul_div_round(self, num: u64, denom: u64) -> Option { + self.mul_div_round(ClockTime::from(num), ClockTime::from(denom)) + } + + fn mul_div_ceil(self, num: u64, denom: u64) -> Option { + self.mul_div_ceil(ClockTime::from(num), ClockTime::from(denom)) + } +} + +impl<'a> MulDiv<&'a u64> for ClockTime { + type Output = ClockTime; + + fn mul_div_floor(self, num: &u64, denom: &u64) -> Option { + self.mul_div_floor(*num, *denom) + } + + fn mul_div_round(self, num: &u64, denom: &u64) -> Option { + self.mul_div_round(*num, *denom) + } + + fn mul_div_ceil(self, num: &u64, denom: &u64) -> Option { + self.mul_div_ceil(*num, *denom) + } +} diff --git a/gstreamer/src/element.rs b/gstreamer/src/element.rs index 0bd5ffc02..293aa92a5 100644 --- a/gstreamer/src/element.rs +++ b/gstreamer/src/element.rs @@ -19,6 +19,7 @@ use PadTemplate; use miniobject::MiniObject; use std::ffi::CStr; +use std::mem; use libc; @@ -134,6 +135,29 @@ pub trait ElementExtManual { #[cfg(any(feature = "v1_10", feature = "dox"))] fn remove_property_notify_watch(&self, watch_id: NotifyWatchId); + + fn query_convert>( + &self, + src_val: V, + dest_format: ::Format, + ) -> Option<::FormatValue>; + fn query_duration(&self, format: ::Format) -> Option<::FormatValue>; + fn query_position(&self, format: ::Format) -> Option<::FormatValue>; + + fn seek>( + &self, + rate: f64, + flags: ::SeekFlags, + start_type: ::SeekType, + start: V, + stop_type: ::SeekType, + stop: V, + ) -> Result<(), glib::error::BoolError>; + fn seek_simple>( + &self, + seek_flags: ::SeekFlags, + seek_pos: V, + ) -> Result<(), glib::error::BoolError>; } impl> ElementExtManual for O { @@ -337,6 +361,111 @@ impl> ElementExtManual for O { ffi::gst_element_remove_property_notify_watch(self.to_glib_none().0, watch_id.0); } } + + fn query_convert>( + &self, + src_val: V, + dest_format: ::Format, + ) -> Option<::FormatValue> { + let src_val = src_val.into(); + unsafe { + let mut dest_val = mem::uninitialized(); + let ret = from_glib(ffi::gst_element_query_convert( + self.to_glib_none().0, + src_val.to_format().to_glib(), + src_val.to_value(), + dest_format.to_glib(), + &mut dest_val, + )); + if ret { + Some(::FormatValue::new(dest_format, dest_val)) + } else { + None + } + } + } + + fn query_duration(&self, format: ::Format) -> Option<::FormatValue> { + unsafe { + let mut duration = mem::uninitialized(); + let ret = from_glib(ffi::gst_element_query_duration( + self.to_glib_none().0, + format.to_glib(), + &mut duration, + )); + if ret { + Some(::FormatValue::new(format, duration)) + } else { + None + } + } + } + + fn query_position(&self, format: ::Format) -> Option<::FormatValue> { + unsafe { + let mut cur = mem::uninitialized(); + let ret = from_glib(ffi::gst_element_query_position( + self.to_glib_none().0, + format.to_glib(), + &mut cur, + )); + if ret { + Some(::FormatValue::new(format, cur)) + } else { + None + } + } + } + + fn seek>( + &self, + rate: f64, + flags: ::SeekFlags, + start_type: ::SeekType, + start: V, + stop_type: ::SeekType, + stop: V, + ) -> Result<(), glib::error::BoolError> { + let start = start.into(); + let stop = stop.into(); + + assert_eq!(stop.to_format(), start.to_format()); + + unsafe { + glib::error::BoolError::from_glib( + ffi::gst_element_seek( + self.to_glib_none().0, + rate, + start.to_format().to_glib(), + flags.to_glib(), + start_type.to_glib(), + start.to_value(), + stop_type.to_glib(), + stop.to_value(), + ), + "Failed to seek", + ) + } + } + + fn seek_simple>( + &self, + seek_flags: ::SeekFlags, + seek_pos: V, + ) -> Result<(), glib::error::BoolError> { + let seek_pos = seek_pos.into(); + unsafe { + glib::error::BoolError::from_glib( + ffi::gst_element_seek_simple( + self.to_glib_none().0, + seek_pos.to_format().to_glib(), + seek_flags.to_glib(), + seek_pos.to_value(), + ), + "Failed to seek", + ) + } + } } lazy_static!{ diff --git a/gstreamer/src/event.rs b/gstreamer/src/event.rs index e048f2a53..f1357f968 100644 --- a/gstreamer/src/event.rs +++ b/gstreamer/src/event.rs @@ -151,14 +151,17 @@ impl GstRc { TagBuilder::new(tags) } - pub fn new_buffer_size<'a>( - format: ::Format, - minsize: i64, - maxsize: i64, + pub fn new_buffer_size<'a, V: Into<::FormatValue>>( + minsize: V, + maxsize: V, async: bool, ) -> BufferSizeBuilder<'a> { assert_initialized_main_thread!(); - BufferSizeBuilder::new(format, minsize, maxsize, async) + let minsize = minsize.into(); + let maxsize = maxsize.into(); + assert_eq!(minsize.to_format(), maxsize.to_format()); + + BufferSizeBuilder::new(minsize, maxsize, async) } pub fn new_sink_message<'a>(name: &'a str, msg: &'a ::Message) -> SinkMessageBuilder<'a> { @@ -191,9 +194,10 @@ impl GstRc { ProtectionBuilder::new(system_id, data, origin) } - pub fn new_segment_done<'a>(format: ::Format, position: i64) -> SegmentDoneBuilder<'a> { + pub fn new_segment_done<'a, V: Into<::FormatValue>>(position: V) -> SegmentDoneBuilder<'a> { assert_initialized_main_thread!(); - SegmentDoneBuilder::new(format, position) + let position = position.into(); + SegmentDoneBuilder::new(position) } pub fn new_gap<'a>(timestamp: u64, duration: u64) -> GapBuilder<'a> { @@ -211,17 +215,20 @@ impl GstRc { QosBuilder::new(type_, proportion, diff, timestamp) } - pub fn new_seek<'a>( + pub fn new_seek<'a, V: Into<::FormatValue>>( rate: f64, - format: ::Format, flags: ::SeekFlags, start_type: ::SeekType, - start: i64, + start: V, stop_type: ::SeekType, - stop: i64, + stop: V, ) -> SeekBuilder<'a> { assert_initialized_main_thread!(); - SeekBuilder::new(rate, format, flags, start_type, start, stop_type, stop) + let start = start.into(); + let stop = stop.into(); + assert_eq!(start.to_format(), stop.to_format()); + + SeekBuilder::new(rate, flags, start_type, start, stop_type, stop) } pub fn new_navigation<'a>(structure: ::Structure) -> NavigationBuilder<'a> { @@ -436,7 +443,7 @@ impl<'a> Tag<'a> { pub struct BufferSize<'a>(&'a EventRef); impl<'a> BufferSize<'a> { - pub fn get(&self) -> (::Format, i64, i64, bool) { + pub fn get(&self) -> (::FormatValue, ::FormatValue, bool) { unsafe { let mut fmt = mem::uninitialized(); let mut minsize = mem::uninitialized(); @@ -450,7 +457,11 @@ impl<'a> BufferSize<'a> { &mut maxsize, &mut async, ); - (from_glib(fmt), minsize, maxsize, from_glib(async)) + ( + ::FormatValue::new(from_glib(fmt), minsize), + ::FormatValue::new(from_glib(fmt), maxsize), + from_glib(async), + ) } } } @@ -522,14 +533,14 @@ impl<'a> Protection<'a> { pub struct SegmentDone<'a>(&'a EventRef); impl<'a> SegmentDone<'a> { - pub fn get(&self) -> (::Format, i64) { + pub fn get(&self) -> ::FormatValue { unsafe { let mut fmt = mem::uninitialized(); let mut position = mem::uninitialized(); ffi::gst_event_parse_segment_done(self.0.as_mut_ptr(), &mut fmt, &mut position); - (from_glib(fmt), position) + ::FormatValue::new(from_glib(fmt), position) } } } @@ -573,7 +584,16 @@ impl<'a> Qos<'a> { pub struct Seek<'a>(&'a EventRef); impl<'a> Seek<'a> { - pub fn get(&self) -> (f64, ::Format, ::SeekFlags, ::SeekType, i64, ::SeekType, i64) { + pub fn get( + &self, + ) -> ( + f64, + ::SeekFlags, + ::SeekType, + ::FormatValue, + ::SeekType, + ::FormatValue, + ) { unsafe { let mut rate = mem::uninitialized(); let mut fmt = mem::uninitialized(); @@ -596,12 +616,11 @@ impl<'a> Seek<'a> { ( rate, - from_glib(fmt), from_glib(flags), from_glib(start_type), - start, + ::FormatValue::new(from_glib(fmt), start), from_glib(stop_type), - stop, + ::FormatValue::new(from_glib(fmt), stop), ) } } @@ -921,19 +940,17 @@ pub struct BufferSizeBuilder<'a> { seqnum: Option, running_time_offset: Option, other_fields: Vec<(&'a str, &'a ToValue)>, - fmt: ::Format, - minsize: i64, - maxsize: i64, + minsize: ::FormatValue, + maxsize: ::FormatValue, async: bool, } impl<'a> BufferSizeBuilder<'a> { - fn new(fmt: ::Format, minsize: i64, maxsize: i64, async: bool) -> Self { + fn new(minsize: ::FormatValue, maxsize: ::FormatValue, async: bool) -> Self { skip_assert_initialized!(); Self { seqnum: None, running_time_offset: None, other_fields: Vec::new(), - fmt: fmt, minsize: minsize, maxsize: maxsize, async: async, @@ -941,7 +958,12 @@ impl<'a> BufferSizeBuilder<'a> { } event_builder_generic_impl!(|s: &Self| { - ffi::gst_event_new_buffer_size(s.fmt.to_glib(), s.minsize, s.maxsize, s.async.to_glib()) + ffi::gst_event_new_buffer_size( + s.minsize.to_format().to_glib(), + s.minsize.to_value(), + s.maxsize.to_value(), + s.async.to_glib(), + ) }); } @@ -1067,23 +1089,21 @@ pub struct SegmentDoneBuilder<'a> { seqnum: Option, running_time_offset: Option, other_fields: Vec<(&'a str, &'a ToValue)>, - fmt: ::Format, - position: i64, + position: ::FormatValue, } impl<'a> SegmentDoneBuilder<'a> { - fn new(fmt: ::Format, position: i64) -> Self { + fn new(position: ::FormatValue) -> Self { skip_assert_initialized!(); Self { seqnum: None, running_time_offset: None, other_fields: Vec::new(), - fmt: fmt, position: position, } } event_builder_generic_impl!(|s: &Self| { - ffi::gst_event_new_segment_done(s.fmt.to_glib(), s.position) + ffi::gst_event_new_segment_done(s.position.to_format().to_glib(), s.position.to_value()) }); } @@ -1142,22 +1162,20 @@ pub struct SeekBuilder<'a> { running_time_offset: Option, other_fields: Vec<(&'a str, &'a ToValue)>, rate: f64, - fmt: ::Format, flags: ::SeekFlags, start_type: ::SeekType, - start: i64, + start: ::FormatValue, stop_type: ::SeekType, - stop: i64, + stop: ::FormatValue, } impl<'a> SeekBuilder<'a> { fn new( rate: f64, - fmt: ::Format, flags: ::SeekFlags, start_type: ::SeekType, - start: i64, + start: ::FormatValue, stop_type: ::SeekType, - stop: i64, + stop: ::FormatValue, ) -> Self { skip_assert_initialized!(); Self { @@ -1165,7 +1183,6 @@ impl<'a> SeekBuilder<'a> { running_time_offset: None, other_fields: Vec::new(), rate: rate, - fmt: fmt, flags: flags, start_type, start, @@ -1177,12 +1194,12 @@ impl<'a> SeekBuilder<'a> { event_builder_generic_impl!(|s: &Self| { ffi::gst_event_new_seek( s.rate, - s.fmt.to_glib(), + s.start.to_format().to_glib(), s.flags.to_glib(), s.start_type.to_glib(), - s.start, + s.start.to_value(), s.stop_type.to_glib(), - s.stop, + s.stop.to_value(), ) }); } diff --git a/gstreamer/src/format.rs b/gstreamer/src/format.rs new file mode 100644 index 000000000..a906c8d64 --- /dev/null +++ b/gstreamer/src/format.rs @@ -0,0 +1,169 @@ +// Copyright (C) 2017 Sebastian Dröge +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use ClockTime; +use Format; + +#[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] +pub enum FormatValue { + Undefined(i64), + Default(Option), + Bytes(Option), + Time(ClockTime), + Buffers(Option), + Percent(Option), + Other(Format, i64), +} + +impl FormatValue { + pub fn new(format: Format, value: i64) -> Self { + match format { + Format::Undefined => FormatValue::Undefined(value), + Format::Default => FormatValue::Default(if value == -1 { + None + } else { + Some(value as u64) + }), + Format::Bytes => FormatValue::Bytes(if value == -1 { + None + } else { + Some(value as u64) + }), + Format::Time => FormatValue::Time(if value == -1 { + ClockTime::none() + } else { + ClockTime::from(value as u64) + }), + Format::Buffers => FormatValue::Buffers(if value == -1 { + None + } else { + Some(value as u64) + }), + Format::Percent => FormatValue::Percent(if value == -1 { + None + } else { + Some(value as u32) + }), + Format::__Unknown(_) => FormatValue::Other(format, value), + } + } + + pub fn from_undefined(v: i64) -> Self { + FormatValue::Undefined(v) + } + + pub fn from_default>>(v: V) -> Self { + FormatValue::Default(v.into()) + } + + pub fn from_bytes>>(v: V) -> Self { + FormatValue::Bytes(v.into()) + } + + pub fn from_time(v: ClockTime) -> Self { + FormatValue::Time(v) + } + + pub fn from_buffers>>(v: V) -> Self { + FormatValue::Buffers(v.into()) + } + + pub fn from_percent>>(v: V) -> Self { + FormatValue::Percent(v.into()) + } + + pub fn from_other(format: Format, v: i64) -> Self { + FormatValue::Other(format, v) + } + + pub fn to_format(&self) -> Format { + match *self { + FormatValue::Undefined(_) => Format::Undefined, + FormatValue::Default(_) => Format::Default, + FormatValue::Bytes(_) => Format::Bytes, + FormatValue::Time(_) => Format::Time, + FormatValue::Buffers(_) => Format::Buffers, + FormatValue::Percent(_) => Format::Percent, + FormatValue::Other(f, _) => f, + } + } + + pub fn to_value(&self) -> i64 { + match *self { + FormatValue::Undefined(v) => v, + FormatValue::Default(v) => v.map(|v| v as i64).unwrap_or(-1), + FormatValue::Bytes(v) => v.map(|v| v as i64).unwrap_or(-1), + FormatValue::Time(v) => v.map(|v| v as i64).unwrap_or(-1), + FormatValue::Buffers(v) => v.map(|v| v as i64).unwrap_or(-1), + FormatValue::Percent(v) => v.map(|v| v as i64).unwrap_or(-1), + FormatValue::Other(_, v) => v, + } + } + + pub fn try_to_undefined(&self) -> Option { + if let FormatValue::Undefined(v) = *self { + Some(v) + } else { + None + } + } + + pub fn try_to_default(&self) -> Option> { + if let FormatValue::Default(v) = *self { + Some(v) + } else { + None + } + } + + pub fn try_to_bytes(&self) -> Option> { + if let FormatValue::Bytes(v) = *self { + Some(v) + } else { + None + } + } + + pub fn try_to_time(&self) -> Option { + if let FormatValue::Time(v) = *self { + Some(v) + } else { + None + } + } + + pub fn try_to_buffers(&self) -> Option> { + if let FormatValue::Buffers(v) = *self { + Some(v) + } else { + None + } + } + + pub fn try_to_percent(&self) -> Option> { + if let FormatValue::Percent(v) = *self { + Some(v) + } else { + None + } + } + + pub fn try_to_other(&self) -> Option<(Format, i64)> { + if let FormatValue::Other(f, v) = *self { + Some((f, v)) + } else { + None + } + } +} + +impl From for FormatValue { + fn from(v: ClockTime) -> FormatValue { + FormatValue::Time(v) + } +} diff --git a/gstreamer/src/lib.rs b/gstreamer/src/lib.rs index 18cbced3e..321890b3a 100644 --- a/gstreamer/src/lib.rs +++ b/gstreamer/src/lib.rs @@ -25,6 +25,8 @@ extern crate num_rational; #[cfg(feature = "futures")] extern crate futures; +extern crate muldiv; + use glib::translate::{from_glib, from_glib_full}; macro_rules! callback_guard { @@ -102,6 +104,8 @@ mod iterator; mod device_provider; mod parse_context; mod enums; +mod clock_time; +mod format; pub use object::GstObjectExtManual; pub use element::{ElementExtManual, ElementMessageType, NotifyWatchId}; pub use element::{ELEMENT_METADATA_AUTHOR, ELEMENT_METADATA_DESCRIPTION, ELEMENT_METADATA_DOC_URI, @@ -117,6 +121,8 @@ pub use parse_context::ParseContext; #[cfg(feature = "futures")] pub use bus::BusStream; pub use enums::{StateChangeSuccess, StateChangeError}; +pub use clock_time::ClockTime; +pub use format::FormatValue; mod value; pub use value::*; @@ -151,12 +157,15 @@ pub fn init() -> Result<(), glib::Error> { } pub const BUFFER_OFFSET_NONE: u64 = ffi::GST_BUFFER_OFFSET_NONE; -pub const CLOCK_TIME_NONE: ClockTime = ffi::GST_CLOCK_TIME_NONE; +pub const CLOCK_TIME_NONE: ClockTime = ClockTime(None); -pub const SECOND: ClockTime = 1_000_000_000; -pub const MSECOND: ClockTime = 1_000_000; -pub const USECOND: ClockTime = 1_000; -pub const NSECOND: ClockTime = 1; +pub const SECOND: ClockTime = ClockTime(Some(1_000_000_000)); +pub const MSECOND: ClockTime = ClockTime(Some(1_000_000)); +pub const USECOND: ClockTime = ClockTime(Some(1_000)); +pub const NSECOND: ClockTime = ClockTime(Some(1)); + +pub const FORMAT_PERCENT_MAX: u32 = ffi::GST_FORMAT_PERCENT_MAX as u32; +pub const FORMAT_PERCENT_SCALE: u32 = ffi::GST_FORMAT_PERCENT_SCALE as u32; // Re-export all the traits in a prelude module, so that applications // can always "use gst::prelude::*" without getting conflicts @@ -178,6 +187,8 @@ pub mod prelude { pub use tags::Tag; pub use miniobject::MiniObject; + + pub use muldiv::MulDiv; } mod utils; diff --git a/gstreamer/src/message.rs b/gstreamer/src/message.rs index e78ba8041..8ac0adeac 100644 --- a/gstreamer/src/message.rs +++ b/gstreamer/src/message.rs @@ -200,14 +200,16 @@ impl GstRc { ElementBuilder::new(structure) } - pub fn new_segment_start<'a>(format: ::Format, position: i64) -> SegmentStartBuilder<'a> { + pub fn new_segment_start<'a, V: Into<::FormatValue>>(position: V) -> SegmentStartBuilder<'a> { assert_initialized_main_thread!(); - SegmentStartBuilder::new(format, position) + let position = position.into(); + SegmentStartBuilder::new(position) } - pub fn new_segment_done<'a>(format: ::Format, position: i64) -> SegmentDoneBuilder<'a> { + pub fn new_segment_done<'a, V: Into<::FormatValue>>(position: V) -> SegmentDoneBuilder<'a> { assert_initialized_main_thread!(); - SegmentDoneBuilder::new(format, position) + let position = position.into(); + SegmentDoneBuilder::new(position) } pub fn new_duration_changed<'a>() -> DurationChangedBuilder<'a> { @@ -723,28 +725,28 @@ pub struct Element<'a>(&'a MessageRef); pub struct SegmentStart<'a>(&'a MessageRef); impl<'a> SegmentStart<'a> { - pub fn get(&self) -> (::Format, i64) { + pub fn get(&self) -> ::FormatValue { unsafe { let mut format = mem::uninitialized(); let mut position = mem::uninitialized(); ffi::gst_message_parse_segment_start(self.0.as_mut_ptr(), &mut format, &mut position); - (from_glib(format), position) + ::FormatValue::new(from_glib(format), position) } } } pub struct SegmentDone<'a>(&'a MessageRef); impl<'a> SegmentDone<'a> { - pub fn get(&self) -> (::Format, i64) { + pub fn get(&self) -> ::FormatValue { unsafe { let mut format = mem::uninitialized(); let mut position = mem::uninitialized(); ffi::gst_message_parse_segment_done(self.0.as_mut_ptr(), &mut format, &mut position); - (from_glib(format), position) + ::FormatValue::new(from_glib(format), position) } } } @@ -1749,23 +1751,25 @@ pub struct SegmentStartBuilder<'a> { src: Option, seqnum: Option, other_fields: Vec<(&'a str, &'a ToValue)>, - format: ::Format, - position: i64, + position: ::FormatValue, } impl<'a> SegmentStartBuilder<'a> { - fn new(format: ::Format, position: i64) -> Self { + fn new(position: ::FormatValue) -> Self { skip_assert_initialized!(); Self { src: None, seqnum: None, other_fields: Vec::new(), - format: format, position: position, } } message_builder_generic_impl!(|s: &mut Self, src| { - ffi::gst_message_new_segment_start(src, s.format.to_glib(), s.position) + ffi::gst_message_new_segment_start( + src, + s.position.to_format().to_glib(), + s.position.to_value(), + ) }); } @@ -1773,23 +1777,25 @@ pub struct SegmentDoneBuilder<'a> { src: Option, seqnum: Option, other_fields: Vec<(&'a str, &'a ToValue)>, - format: ::Format, - position: i64, + position: ::FormatValue, } impl<'a> SegmentDoneBuilder<'a> { - fn new(format: ::Format, position: i64) -> Self { + fn new(position: ::FormatValue) -> Self { skip_assert_initialized!(); Self { src: None, seqnum: None, other_fields: Vec::new(), - format: format, position: position, } } message_builder_generic_impl!(|s: &mut Self, src| { - ffi::gst_message_new_segment_done(src, s.format.to_glib(), s.position) + ffi::gst_message_new_segment_done( + src, + s.position.to_format().to_glib(), + s.position.to_value(), + ) }); } diff --git a/gstreamer/src/pad.rs b/gstreamer/src/pad.rs index 24c58d601..3cdcce13b 100644 --- a/gstreamer/src/pad.rs +++ b/gstreamer/src/pad.rs @@ -11,6 +11,7 @@ use PadProbeType; use PadProbeReturn; use Buffer; use BufferList; +use Format; use FlowReturn; use Query; use QueryRef; @@ -183,6 +184,21 @@ pub trait PadExtManual { F: Fn(&Pad, &Option<::Object>) + Send + Sync + 'static; fn start_task(&self, func: F) -> Result<(), glib::BoolError>; + + fn peer_query_convert>( + &self, + src_val: V, + dest_format: Format, + ) -> Option<::FormatValue>; + fn peer_query_duration(&self, format: Format) -> Option<::FormatValue>; + fn peer_query_position(&self, format: Format) -> Option<::FormatValue>; + fn query_convert>( + &self, + src_val: V, + dest_format: Format, + ) -> Option<::FormatValue>; + fn query_duration(&self, format: Format) -> Option<::FormatValue>; + fn query_position(&self, format: Format) -> Option<::FormatValue>; } impl> PadExtManual for O { @@ -593,6 +609,117 @@ impl> PadExtManual for O { ) } } + + fn peer_query_convert>( + &self, + src_val: V, + dest_format: Format, + ) -> Option<::FormatValue> { + let src_val = src_val.into(); + unsafe { + let mut dest_val = mem::uninitialized(); + let ret = from_glib(ffi::gst_pad_peer_query_convert( + self.to_glib_none().0, + src_val.to_format().to_glib(), + src_val.to_value(), + dest_format.to_glib(), + &mut dest_val, + )); + if ret { + Some(::FormatValue::new(dest_format, dest_val)) + } else { + None + } + } + } + + fn peer_query_duration(&self, format: Format) -> Option<::FormatValue> { + unsafe { + let mut duration = mem::uninitialized(); + let ret = from_glib(ffi::gst_pad_peer_query_duration( + self.to_glib_none().0, + format.to_glib(), + &mut duration, + )); + if ret { + Some(::FormatValue::new(format, duration)) + } else { + None + } + } + } + + fn peer_query_position(&self, format: Format) -> Option<::FormatValue> { + unsafe { + let mut cur = mem::uninitialized(); + let ret = from_glib(ffi::gst_pad_peer_query_position( + self.to_glib_none().0, + format.to_glib(), + &mut cur, + )); + if ret { + Some(::FormatValue::new(format, cur)) + } else { + None + } + } + } + + fn query_convert>( + &self, + src_val: V, + dest_format: Format, + ) -> Option<::FormatValue> { + let src_val = src_val.into(); + + unsafe { + let mut dest_val = mem::uninitialized(); + let ret = from_glib(ffi::gst_pad_query_convert( + self.to_glib_none().0, + src_val.to_format().to_glib(), + src_val.to_value(), + dest_format.to_glib(), + &mut dest_val, + )); + if ret { + Some(::FormatValue::new(dest_format, dest_val)) + } else { + None + } + } + } + + fn query_duration(&self, format: Format) -> Option<::FormatValue> { + unsafe { + let mut duration = mem::uninitialized(); + let ret = from_glib(ffi::gst_pad_query_duration( + self.to_glib_none().0, + format.to_glib(), + &mut duration, + )); + if ret { + Some(::FormatValue::new(format, duration)) + } else { + None + } + } + } + + fn query_position(&self, format: Format) -> Option<::FormatValue> { + unsafe { + let mut cur = mem::uninitialized(); + let ret = from_glib(ffi::gst_pad_query_position( + self.to_glib_none().0, + format.to_glib(), + &mut cur, + )); + if ret { + Some(::FormatValue::new(format, cur)) + } else { + None + } + } + } } unsafe extern "C" fn trampoline_pad_probe( diff --git a/gstreamer/src/query.rs b/gstreamer/src/query.rs index 98f3ac623..fb5816b7d 100644 --- a/gstreamer/src/query.rs +++ b/gstreamer/src/query.rs @@ -56,12 +56,12 @@ impl GstRc { unsafe { from_glib_full(ffi::gst_query_new_segment(fmt.to_glib())) } } - pub fn new_convert(src_fmt: ::Format, value: i64, dest_fmt: ::Format) -> Self { + pub fn new_convert(value: ::FormatValue, dest_fmt: ::Format) -> Self { assert_initialized_main_thread!(); unsafe { from_glib_full(ffi::gst_query_new_convert( - src_fmt.to_glib(), - value, + value.to_format().to_glib(), + value.to_value(), dest_fmt.to_glib(), )) } @@ -207,14 +207,14 @@ pub enum QueryView { pub struct Position(T); impl<'a> Position<&'a QueryRef> { - pub fn get(&self) -> (::Format, i64) { + pub fn get(&self) -> ::FormatValue { unsafe { let mut fmt = mem::uninitialized(); let mut pos = mem::uninitialized(); ffi::gst_query_parse_position(self.0.as_mut_ptr(), &mut fmt, &mut pos); - (from_glib(fmt), pos) + ::FormatValue::new(from_glib(fmt), pos) } } @@ -224,9 +224,14 @@ impl<'a> Position<&'a QueryRef> { } impl<'a> Position<&'a mut QueryRef> { - pub fn set(&mut self, fmt: ::Format, pos: i64) { + pub fn set>(&mut self, pos: V) { + let pos = pos.into(); unsafe { - ffi::gst_query_set_position(self.0.as_mut_ptr(), fmt.to_glib(), pos); + ffi::gst_query_set_position( + self.0.as_mut_ptr(), + pos.to_format().to_glib(), + pos.to_value(), + ); } } @@ -237,14 +242,14 @@ impl<'a> Position<&'a mut QueryRef> { pub struct Duration(T); impl<'a> Duration<&'a QueryRef> { - pub fn get(&self) -> (::Format, i64) { + pub fn get(&self) -> ::FormatValue { unsafe { let mut fmt = mem::uninitialized(); let mut pos = mem::uninitialized(); ffi::gst_query_parse_duration(self.0.as_mut_ptr(), &mut fmt, &mut pos); - (from_glib(fmt), pos) + ::FormatValue::new(from_glib(fmt), pos) } } @@ -254,9 +259,14 @@ impl<'a> Duration<&'a QueryRef> { } impl<'a> Duration<&'a mut QueryRef> { - pub fn set(&mut self, fmt: ::Format, pos: i64) { + pub fn set>(&mut self, dur: V) { + let dur = dur.into(); unsafe { - ffi::gst_query_set_duration(self.0.as_mut_ptr(), fmt.to_glib(), pos); + ffi::gst_query_set_duration( + self.0.as_mut_ptr(), + dur.to_format().to_glib(), + dur.to_value(), + ); } } @@ -324,7 +334,7 @@ impl<'a> Rate<&'a mut QueryRef> { pub struct Seeking(T); impl<'a> Seeking<&'a QueryRef> { - pub fn get(&self) -> (::Format, bool, i64, i64) { + pub fn get(&self) -> (bool, ::FormatValue, ::FormatValue) { unsafe { let mut fmt = mem::uninitialized(); let mut seekable = mem::uninitialized(); @@ -338,7 +348,11 @@ impl<'a> Seeking<&'a QueryRef> { &mut end, ); - (from_glib(fmt), from_glib(seekable), start, end) + ( + from_glib(seekable), + ::FormatValue::new(from_glib(fmt), start), + ::FormatValue::new(from_glib(fmt), end), + ) } } @@ -348,14 +362,19 @@ impl<'a> Seeking<&'a QueryRef> { } impl<'a> Seeking<&'a mut QueryRef> { - pub fn set(&mut self, fmt: ::Format, seekable: bool, start: i64, end: i64) { + pub fn set>(&mut self, seekable: bool, start: V, end: V) { + let start = start.into(); + let end = end.into(); + + assert_eq!(start.to_format(), end.to_format()); + unsafe { ffi::gst_query_set_seeking( self.0.as_mut_ptr(), - fmt.to_glib(), + start.to_format().to_glib(), seekable.to_glib(), - start, - end, + start.to_value(), + end.to_value(), ); } } @@ -367,7 +386,7 @@ impl<'a> Seeking<&'a mut QueryRef> { pub struct Segment(T); impl<'a> Segment<&'a QueryRef> { - pub fn get(&self) -> (f64, ::Format, i64, i64) { + pub fn get(&self) -> (f64, ::FormatValue, ::FormatValue) { unsafe { let mut rate = mem::uninitialized(); let mut fmt = mem::uninitialized(); @@ -381,7 +400,11 @@ impl<'a> Segment<&'a QueryRef> { &mut start, &mut stop, ); - (rate, from_glib(fmt), start, stop) + ( + rate, + ::FormatValue::new(from_glib(fmt), start), + ::FormatValue::new(from_glib(fmt), stop), + ) } } @@ -391,9 +414,20 @@ impl<'a> Segment<&'a QueryRef> { } impl<'a> Segment<&'a mut QueryRef> { - pub fn set(&mut self, rate: f64, fmt: ::Format, start: i64, stop: i64) { + pub fn set>(&mut self, rate: f64, start: V, stop: V) { + let start = start.into(); + let stop = stop.into(); + + assert_eq!(start.to_format(), stop.to_format()); + unsafe { - ffi::gst_query_set_segment(self.0.as_mut_ptr(), rate, fmt.to_glib(), start, stop); + ffi::gst_query_set_segment( + self.0.as_mut_ptr(), + rate, + start.to_format().to_glib(), + start.to_value(), + stop.to_value(), + ); } } @@ -404,7 +438,7 @@ impl<'a> Segment<&'a mut QueryRef> { pub struct Convert(T); impl<'a> Convert<&'a QueryRef> { - pub fn get(&self) -> (::Format, i64, ::Format, i64) { + pub fn get(&self) -> (::FormatValue, ::FormatValue) { unsafe { let mut src_fmt = mem::uninitialized(); let mut src = mem::uninitialized(); @@ -418,7 +452,10 @@ impl<'a> Convert<&'a QueryRef> { &mut dest_fmt, &mut dest, ); - (from_glib(src_fmt), src, from_glib(dest_fmt), dest) + ( + ::FormatValue::new(from_glib(src_fmt), src), + ::FormatValue::new(from_glib(dest_fmt), dest), + ) } } @@ -428,14 +465,17 @@ impl<'a> Convert<&'a QueryRef> { } impl<'a> Convert<&'a mut QueryRef> { - pub fn set(&mut self, src_fmt: ::Format, src: i64, dest_fmt: ::Format, dest: i64) { + pub fn set>(&mut self, src: V, dest: V) { + let src = src.into(); + let dest = dest.into(); + unsafe { ffi::gst_query_set_convert( self.0.as_mut_ptr(), - src_fmt.to_glib(), - src, - dest_fmt.to_glib(), - dest, + src.to_format().to_glib(), + src.to_value(), + dest.to_format().to_glib(), + dest.to_value(), ); } } @@ -494,7 +534,7 @@ impl<'a> Buffering<&'a QueryRef> { } } - pub fn get_range(&self) -> (::Format, i64, i64, i64) { + pub fn get_range(&self) -> (::FormatValue, ::FormatValue, i64) { unsafe { let mut fmt = mem::uninitialized(); let mut start = mem::uninitialized(); @@ -508,7 +548,11 @@ impl<'a> Buffering<&'a QueryRef> { &mut stop, &mut estimated_total, ); - (from_glib(fmt), start, stop, estimated_total) + ( + ::FormatValue::new(from_glib(fmt), start), + ::FormatValue::new(from_glib(fmt), stop), + estimated_total, + ) } } @@ -531,8 +575,18 @@ impl<'a> Buffering<&'a QueryRef> { } } - pub fn get_ranges(&self) -> Vec<(i64, i64)> { + pub fn get_ranges(&self) -> Vec<(::FormatValue, ::FormatValue)> { unsafe { + let mut fmt = mem::uninitialized(); + ffi::gst_query_parse_buffering_range( + self.0.as_mut_ptr(), + &mut fmt, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ); + let fmt = from_glib(fmt); + let n = ffi::gst_query_get_n_buffering_ranges(self.0.as_mut_ptr()); let mut res = Vec::with_capacity(n as usize); for i in 0..n { @@ -545,7 +599,10 @@ impl<'a> Buffering<&'a QueryRef> { &mut stop, )); if s { - res.push((start, stop)); + res.push(( + ::FormatValue::new(fmt, start), + ::FormatValue::new(fmt, stop), + )); } } @@ -565,13 +622,18 @@ impl<'a> Buffering<&'a mut QueryRef> { } } - pub fn set_range(&mut self, fmt: ::Format, start: i64, stop: i64, estimated_total: i64) { + pub fn set_range>(&mut self, start: V, stop: V, estimated_total: i64) { + let start = start.into(); + let stop = stop.into(); + + assert_eq!(start.to_format(), stop.to_format()); + unsafe { ffi::gst_query_set_buffering_range( self.0.as_mut_ptr(), - fmt.to_glib(), - start, - stop, + start.to_format().to_glib(), + start.to_value(), + stop.to_value(), estimated_total, ); } @@ -596,10 +658,28 @@ impl<'a> Buffering<&'a mut QueryRef> { } } - pub fn add_buffering_ranges(&mut self, ranges: &[(i64, i64)]) { + pub fn add_buffering_ranges + Copy>(&mut self, ranges: &[(V, V)]) { unsafe { + let mut fmt = mem::uninitialized(); + ffi::gst_query_parse_buffering_range( + self.0.as_mut_ptr(), + &mut fmt, + ptr::null_mut(), + ptr::null_mut(), + ptr::null_mut(), + ); + let fmt = from_glib(fmt); + for &(start, stop) in ranges { - ffi::gst_query_add_buffering_range(self.0.as_mut_ptr(), start, stop); + let start = start.into(); + let stop = stop.into(); + assert_eq!(start.to_format(), fmt); + assert_eq!(stop.to_format(), fmt); + ffi::gst_query_add_buffering_range( + self.0.as_mut_ptr(), + start.to_value(), + stop.to_value(), + ); } } } @@ -955,28 +1035,25 @@ mod tests { match q.view() { QueryView::Position(ref p) => { - let (fmt, pos) = p.get(); - assert_eq!(fmt, ::Format::Time); - assert_eq!(pos, -1); + let pos = p.get(); + assert_eq!(pos.try_to_time(), Some(::CLOCK_TIME_NONE)); } _ => (), } match q.get_mut().unwrap().view_mut() { QueryView::Position(ref mut p) => { - let (fmt, pos) = p.get(); - assert_eq!(fmt, ::Format::Time); - assert_eq!(pos, -1); - p.set(::Format::Time, 2); + let pos = p.get(); + assert_eq!(pos.try_to_time(), Some(::CLOCK_TIME_NONE)); + p.set(2 * ::SECOND); } _ => (), } match q.view() { QueryView::Position(ref p) => { - let (fmt, pos) = p.get(); - assert_eq!(fmt, ::Format::Time); - assert_eq!(pos, 2); + let pos = p.get(); + assert_eq!(pos.try_to_time(), Some(2 * ::SECOND)); } _ => (), } diff --git a/tutorials/src/bin/basic-tutorial-4.rs b/tutorials/src/bin/basic-tutorial-4.rs index 5d53af5f6..cce6ae5c7 100644 --- a/tutorials/src/bin/basic-tutorial-4.rs +++ b/tutorials/src/bin/basic-tutorial-4.rs @@ -55,16 +55,16 @@ fn main() { let position = custom_data .playbin .query_position(gst::Format::Time) + .and_then(|v| v.try_to_time()) .expect("Could not query current position."); - let position = position as gst::ClockTime; // If we didn't know it yet, query the stream duration if custom_data.duration == gst::CLOCK_TIME_NONE { custom_data.duration = custom_data .playbin .query_duration(gst::Format::Time) + .and_then(|v| v.try_to_time()) .expect("Could not query current duration.") - as gst::ClockTime; } // Print current position and total duration @@ -78,9 +78,8 @@ fn main() { custom_data .playbin .seek_simple( - gst::Format::Time, gst::SeekFlags::FLUSH | gst::SeekFlags::KEY_UNIT, - (30 * gst::SECOND) as i64, + 30 * gst::SECOND, ) .expect("Failed to seek."); custom_data.seek_done = true; @@ -130,10 +129,10 @@ fn handle_message(custom_data: &mut CustomData, msg: &gst::GstRc { - let (_fmt, seekable, start, end) = seek.get(); + let (seekable, start, end) = seek.get(); custom_data.seek_enabled = seekable; if seekable { - println!("Seeking is ENABLED from {} to {}", start, end) + println!("Seeking is ENABLED from {:?} to {:?}", start, end) } else { println!("Seeking is DISABLED for this stream.") } diff --git a/tutorials/src/bin/basic-tutorial-5.rs b/tutorials/src/bin/basic-tutorial-5.rs index ec1159f2b..4cc45083c 100644 --- a/tutorials/src/bin/basic-tutorial-5.rs +++ b/tutorials/src/bin/basic-tutorial-5.rs @@ -132,9 +132,8 @@ mod tutorial5 { let pipeline = &pipeline; let value = slider.get_value() as u64; if let Err(_) = pipeline.seek_simple( - gst::Format::Time, gst::SeekFlags::FLUSH | gst::SeekFlags::KEY_UNIT, - ((value * gst::SECOND) as i64), + value * gst::SECOND, ) { eprintln!("Seeking to {} failed", value); } @@ -148,16 +147,15 @@ mod tutorial5 { let pipeline = &pipeline; let lslider = &lslider; - if let Some(dur) = pipeline.query_duration(gst::Format::Time) { - let seconds = (dur as u64) / gst::SECOND; - lslider.set_range(0.0, seconds as f64); + if let Some(gst::FormatValue::Time(dur)) = pipeline.query_duration(gst::Format::Time) { + let seconds = dur / gst::SECOND; + lslider.set_range(0.0, seconds.map(|v| v as f64).unwrap_or(0.0)); } - let position = pipeline.query_position(gst::Format::Time); - if let Some(position) = position { - let seconds = (position as u64) / gst::SECOND; + if let Some(gst::FormatValue::Time(pos)) = pipeline.query_position(gst::Format::Time) { + let seconds = pos / gst::SECOND; lslider.block_signal(&slider_update_signal_id); - lslider.set_value(seconds as f64); + lslider.set_value(seconds.map(|v| v as f64).unwrap_or(0.0)); lslider.unblock_signal(&slider_update_signal_id); }