linux-capture: Add PipeWire-based capture
Add a new Linux capture based on PipeWire [1] and the Desktop portal [2].
This new capture starts by asking the Desktop portal for a screencapture session.
There are quite a few D-Bus calls involved in this, but the key points are:
1. A connection to org.freedesktop.portal.ScreenCast is estabilished, and the
available cursor modes are updated.
2. CreateSession() is called. This is the first step of the negotiation.
3. SelectSources() is called. This is when a system dialog pops up asking the
user to either select a monitor (desktop capture) or a window (window capture).
4. Start() is called. This signals the compositor that it can setup a PipeWire
stream, and start sending buffers.
The reply to this fourth call gives OBS Studio the PipeWire fd, and the id of the
PipeWire node where the buffers are being sent to. This allows creating a consumer
PipeWire stream, and receive the buffers.
Metadata cursor is always preferred, but on the lack of it, we ask the stream for
an embedded cursor (i.e. the cursor is drawn at the buffer, and OBS Studio has no
control over it.)
Window capturing is implemented as a crop operation on the buffer. Compositors
can send big buffers, and a crop rectangle, and this is used to paint a subregion
of the buffer in the scene.
The new capture is only loaded when running on EGL, since it depends on EGL to
call gs_texture_create_from_dmabuf().
[1] https://pipewire.org/
[2] https://github.com/flatpak/xdg-desktop-portal/
2021-02-25 19:57:33 +00:00
|
|
|
/* pipewire.h
|
|
|
|
*
|
|
|
|
* Copyright 2020 Georges Basile Stavracas Neto <georges.stavracas@gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <obs-module.h>
|
|
|
|
|
2022-07-02 12:06:07 +00:00
|
|
|
#include <pipewire/pipewire.h>
|
2022-06-28 22:28:26 +00:00
|
|
|
|
2022-07-01 20:21:43 +00:00
|
|
|
typedef struct _obs_pipewire obs_pipewire;
|
linux-pipewire: Separate PipeWire core and streams
Sorry, this is a painful commit to review :(
Until now, the only consumer of the PipeWire code is the screen
cast portal code. This portal code only ever has one PipeWire
connection, and one PipeWire stream, every time a monitor or a
window is selected. This is reflected on obs_pipewire, which only
handles a single stream for any given connection.
For cameras and audio, however, a single PipeWire connection can
and most likely always will provide multiple streams. For example,
computers with multiple webcams will have one PipeWire connection
reporting multiple PipeWire nodes, one node for each camera.
This commit breaks this one-stream-per-connection assumption, and
makes obs_pipewire_connect_stream() return an independent object
(obs_pipewire_stream) that represents a single stream.
The screencast portal code continues to only ever have one connection
and one stream.
2022-07-01 21:22:02 +00:00
|
|
|
typedef struct _obs_pipewire_stream obs_pipewire_stream;
|
linux-capture: Add PipeWire-based capture
Add a new Linux capture based on PipeWire [1] and the Desktop portal [2].
This new capture starts by asking the Desktop portal for a screencapture session.
There are quite a few D-Bus calls involved in this, but the key points are:
1. A connection to org.freedesktop.portal.ScreenCast is estabilished, and the
available cursor modes are updated.
2. CreateSession() is called. This is the first step of the negotiation.
3. SelectSources() is called. This is when a system dialog pops up asking the
user to either select a monitor (desktop capture) or a window (window capture).
4. Start() is called. This signals the compositor that it can setup a PipeWire
stream, and start sending buffers.
The reply to this fourth call gives OBS Studio the PipeWire fd, and the id of the
PipeWire node where the buffers are being sent to. This allows creating a consumer
PipeWire stream, and receive the buffers.
Metadata cursor is always preferred, but on the lack of it, we ask the stream for
an embedded cursor (i.e. the cursor is drawn at the buffer, and OBS Studio has no
control over it.)
Window capturing is implemented as a crop operation on the buffer. Compositors
can send big buffers, and a crop rectangle, and this is used to paint a subregion
of the buffer in the scene.
The new capture is only loaded when running on EGL, since it depends on EGL to
call gs_texture_create_from_dmabuf().
[1] https://pipewire.org/
[2] https://github.com/flatpak/xdg-desktop-portal/
2021-02-25 19:57:33 +00:00
|
|
|
|
2023-12-14 00:21:05 +00:00
|
|
|
struct obs_pipwire_connect_stream_info {
|
|
|
|
const char *stream_name;
|
|
|
|
struct pw_properties *stream_properties;
|
2023-12-13 20:07:29 +00:00
|
|
|
struct {
|
|
|
|
bool cursor_visible;
|
|
|
|
} screencast;
|
2023-12-13 22:09:24 +00:00
|
|
|
struct {
|
|
|
|
const struct spa_rectangle *resolution;
|
|
|
|
const struct spa_fraction *framerate;
|
|
|
|
} video;
|
2023-12-14 00:21:05 +00:00
|
|
|
};
|
|
|
|
|
2022-07-02 12:06:07 +00:00
|
|
|
obs_pipewire *
|
2023-09-20 20:25:08 +00:00
|
|
|
obs_pipewire_connect_fd(int pipewire_fd,
|
|
|
|
const struct pw_registry_events *registry_events,
|
|
|
|
void *user_data);
|
2022-07-02 12:06:07 +00:00
|
|
|
struct pw_registry *obs_pipewire_get_registry(obs_pipewire *obs_pw);
|
2022-07-02 12:08:01 +00:00
|
|
|
void obs_pipewire_roundtrip(obs_pipewire *obs_pw);
|
2022-07-01 20:24:37 +00:00
|
|
|
void obs_pipewire_destroy(obs_pipewire *obs_pw);
|
|
|
|
|
2023-12-14 00:21:05 +00:00
|
|
|
obs_pipewire_stream *obs_pipewire_connect_stream(
|
|
|
|
obs_pipewire *obs_pw, obs_source_t *source, int pipewire_node,
|
|
|
|
const struct obs_pipwire_connect_stream_info *connect_info);
|
linux-pipewire: Separate PipeWire core and streams
Sorry, this is a painful commit to review :(
Until now, the only consumer of the PipeWire code is the screen
cast portal code. This portal code only ever has one PipeWire
connection, and one PipeWire stream, every time a monitor or a
window is selected. This is reflected on obs_pipewire, which only
handles a single stream for any given connection.
For cameras and audio, however, a single PipeWire connection can
and most likely always will provide multiple streams. For example,
computers with multiple webcams will have one PipeWire connection
reporting multiple PipeWire nodes, one node for each camera.
This commit breaks this one-stream-per-connection assumption, and
makes obs_pipewire_connect_stream() return an independent object
(obs_pipewire_stream) that represents a single stream.
The screencast portal code continues to only ever have one connection
and one stream.
2022-07-01 21:22:02 +00:00
|
|
|
|
2023-12-14 00:14:35 +00:00
|
|
|
void obs_pipewire_stream_show(obs_pipewire_stream *obs_pw_stream);
|
|
|
|
void obs_pipewire_stream_hide(obs_pipewire_stream *obs_pw_stream);
|
|
|
|
uint32_t obs_pipewire_stream_get_width(obs_pipewire_stream *obs_pw_stream);
|
|
|
|
uint32_t obs_pipewire_stream_get_height(obs_pipewire_stream *obs_pw_stream);
|
|
|
|
void obs_pipewire_stream_video_render(obs_pipewire_stream *obs_pw_stream,
|
linux-pipewire: Separate PipeWire core and streams
Sorry, this is a painful commit to review :(
Until now, the only consumer of the PipeWire code is the screen
cast portal code. This portal code only ever has one PipeWire
connection, and one PipeWire stream, every time a monitor or a
window is selected. This is reflected on obs_pipewire, which only
handles a single stream for any given connection.
For cameras and audio, however, a single PipeWire connection can
and most likely always will provide multiple streams. For example,
computers with multiple webcams will have one PipeWire connection
reporting multiple PipeWire nodes, one node for each camera.
This commit breaks this one-stream-per-connection assumption, and
makes obs_pipewire_connect_stream() return an independent object
(obs_pipewire_stream) that represents a single stream.
The screencast portal code continues to only ever have one connection
and one stream.
2022-07-01 21:22:02 +00:00
|
|
|
gs_effect_t *effect);
|
|
|
|
|
2023-12-14 00:14:35 +00:00
|
|
|
void obs_pipewire_stream_set_cursor_visible(obs_pipewire_stream *obs_pw_stream,
|
linux-pipewire: Separate PipeWire core and streams
Sorry, this is a painful commit to review :(
Until now, the only consumer of the PipeWire code is the screen
cast portal code. This portal code only ever has one PipeWire
connection, and one PipeWire stream, every time a monitor or a
window is selected. This is reflected on obs_pipewire, which only
handles a single stream for any given connection.
For cameras and audio, however, a single PipeWire connection can
and most likely always will provide multiple streams. For example,
computers with multiple webcams will have one PipeWire connection
reporting multiple PipeWire nodes, one node for each camera.
This commit breaks this one-stream-per-connection assumption, and
makes obs_pipewire_connect_stream() return an independent object
(obs_pipewire_stream) that represents a single stream.
The screencast portal code continues to only ever have one connection
and one stream.
2022-07-01 21:22:02 +00:00
|
|
|
bool cursor_visible);
|
|
|
|
void obs_pipewire_stream_destroy(obs_pipewire_stream *obs_pw_stream);
|
2022-10-31 11:20:47 +00:00
|
|
|
|
|
|
|
void obs_pipewire_stream_set_framerate(obs_pipewire_stream *obs_pw_stream,
|
|
|
|
const struct spa_fraction *framerate);
|
|
|
|
void obs_pipewire_stream_set_resolution(obs_pipewire_stream *obs_pw,
|
|
|
|
const struct spa_rectangle *resolution);
|