mirror of
https://github.com/servo/servo.git
synced 2025-08-05 13:40:08 +01:00
Auto merge of #27456 - asajeffrey:gst-plugin-hubs, r=Manishearth
Get the gstreamer plugin to stream Hubs rooms <!-- Please describe your changes on the following line: --> This is thje changes needed to the gstreamer plugin to stream a Hubs room: - Add the ability to specify servo prefs as a gstreamer plugin property - Fix a deadlock caused by using bounded channel, which Hubs hits because it takes ~30s to enter webxr. Also add a recipe for streaming Hubs. --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `___` with appropriate data: --> - [x] `./mach build -d` does not report any errors - [x] `./mach test-tidy` does not report any errors - [x] These changes do not require tests because we don't test the gstreamer plugin <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->
This commit is contained in:
commit
a360b873be
2 changed files with 60 additions and 6 deletions
|
@ -91,6 +91,23 @@ GST_PLUGIN_PATH=target/gstplugins \
|
||||||
This requires the webxr content to support the `sessionavailable` event for launching directly into immersive mode.
|
This requires the webxr content to support the `sessionavailable` event for launching directly into immersive mode.
|
||||||
Values for `webxr` include `none`, `left-right`, `red-cyan`, `cubemap` and `spherical`.
|
Values for `webxr` include `none`, `left-right`, `red-cyan`, `cubemap` and `spherical`.
|
||||||
|
|
||||||
|
To stream a Hubs room and save to a file (there'll be ~30s black at the beginning while Hubs starts up):
|
||||||
|
```
|
||||||
|
GST_PLUGIN_PATH=$PWD/target/gstplugins \
|
||||||
|
gst-launch-1.0 -e servowebsrc \
|
||||||
|
url="https://hubs.mozilla.com/$ROOM?no_force_webvr&vr_entry_type=vr_now" \
|
||||||
|
webxr=red-cyan \
|
||||||
|
prefs='{"dom.gamepad.enabled":true, "dom.svg.enabled":true, "dom.canvas_capture.enabled": true, "dom.canvas_capture.enabled":true, "dom.webrtc.enabled":true, "dom.webrtc.transceiver.enabled":true}' \
|
||||||
|
! video/x-raw\(memory:GLMemory\),framerate=50/1,width=1920,height=1080,format=RGBA \
|
||||||
|
! glvideoflip video-direction=vert \
|
||||||
|
! glcolorconvert \
|
||||||
|
! gldownload \
|
||||||
|
! queue \
|
||||||
|
! x264enc \
|
||||||
|
! mp4mux \
|
||||||
|
! filesink location=test.mp4
|
||||||
|
```
|
||||||
|
|
||||||
*Note*: killing the gstreamer pipeline with control-C sometimes locks up macOS to the point
|
*Note*: killing the gstreamer pipeline with control-C sometimes locks up macOS to the point
|
||||||
of needing a power cycle. Killing the pipeline by closing the window seems to work.
|
of needing a power cycle. Killing the pipeline by closing the window seems to work.
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,9 @@ use servo::compositing::windowing::WindowMethods;
|
||||||
use servo::embedder_traits::EmbedderProxy;
|
use servo::embedder_traits::EmbedderProxy;
|
||||||
use servo::embedder_traits::EventLoopWaker;
|
use servo::embedder_traits::EventLoopWaker;
|
||||||
use servo::msg::constellation_msg::TopLevelBrowsingContextId;
|
use servo::msg::constellation_msg::TopLevelBrowsingContextId;
|
||||||
|
use servo::servo_config::prefs::add_user_prefs;
|
||||||
|
use servo::servo_config::prefs::read_prefs_map;
|
||||||
|
use servo::servo_config::prefs::PrefValue;
|
||||||
use servo::servo_config::set_pref;
|
use servo::servo_config::set_pref;
|
||||||
use servo::servo_url::ServoUrl;
|
use servo::servo_url::ServoUrl;
|
||||||
use servo::webrender_api::units::DevicePixel;
|
use servo::webrender_api::units::DevicePixel;
|
||||||
|
@ -115,6 +118,7 @@ pub struct ServoWebSrc {
|
||||||
sender: Sender<ServoWebSrcMsg>,
|
sender: Sender<ServoWebSrcMsg>,
|
||||||
url: Mutex<Option<String>>,
|
url: Mutex<Option<String>>,
|
||||||
webxr_mode: Mutex<Option<WebXRMode>>,
|
webxr_mode: Mutex<Option<WebXRMode>>,
|
||||||
|
prefs: Mutex<Option<String>>,
|
||||||
outcaps: Mutex<Option<Caps>>,
|
outcaps: Mutex<Option<Caps>>,
|
||||||
info: Mutex<Option<VideoInfo>>,
|
info: Mutex<Option<VideoInfo>>,
|
||||||
buffer_pool: Mutex<Option<BufferPool>>,
|
buffer_pool: Mutex<Option<BufferPool>>,
|
||||||
|
@ -172,6 +176,7 @@ enum ServoWebSrcMsg {
|
||||||
ConnectionWhichImplementsDebug,
|
ConnectionWhichImplementsDebug,
|
||||||
ServoUrl,
|
ServoUrl,
|
||||||
Option<WebXRMode>,
|
Option<WebXRMode>,
|
||||||
|
HashMap<String, PrefValue>,
|
||||||
Size2D<i32, DevicePixel>,
|
Size2D<i32, DevicePixel>,
|
||||||
),
|
),
|
||||||
GetSwapChain(Sender<SwapChain<Device>>),
|
GetSwapChain(Sender<SwapChain<Device>>),
|
||||||
|
@ -195,13 +200,16 @@ struct ServoThread {
|
||||||
|
|
||||||
impl ServoThread {
|
impl ServoThread {
|
||||||
fn new(sender: Sender<ServoWebSrcMsg>, receiver: Receiver<ServoWebSrcMsg>) -> Self {
|
fn new(sender: Sender<ServoWebSrcMsg>, receiver: Receiver<ServoWebSrcMsg>) -> Self {
|
||||||
let (connection, url, webxr_mode, size) = match receiver.recv() {
|
let (connection, url, webxr_mode, prefs, size) = match receiver.recv() {
|
||||||
Ok(ServoWebSrcMsg::Start(connection, url, webxr_mode, size)) => {
|
Ok(ServoWebSrcMsg::Start(connection, url, webxr_mode, prefs, size)) => {
|
||||||
(connection.0, url, webxr_mode, size)
|
(connection.0, url, webxr_mode, prefs, size)
|
||||||
},
|
},
|
||||||
e => panic!("Failed to start ({:?})", e),
|
e => panic!("Failed to start ({:?})", e),
|
||||||
};
|
};
|
||||||
info!("Created new servo thread for {} ({:?})", url, webxr_mode);
|
info!(
|
||||||
|
"Created new servo thread for {} ({:?}, {:?})",
|
||||||
|
url, webxr_mode, prefs
|
||||||
|
);
|
||||||
let window = Rc::new(ServoWebSrcWindow::new(connection, webxr_mode, sender, size));
|
let window = Rc::new(ServoWebSrcWindow::new(connection, webxr_mode, sender, size));
|
||||||
let embedder = Box::new(ServoWebSrcEmbedder::new(&window));
|
let embedder = Box::new(ServoWebSrcEmbedder::new(&window));
|
||||||
let webrender_swap_chain = window
|
let webrender_swap_chain = window
|
||||||
|
@ -224,6 +232,8 @@ impl ServoThread {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
add_user_prefs(prefs);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
receiver,
|
receiver,
|
||||||
servo,
|
servo,
|
||||||
|
@ -443,7 +453,16 @@ impl WebXRWindow for ServoWebSrcWebXR {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static PROPERTIES: [Property; 2] = [
|
static PROPERTIES: [Property; 3] = [
|
||||||
|
Property("prefs", |name| {
|
||||||
|
ParamSpec::string(
|
||||||
|
name,
|
||||||
|
"prefs",
|
||||||
|
"Servo preferences",
|
||||||
|
None,
|
||||||
|
glib::ParamFlags::READWRITE,
|
||||||
|
)
|
||||||
|
}),
|
||||||
Property("url", |name| {
|
Property("url", |name| {
|
||||||
ParamSpec::string(
|
ParamSpec::string(
|
||||||
name,
|
name,
|
||||||
|
@ -485,6 +504,7 @@ impl ObjectSubclass for ServoWebSrc {
|
||||||
let info = Mutex::new(None);
|
let info = Mutex::new(None);
|
||||||
let outcaps = Mutex::new(None);
|
let outcaps = Mutex::new(None);
|
||||||
let url = Mutex::new(None);
|
let url = Mutex::new(None);
|
||||||
|
let prefs = Mutex::new(None);
|
||||||
let webxr_mode = Mutex::new(None);
|
let webxr_mode = Mutex::new(None);
|
||||||
let buffer_pool = Mutex::new(None);
|
let buffer_pool = Mutex::new(None);
|
||||||
let gl_context = Mutex::new(None);
|
let gl_context = Mutex::new(None);
|
||||||
|
@ -497,6 +517,7 @@ impl ObjectSubclass for ServoWebSrc {
|
||||||
info,
|
info,
|
||||||
outcaps,
|
outcaps,
|
||||||
url,
|
url,
|
||||||
|
prefs,
|
||||||
webxr_mode,
|
webxr_mode,
|
||||||
buffer_pool,
|
buffer_pool,
|
||||||
gl_context,
|
gl_context,
|
||||||
|
@ -539,6 +560,11 @@ impl ObjectImpl for ServoWebSrc {
|
||||||
fn set_property(&self, _obj: &Object, id: usize, value: &Value) {
|
fn set_property(&self, _obj: &Object, id: usize, value: &Value) {
|
||||||
let prop = &PROPERTIES[id];
|
let prop = &PROPERTIES[id];
|
||||||
match *prop {
|
match *prop {
|
||||||
|
Property("prefs", ..) => {
|
||||||
|
let mut guard = self.prefs.lock().expect("Failed to lock mutex");
|
||||||
|
let prefs = value.get().expect("Failed to get prefs value");
|
||||||
|
*guard = prefs;
|
||||||
|
},
|
||||||
Property("url", ..) => {
|
Property("url", ..) => {
|
||||||
let mut guard = self.url.lock().expect("Failed to lock mutex");
|
let mut guard = self.url.lock().expect("Failed to lock mutex");
|
||||||
let url = value.get().expect("Failed to get url value");
|
let url = value.get().expect("Failed to get url value");
|
||||||
|
@ -564,6 +590,10 @@ impl ObjectImpl for ServoWebSrc {
|
||||||
fn get_property(&self, _obj: &Object, id: usize) -> Result<Value, ()> {
|
fn get_property(&self, _obj: &Object, id: usize) -> Result<Value, ()> {
|
||||||
let prop = &PROPERTIES[id];
|
let prop = &PROPERTIES[id];
|
||||||
match *prop {
|
match *prop {
|
||||||
|
Property("prefs", ..) => {
|
||||||
|
let guard = self.url.lock().expect("Failed to lock mutex");
|
||||||
|
Ok(Value::from(guard.as_ref()))
|
||||||
|
},
|
||||||
Property("url", ..) => {
|
Property("url", ..) => {
|
||||||
let guard = self.url.lock().expect("Failed to lock mutex");
|
let guard = self.url.lock().expect("Failed to lock mutex");
|
||||||
Ok(Value::from(guard.as_ref()))
|
Ok(Value::from(guard.as_ref()))
|
||||||
|
@ -761,6 +791,12 @@ impl ServoWebSrc {
|
||||||
error!("Failed to parse url {} ({:?})", url_string, e);
|
error!("Failed to parse url {} ({:?})", url_string, e);
|
||||||
FlowError::Error
|
FlowError::Error
|
||||||
})?;
|
})?;
|
||||||
|
let prefs_guard = self.prefs.lock().expect("Poisoned mutex");
|
||||||
|
let prefs_string = prefs_guard.as_ref().map(|s| &**s).unwrap_or("{}");
|
||||||
|
let prefs = read_prefs_map(prefs_string).map_err(|e| {
|
||||||
|
error!("Failed to parse prefs {} ({:?})", prefs_string, e);
|
||||||
|
FlowError::Error
|
||||||
|
})?;
|
||||||
let size = self
|
let size = self
|
||||||
.info
|
.info
|
||||||
.lock()
|
.lock()
|
||||||
|
@ -773,6 +809,7 @@ impl ServoWebSrc {
|
||||||
ConnectionWhichImplementsDebug(connection),
|
ConnectionWhichImplementsDebug(connection),
|
||||||
url,
|
url,
|
||||||
webxr_mode,
|
webxr_mode,
|
||||||
|
prefs,
|
||||||
size,
|
size,
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@ -925,7 +962,7 @@ impl ServoWebSrc {
|
||||||
|
|
||||||
if gfx.swap_chain.is_none() {
|
if gfx.swap_chain.is_none() {
|
||||||
debug!("Getting the swap chain");
|
debug!("Getting the swap chain");
|
||||||
let (acks, ackr) = crossbeam_channel::bounded(1);
|
let (acks, ackr) = crossbeam_channel::unbounded();
|
||||||
let _ = self.sender.send(ServoWebSrcMsg::GetSwapChain(acks));
|
let _ = self.sender.send(ServoWebSrcMsg::GetSwapChain(acks));
|
||||||
gfx.swap_chain = ackr.recv_timeout(Duration::from_millis(16)).ok();
|
gfx.swap_chain = ackr.recv_timeout(Duration::from_millis(16)).ok();
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue