From 014606f44cfc65078b0cf6e0cf5074198d9fdb5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 13 Nov 2018 16:51:21 +0100 Subject: [PATCH 01/18] Set player flags to enable progressive downloading --- backends/gstreamer/src/player.rs | 40 ++++++++++++++++++++++++++++++-- player/src/lib.rs | 2 +- 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 712b9845..18310a9b 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -302,7 +302,30 @@ impl GStreamerPlayer { /* video renderer */ None, /* signal dispatcher */ None, ); - // Set position interval update to 0.5 seconds. + let pipeline = player.get_pipeline(); + + // Set player to perform progressive downloading. This will make the + // player store the downloaded media in a local temporary file for + // faster playback of already-downloaded chunks. + let flags = pipeline.get_property("flags") + .map_err(|e| BackendError::GetPropertyFailed(e.0))?; + let flags_class = match FlagsClass::new(flags.type_()) { + Some(flags) => flags, + None => return Err(BackendError::PlayerFlagsSetupFailed), + }; + let flags_class = match flags_class.builder_with_value(flags) { + Some(class) => class, + None => return Err(BackendError::PlayerFlagsSetupFailed) + }; + let flags = match flags_class.set_by_nick("download") + .build() { + Some(flags) => flags, + None => return Err(BackendError::PlayerFlagsSetupFailed), + }; + pipeline.set_property("flags", &flags) + .map_err(|e| BackendError::SetPropertyFailed(e.0))?; + + // Set player position interval update to 0.5 seconds. let mut config = player.get_config(); config.set_position_update_interval(500u32); player @@ -311,7 +334,6 @@ impl GStreamerPlayer { let video_sink = gst::ElementFactory::make("appsink", None) .ok_or(PlayerError::Backend("appsink creation failed".to_owned()))?; - let pipeline = player.get_pipeline(); pipeline .set_property("video-sink", &video_sink.to_value()) .map_err(|e| PlayerError::Backend(e.to_string()))?; @@ -348,6 +370,7 @@ impl GStreamerPlayer { let inner = self.inner.borrow(); let inner = inner.as_ref().unwrap(); let observers = self.observers.clone(); + // Handle `end-of-stream` signal. inner .lock() .unwrap() @@ -357,17 +380,25 @@ impl GStreamerPlayer { }); let observers = self.observers.clone(); + // Handle `error` signal inner.lock().unwrap().player.connect_error(move |_, _| { observers.lock().unwrap().notify(PlayerEvent::Error); }); + // Handle `buffering` signal. + inner.lock().unwrap().player.connect_buffering(move |_, _| { + println!("BUFFERING"); + }); + let observers = self.observers.clone(); + // Handle `state-changed` signal. inner .lock() .unwrap() .player .connect_state_changed(move |_, player_state| { let state = match player_state { + gst_player::PlayerState::Buffering => Some(PlaybackState::Buffering), gst_player::PlayerState::Stopped => Some(PlaybackState::Stopped), gst_player::PlayerState::Paused => Some(PlaybackState::Paused), gst_player::PlayerState::Playing => Some(PlaybackState::Playing), @@ -382,6 +413,7 @@ impl GStreamerPlayer { }); let observers = self.observers.clone(); + // Handle `position-update` signal. inner .lock() .unwrap() @@ -396,6 +428,7 @@ impl GStreamerPlayer { }); let observers = self.observers.clone(); + // Handle `seek-done` signal. inner .lock() .unwrap() @@ -409,6 +442,7 @@ impl GStreamerPlayer { } }); + // Handle `media-info-updated` signal. let inner_clone = inner.clone(); let observers = self.observers.clone(); inner @@ -431,6 +465,7 @@ impl GStreamerPlayer { } }); + // Handle `duration-changed` signal. let inner_clone = inner.clone(); let observers = self.observers.clone(); inner @@ -472,6 +507,7 @@ impl GStreamerPlayer { let observers = self.observers.clone(); let renderers = self.renderers.clone(); + // Set appsink callbacks. inner.lock().unwrap().appsink.set_callbacks( gst_app::AppSinkCallbacks::new() .new_preroll(|_| gst::FlowReturn::Ok) diff --git a/player/src/lib.rs b/player/src/lib.rs index 3f798b90..84c4f185 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -11,7 +11,7 @@ use std::sync::{Arc, Mutex}; #[derive(Clone, Debug, Deserialize, Serialize)] pub enum PlaybackState { Stopped, - // Buffering, + Buffering, Paused, Playing, } From 7cb85f05485fea5c01d5fb04641e3344a85e35bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 14 Nov 2018 12:24:25 +0100 Subject: [PATCH 02/18] Handle appsrc scheduling query to report itself as bandwidth limited --- backends/gstreamer/src/player.rs | 70 ++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 13 deletions(-) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 18310a9b..96114d44 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -1,6 +1,7 @@ use glib; use glib::*; -use gst; +use gst::{self, ElementExt, PadExtManual}; +use gst::query::QueryView; use gst_app::{self, AppSrcCallbacks, AppStreamType}; use gst_player; use gst_player::{PlayerMediaInfo, PlayerStreamInfoExt}; @@ -317,7 +318,8 @@ impl GStreamerPlayer { Some(class) => class, None => return Err(BackendError::PlayerFlagsSetupFailed) }; - let flags = match flags_class.set_by_nick("download") + let flags = match flags_class + .set_by_nick("download") .build() { Some(flags) => flags, None => return Err(BackendError::PlayerFlagsSetupFailed), @@ -386,8 +388,8 @@ impl GStreamerPlayer { }); // Handle `buffering` signal. - inner.lock().unwrap().player.connect_buffering(move |_, _| { - println!("BUFFERING"); + inner.lock().unwrap().player.connect_buffering(move |_, data| { + println!("BUFFERING {:?}", data); }); let observers = self.observers.clone(); @@ -540,15 +542,57 @@ impl GStreamerPlayer { let is_ready_clone = self.is_ready.clone(); let observers = self.observers.clone(); let connect_result = pipeline.connect("source-setup", false, move |args| { - let source = args[1].get::(); - if source.is_none() { - let _ = sender - .lock() - .unwrap() - .send(Err(PlayerError::Backend("Source setup failed".to_owned()))); - return None; - } - let source = source.unwrap(); + let source = match args[1].get::() { + Some(source) => source, + None => { + let _ = sender + .lock() + .unwrap() + .send(Err(PlayerError::Backend("Source setup failed".to_owned()))); + return None; + }, + }; + + // In order to make buffering/downloading work as we want, apart from + // setting the appropriate flags, the source needs to either: + // + // 1. be an http, mms, etc. scheme + // 2. report that it is "bandwidth limited". + // + // 1. is not straightforward because we are using an appsrc scheme for now. + // This may change in the future if we end up implementing something + // like a custom `servohttpsrc` or wrapping the existing appsrc + // in a bin src that implements http/https/data URI handlers, which + // is what WebKit does. + // + // For 2. we need to make appsrc handle the scheduling properties query + // to report that it "is bandwidth limited". + let src_pad = match source.get_static_pad("src") { + Some(src_pad) => src_pad, + None => { + let _ = sender + .lock() + .unwrap() + .send(Err(BackendError::PlayerSourceSetupFailed)); + return None; + }, + }; + src_pad.add_probe(gst::PadProbeType::QUERY_UPSTREAM, |_, probe_info| { + if let Some(gst::PadProbeData::Query(ref mut query)) = probe_info.data { + if let QueryView::Scheduling(ref mut query) = query.view_mut() { + query.set( + gst::SchedulingFlags::SEQUENTIAL | + gst::SchedulingFlags::BANDWIDTH_LIMITED, + 1, -1, 0 + ); + query.add_scheduling_modes(&[gst::PadMode::Push]); + println!("QUERY {:?}", query); + return gst::PadProbeReturn::Handled; + } + } + gst::PadProbeReturn::Ok + }); + let mut inner = inner_clone.lock().unwrap(); let appsrc = source .clone() From 86333feccc39d538da7820d8c6524fac970d3289 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 16 Nov 2018 09:48:23 +0100 Subject: [PATCH 03/18] Introduce servosrc --- Cargo.lock | 72 +++++-- Cargo.toml | 3 +- backends/gstreamer/Cargo.toml | 3 + backends/gstreamer/source-element/Cargo.toml | 19 ++ backends/gstreamer/source-element/src/lib.rs | 12 ++ .../gstreamer/source-element/src/source.rs | 192 ++++++++++++++++++ backends/gstreamer/src/lib.rs | 2 + backends/gstreamer/src/player.rs | 100 +++------ 8 files changed, 321 insertions(+), 82 deletions(-) create mode 100644 backends/gstreamer/source-element/Cargo.toml create mode 100644 backends/gstreamer/source-element/src/lib.rs create mode 100644 backends/gstreamer/source-element/src/source.rs diff --git a/Cargo.lock b/Cargo.lock index 4faee7bf..175afd23 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -525,6 +525,17 @@ dependencies = [ "x11-dl 2.18.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gobject-subclass" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gobject-sys" version = "0.7.0" @@ -535,6 +546,24 @@ dependencies = [ "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "gst-plugin" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-subclass 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-base 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "gstreamer" version = "0.12.0" @@ -545,7 +574,7 @@ dependencies = [ "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "muldiv 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -565,7 +594,7 @@ dependencies = [ "gstreamer-app-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -576,7 +605,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -593,7 +622,7 @@ dependencies = [ "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-audio-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -604,7 +633,7 @@ dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -620,7 +649,7 @@ dependencies = [ "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -630,7 +659,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -646,7 +675,7 @@ dependencies = [ "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-player-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -658,7 +687,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", @@ -666,7 +695,7 @@ dependencies = [ [[package]] name = "gstreamer-sys" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -687,7 +716,7 @@ dependencies = [ "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -700,7 +729,7 @@ dependencies = [ "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", "pkg-config 0.3.12 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1278,6 +1307,7 @@ dependencies = [ "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "servo-media-audio 0.1.0", "servo-media-player 0.1.0", + "source-element 1.0.0", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1346,6 +1376,20 @@ dependencies = [ "wayland-protocols 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "source-element" +version = "1.0.0" +dependencies = [ + "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-subclass 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gst-plugin 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "stable_deref_trait" version = "1.1.1" @@ -1751,7 +1795,9 @@ dependencies = [ "checksum glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740f7fda8dde5f5e3944dabdb4a73ac6094a8a7fdf0af377468e98ca93733e61" "checksum glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3573351e846caed9f11207b275cd67bc07f0c2c94fb628e5d7c92ca056c7882d" "checksum glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "535c6eda58adbb227604b2db10a022ffd6339d7ea3e970f338e7d98aeb24fcc3" +"checksum gobject-subclass 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d9779ce804d2fb1cbe2df538224e9c4f541d208e9d7a30f6f2813c953930ff3" "checksum gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08475e4a08f27e6e2287005950114735ed61cec2cb8c1187682a5aec8c69b715" +"checksum gst-plugin 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9f81b965c9c999b52b554d8a13d5ab0bda32b0389e652fd9fcb5bceb0ed9bc2" "checksum gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df451f98ea8b987b5fc1b647b9f038ca6ea106b08c3bccc1ef3126d4f0a687c1" "checksum gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f4f865cf7f22c66907372a2e3b0f0ced3d3fedab823641d6667d2568be71408" "checksum gstreamer-app-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0b8319fe7a8a015412a76a56b248a3c68561a39225a3fa0fcbb58aab8e12392" @@ -1761,7 +1807,7 @@ dependencies = [ "checksum gstreamer-base-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1eb57a7d013604ab7af2b843b62b13b8fb30f22d066919f7e198f528c3296cd0" "checksum gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1144c6c5c3af25dd1f89b4f9d2762f1c2d8789e65cdc79e2451dd24350d84dd2" "checksum gstreamer-player-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0e642cb58d3733e2724def7186101bb00144fc97d45b2c379eba6d0c0662dec" -"checksum gstreamer-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "18e3ff41a9e0bc96d345f25b1dd00cfda31edcab2aa19535af5312fdb80d062b" +"checksum gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "3aec69f30ab98a7b0cf4a29179eeffa8a1e7d6062f5ee55e9792917cb0980bda" "checksum gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1f04816d7e183714830da26274f97e7aeff09ae6641058538d21443b4ec07d" "checksum gstreamer-video-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e2efb301a0b94fa4af503122faa04247085936dd888fd59fa4e21eab3cbd37" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" diff --git a/Cargo.toml b/Cargo.toml index ad4c9b37..40ec6272 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,10 +2,11 @@ members = [ "audio", "backends/gstreamer", + "backends/gstreamer/source-element", "examples", "examples/android/lib", "player", "servo-media", - "servo-media-derive" + "servo-media-derive", ] license = "MPL-2.0" diff --git a/backends/gstreamer/Cargo.toml b/backends/gstreamer/Cargo.toml index 3347dcbd..045aa1f2 100644 --- a/backends/gstreamer/Cargo.toml +++ b/backends/gstreamer/Cargo.toml @@ -36,3 +36,6 @@ path = "../../audio" [dependencies.servo-media-player] path = "../../player" + +[dependencies.source-element] +path = "source-element" diff --git a/backends/gstreamer/source-element/Cargo.toml b/backends/gstreamer/source-element/Cargo.toml new file mode 100644 index 00000000..28035dd5 --- /dev/null +++ b/backends/gstreamer/source-element/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "source-element" +version = "1.0.0" +repository = "https://github.com/servo/media" +license = "MPL2.0" + +[dependencies] +glib = "0.6" +glib-sys = "0.7" +gobject-subclass = "0.2" +gobject-sys = "0.7" +gst-plugin = "0.3" +gstreamer = "0.12" +gstreamer-app = "0.12" +gstreamer-sys = "0.6.1" + +[lib] +name = "source_element" +path = "src/lib.rs" diff --git a/backends/gstreamer/source-element/src/lib.rs b/backends/gstreamer/source-element/src/lib.rs new file mode 100644 index 00000000..96604a5b --- /dev/null +++ b/backends/gstreamer/source-element/src/lib.rs @@ -0,0 +1,12 @@ +#[macro_use] +extern crate glib; +extern crate glib_sys as glib_ffi; +extern crate gobject_sys as gobject_ffi; +#[macro_use] +extern crate gobject_subclass; +extern crate gst_plugin; +extern crate gstreamer as gst; +extern crate gstreamer_app as gst_app; +extern crate gstreamer_sys as gst_ffi; + +pub mod source; diff --git a/backends/gstreamer/source-element/src/source.rs b/backends/gstreamer/source-element/src/source.rs new file mode 100644 index 00000000..d8f79e75 --- /dev/null +++ b/backends/gstreamer/source-element/src/source.rs @@ -0,0 +1,192 @@ +use glib; +use glib::prelude::*; +use glib::translate::*; +use glib_ffi; +use gobject_ffi; +use gobject_subclass::object::*; +use gst; +use gst_app::{self, AppSrc, AppSrcCallbacks, AppStreamType}; +use gst_ffi; +use gst_plugin::bin::*; +use gst_plugin::element::{ElementClassExt, ElementImpl}; +use gst_plugin::object::ElementInstanceStruct; +use gst_plugin::uri_handler::{register_uri_handler, URIHandlerImpl, URIHandlerImplStatic}; +use std::ptr; +use std::mem; +use std::sync::{Once, ONCE_INIT}; + +mod imp { + use super::*; + + macro_rules! inner_appsrc_proxy { + ($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => ( + pub fn $fn_name(&self, $arg1: $arg1_type) -> Result<$return_type, ()> { + match self.appsrc { + Some(ref appsrc) => Ok(appsrc.$fn_name($arg1)), + None => Err(()), + } + } + ) + } + + pub struct ServoSrc { + appsrc: Option, + } + + impl ServoSrc { + fn init(_bin: &Bin) -> Box> { + let appsrc = gst::ElementFactory::make("appsrc", None) + .map(|e| e.downcast::().unwrap()); + + Box::new(Self { + appsrc, + }) + } + + pub fn get_type() -> glib::Type { + static ONCE: Once = ONCE_INIT; + static mut TYPE: glib::Type = glib::Type::Invalid; + + ONCE.call_once(|| { + let t = register_type(ServoSrcStatic); + unsafe { + TYPE = t; + } + }); + + unsafe { TYPE } + } + + fn class_init(klass: &mut BinClass) { + klass.set_metadata( + "Servo Media Source", + "Source/Audio/Video", + "Feed player with media data", + "Servo developers", + ); + + let caps = gst::Caps::new_simple( + "video/x-raw", + &[ + ("format", &"BGRA"), + ("pixel-aspect-ratio", &gst::Fraction::from((1, 1))), + ], + ); + + let src_pad_template = gst::PadTemplate::new( + "src", + gst::PadDirection::Src, + gst::PadPresence::Always, + &caps, + ); + + klass.add_pad_template(src_pad_template); + } + + pub fn connect_need_data( + &self, + f: F + ) -> Result { + match self.appsrc { + Some(ref appsrc) => Ok(appsrc.connect_need_data(f)), + None => Err(()), + } + } + pub fn end_of_stream(&self) -> Result { + match self.appsrc { + Some(ref appsrc) => Ok(appsrc.end_of_stream()), + None => Err(()), + } + } + + inner_appsrc_proxy!(push_buffer, buffer, gst::Buffer, gst::FlowReturn); + inner_appsrc_proxy!(set_callbacks, callbacks, AppSrcCallbacks, ()); + inner_appsrc_proxy!(set_property_format, format, gst::Format, ()); + inner_appsrc_proxy!(set_size, size, i64, ()); + inner_appsrc_proxy!(set_stream_type, type_, AppStreamType, ()); + } + + impl ObjectImpl for ServoSrc { } + + impl ElementImpl for ServoSrc { } + + impl BinImpl for ServoSrc { } + + impl URIHandlerImpl for ServoSrc { + fn get_uri(&self, _element: &gst::URIHandler) -> Option { + Some("servosrc://".to_string()) + } + + fn set_uri(&self, _element: &gst::URIHandler, _uri: Option) -> Result<(), glib::Error> { + Ok(()) + } + } + + pub struct ServoSrcStatic; + + impl ImplTypeStatic for ServoSrcStatic { + fn get_name(&self) -> &str { + "ServoSrc" + } + + fn new(&self, bin: &Bin) -> Box> { + ServoSrc::init(bin) + } + + fn class_init(&self, klass: &mut BinClass) { + ServoSrc::class_init(klass); + } + + fn type_init(&self, token: &TypeInitToken, type_: glib::Type) { + register_uri_handler(token, type_, self); + } + } + + impl URIHandlerImplStatic for ServoSrcStatic { + fn get_impl<'a>(&self, imp: &'a Box>) -> &'a URIHandlerImpl { + imp.downcast_ref::().unwrap() + } + + fn get_type(&self) -> gst::URIType { + gst::URIType::Src + } + + fn get_protocols(&self) -> Vec { + vec!["servosrc".into()] + } + } +} + +glib_wrapper! { + pub struct ServoSrc(Object): + [Bin => ElementInstanceStruct, + gst::Bin => gst_ffi::GstBin, + gst::Element => gst_ffi::GstElement, + gst::Object => gst_ffi::GstObject]; + + match fn { + get_type => || imp::ServoSrc::get_type().to_glib(), + } +} + +gobject_subclass_deref!(ServoSrc, Bin); + +unsafe impl Send for ServoSrc {} +unsafe impl Sync for ServoSrc {} + +impl ServoSrc { + pub fn new() -> ServoSrc { + use glib::object::Downcast; + + unsafe { + glib::Object::new(Self::static_type(), &[]) + .unwrap() + .downcast_unchecked() + } + } +} + +pub fn register_servo_src() -> bool { + let type_ = imp::ServoSrc::get_type(); + gst::Element::register(None, "servosrc", 0, type_) +} diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 59662bdb..888c21d3 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -10,6 +10,7 @@ extern crate ipc_channel; extern crate servo_media_audio; extern crate servo_media_player; +extern crate source_element; use servo_media_audio::sink::AudioSinkError; use servo_media_audio::AudioBackend; @@ -44,3 +45,4 @@ impl GStreamerBackend { gst::init().unwrap(); } } + diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 96114d44..01fb14a8 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -1,7 +1,6 @@ use glib; use glib::*; -use gst::{self, ElementExt, PadExtManual}; -use gst::query::QueryView; +use gst::{self, PadExtManual}; use gst_app::{self, AppSrcCallbacks, AppStreamType}; use gst_player; use gst_player::{PlayerMediaInfo, PlayerStreamInfoExt}; @@ -10,6 +9,7 @@ use ipc_channel::ipc::IpcSender; use servo_media_player::frame::{Frame, FrameRenderer}; use servo_media_player::metadata::Metadata; use servo_media_player::{PlaybackState, Player, PlayerError, PlayerEvent, StreamType}; +use source_element::source::{register_servo_src, ServoSrc}; use std::cell::RefCell; use std::error::Error; use std::sync::mpsc; @@ -92,7 +92,7 @@ fn metadata_from_media_info(media_info: &PlayerMediaInfo) -> Result, + servosrc: Option, appsink: gst_app::AppSink, input_size: u64, rate: f64, @@ -105,11 +105,11 @@ impl PlayerInner { // Set input_size to proxy its value, since it // could be set by the user before calling .setup(). self.input_size = size; - if let Some(ref mut appsrc) = self.appsrc { + if let Some(ref mut servosrc) = self.servosrc { if size > 0 { - appsrc.set_size(size as i64); + servosrc.set_size(size as i64); } else { - appsrc.set_size(-1); // live source + servosrc.set_size(-1); // live source } } Ok(()) @@ -138,8 +138,8 @@ impl PlayerInner { // Set stream_type to proxy its value, since it // could be set by the user before calling .setup(). self.stream_type = Some(type_); - if let Some(ref appsrc) = self.appsrc { - appsrc.set_stream_type(type_); + if let Some(ref servosrc) = self.servosrc { + servosrc.set_stream_type(type_); } Ok(()) } @@ -152,7 +152,7 @@ impl PlayerInner { pub fn stop(&mut self) -> Result<(), PlayerError> { self.player.stop(); self.last_metadata = None; - self.appsrc = None; + self.servosrc = None; Ok(()) } @@ -162,8 +162,8 @@ impl PlayerInner { } pub fn end_of_stream(&mut self) -> Result<(), PlayerError> { - if let Some(ref mut appsrc) = self.appsrc { - if appsrc.end_of_stream() == gst::FlowReturn::Ok { + if let Some(ref mut servosrc) = self.servosrc { + if let Ok(gst::FlowReturn::Ok) = servosrc.end_of_stream() { return Ok(()); } } @@ -198,21 +198,21 @@ impl PlayerInner { } pub fn push_data(&mut self, data: Vec) -> Result<(), PlayerError> { - if let Some(ref mut appsrc) = self.appsrc { - if appsrc.get_current_level_bytes() + data.len() as u64 > appsrc.get_max_bytes() { + if let Some(ref mut servosrc) = self.servosrc { + if servosrc.get_current_level_bytes() + data.len() as u64 > servosrc.get_max_bytes() { return Err(PlayerError::EnoughData); } let buffer = gst::Buffer::from_slice(data).ok_or_else(|| PlayerError::BufferPushFailed)?; - if appsrc.push_buffer(buffer) == gst::FlowReturn::Ok { + if servosrc.push_buffer(buffer) == gst::FlowReturn::Ok { return Ok(()); } } Err(PlayerError::BufferPushFailed) } - pub fn set_app_src(&mut self, appsrc: gst_app::AppSrc) { - self.appsrc = Some(appsrc); + pub fn set_src(&mut self, servosrc: ServoSrc) { + self.servosrc = Some(servosrc); } } @@ -298,6 +298,10 @@ impl GStreamerPlayer { ))); } } + + if !register_servo_src() { + return Err(PlayerError::Backend("servosrc registration error".to_owned())); + } let player = gst_player::Player::new( /* video renderer */ None, /* signal dispatcher */ None, @@ -356,12 +360,12 @@ impl GStreamerPlayer { // The estimated version for the fix is 1.14.5 / 1.15.1. // https://github.com/servo/servo/issues/22010#issuecomment-432599657 player - .set_property("uri", &Value::from("appsrc://")) + .set_property("uri", &Value::from("servosrc://")) .map_err(|e| PlayerError::Backend(e.to_string()))?; *self.inner.borrow_mut() = Some(Arc::new(Mutex::new(PlayerInner { player, - appsrc: None, + servosrc: None, appsink: video_sink, input_size: 0, rate: 1.0, @@ -553,62 +557,22 @@ impl GStreamerPlayer { }, }; - // In order to make buffering/downloading work as we want, apart from - // setting the appropriate flags, the source needs to either: - // - // 1. be an http, mms, etc. scheme - // 2. report that it is "bandwidth limited". - // - // 1. is not straightforward because we are using an appsrc scheme for now. - // This may change in the future if we end up implementing something - // like a custom `servohttpsrc` or wrapping the existing appsrc - // in a bin src that implements http/https/data URI handlers, which - // is what WebKit does. - // - // For 2. we need to make appsrc handle the scheduling properties query - // to report that it "is bandwidth limited". - let src_pad = match source.get_static_pad("src") { - Some(src_pad) => src_pad, - None => { - let _ = sender - .lock() - .unwrap() - .send(Err(BackendError::PlayerSourceSetupFailed)); - return None; - }, - }; - src_pad.add_probe(gst::PadProbeType::QUERY_UPSTREAM, |_, probe_info| { - if let Some(gst::PadProbeData::Query(ref mut query)) = probe_info.data { - if let QueryView::Scheduling(ref mut query) = query.view_mut() { - query.set( - gst::SchedulingFlags::SEQUENTIAL | - gst::SchedulingFlags::BANDWIDTH_LIMITED, - 1, -1, 0 - ); - query.add_scheduling_modes(&[gst::PadMode::Push]); - println!("QUERY {:?}", query); - return gst::PadProbeReturn::Handled; - } - } - gst::PadProbeReturn::Ok - }); - let mut inner = inner_clone.lock().unwrap(); - let appsrc = source + let servosrc = source .clone() - .dynamic_cast::() - .expect("Source element is expected to be an appsrc!"); + .dynamic_cast::() + .expect("Source element is expected to be a servosrc!"); - appsrc.set_max_bytes(MAX_SRC_QUEUE_SIZE); - appsrc.set_property_block(false); + servosrc.set_max_bytes(MAX_SRC_QUEUE_SIZE); + servosrc.set_property_block(false); - appsrc.set_property_format(gst::Format::Bytes); + servosrc.set_property_format(gst::Format::Bytes); if inner.input_size > 0 { - appsrc.set_size(inner.input_size as i64); + servosrc.set_size(inner.input_size as i64); } if let Some(ref stream_type) = inner.stream_type { - appsrc.set_stream_type(*stream_type); + servosrc.set_stream_type(*stream_type); } let sender_clone = sender.clone(); @@ -616,7 +580,7 @@ impl GStreamerPlayer { let observers_ = observers.clone(); let observers__ = observers.clone(); let observers___ = observers.clone(); - appsrc.set_callbacks( + servosrc.set_callbacks( AppSrcCallbacks::new() .need_data(move |_, _| { // We block the caller of the setup method until we get @@ -642,7 +606,7 @@ impl GStreamerPlayer { .build(), ); - inner.set_app_src(appsrc); + inner.set_src(servosrc); None }); From 03032889569eae98f37bc3abfb0fd25b210fed91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 20 Nov 2018 15:50:43 +0100 Subject: [PATCH 04/18] Make player play a/v again with servosrc --- Cargo.lock | 14 +++--- backends/gstreamer/source-element/Cargo.toml | 4 +- .../gstreamer/source-element/src/source.rs | 45 ++++++++++++++----- 3 files changed, 43 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 175afd23..f1b5c6c2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -527,7 +527,7 @@ dependencies = [ [[package]] name = "gobject-subclass" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -548,13 +548,13 @@ dependencies = [ [[package]] name = "gst-plugin" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.4 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-subclass 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-base 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1382,9 +1382,9 @@ version = "1.0.0" dependencies = [ "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-subclass 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gst-plugin 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gst-plugin 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1795,9 +1795,9 @@ dependencies = [ "checksum glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "740f7fda8dde5f5e3944dabdb4a73ac6094a8a7fdf0af377468e98ca93733e61" "checksum glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3573351e846caed9f11207b275cd67bc07f0c2c94fb628e5d7c92ca056c7882d" "checksum glutin 0.19.0 (registry+https://github.com/rust-lang/crates.io-index)" = "535c6eda58adbb227604b2db10a022ffd6339d7ea3e970f338e7d98aeb24fcc3" -"checksum gobject-subclass 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d9779ce804d2fb1cbe2df538224e9c4f541d208e9d7a30f6f2813c953930ff3" +"checksum gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "23a365ac97171d914fc0f2ccf86f3a05ae4ee870427eee9c82f6bb95bbf201b6" "checksum gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "08475e4a08f27e6e2287005950114735ed61cec2cb8c1187682a5aec8c69b715" -"checksum gst-plugin 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a9f81b965c9c999b52b554d8a13d5ab0bda32b0389e652fd9fcb5bceb0ed9bc2" +"checksum gst-plugin 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c0211cec5228a72501a912a45b43d5450db7bc20d14e68631786ac8270908b8d" "checksum gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df451f98ea8b987b5fc1b647b9f038ca6ea106b08c3bccc1ef3126d4f0a687c1" "checksum gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3f4f865cf7f22c66907372a2e3b0f0ced3d3fedab823641d6667d2568be71408" "checksum gstreamer-app-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f0b8319fe7a8a015412a76a56b248a3c68561a39225a3fa0fcbb58aab8e12392" diff --git a/backends/gstreamer/source-element/Cargo.toml b/backends/gstreamer/source-element/Cargo.toml index 28035dd5..90aed8d9 100644 --- a/backends/gstreamer/source-element/Cargo.toml +++ b/backends/gstreamer/source-element/Cargo.toml @@ -7,9 +7,9 @@ license = "MPL2.0" [dependencies] glib = "0.6" glib-sys = "0.7" -gobject-subclass = "0.2" +gobject-subclass = "0.2.1" gobject-sys = "0.7" -gst-plugin = "0.3" +gst-plugin = "0.3.1" gstreamer = "0.12" gstreamer-app = "0.12" gstreamer-sys = "0.6.1" diff --git a/backends/gstreamer/source-element/src/source.rs b/backends/gstreamer/source-element/src/source.rs index d8f79e75..02edcb8b 100644 --- a/backends/gstreamer/source-element/src/source.rs +++ b/backends/gstreamer/source-element/src/source.rs @@ -4,16 +4,17 @@ use glib::translate::*; use glib_ffi; use gobject_ffi; use gobject_subclass::object::*; -use gst; +use gst::{self, ElementExt}; use gst_app::{self, AppSrc, AppSrcCallbacks, AppStreamType}; use gst_ffi; use gst_plugin::bin::*; use gst_plugin::element::{ElementClassExt, ElementImpl}; use gst_plugin::object::ElementInstanceStruct; use gst_plugin::uri_handler::{register_uri_handler, URIHandlerImpl, URIHandlerImplStatic}; +use std::cell::RefCell; use std::ptr; use std::mem; -use std::sync::{Once, ONCE_INIT}; +use std::sync::{Arc, Mutex, Once, ONCE_INIT}; mod imp { use super::*; @@ -21,7 +22,9 @@ mod imp { macro_rules! inner_appsrc_proxy { ($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => ( pub fn $fn_name(&self, $arg1: $arg1_type) -> Result<$return_type, ()> { - match self.appsrc { + let appsrc = self.appsrc.lock().unwrap(); + let appsrc = appsrc.borrow(); + match *appsrc { Some(ref appsrc) => Ok(appsrc.$fn_name($arg1)), None => Err(()), } @@ -30,16 +33,13 @@ mod imp { } pub struct ServoSrc { - appsrc: Option, + appsrc: Arc>>>, } impl ServoSrc { fn init(_bin: &Bin) -> Box> { - let appsrc = gst::ElementFactory::make("appsrc", None) - .map(|e| e.downcast::().unwrap()); - Box::new(Self { - appsrc, + appsrc: Arc::new(Mutex::new(RefCell::new(None))), }) } @@ -87,13 +87,17 @@ mod imp { &self, f: F ) -> Result { - match self.appsrc { + let appsrc = self.appsrc.lock().unwrap(); + let appsrc = appsrc.borrow(); + match *appsrc { Some(ref appsrc) => Ok(appsrc.connect_need_data(f)), None => Err(()), } } pub fn end_of_stream(&self) -> Result { - match self.appsrc { + let appsrc = self.appsrc.lock().unwrap(); + let appsrc = appsrc.borrow(); + match *appsrc { Some(ref appsrc) => Ok(appsrc.end_of_stream()), None => Err(()), } @@ -106,7 +110,26 @@ mod imp { inner_appsrc_proxy!(set_stream_type, type_, AppStreamType, ()); } - impl ObjectImpl for ServoSrc { } + impl ObjectImpl for ServoSrc { + fn constructed(&self, bin: &Bin) { + bin.parent_constructed(); + + let elem = gst::ElementFactory::make("appsrc", None) + .expect("Could not create source element"); + let pad = elem.get_static_pad("src") + .expect("Could not get src pad"); + + self.add_element(bin, &elem); + + let ghost_pad = gst::GhostPad::new("src", &pad) + .expect("Could not create src ghost pad"); + bin.add_pad(&ghost_pad) + .expect("Could not add src ghost pad to bin"); + + let appsrc = self.appsrc.lock().unwrap(); + *appsrc.borrow_mut() = Some(elem.downcast::().unwrap()); + } + } impl ElementImpl for ServoSrc { } From ffb7c507f96e7582e2cb92b887c8de90c61c9d4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 20 Nov 2018 16:27:53 +0100 Subject: [PATCH 05/18] Set query function on the bin appsrc ghostpad to report that we are bandwidth limited --- .../gstreamer/source-element/src/source.rs | 36 ++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/backends/gstreamer/source-element/src/source.rs b/backends/gstreamer/source-element/src/source.rs index 02edcb8b..4ba5b90a 100644 --- a/backends/gstreamer/source-element/src/source.rs +++ b/backends/gstreamer/source-element/src/source.rs @@ -4,7 +4,8 @@ use glib::translate::*; use glib_ffi; use gobject_ffi; use gobject_subclass::object::*; -use gst::{self, ElementExt}; +use gst::{self, ElementExt, PadExtManual}; +use gst::query::QueryView; use gst_app::{self, AppSrc, AppSrcCallbacks, AppStreamType}; use gst_ffi; use gst_plugin::bin::*; @@ -38,6 +39,9 @@ mod imp { impl ServoSrc { fn init(_bin: &Bin) -> Box> { + // At this point the bin is not completely created yet, + // so we cannot create and link the appsrc yet. + // We have to wait until ObjectImpl::constructed. Box::new(Self { appsrc: Arc::new(Mutex::new(RefCell::new(None))), }) @@ -123,6 +127,36 @@ mod imp { let ghost_pad = gst::GhostPad::new("src", &pad) .expect("Could not create src ghost pad"); + + // In order to make buffering/downloading work as we want, apart from + // setting the appropriate flags on the player playbin, + // the source needs to either: + // + // 1. be an http, mms, etc. scheme + // 2. report that it is "bandwidth limited". + // + // 1. is not straightforward because we are using a servosrc scheme for now. + // This may change in the future if we end up handling http/https/data + // URIs, which is what WebKit does. + // + // For 2. we need to make servosrc handle the scheduling properties query + // to report that it "is bandwidth limited". + ghost_pad.add_probe(gst::PadProbeType::QUERY_UPSTREAM, |_, probe_info| { + if let Some(gst::PadProbeData::Query(ref mut query)) = probe_info.data { + if let QueryView::Scheduling(ref mut query) = query.view_mut() { + query.set( + gst::SchedulingFlags::SEQUENTIAL | + gst::SchedulingFlags::BANDWIDTH_LIMITED, + 1, -1, 0 + ); + query.add_scheduling_modes(&[gst::PadMode::Push]); + println!("QUERY {:?}", query); + return gst::PadProbeReturn::Handled; + } + } + gst::PadProbeReturn::Ok + }); + bin.add_pad(&ghost_pad) .expect("Could not add src ghost pad to bin"); From f0fdf0e6766fed8c98356742d0676c3335459049 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Tue, 20 Nov 2018 18:10:39 +0100 Subject: [PATCH 06/18] Simplify ServoSrc.appsrc property and fix unused imports warnings --- .../gstreamer/source-element/src/source.rs | 59 +++++++------------ backends/gstreamer/src/player.rs | 4 +- 2 files changed, 24 insertions(+), 39 deletions(-) diff --git a/backends/gstreamer/source-element/src/source.rs b/backends/gstreamer/source-element/src/source.rs index 4ba5b90a..a3a727cd 100644 --- a/backends/gstreamer/source-element/src/source.rs +++ b/backends/gstreamer/source-element/src/source.rs @@ -4,46 +4,46 @@ use glib::translate::*; use glib_ffi; use gobject_ffi; use gobject_subclass::object::*; -use gst::{self, ElementExt, PadExtManual}; +use gst; use gst::query::QueryView; use gst_app::{self, AppSrc, AppSrcCallbacks, AppStreamType}; use gst_ffi; use gst_plugin::bin::*; -use gst_plugin::element::{ElementClassExt, ElementImpl}; +use gst_plugin::element::ElementImpl; use gst_plugin::object::ElementInstanceStruct; use gst_plugin::uri_handler::{register_uri_handler, URIHandlerImpl, URIHandlerImplStatic}; -use std::cell::RefCell; use std::ptr; use std::mem; -use std::sync::{Arc, Mutex, Once, ONCE_INIT}; +use std::sync::{Once, ONCE_INIT}; mod imp { use super::*; + use gst::{ElementExt, PadExtManual}; + use gst_plugin::element::ElementClassExt; macro_rules! inner_appsrc_proxy { ($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => ( - pub fn $fn_name(&self, $arg1: $arg1_type) -> Result<$return_type, ()> { - let appsrc = self.appsrc.lock().unwrap(); - let appsrc = appsrc.borrow(); - match *appsrc { - Some(ref appsrc) => Ok(appsrc.$fn_name($arg1)), - None => Err(()), - } + pub fn $fn_name(&self, $arg1: $arg1_type) -> $return_type { + self.appsrc.$fn_name($arg1) } ) } pub struct ServoSrc { - appsrc: Arc>>>, + appsrc: gst_app::AppSrc, } impl ServoSrc { fn init(_bin: &Bin) -> Box> { - // At this point the bin is not completely created yet, - // so we cannot create and link the appsrc yet. + let appsrc = gst::ElementFactory::make("appsrc", None) + .map(|elem| elem.downcast::().unwrap()) + .expect("Could not create appsrc element"); + + // At this point the bin is not completely created, + // so we cannot add anything to it yet. // We have to wait until ObjectImpl::constructed. Box::new(Self { - appsrc: Arc::new(Mutex::new(RefCell::new(None))), + appsrc, }) } @@ -90,21 +90,11 @@ mod imp { pub fn connect_need_data( &self, f: F - ) -> Result { - let appsrc = self.appsrc.lock().unwrap(); - let appsrc = appsrc.borrow(); - match *appsrc { - Some(ref appsrc) => Ok(appsrc.connect_need_data(f)), - None => Err(()), - } + ) -> glib::SignalHandlerId { + self.appsrc.connect_need_data(f) } - pub fn end_of_stream(&self) -> Result { - let appsrc = self.appsrc.lock().unwrap(); - let appsrc = appsrc.borrow(); - match *appsrc { - Some(ref appsrc) => Ok(appsrc.end_of_stream()), - None => Err(()), - } + pub fn end_of_stream(&self) -> gst::FlowReturn { + self.appsrc.end_of_stream() } inner_appsrc_proxy!(push_buffer, buffer, gst::Buffer, gst::FlowReturn); @@ -118,12 +108,10 @@ mod imp { fn constructed(&self, bin: &Bin) { bin.parent_constructed(); - let elem = gst::ElementFactory::make("appsrc", None) - .expect("Could not create source element"); - let pad = elem.get_static_pad("src") - .expect("Could not get src pad"); + self.add_element(bin, &self.appsrc.clone().upcast()); - self.add_element(bin, &elem); + let pad = self.appsrc.get_static_pad("src") + .expect("Could not get src pad"); let ghost_pad = gst::GhostPad::new("src", &pad) .expect("Could not create src ghost pad"); @@ -159,9 +147,6 @@ mod imp { bin.add_pad(&ghost_pad) .expect("Could not add src ghost pad to bin"); - - let appsrc = self.appsrc.lock().unwrap(); - *appsrc.borrow_mut() = Some(elem.downcast::().unwrap()); } } diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 01fb14a8..452e49ae 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -1,6 +1,6 @@ use glib; use glib::*; -use gst::{self, PadExtManual}; +use gst; use gst_app::{self, AppSrcCallbacks, AppStreamType}; use gst_player; use gst_player::{PlayerMediaInfo, PlayerStreamInfoExt}; @@ -163,7 +163,7 @@ impl PlayerInner { pub fn end_of_stream(&mut self) -> Result<(), PlayerError> { if let Some(ref mut servosrc) = self.servosrc { - if let Ok(gst::FlowReturn::Ok) = servosrc.end_of_stream() { + if servosrc.end_of_stream() == gst::FlowReturn::Ok { return Ok(()); } } From e0a55415d026a8ea34f3bd9ecc8446cf234b2465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 21 Nov 2018 10:19:28 +0100 Subject: [PATCH 07/18] No need to have an independent crate for servosrc --- Cargo.lock | 20 +++++-------------- Cargo.toml | 2 -- backends/gstreamer/Cargo.toml | 20 +++++++++++++++---- backends/gstreamer/source-element/Cargo.toml | 19 ------------------ backends/gstreamer/source-element/src/lib.rs | 12 ----------- backends/gstreamer/src/lib.rs | 9 ++++++++- backends/gstreamer/src/player.rs | 2 +- .../{source-element => }/src/source.rs | 14 ++----------- 8 files changed, 32 insertions(+), 66 deletions(-) delete mode 100644 backends/gstreamer/source-element/Cargo.toml delete mode 100644 backends/gstreamer/source-element/src/lib.rs rename backends/gstreamer/{source-element => }/src/source.rs (96%) diff --git a/Cargo.lock b/Cargo.lock index f1b5c6c2..5a36ba06 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1298,16 +1298,20 @@ version = "0.1.0" dependencies = [ "byte-slice-cast 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gst-plugin 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-audio 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-player 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", + "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", "gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "servo-media-audio 0.1.0", "servo-media-player 0.1.0", - "source-element 1.0.0", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1376,20 +1380,6 @@ dependencies = [ "wayland-protocols 0.21.4 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "source-element" -version = "1.0.0" -dependencies = [ - "glib 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "glib-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-subclass 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gobject-sys 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gst-plugin 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-app 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", - "gstreamer-sys 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "stable_deref_trait" version = "1.1.1" diff --git a/Cargo.toml b/Cargo.toml index 40ec6272..cded2571 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,11 +2,9 @@ members = [ "audio", "backends/gstreamer", - "backends/gstreamer/source-element", "examples", "examples/android/lib", "player", "servo-media", "servo-media-derive", ] -license = "MPL-2.0" diff --git a/backends/gstreamer/Cargo.toml b/backends/gstreamer/Cargo.toml index 045aa1f2..144efd90 100644 --- a/backends/gstreamer/Cargo.toml +++ b/backends/gstreamer/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "servo-media-gstreamer" version = "0.1.0" -authors = ["Manish Goregaokar "] +authors = ["The Servo Project Developers"] [build-dependencies] regex = "1.0" @@ -13,6 +13,18 @@ version = "0.2" [dependencies.glib] version = "0.6" +[dependencies.glib-sys] +version = "0.7" + +[dependencies.gobject-subclass] +version = "0.2.1" + +[dependencies.gobject-sys] +version = "0.7" + +[dependencies.gst-plugin] +version = "0.3.1" + [dependencies.gstreamer] version = "0.12" @@ -25,6 +37,9 @@ version = "0.12" [dependencies.gstreamer-player] version = "0.12" +[dependencies.gstreamer-sys] +version = "0.6.1" + [dependencies.gstreamer-video] version = "0.12" @@ -36,6 +51,3 @@ path = "../../audio" [dependencies.servo-media-player] path = "../../player" - -[dependencies.source-element] -path = "source-element" diff --git a/backends/gstreamer/source-element/Cargo.toml b/backends/gstreamer/source-element/Cargo.toml deleted file mode 100644 index 90aed8d9..00000000 --- a/backends/gstreamer/source-element/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "source-element" -version = "1.0.0" -repository = "https://github.com/servo/media" -license = "MPL2.0" - -[dependencies] -glib = "0.6" -glib-sys = "0.7" -gobject-subclass = "0.2.1" -gobject-sys = "0.7" -gst-plugin = "0.3.1" -gstreamer = "0.12" -gstreamer-app = "0.12" -gstreamer-sys = "0.6.1" - -[lib] -name = "source_element" -path = "src/lib.rs" diff --git a/backends/gstreamer/source-element/src/lib.rs b/backends/gstreamer/source-element/src/lib.rs deleted file mode 100644 index 96604a5b..00000000 --- a/backends/gstreamer/source-element/src/lib.rs +++ /dev/null @@ -1,12 +0,0 @@ -#[macro_use] -extern crate glib; -extern crate glib_sys as glib_ffi; -extern crate gobject_sys as gobject_ffi; -#[macro_use] -extern crate gobject_subclass; -extern crate gst_plugin; -extern crate gstreamer as gst; -extern crate gstreamer_app as gst_app; -extern crate gstreamer_sys as gst_ffi; - -pub mod source; diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 888c21d3..9fe6c4cd 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -1,16 +1,22 @@ extern crate byte_slice_cast; +#[macro_use] extern crate glib; +extern crate glib_sys as glib_ffi; +extern crate gobject_sys as gobject_ffi; +#[macro_use] +extern crate gobject_subclass; +extern crate gst_plugin; extern crate gstreamer as gst; extern crate gstreamer_app as gst_app; extern crate gstreamer_audio as gst_audio; extern crate gstreamer_player as gst_player; +extern crate gstreamer_sys as gst_ffi; extern crate gstreamer_video as gst_video; extern crate ipc_channel; extern crate servo_media_audio; extern crate servo_media_player; -extern crate source_element; use servo_media_audio::sink::AudioSinkError; use servo_media_audio::AudioBackend; @@ -19,6 +25,7 @@ use servo_media_player::PlayerBackend; pub mod audio_decoder; pub mod audio_sink; pub mod player; +mod source; pub struct GStreamerBackend; diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 452e49ae..755fcf90 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -9,7 +9,7 @@ use ipc_channel::ipc::IpcSender; use servo_media_player::frame::{Frame, FrameRenderer}; use servo_media_player::metadata::Metadata; use servo_media_player::{PlaybackState, Player, PlayerError, PlayerEvent, StreamType}; -use source_element::source::{register_servo_src, ServoSrc}; +use source::{register_servo_src, ServoSrc}; use std::cell::RefCell; use std::error::Error; use std::sync::mpsc; diff --git a/backends/gstreamer/source-element/src/source.rs b/backends/gstreamer/src/source.rs similarity index 96% rename from backends/gstreamer/source-element/src/source.rs rename to backends/gstreamer/src/source.rs index a3a727cd..749c1bd7 100644 --- a/backends/gstreamer/source-element/src/source.rs +++ b/backends/gstreamer/src/source.rs @@ -1,5 +1,4 @@ use glib; -use glib::prelude::*; use glib::translate::*; use glib_ffi; use gobject_ffi; @@ -18,6 +17,7 @@ use std::sync::{Once, ONCE_INIT}; mod imp { use super::*; + use glib::prelude::*; use gst::{ElementExt, PadExtManual}; use gst_plugin::element::ElementClassExt; @@ -216,17 +216,7 @@ gobject_subclass_deref!(ServoSrc, Bin); unsafe impl Send for ServoSrc {} unsafe impl Sync for ServoSrc {} -impl ServoSrc { - pub fn new() -> ServoSrc { - use glib::object::Downcast; - - unsafe { - glib::Object::new(Self::static_type(), &[]) - .unwrap() - .downcast_unchecked() - } - } -} +impl ServoSrc {} pub fn register_servo_src() -> bool { let type_ = imp::ServoSrc::get_type(); From baa3b7dc156d43a5f34c50354366f7cd139aa359 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 23 Nov 2018 16:09:13 +0100 Subject: [PATCH 08/18] Add flag to tell whether a media source is live or not --- backends/gstreamer/src/player.rs | 2 ++ backends/gstreamer/src/source.rs | 1 - player/src/metadata.rs | 2 ++ 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 755fcf90..e8217fc4 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -78,6 +78,7 @@ fn metadata_from_media_info(media_info: &PlayerMediaInfo) -> Result Result, pub audio_tracks: Vec, + // Whether the media comes from a live source or not. + pub is_live: bool, } From cc5797dff557be365b7dd041dd3f5e11df22015f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 28 Nov 2018 11:00:36 +0100 Subject: [PATCH 09/18] Get buffering stats --- backends/gstreamer/src/player.rs | 78 +++++++++++++++++++++----------- player/src/lib.rs | 8 ++++ 2 files changed, 59 insertions(+), 27 deletions(-) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index e8217fc4..6c5bacbb 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -1,6 +1,7 @@ use glib; use glib::*; -use gst; +use gst::{self, ElementExtManual}; +use gst::GenericFormattedValue::Percent; use gst_app::{self, AppSrcCallbacks, AppStreamType}; use gst_player; use gst_player::{PlayerMediaInfo, PlayerStreamInfoExt}; @@ -12,6 +13,7 @@ use servo_media_player::{PlaybackState, Player, PlayerError, PlayerEvent, Stream use source::{register_servo_src, ServoSrc}; use std::cell::RefCell; use std::error::Error; +use std::ops::Range; use std::sync::mpsc; use std::sync::{Arc, Mutex, Once}; use std::time; @@ -216,6 +218,32 @@ impl PlayerInner { pub fn set_src(&mut self, servosrc: ServoSrc) { self.servosrc = Some(servosrc); } + + pub fn buffered(&mut self) -> Result>, BackendError> { + let mut result = vec![]; + let pipeline = self.player.get_pipeline(); + let mut buffering = gst::Query::new_buffering(gst::Format::Percent); + if pipeline.query(&mut buffering) { + let ranges = buffering.get_ranges(); + for i in 0..ranges.len() { + let start = ranges[i].0; + let end = ranges[i].1; + let start = if let Percent(start) = start { + start.unwrap() + } else { + 0 + } / (gst::FORMAT_PERCENT_MAX / 100); + let end = if let Percent(end) = end { + end.unwrap() + } else { + 0 + } / (gst::FORMAT_PERCENT_MAX / 100); + result.push(Range { start, end }); + } + } + + Ok(result) + } } type PlayerEventObserver = IpcSender; @@ -314,23 +342,23 @@ impl GStreamerPlayer { // Set player to perform progressive downloading. This will make the // player store the downloaded media in a local temporary file for // faster playback of already-downloaded chunks. - let flags = pipeline.get_property("flags") + let flags = pipeline + .get_property("flags") .map_err(|e| BackendError::GetPropertyFailed(e.0))?; let flags_class = match FlagsClass::new(flags.type_()) { - Some(flags) => flags, - None => return Err(BackendError::PlayerFlagsSetupFailed), - }; + Some(flags) => flags, + None => return Err(BackendError::PlayerFlagsSetupFailed), + }; let flags_class = match flags_class.builder_with_value(flags) { - Some(class) => class, - None => return Err(BackendError::PlayerFlagsSetupFailed) - }; - let flags = match flags_class - .set_by_nick("download") - .build() { - Some(flags) => flags, - None => return Err(BackendError::PlayerFlagsSetupFailed), - }; - pipeline.set_property("flags", &flags) + Some(class) => class, + None => return Err(BackendError::PlayerFlagsSetupFailed), + }; + let flags = match flags_class.set_by_nick("download").build() { + Some(flags) => flags, + None => return Err(BackendError::PlayerFlagsSetupFailed), + }; + pipeline + .set_property("flags", &flags) .map_err(|e| BackendError::SetPropertyFailed(e.0))?; // Set player position interval update to 0.5 seconds. @@ -393,11 +421,6 @@ impl GStreamerPlayer { observers.lock().unwrap().notify(PlayerEvent::Error); }); - // Handle `buffering` signal. - inner.lock().unwrap().player.connect_buffering(move |_, data| { - println!("BUFFERING {:?}", data); - }); - let observers = self.observers.clone(); // Handle `state-changed` signal. inner @@ -556,7 +579,7 @@ impl GStreamerPlayer { .unwrap() .send(Err(PlayerError::Backend("Source setup failed".to_owned()))); return None; - }, + } }; let mut inner = inner_clone.lock().unwrap(); @@ -640,8 +663,8 @@ impl GStreamerPlayer { } macro_rules! inner_player_proxy { - ($fn_name:ident) => ( - fn $fn_name(&self) -> Result<(), PlayerError> { + ($fn_name:ident, $return_type:ty) => ( + fn $fn_name(&self) -> Result<$return_type, PlayerError> { self.setup()?; let inner = self.inner.borrow(); let mut inner = inner.as_ref().unwrap().lock().unwrap(); @@ -660,16 +683,17 @@ macro_rules! inner_player_proxy { } impl Player for GStreamerPlayer { - inner_player_proxy!(play); - inner_player_proxy!(pause); - inner_player_proxy!(stop); - inner_player_proxy!(end_of_stream); + inner_player_proxy!(play, ()); + inner_player_proxy!(pause, ()); + inner_player_proxy!(stop, ()); + inner_player_proxy!(end_of_stream, ()); inner_player_proxy!(set_input_size, size, u64); inner_player_proxy!(set_rate, rate, f64); inner_player_proxy!(set_stream_type, type_, StreamType); inner_player_proxy!(push_data, data, Vec); inner_player_proxy!(seek, time, f64); inner_player_proxy!(set_volume, value, f64); + inner_player_proxy!(buffered, Vec>); fn register_event_handler(&self, sender: IpcSender) { self.observers.lock().unwrap().register(sender); diff --git a/player/src/lib.rs b/player/src/lib.rs index 84c4f185..a9d4d7ab 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -6,6 +6,8 @@ pub mod frame; pub mod metadata; use ipc_channel::ipc::IpcSender; +use std::fmt::Debug; +use std::ops::Range; use std::sync::{Arc, Mutex}; #[derive(Clone, Debug, Deserialize, Serialize)] @@ -76,6 +78,9 @@ pub trait Player: Send { fn set_stream_type(&self, type_: StreamType) -> Result<(), PlayerError>; fn push_data(&self, data: Vec) -> Result<(), PlayerError>; fn end_of_stream(&self) -> Result<(), PlayerError>; + /// Get the list of time ranges in seconds that have been + /// buffered. + fn buffered(&self) -> Result>, PlayerError>; } pub struct DummyPlayer {} @@ -116,6 +121,9 @@ impl Player for DummyPlayer { fn end_of_stream(&self) -> Result<(), PlayerError> { Ok(()) } + fn buffered(&self) -> Result>, PlayerError> { + Ok(vec![]) + } } pub trait PlayerBackend { From 39a5af0bbf5910e95ba24f33f326f7f9e58602d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 7 Dec 2018 11:08:24 -0500 Subject: [PATCH 10/18] Do not allow setting the size twice --- backends/gstreamer/src/source.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backends/gstreamer/src/source.rs b/backends/gstreamer/src/source.rs index de27fc97..a2a01611 100644 --- a/backends/gstreamer/src/source.rs +++ b/backends/gstreamer/src/source.rs @@ -93,14 +93,21 @@ mod imp { ) -> glib::SignalHandlerId { self.appsrc.connect_need_data(f) } + pub fn end_of_stream(&self) -> gst::FlowReturn { self.appsrc.end_of_stream() } + pub fn set_size(&self, size: i64) { + if self.appsrc.get_size() != -1 { + return; + } + self.appsrc.set_size(size); + } + inner_appsrc_proxy!(push_buffer, buffer, gst::Buffer, gst::FlowReturn); inner_appsrc_proxy!(set_callbacks, callbacks, AppSrcCallbacks, ()); inner_appsrc_proxy!(set_property_format, format, gst::Format, ()); - inner_appsrc_proxy!(set_size, size, i64, ()); inner_appsrc_proxy!(set_stream_type, type_, AppStreamType, ()); } From a1b07529c1957b087dad579c5fd9409353fdb3e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Fri, 7 Dec 2018 11:13:04 -0500 Subject: [PATCH 11/18] Set player buffer size --- backends/gstreamer/src/player.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 6c5bacbb..78c5f015 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -20,6 +20,7 @@ use std::time; use std::u64; const MAX_SRC_QUEUE_SIZE: u64 = 50 * 1024 * 1024; // 50 MB. +const MAX_BUFFER_SIZE: i32 = 500 * 1024; fn frame_from_sample(sample: &gst::Sample) -> Result { let buffer = sample.get_buffer().ok_or_else(|| ())?; @@ -361,6 +362,11 @@ impl GStreamerPlayer { .set_property("flags", &flags) .map_err(|e| BackendError::SetPropertyFailed(e.0))?; + // Set max size for the player buffer. + pipeline + .set_property("buffer-size", &MAX_BUFFER_SIZE) + .map_err(|e| BackendError::SetPropertyFailed(e.0))?; + // Set player position interval update to 0.5 seconds. let mut config = player.get_config(); config.set_position_update_interval(500u32); From 59141c876c6544a06777c6b4c0ad923897e502ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 10 Jan 2019 11:00:31 +0100 Subject: [PATCH 12/18] Cleanup and fix build errors after long rebase --- backends/gstreamer/src/lib.rs | 1 - backends/gstreamer/src/player.rs | 34 ++++++++++++++------ backends/gstreamer/src/source.rs | 54 ++++++++++++++++++-------------- player/src/lib.rs | 1 - 4 files changed, 54 insertions(+), 36 deletions(-) diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 9fe6c4cd..99c46700 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -52,4 +52,3 @@ impl GStreamerBackend { gst::init().unwrap(); } } - diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 78c5f015..9b208663 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -1,7 +1,7 @@ use glib; use glib::*; -use gst::{self, ElementExtManual}; use gst::GenericFormattedValue::Percent; +use gst::{self, ElementExtManual}; use gst_app::{self, AppSrcCallbacks, AppStreamType}; use gst_player; use gst_player::{PlayerMediaInfo, PlayerStreamInfoExt}; @@ -220,7 +220,7 @@ impl PlayerInner { self.servosrc = Some(servosrc); } - pub fn buffered(&mut self) -> Result>, BackendError> { + pub fn buffered(&mut self) -> Result>, PlayerError> { let mut result = vec![]; let pipeline = self.player.get_pipeline(); let mut buffering = gst::Query::new_buffering(gst::Format::Percent); @@ -329,9 +329,11 @@ impl GStreamerPlayer { ))); } } - + if !register_servo_src() { - return Err(PlayerError::Backend("servosrc registration error".to_owned())); + return Err(PlayerError::Backend( + "servosrc registration error".to_owned(), + )); } let player = gst_player::Player::new( @@ -345,27 +347,39 @@ impl GStreamerPlayer { // faster playback of already-downloaded chunks. let flags = pipeline .get_property("flags") - .map_err(|e| BackendError::GetPropertyFailed(e.0))?; + .map_err(|e| PlayerError::Backend(e.0.to_owned()))?; let flags_class = match FlagsClass::new(flags.type_()) { Some(flags) => flags, - None => return Err(BackendError::PlayerFlagsSetupFailed), + None => { + return Err(PlayerError::Backend( + "FlagsClass creation failed".to_owned(), + )) + } }; let flags_class = match flags_class.builder_with_value(flags) { Some(class) => class, - None => return Err(BackendError::PlayerFlagsSetupFailed), + None => { + return Err(PlayerError::Backend( + "FlagsClass creation failed".to_owned(), + )) + } }; let flags = match flags_class.set_by_nick("download").build() { Some(flags) => flags, - None => return Err(BackendError::PlayerFlagsSetupFailed), + None => { + return Err(PlayerError::Backend( + "FlagsClass creation failed".to_owned(), + )) + } }; pipeline .set_property("flags", &flags) - .map_err(|e| BackendError::SetPropertyFailed(e.0))?; + .map_err(|e| PlayerError::Backend(e.0.to_owned()))?; // Set max size for the player buffer. pipeline .set_property("buffer-size", &MAX_BUFFER_SIZE) - .map_err(|e| BackendError::SetPropertyFailed(e.0))?; + .map_err(|e| PlayerError::Backend(e.0.to_owned()))?; // Set player position interval update to 0.5 seconds. let mut config = player.get_config(); diff --git a/backends/gstreamer/src/source.rs b/backends/gstreamer/src/source.rs index a2a01611..4ca56f29 100644 --- a/backends/gstreamer/src/source.rs +++ b/backends/gstreamer/src/source.rs @@ -11,8 +11,8 @@ use gst_plugin::bin::*; use gst_plugin::element::ElementImpl; use gst_plugin::object::ElementInstanceStruct; use gst_plugin::uri_handler::{register_uri_handler, URIHandlerImpl, URIHandlerImplStatic}; -use std::ptr; use std::mem; +use std::ptr; use std::sync::{Once, ONCE_INIT}; mod imp { @@ -22,6 +22,12 @@ mod imp { use gst_plugin::element::ElementClassExt; macro_rules! inner_appsrc_proxy { + ($fn_name:ident, $return_type:ty) => ( + pub fn $fn_name(&self) -> $return_type { + self.appsrc.$fn_name() + } + ); + ($fn_name:ident, $arg1:ident, $arg1_type:ty, $return_type:ty) => ( pub fn $fn_name(&self, $arg1: $arg1_type) -> $return_type { self.appsrc.$fn_name($arg1) @@ -42,9 +48,7 @@ mod imp { // At this point the bin is not completely created, // so we cannot add anything to it yet. // We have to wait until ObjectImpl::constructed. - Box::new(Self { - appsrc, - }) + Box::new(Self { appsrc }) } pub fn get_type() -> glib::Type { @@ -87,17 +91,6 @@ mod imp { klass.add_pad_template(src_pad_template); } - pub fn connect_need_data( - &self, - f: F - ) -> glib::SignalHandlerId { - self.appsrc.connect_need_data(f) - } - - pub fn end_of_stream(&self) -> gst::FlowReturn { - self.appsrc.end_of_stream() - } - pub fn set_size(&self, size: i64) { if self.appsrc.get_size() != -1 { return; @@ -105,8 +98,13 @@ mod imp { self.appsrc.set_size(size); } + inner_appsrc_proxy!(end_of_stream, gst::FlowReturn); + inner_appsrc_proxy!(get_current_level_bytes, u64); + inner_appsrc_proxy!(get_max_bytes, u64); inner_appsrc_proxy!(push_buffer, buffer, gst::Buffer, gst::FlowReturn); inner_appsrc_proxy!(set_callbacks, callbacks, AppSrcCallbacks, ()); + inner_appsrc_proxy!(set_max_bytes, bytes, u64, ()); + inner_appsrc_proxy!(set_property_block, block, bool, ()); inner_appsrc_proxy!(set_property_format, format, gst::Format, ()); inner_appsrc_proxy!(set_stream_type, type_, AppStreamType, ()); } @@ -117,11 +115,13 @@ mod imp { self.add_element(bin, &self.appsrc.clone().upcast()); - let pad = self.appsrc.get_static_pad("src") + let pad = self + .appsrc + .get_static_pad("src") .expect("Could not get src pad"); - let ghost_pad = gst::GhostPad::new("src", &pad) - .expect("Could not create src ghost pad"); + let ghost_pad = + gst::GhostPad::new("src", &pad).expect("Could not create src ghost pad"); // In order to make buffering/downloading work as we want, apart from // setting the appropriate flags on the player playbin, @@ -140,9 +140,11 @@ mod imp { if let Some(gst::PadProbeData::Query(ref mut query)) = probe_info.data { if let QueryView::Scheduling(ref mut query) = query.view_mut() { query.set( - gst::SchedulingFlags::SEQUENTIAL | - gst::SchedulingFlags::BANDWIDTH_LIMITED, - 1, -1, 0 + gst::SchedulingFlags::SEQUENTIAL + | gst::SchedulingFlags::BANDWIDTH_LIMITED, + 1, + -1, + 0, ); query.add_scheduling_modes(&[gst::PadMode::Push]); return gst::PadProbeReturn::Handled; @@ -156,16 +158,20 @@ mod imp { } } - impl ElementImpl for ServoSrc { } + impl ElementImpl for ServoSrc {} - impl BinImpl for ServoSrc { } + impl BinImpl for ServoSrc {} impl URIHandlerImpl for ServoSrc { fn get_uri(&self, _element: &gst::URIHandler) -> Option { Some("servosrc://".to_string()) } - fn set_uri(&self, _element: &gst::URIHandler, _uri: Option) -> Result<(), glib::Error> { + fn set_uri( + &self, + _element: &gst::URIHandler, + _uri: Option, + ) -> Result<(), glib::Error> { Ok(()) } } diff --git a/player/src/lib.rs b/player/src/lib.rs index a9d4d7ab..ed87234a 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -6,7 +6,6 @@ pub mod frame; pub mod metadata; use ipc_channel::ipc::IpcSender; -use std::fmt::Debug; use std::ops::Range; use std::sync::{Arc, Mutex}; From e21ec6d05f8bd99d5a3d2b96b8e9ff1f96366ed5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Thu, 10 Jan 2019 18:10:42 +0100 Subject: [PATCH 13/18] Actually return seconds and not a percentage of buffered media --- backends/gstreamer/src/player.rs | 45 +++++++++++++++++--------------- player/src/lib.rs | 7 +++-- 2 files changed, 27 insertions(+), 25 deletions(-) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 9b208663..89d18eb0 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -220,29 +220,32 @@ impl PlayerInner { self.servosrc = Some(servosrc); } - pub fn buffered(&mut self) -> Result>, PlayerError> { + pub fn buffered(&mut self) -> Result>, PlayerError> { let mut result = vec![]; - let pipeline = self.player.get_pipeline(); - let mut buffering = gst::Query::new_buffering(gst::Format::Percent); - if pipeline.query(&mut buffering) { - let ranges = buffering.get_ranges(); - for i in 0..ranges.len() { - let start = ranges[i].0; - let end = ranges[i].1; - let start = if let Percent(start) = start { - start.unwrap() - } else { - 0 - } / (gst::FORMAT_PERCENT_MAX / 100); - let end = if let Percent(end) = end { - end.unwrap() - } else { - 0 - } / (gst::FORMAT_PERCENT_MAX / 100); - result.push(Range { start, end }); + if let Some(ref metadata) = self.last_metadata { + if let Some(ref duration) = metadata.duration { + let pipeline = self.player.get_pipeline(); + let mut buffering = gst::Query::new_buffering(gst::Format::Percent); + if pipeline.query(&mut buffering) { + let ranges = buffering.get_ranges(); + for i in 0..ranges.len() { + let start = ranges[i].0; + let end = ranges[i].1; + let start = (if let Percent(start) = start { + start.unwrap() + } else { + 0 + } * duration.as_secs() as u32 / (gst::FORMAT_PERCENT_MAX)) as f64; + let end = (if let Percent(end) = end { + end.unwrap() + } else { + 0 + } * duration.as_secs() as u32 / (gst::FORMAT_PERCENT_MAX)) as f64; + result.push(Range { start, end }); + } + } } } - Ok(result) } } @@ -713,7 +716,7 @@ impl Player for GStreamerPlayer { inner_player_proxy!(push_data, data, Vec); inner_player_proxy!(seek, time, f64); inner_player_proxy!(set_volume, value, f64); - inner_player_proxy!(buffered, Vec>); + inner_player_proxy!(buffered, Vec>); fn register_event_handler(&self, sender: IpcSender) { self.observers.lock().unwrap().register(sender); diff --git a/player/src/lib.rs b/player/src/lib.rs index ed87234a..23dfb580 100644 --- a/player/src/lib.rs +++ b/player/src/lib.rs @@ -77,9 +77,8 @@ pub trait Player: Send { fn set_stream_type(&self, type_: StreamType) -> Result<(), PlayerError>; fn push_data(&self, data: Vec) -> Result<(), PlayerError>; fn end_of_stream(&self) -> Result<(), PlayerError>; - /// Get the list of time ranges in seconds that have been - /// buffered. - fn buffered(&self) -> Result>, PlayerError>; + /// Get the list of time ranges in seconds that have been buffered. + fn buffered(&self) -> Result>, PlayerError>; } pub struct DummyPlayer {} @@ -120,7 +119,7 @@ impl Player for DummyPlayer { fn end_of_stream(&self) -> Result<(), PlayerError> { Ok(()) } - fn buffered(&self) -> Result>, PlayerError> { + fn buffered(&self) -> Result>, PlayerError> { Ok(vec![]) } } From 09a8ae51e95a1000938be3d64f55ff05296dcb65 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 16 Jan 2019 11:55:31 +0100 Subject: [PATCH 14/18] Do not set caps at the source element's source pad --- backends/gstreamer/src/source.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/backends/gstreamer/src/source.rs b/backends/gstreamer/src/source.rs index 4ca56f29..05f35647 100644 --- a/backends/gstreamer/src/source.rs +++ b/backends/gstreamer/src/source.rs @@ -72,23 +72,6 @@ mod imp { "Feed player with media data", "Servo developers", ); - - let caps = gst::Caps::new_simple( - "video/x-raw", - &[ - ("format", &"BGRA"), - ("pixel-aspect-ratio", &gst::Fraction::from((1, 1))), - ], - ); - - let src_pad_template = gst::PadTemplate::new( - "src", - gst::PadDirection::Src, - gst::PadPresence::Always, - &caps, - ); - - klass.add_pad_template(src_pad_template); } pub fn set_size(&self, size: i64) { From 0b033e53c6d1d91d11fef99038cdac83b395f34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 16 Jan 2019 12:02:40 +0100 Subject: [PATCH 15/18] Set constant properties in servosrc --- backends/gstreamer/src/player.rs | 7 +------ backends/gstreamer/src/source.rs | 9 ++++++--- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 89d18eb0..5bf5f2af 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -19,8 +19,7 @@ use std::sync::{Arc, Mutex, Once}; use std::time; use std::u64; -const MAX_SRC_QUEUE_SIZE: u64 = 50 * 1024 * 1024; // 50 MB. -const MAX_BUFFER_SIZE: i32 = 500 * 1024; +const MAX_BUFFER_SIZE: i32 = 500 * 1024 * 1024; fn frame_from_sample(sample: &gst::Sample) -> Result { let buffer = sample.get_buffer().ok_or_else(|| ())?; @@ -611,10 +610,6 @@ impl GStreamerPlayer { .dynamic_cast::() .expect("Source element is expected to be a servosrc!"); - servosrc.set_max_bytes(MAX_SRC_QUEUE_SIZE); - servosrc.set_property_block(false); - - servosrc.set_property_format(gst::Format::Bytes); if inner.input_size > 0 { servosrc.set_size(inner.input_size as i64); } diff --git a/backends/gstreamer/src/source.rs b/backends/gstreamer/src/source.rs index 05f35647..361d2991 100644 --- a/backends/gstreamer/src/source.rs +++ b/backends/gstreamer/src/source.rs @@ -15,6 +15,8 @@ use std::mem; use std::ptr; use std::sync::{Once, ONCE_INIT}; +const MAX_SRC_QUEUE_SIZE: u64 = 50 * 1024 * 1024; // 50 MB. + mod imp { use super::*; use glib::prelude::*; @@ -45,6 +47,10 @@ mod imp { .map(|elem| elem.downcast::().unwrap()) .expect("Could not create appsrc element"); + appsrc.set_max_bytes(MAX_SRC_QUEUE_SIZE); + appsrc.set_property_block(false); + appsrc.set_property_format(gst::Format::Bytes); + // At this point the bin is not completely created, // so we cannot add anything to it yet. // We have to wait until ObjectImpl::constructed. @@ -86,9 +92,6 @@ mod imp { inner_appsrc_proxy!(get_max_bytes, u64); inner_appsrc_proxy!(push_buffer, buffer, gst::Buffer, gst::FlowReturn); inner_appsrc_proxy!(set_callbacks, callbacks, AppSrcCallbacks, ()); - inner_appsrc_proxy!(set_max_bytes, bytes, u64, ()); - inner_appsrc_proxy!(set_property_block, block, bool, ()); - inner_appsrc_proxy!(set_property_format, format, gst::Format, ()); inner_appsrc_proxy!(set_stream_type, type_, AppStreamType, ()); } From 3db1a4f1f88ca10239e116d66838b1c506df4fb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 16 Jan 2019 12:04:59 +0100 Subject: [PATCH 16/18] Use ToString trait to get GLib error description --- backends/gstreamer/src/player.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/backends/gstreamer/src/player.rs b/backends/gstreamer/src/player.rs index 5bf5f2af..218af738 100644 --- a/backends/gstreamer/src/player.rs +++ b/backends/gstreamer/src/player.rs @@ -349,7 +349,7 @@ impl GStreamerPlayer { // faster playback of already-downloaded chunks. let flags = pipeline .get_property("flags") - .map_err(|e| PlayerError::Backend(e.0.to_owned()))?; + .map_err(|e| PlayerError::Backend(e.to_string()))?; let flags_class = match FlagsClass::new(flags.type_()) { Some(flags) => flags, None => { @@ -376,12 +376,12 @@ impl GStreamerPlayer { }; pipeline .set_property("flags", &flags) - .map_err(|e| PlayerError::Backend(e.0.to_owned()))?; + .map_err(|e| PlayerError::Backend(e.to_string()))?; // Set max size for the player buffer. pipeline .set_property("buffer-size", &MAX_BUFFER_SIZE) - .map_err(|e| PlayerError::Backend(e.0.to_owned()))?; + .map_err(|e| PlayerError::Backend(e.to_string()))?; // Set player position interval update to 0.5 seconds. let mut config = player.get_config(); From adbb1530c006bda55529355a0d374c8ce7500aad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 16 Jan 2019 12:50:43 +0100 Subject: [PATCH 17/18] Report bandwidth limited through servosrc overrided query method --- backends/gstreamer/src/source.rs | 44 +++++++++++++++----------------- 1 file changed, 21 insertions(+), 23 deletions(-) diff --git a/backends/gstreamer/src/source.rs b/backends/gstreamer/src/source.rs index 361d2991..7a8489b3 100644 --- a/backends/gstreamer/src/source.rs +++ b/backends/gstreamer/src/source.rs @@ -4,7 +4,7 @@ use glib_ffi; use gobject_ffi; use gobject_subclass::object::*; use gst; -use gst::query::QueryView; +use gst::query::{QueryRef, QueryView}; use gst_app::{self, AppSrc, AppSrcCallbacks, AppStreamType}; use gst_ffi; use gst_plugin::bin::*; @@ -20,7 +20,7 @@ const MAX_SRC_QUEUE_SIZE: u64 = 50 * 1024 * 1024; // 50 MB. mod imp { use super::*; use glib::prelude::*; - use gst::{ElementExt, PadExtManual}; + use gst::ElementExt; use gst_plugin::element::ElementClassExt; macro_rules! inner_appsrc_proxy { @@ -109,6 +109,13 @@ mod imp { let ghost_pad = gst::GhostPad::new("src", &pad).expect("Could not create src ghost pad"); + bin.add_pad(&ghost_pad) + .expect("Could not add src ghost pad to bin"); + } + } + + impl ElementImpl for ServoSrc { + fn query(&self, _element: &Bin, query: &mut QueryRef) -> bool { // In order to make buffering/downloading work as we want, apart from // setting the appropriate flags on the player playbin, // the source needs to either: @@ -122,30 +129,21 @@ mod imp { // // For 2. we need to make servosrc handle the scheduling properties query // to report that it "is bandwidth limited". - ghost_pad.add_probe(gst::PadProbeType::QUERY_UPSTREAM, |_, probe_info| { - if let Some(gst::PadProbeData::Query(ref mut query)) = probe_info.data { - if let QueryView::Scheduling(ref mut query) = query.view_mut() { - query.set( - gst::SchedulingFlags::SEQUENTIAL - | gst::SchedulingFlags::BANDWIDTH_LIMITED, - 1, - -1, - 0, - ); - query.add_scheduling_modes(&[gst::PadMode::Push]); - return gst::PadProbeReturn::Handled; - } - } - gst::PadProbeReturn::Ok - }); - - bin.add_pad(&ghost_pad) - .expect("Could not add src ghost pad to bin"); + if let QueryView::Scheduling(ref mut query) = query.view_mut() { + query.set( + gst::SchedulingFlags::SEQUENTIAL + | gst::SchedulingFlags::BANDWIDTH_LIMITED, + 1, + -1, + 0, + ); + query.add_scheduling_modes(&[gst::PadMode::Push]); + return true; + } + false } } - impl ElementImpl for ServoSrc {} - impl BinImpl for ServoSrc {} impl URIHandlerImpl for ServoSrc { From 1ad95313c761f68a4662e8a48e3db1f44cdab6d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fernando=20Jim=C3=A9nez=20Moreno?= Date: Wed, 16 Jan 2019 13:18:07 +0100 Subject: [PATCH 18/18] Check servosrc uri --- Cargo.lock | 44 ++++++++++++++++++++++++++++++++ backends/gstreamer/Cargo.toml | 3 +++ backends/gstreamer/src/lib.rs | 2 +- backends/gstreamer/src/source.rs | 15 +++++++++-- 4 files changed, 61 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 5a36ba06..f1a13e1b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -742,6 +742,16 @@ dependencies = [ "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "idna" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "iovec" version = "0.1.2" @@ -864,6 +874,11 @@ dependencies = [ "libc 0.2.42 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "matches" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "memchr" version = "2.0.1" @@ -1312,6 +1327,7 @@ dependencies = [ "regex 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "servo-media-audio 0.1.0", "servo-media-player 0.1.0", + "url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "zip 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1472,6 +1488,19 @@ name = "ucd-util" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unicode-bidi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-normalization" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "unicode-xid" version = "0.1.0" @@ -1485,6 +1514,16 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "url" +version = "1.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "utf8-ranges" version = "1.0.0" @@ -1801,6 +1840,7 @@ dependencies = [ "checksum gstreamer-video 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0c1f04816d7e183714830da26274f97e7aeff09ae6641058538d21443b4ec07d" "checksum gstreamer-video-sys 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e2efb301a0b94fa4af503122faa04247085936dd888fd59fa4e21eab3cbd37" "checksum humantime 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0484fda3e7007f2a4a0d9c3a703ca38c71c54c55602ce4660c419fd32e188c9e" +"checksum idna 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "38f09e0f0b1fb55fdee1f17470ad800da77af5186a1a76c026b679358b7e844e" "checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" "checksum ipc-channel 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "dd75debad4ffd295c00c6e3634d254df30050b0837a85e5cd039ac424365f24a" "checksum jni 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cffc930ce6a38a4013e30567b559bdc79f601013ba4a81e65dbda9207263efd4" @@ -1816,6 +1856,7 @@ dependencies = [ "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fcce5fa49cc693c312001daf1d13411c4a5283796bac1084299ea3e567113f" "checksum malloc_buf 0.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum memchr 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "796fba70e76612589ed2ce7f45282f5af869e0fdd7cc6199fa1aa1f1d591ba9d" "checksum memmap 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e2ffa2c986de11a9df78620c01eeaaf27d94d3ff02bf81bfcca953102dd0c6ff" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" @@ -1879,8 +1920,11 @@ dependencies = [ "checksum thread_profiler 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "5920e77802b177479ab5795767fa48e68f61b2f516c2ac0041e2978dd8efe483" "checksum time 0.1.40 (registry+https://github.com/rust-lang/crates.io-index)" = "d825be0eb33fda1a7e68012d51e9c7f451dc1a69391e7fdc197060bb8c56667b" "checksum ucd-util 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fd2be2d6639d0f8fe6cdda291ad456e23629558d466e2789d2c3e9892bda285d" +"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" +"checksum unicode-normalization 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6a0180bc61fc5a987082bfa111f4cc95c4caff7f9799f3e46df09163a937aa25" "checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" "checksum unreachable 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +"checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" "checksum uuid 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e1436e58182935dcd9ce0add9ea0b558e8a87befe01c1a301e6020aeb0876363" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/backends/gstreamer/Cargo.toml b/backends/gstreamer/Cargo.toml index 144efd90..7bbfe285 100644 --- a/backends/gstreamer/Cargo.toml +++ b/backends/gstreamer/Cargo.toml @@ -51,3 +51,6 @@ path = "../../audio" [dependencies.servo-media-player] path = "../../player" + +[dependencies.url] +version = "1.7.2" diff --git a/backends/gstreamer/src/lib.rs b/backends/gstreamer/src/lib.rs index 99c46700..7085d774 100644 --- a/backends/gstreamer/src/lib.rs +++ b/backends/gstreamer/src/lib.rs @@ -14,9 +14,9 @@ extern crate gstreamer_player as gst_player; extern crate gstreamer_sys as gst_ffi; extern crate gstreamer_video as gst_video; extern crate ipc_channel; - extern crate servo_media_audio; extern crate servo_media_player; +extern crate url; use servo_media_audio::sink::AudioSinkError; use servo_media_audio::AudioBackend; diff --git a/backends/gstreamer/src/source.rs b/backends/gstreamer/src/source.rs index 7a8489b3..a54eb682 100644 --- a/backends/gstreamer/src/source.rs +++ b/backends/gstreamer/src/source.rs @@ -14,6 +14,7 @@ use gst_plugin::uri_handler::{register_uri_handler, URIHandlerImpl, URIHandlerIm use std::mem; use std::ptr; use std::sync::{Once, ONCE_INIT}; +use url::Url; const MAX_SRC_QUEUE_SIZE: u64 = 50 * 1024 * 1024; // 50 MB. @@ -154,9 +155,19 @@ mod imp { fn set_uri( &self, _element: &gst::URIHandler, - _uri: Option, + uri: Option, ) -> Result<(), glib::Error> { - Ok(()) + if let Some(ref uri) = uri { + if let Ok(uri) = Url::parse(uri) { + if uri.scheme() == "servosrc" { + return Ok(()) + } + } + } + Err(glib::Error::new( + gst::URIError::BadUri, + format!("Invalid URI '{:?}'", uri,).as_str(), + )) } }