frontends (tools/webrtc): Fix pipeline for desktop sharing:

Fix desktop sharing, and improve error handling.
This commit is contained in:
Goffi 2025-11-06 22:23:51 +01:00
commit a5e1280af8

View file

@ -1502,27 +1502,87 @@ class WebRTC:
log.debug(f"setting {source_elt} property: {key!r}={value!r}")
desktop_src.set_property(key, value)
video_convert = Gst.ElementFactory.make("videoconvert", "desktop_videoconvert")
video_rate = Gst.ElementFactory.make("videorate", "desktop_videorate")
video_scale = Gst.ElementFactory.make("videoscale", "desktop_videoscale")
# Add capsfilter to ensure proper format matching with video_selector
capsfilter = Gst.ElementFactory.make("capsfilter", "desktop_capsfilter")
caps = Gst.Caps.from_string("video/x-raw,framerate=30/1")
capsfilter.set_property("caps", caps)
queue = Gst.ElementFactory.make("queue", "desktop_queue")
queue.set_property("leaky", "downstream")
queue.set_property("max-size-buffers", 3)
self.pipeline.add(desktop_src)
self.pipeline.add(video_convert)
self.pipeline.add(video_rate)
self.pipeline.add(video_scale)
self.pipeline.add(capsfilter)
self.pipeline.add(queue)
desktop_src.link(video_convert)
video_convert.link(queue)
# Link the elements: src → convert → rate → scale → capsfilter → queue
if not desktop_src.link(video_convert):
log.error("Failed to link desktop_src to videoconvert")
self._cleanup_desktop_elements([desktop_src, video_convert, video_rate,
video_scale, capsfilter, queue])
return
if not video_convert.link(video_rate):
log.error("Failed to link videoconvert to videorate")
self._cleanup_desktop_elements([desktop_src, video_convert, video_rate,
video_scale, capsfilter, queue])
return
if not video_rate.link(video_scale):
log.error("Failed to link videorate to videoscale")
self._cleanup_desktop_elements([desktop_src, video_convert, video_rate,
video_scale, capsfilter, queue])
return
if not video_scale.link(capsfilter):
log.error("Failed to link videoscale to capsfilter")
self._cleanup_desktop_elements([desktop_src, video_convert, video_rate,
video_scale, capsfilter, queue])
return
if not capsfilter.link(queue):
log.error("Failed to link capsfilter to queue")
self._cleanup_desktop_elements([desktop_src, video_convert, video_rate,
video_scale, capsfilter, queue])
return
sink_pad_template = self.video_selector.get_pad_template("sink_%u")
self.desktop_sink_pad = self.video_selector.request_pad(
sink_pad_template, None, None
)
queue_src_pad = queue.get_static_pad("src")
queue_src_pad.link(self.desktop_sink_pad)
link_ret = queue_src_pad.link(self.desktop_sink_pad)
if link_ret != Gst.PadLinkReturn.OK:
log.error(f"Failed to link queue to video_selector: {link_ret}")
self._cleanup_desktop_elements([desktop_src, video_convert, video_rate,
video_scale, capsfilter, queue])
return
desktop_src.sync_state_with_parent()
video_convert.sync_state_with_parent()
video_rate.sync_state_with_parent()
video_scale.sync_state_with_parent()
capsfilter.sync_state_with_parent()
queue.sync_state_with_parent()
log.info("Desktop source pipeline successfully created and linked")
def _cleanup_desktop_elements(self, elements: list[Gst.Element]) -> None:
"""Helper to cleanup elements on error.
@param elements: List of elements to remove from pipeline
"""
for element in elements:
if element:
element.set_state(Gst.State.NULL)
self.pipeline.remove(element)
def _remove_desktop_source(self, desktop_src: Gst.Element) -> None:
"""Remove the desktop source from the pipeline.
@ -1530,19 +1590,18 @@ class WebRTC:
"""
# Remove elements for the desktop source
video_convert = self.pipeline.get_by_name("desktop_videoconvert")
video_rate = self.pipeline.get_by_name("desktop_videorate")
video_scale = self.pipeline.get_by_name("desktop_videoscale")
capsfilter = self.pipeline.get_by_name("desktop_capsfilter")
queue = self.pipeline.get_by_name("desktop_queue")
if video_convert:
video_convert.set_state(Gst.State.NULL)
desktop_src.unlink(video_convert)
self.pipeline.remove(video_convert)
# Unlink and remove in reverse order
elements = [queue, capsfilter, video_scale, video_rate, video_convert, desktop_src]
if queue:
queue.set_state(Gst.State.NULL)
self.pipeline.remove(queue)
desktop_src.set_state(Gst.State.NULL)
self.pipeline.remove(desktop_src)
for element in elements:
if element:
element.set_state(Gst.State.NULL)
self.pipeline.remove(element)
# Release the pad associated with the desktop source
if self.desktop_sink_pad: