Last active
June 11, 2024 05:33
-
-
Save pojntfx/c3bbbf6dbf3759e75607c5e085ab8740 to your computer and use it in GitHub Desktop.
Stream Wayland desktop over network with Pipewire, GStreamer and MJPEG
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
gst-launch-1.0 tcpclientsrc host=localhost port=5000 ! multipartdemux ! jpegdec ! videoconvert ! autovideosink |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python3 | |
# See https://gitlab.gnome.org/-/snippets/19 | |
import re | |
import signal | |
import dbus | |
from gi.repository import GLib, GObject, Gst | |
from dbus.mainloop.glib import DBusGMainLoop | |
DBusGMainLoop(set_as_default=True) | |
Gst.init(None) | |
loop = GLib.MainLoop() | |
bus = dbus.SessionBus() | |
request_iface = 'org.freedesktop.portal.Request' | |
screen_cast_iface = 'org.freedesktop.portal.ScreenCast' | |
pipeline = None | |
request_token_counter = 0 | |
session_token_counter = 0 | |
sender_name = re.sub(r'\.', '_', bus.get_unique_name()[1:]) | |
def new_request_path(): | |
global request_token_counter | |
request_token_counter += 1 | |
token = f'u{request_token_counter}' | |
return f'/org/freedesktop/portal/desktop/request/{sender_name}/{token}', token | |
def new_session_path(): | |
global session_token_counter | |
session_token_counter += 1 | |
token = f'u{session_token_counter}' | |
return f'/org/freedesktop/portal/desktop/session/{sender_name}/{token}', token | |
def screen_cast_call(method, callback, *args, options={}): | |
request_path, request_token = new_request_path() | |
bus.add_signal_receiver(callback, 'Response', request_iface, 'org.freedesktop.portal.Desktop', request_path) | |
options['handle_token'] = request_token | |
method(*args, options, dbus_interface=screen_cast_iface) | |
portal = bus.get_object('org.freedesktop.portal.Desktop', '/org/freedesktop/portal/desktop') | |
screen_cast_call(portal.CreateSession, | |
lambda response, results: ( | |
print(f"Failed to create session: {response}") if response != 0 else ( | |
globals().update({'session': results['session_handle']}), | |
print(f"session {results['session_handle']} created"), | |
screen_cast_call(portal.SelectSources, | |
lambda response, results: ( | |
print(f"Failed to select sources: {response}") if response != 0 else ( | |
print("sources selected"), | |
screen_cast_call(portal.Start, | |
lambda response, results: ( | |
print(f"Failed to start: {response}") if response != 0 else ( | |
print("streams:"), | |
[( | |
print(f"stream {node_id}"), | |
(pipeline := Gst.parse_launch(f'pipewiresrc fd={portal.OpenPipeWireRemote(session, dbus.Dictionary(signature="sv"), dbus_interface=screen_cast_iface).take()} path={node_id} ! videorate ! video/x-raw,framerate=60/1 ! videoconvert ! clockoverlay shaded-background=true font-desc="Sans 38" ! queue ! jpegenc ! multipartmux ! queue ! tcpserversink host=0.0.0.0 port=5000')).set_state(Gst.State.PLAYING), | |
pipeline.get_bus().connect('message', | |
lambda bus, message: ( | |
(pipeline.set_state(Gst.State.NULL), loop.quit()) if message.type in (Gst.MessageType.EOS, Gst.MessageType.ERROR) else None | |
) | |
) | |
) for node_id, _ in results['streams']] | |
) | |
), | |
session, '' | |
) | |
) | |
), | |
session, options={'multiple': False, 'types': dbus.UInt32(1 | 2)} | |
) | |
) | |
), | |
options={'session_handle_token': new_session_path()[1]} | |
) | |
try: | |
loop.run() | |
except KeyboardInterrupt: | |
pipeline.set_state(Gst.State.NULL) if pipeline else None | |
loop.quit() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment