mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-07-14 15:24:07 +00:00
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/
This commit is contained in:
parent
a0464b0f8f
commit
c2f8b2058b
121
cmake/Modules/FindPipeWire.cmake
Normal file
121
cmake/Modules/FindPipeWire.cmake
Normal file
|
@ -0,0 +1,121 @@
|
|||
#.rst:
|
||||
# FindPipeWire
|
||||
# -------
|
||||
#
|
||||
# Try to find PipeWire on a Unix system.
|
||||
#
|
||||
# This will define the following variables:
|
||||
#
|
||||
# ``PIPEWIRE_FOUND``
|
||||
# True if (the requested version of) PipeWire is available
|
||||
# ``PIPEWIRE_VERSION``
|
||||
# The version of PipeWire
|
||||
# ``PIPEWIRE_LIBRARIES``
|
||||
# This can be passed to target_link_libraries() instead of the ``PipeWire::PipeWire``
|
||||
# target
|
||||
# ``PIPEWIRE_INCLUDE_DIRS``
|
||||
# This should be passed to target_include_directories() if the target is not
|
||||
# used for linking
|
||||
# ``PIPEWIRE_DEFINITIONS``
|
||||
# This should be passed to target_compile_options() if the target is not
|
||||
# used for linking
|
||||
#
|
||||
# If ``PIPEWIRE_FOUND`` is TRUE, it will also define the following imported target:
|
||||
#
|
||||
# ``PipeWire::PipeWire``
|
||||
# The PipeWire library
|
||||
#
|
||||
# In general we recommend using the imported target, as it is easier to use.
|
||||
# Bear in mind, however, that if the target is in the link interface of an
|
||||
# exported library, it must be made available by the package config file.
|
||||
|
||||
#=============================================================================
|
||||
# Copyright 2014 Alex Merry <alex.merry@kde.org>
|
||||
# Copyright 2014 Martin Gräßlin <mgraesslin@kde.org>
|
||||
# Copyright 2018-2020 Jan Grulich <jgrulich@redhat.com>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
#
|
||||
# 1. Redistributions of source code must retain the copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
# 3. The name of the author may not be used to endorse or promote products
|
||||
# derived from this software without specific prior written permission.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
# IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
# OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
# IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
# NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
# THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#=============================================================================
|
||||
|
||||
# Use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
find_package(PkgConfig QUIET)
|
||||
|
||||
pkg_search_module(PKG_PIPEWIRE QUIET libpipewire-0.3)
|
||||
pkg_search_module(PKG_SPA QUIET libspa-0.2)
|
||||
|
||||
set(PIPEWIRE_DEFINITIONS "${PKG_PIPEWIRE_CFLAGS}" "${PKG_SPA_CFLAGS}")
|
||||
set(PIPEWIRE_VERSION "${PKG_PIPEWIRE_VERSION}")
|
||||
|
||||
find_path(PIPEWIRE_INCLUDE_DIRS
|
||||
NAMES
|
||||
pipewire/pipewire.h
|
||||
HINTS
|
||||
${PKG_PIPEWIRE_INCLUDE_DIRS}
|
||||
${PKG_PIPEWIRE_INCLUDE_DIRS}/pipewire-0.3
|
||||
)
|
||||
|
||||
find_path(SPA_INCLUDE_DIRS
|
||||
NAMES
|
||||
spa/param/props.h
|
||||
HINTS
|
||||
${PKG_SPA_INCLUDE_DIRS}
|
||||
${PKG_SPA_INCLUDE_DIRS}/spa-0.2
|
||||
)
|
||||
|
||||
find_library(PIPEWIRE_LIBRARIES
|
||||
NAMES
|
||||
pipewire-0.3
|
||||
HINTS
|
||||
${PKG_PIPEWIRE_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(PipeWire
|
||||
FOUND_VAR
|
||||
PIPEWIRE_FOUND
|
||||
REQUIRED_VARS
|
||||
PIPEWIRE_LIBRARIES
|
||||
PIPEWIRE_INCLUDE_DIRS
|
||||
SPA_INCLUDE_DIRS
|
||||
VERSION_VAR
|
||||
PIPEWIRE_VERSION
|
||||
)
|
||||
|
||||
if(PIPEWIRE_FOUND AND NOT TARGET PipeWire::PipeWire)
|
||||
add_library(PipeWire::PipeWire UNKNOWN IMPORTED)
|
||||
set_target_properties(PipeWire::PipeWire PROPERTIES
|
||||
IMPORTED_LOCATION "${PIPEWIRE_LIBRARIES}"
|
||||
INTERFACE_COMPILE_OPTIONS "${PIPEWIRE_DEFINITIONS}"
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${PIPEWIRE_INCLUDE_DIRS};${SPA_INCLUDE_DIRS}"
|
||||
)
|
||||
endif()
|
||||
|
||||
mark_as_advanced(PIPEWIRE_LIBRARIES PIPEWIRE_INCLUDE_DIRS)
|
||||
|
||||
include(FeatureSummary)
|
||||
set_package_properties(PipeWire PROPERTIES
|
||||
URL "https://www.pipewire.org"
|
||||
DESCRIPTION "PipeWire - multimedia processing"
|
||||
)
|
|
@ -44,6 +44,41 @@ set(linux-capture_LIBRARIES
|
|||
${XCB_LIBRARIES}
|
||||
)
|
||||
|
||||
option(ENABLE_PIPEWIRE "Enable PipeWire support" ON)
|
||||
if(ENABLE_PIPEWIRE)
|
||||
find_package(PipeWire REQUIRED)
|
||||
find_package(Gio REQUIRED)
|
||||
|
||||
add_definitions(-DENABLE_PIPEWIRE)
|
||||
|
||||
set(linux-capture_INCLUDES
|
||||
${linux-capture_INCLUDES}
|
||||
${GIO_INCLUDE_DIRS}
|
||||
${PIPEWIRE_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
add_definitions(
|
||||
${GIO_DEFINITIONS}
|
||||
${PIPEWIRE_DEFINITIONS}
|
||||
)
|
||||
|
||||
set(linux-capture_SOURCES
|
||||
${linux-capture_SOURCES}
|
||||
pipewire.c
|
||||
pipewire-capture.c
|
||||
)
|
||||
set(linux-capture_HEADERS
|
||||
${linux-capture_HEADERS}
|
||||
pipewire.h
|
||||
pipewire-capture.h
|
||||
)
|
||||
set(linux-capture_LIBRARIES
|
||||
${linux-capture_LIBRARIES}
|
||||
${GIO_LIBRARIES}
|
||||
${PIPEWIRE_LIBRARIES}
|
||||
)
|
||||
endif()
|
||||
|
||||
include_directories(SYSTEM
|
||||
${linux-capture_INCLUDES}
|
||||
)
|
||||
|
|
|
@ -13,3 +13,8 @@ SwapRedBlue="Swap red and blue"
|
|||
LockX="Lock X server when capturing"
|
||||
IncludeXBorder="Include X Border"
|
||||
ExcludeAlpha="Use alpha-less texture format (Mesa workaround)"
|
||||
PipeWireDesktopCapture="Screen Capture (PipeWire)"
|
||||
PipeWireSelectMonitor="Select Monitor"
|
||||
PipeWireSelectWindow="Select Window"
|
||||
PipeWireWindowCapture="Window Capture (PipeWire)"
|
||||
ShowCursor="Show Cursor"
|
||||
|
|
|
@ -17,6 +17,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include <obs-module.h>
|
||||
#include <obs-nix-platform.h>
|
||||
|
||||
#ifdef ENABLE_PIPEWIRE
|
||||
#include "pipewire-capture.h"
|
||||
#endif
|
||||
|
||||
OBS_DECLARE_MODULE()
|
||||
OBS_MODULE_USE_DEFAULT_LOCALE("linux-xshm", "en-US")
|
||||
MODULE_EXPORT const char *obs_module_description(void)
|
||||
|
@ -31,17 +35,24 @@ extern void xcomposite_unload(void);
|
|||
|
||||
bool obs_module_load(void)
|
||||
{
|
||||
if (obs_get_nix_platform() != OBS_NIX_PLATFORM_X11_GLX) {
|
||||
blog(LOG_ERROR, "linux-capture cannot run on EGL platforms");
|
||||
return false;
|
||||
if (obs_get_nix_platform() == OBS_NIX_PLATFORM_X11_GLX) {
|
||||
obs_register_source(&xshm_input);
|
||||
xcomposite_load();
|
||||
#ifdef ENABLE_PIPEWIRE
|
||||
} else {
|
||||
pipewire_capture_load();
|
||||
#endif
|
||||
}
|
||||
|
||||
obs_register_source(&xshm_input);
|
||||
xcomposite_load();
|
||||
return true;
|
||||
}
|
||||
|
||||
void obs_module_unload(void)
|
||||
{
|
||||
xcomposite_unload();
|
||||
if (obs_get_nix_platform() == OBS_NIX_PLATFORM_X11_GLX)
|
||||
xcomposite_unload();
|
||||
#ifdef ENABLE_PIPEWIRE
|
||||
else
|
||||
pipewire_capture_unload();
|
||||
#endif
|
||||
}
|
||||
|
|
155
plugins/linux-capture/pipewire-capture.c
Normal file
155
plugins/linux-capture/pipewire-capture.c
Normal file
|
@ -0,0 +1,155 @@
|
|||
/* pipewire-capture.c
|
||||
*
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include "pipewire.h"
|
||||
|
||||
/* obs_source_info methods */
|
||||
|
||||
static const char *pipewire_desktop_capture_get_name(void *data)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
return obs_module_text("PipeWireDesktopCapture");
|
||||
}
|
||||
|
||||
static const char *pipewire_window_capture_get_name(void *data)
|
||||
{
|
||||
UNUSED_PARAMETER(data);
|
||||
return obs_module_text("PipeWireWindowCapture");
|
||||
}
|
||||
|
||||
static void *pipewire_desktop_capture_create(obs_data_t *settings,
|
||||
obs_source_t *source)
|
||||
{
|
||||
return obs_pipewire_create(DESKTOP_CAPTURE, settings, source);
|
||||
}
|
||||
static void *pipewire_window_capture_create(obs_data_t *settings,
|
||||
obs_source_t *source)
|
||||
{
|
||||
return obs_pipewire_create(WINDOW_CAPTURE, settings, source);
|
||||
}
|
||||
|
||||
static void pipewire_capture_destroy(void *data)
|
||||
{
|
||||
obs_pipewire_destroy(data);
|
||||
}
|
||||
|
||||
static void pipewire_capture_get_defaults(obs_data_t *settings)
|
||||
{
|
||||
obs_pipewire_get_defaults(settings);
|
||||
}
|
||||
|
||||
static obs_properties_t *pipewire_capture_get_properties(void *data)
|
||||
{
|
||||
enum obs_pw_capture_type capture_type;
|
||||
obs_pipewire_data *obs_pw = data;
|
||||
|
||||
capture_type = obs_pipewire_get_capture_type(obs_pw);
|
||||
|
||||
switch (capture_type) {
|
||||
case DESKTOP_CAPTURE:
|
||||
return obs_pipewire_get_properties(data,
|
||||
"PipeWireSelectMonitor");
|
||||
case WINDOW_CAPTURE:
|
||||
return obs_pipewire_get_properties(data,
|
||||
"PipeWireSelectWindow");
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static void pipewire_capture_update(void *data, obs_data_t *settings)
|
||||
{
|
||||
obs_pipewire_update(data, settings);
|
||||
}
|
||||
|
||||
static void pipewire_capture_show(void *data)
|
||||
{
|
||||
obs_pipewire_show(data);
|
||||
}
|
||||
|
||||
static void pipewire_capture_hide(void *data)
|
||||
{
|
||||
obs_pipewire_hide(data);
|
||||
}
|
||||
|
||||
static uint32_t pipewire_capture_get_width(void *data)
|
||||
{
|
||||
return obs_pipewire_get_width(data);
|
||||
}
|
||||
|
||||
static uint32_t pipewire_capture_get_height(void *data)
|
||||
{
|
||||
return obs_pipewire_get_height(data);
|
||||
}
|
||||
|
||||
static void pipewire_capture_video_render(void *data, gs_effect_t *effect)
|
||||
{
|
||||
obs_pipewire_video_render(data, effect);
|
||||
}
|
||||
|
||||
void pipewire_capture_load(void)
|
||||
{
|
||||
// Desktop capture
|
||||
const struct obs_source_info pipewire_desktop_capture_info = {
|
||||
.id = "pipewire-desktop-capture-source",
|
||||
.type = OBS_SOURCE_TYPE_INPUT,
|
||||
.output_flags = OBS_SOURCE_VIDEO,
|
||||
.get_name = pipewire_desktop_capture_get_name,
|
||||
.create = pipewire_desktop_capture_create,
|
||||
.destroy = pipewire_capture_destroy,
|
||||
.get_defaults = pipewire_capture_get_defaults,
|
||||
.get_properties = pipewire_capture_get_properties,
|
||||
.update = pipewire_capture_update,
|
||||
.show = pipewire_capture_show,
|
||||
.hide = pipewire_capture_hide,
|
||||
.get_width = pipewire_capture_get_width,
|
||||
.get_height = pipewire_capture_get_height,
|
||||
.video_render = pipewire_capture_video_render,
|
||||
.icon_type = OBS_ICON_TYPE_DESKTOP_CAPTURE,
|
||||
};
|
||||
obs_register_source(&pipewire_desktop_capture_info);
|
||||
|
||||
// Window capture
|
||||
const struct obs_source_info pipewire_window_capture_info = {
|
||||
.id = "pipewire-window-capture-source",
|
||||
.type = OBS_SOURCE_TYPE_INPUT,
|
||||
.output_flags = OBS_SOURCE_VIDEO,
|
||||
.get_name = pipewire_window_capture_get_name,
|
||||
.create = pipewire_window_capture_create,
|
||||
.destroy = pipewire_capture_destroy,
|
||||
.get_defaults = pipewire_capture_get_defaults,
|
||||
.get_properties = pipewire_capture_get_properties,
|
||||
.update = pipewire_capture_update,
|
||||
.show = pipewire_capture_show,
|
||||
.hide = pipewire_capture_hide,
|
||||
.get_width = pipewire_capture_get_width,
|
||||
.get_height = pipewire_capture_get_height,
|
||||
.video_render = pipewire_capture_video_render,
|
||||
.icon_type = OBS_ICON_TYPE_WINDOW_CAPTURE,
|
||||
};
|
||||
obs_register_source(&pipewire_window_capture_info);
|
||||
|
||||
pw_init(NULL, NULL);
|
||||
}
|
||||
|
||||
void pipewire_capture_unload(void)
|
||||
{
|
||||
pw_deinit();
|
||||
}
|
24
plugins/linux-capture/pipewire-capture.h
Normal file
24
plugins/linux-capture/pipewire-capture.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
/* pipewire-capture.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
|
||||
|
||||
void pipewire_capture_load(void);
|
||||
void pipewire_capture_unload(void);
|
1232
plugins/linux-capture/pipewire.c
Normal file
1232
plugins/linux-capture/pipewire.c
Normal file
File diff suppressed because it is too large
Load diff
53
plugins/linux-capture/pipewire.h
Normal file
53
plugins/linux-capture/pipewire.h
Normal file
|
@ -0,0 +1,53 @@
|
|||
/* 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>
|
||||
#include <pipewire/pipewire.h>
|
||||
|
||||
typedef struct _obs_pipewire_data obs_pipewire_data;
|
||||
|
||||
enum obs_pw_capture_type {
|
||||
DESKTOP_CAPTURE = 1,
|
||||
WINDOW_CAPTURE = 2,
|
||||
};
|
||||
|
||||
void *obs_pipewire_create(enum obs_pw_capture_type capture_type,
|
||||
obs_data_t *settings, obs_source_t *source);
|
||||
|
||||
void obs_pipewire_destroy(obs_pipewire_data *obs_pw);
|
||||
|
||||
void obs_pipewire_get_defaults(obs_data_t *settings);
|
||||
|
||||
obs_properties_t *obs_pipewire_get_properties(obs_pipewire_data *obs_pw,
|
||||
const char *reload_string_id);
|
||||
|
||||
void obs_pipewire_update(obs_pipewire_data *obs_pw, obs_data_t *settings);
|
||||
|
||||
void obs_pipewire_show(obs_pipewire_data *obs_pw);
|
||||
|
||||
void obs_pipewire_hide(obs_pipewire_data *obs_pw);
|
||||
uint32_t obs_pipewire_get_width(obs_pipewire_data *obs_pw);
|
||||
uint32_t obs_pipewire_get_height(obs_pipewire_data *obs_pw);
|
||||
void obs_pipewire_video_render(obs_pipewire_data *obs_pw, gs_effect_t *effect);
|
||||
|
||||
enum obs_pw_capture_type
|
||||
obs_pipewire_get_capture_type(obs_pipewire_data *obs_pw);
|
Loading…
Reference in a new issue