UltraGrid
UltraGrid Low-Latency High-Resolution Transmission System
Loading...
Searching...
No Matches
pipewire.cpp File Reference
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <chrono>
#include <cassert>
#include <algorithm>
#include <vector>
#include <mutex>
#include <unistd.h>
#include <pipewire/pipewire.h>
#include <pipewire/version.h>
#include <spa/utils/result.h>
#include <spa/param/video/format-utils.h>
#include <spa/param/props.h>
#include <spa/debug/types.h>
#include "debug.h"
#include "lib_common.h"
#include "utils/color_out.h"
#include "utils/dbus_portal.hpp"
#include "utils/synchronized_queue.h"
#include "utils/profile_timer.hpp"
#include "video_frame.h"
#include "video_codec.h"
#include "video_capture.h"
#include "pipewire_common.hpp"
#include "pixfmt_conv.h"
Include dependency graph for pipewire.cpp:

Go to the source code of this file.

Classes

struct  frame_deleter
 
struct  vcap_pw_state
 

Macros

#define MOD_NAME   "[PW vcap] "
 

Typedefs

using unique_frame = std::unique_ptr<video_frame, frame_deleter>
 

Functions

static void on_add_buffer (void *, struct pw_buffer *)
 
static void on_drained (void *)
 
static void on_process (void *state)
 
static void on_remove_buffer (void *, struct pw_buffer *)
 
static void on_stream_param_changed (void *state, uint32_t id, const struct spa_pod *param)
 
static void on_stream_state_changed (void *, enum pw_stream_state old, enum pw_stream_state state, const char *error)
 
static int parse_params (struct vidcap_params *params, vcap_pw_state *s)
 
static void pw_frame_to_uv_frame_memcpy (video_frame *dst, spa_buffer *src, spa_video_format fmt, spa_rectangle size, const spa_region *crop)
 
 REGISTER_MODULE (pipewire, &vidcap_pw_info, LIBRARY_CLASS_VIDEO_CAPTURE, VIDEO_CAPTURE_ABI_VERSION)
 
static void show_generic_help ()
 
static void show_screen_help ()
 
static int start_pipewire (vcap_pw_state *s)
 
static int vidcap_pw_init (struct vidcap_params *params, void **state)
 
static void vidcap_pw_probe (struct device_info **available_devices, int *count, void(**deleter)(void *))
 
static void vidcap_screen_pw_done (void *state)
 
static struct video_frame * vidcap_screen_pw_grab (void *state, struct audio_frame **audio)
 
static void vidcap_screen_pw_probe (struct device_info **available_devices, int *count, void(**deleter)(void *))
 

Variables

static constexpr int DEFAULT_BUFFERS_PW = 2
 
static constexpr int DEFAULT_EXPECTING_FPS = 30
 
static constexpr int MAX_BUFFERS_PW = 10
 
static constexpr int MIN_BUFFERS_PW = 2
 
static constexpr int QUEUE_SIZE = 3
 
static const struct pw_stream_events stream_events
 
static const struct video_capture_info vidcap_pw_info
 

Detailed Description

Macro Definition Documentation

◆ MOD_NAME

#define MOD_NAME   "[PW vcap] "

Definition at line 69 of file pipewire.cpp.

Typedef Documentation

◆ unique_frame

using unique_frame = std::unique_ptr<video_frame, frame_deleter>

Definition at line 78 of file pipewire.cpp.

Function Documentation

◆ on_add_buffer()

static void on_add_buffer ( void * ,
struct pw_buffer *  )
static

Definition at line 317 of file pipewire.cpp.

318{
319 LOG(LOG_LEVEL_VERBOSE) << MOD_NAME "pipewire: add_buffer\n";
320}
#define MOD_NAME
Definition pipewire.cpp:57
#define LOG_LEVEL_VERBOSE
Definition debug.h:63
#define LOG(level)
Definition debug.h:313

References LOG, LOG_LEVEL_VERBOSE, and MOD_NAME.

◆ on_drained()

static void on_drained ( void * )
static

Definition at line 312 of file pipewire.cpp.

313{
314 LOG(LOG_LEVEL_VERBOSE) << MOD_NAME "pipewire: drained\n";
315}

References LOG, LOG_LEVEL_VERBOSE, and MOD_NAME.

◆ on_process()

static void on_process ( void * state)
static

Definition at line 243 of file pipewire.cpp.

243 {
245
246 auto s= static_cast<vcap_pw_state *>(state);
247 pw_buffer *buffer;
248 [[maybe_unused]] int n_buffers_from_pw = 0;
249 while((buffer = pw_stream_dequeue_buffer(s->stream.get())) != nullptr){
250 ++n_buffers_from_pw;
251
252 unique_frame next_frame;
253
254 assert(buffer->buffer != nullptr);
255 assert(buffer->buffer->datas != nullptr);
256 assert(buffer->buffer->n_datas == 1);
257 assert(buffer->buffer->datas[0].data != nullptr);
258
259 if(buffer->buffer->datas[0].chunk == nullptr || buffer->buffer->datas[0].chunk->size == 0) {
260 LOG(LOG_LEVEL_DEBUG) << MOD_NAME "dropping - empty pw frame " << "\n";
261 pw_stream_queue_buffer(s->stream.get(), buffer);
262 continue;
263 }
264
265 {
266 std::lock_guard<std::mutex> lock(s->mut);
267 if(!s->blank_frames.empty()){
268 next_frame = std::move(s->blank_frames.back());
269 s->blank_frames.pop_back();
270 }
271 }
272
273 if(!next_frame) {
274 LOG(LOG_LEVEL_DEBUG) << MOD_NAME "dropping frame (no blank frames)\n";
275 pw_stream_queue_buffer(s->stream.get(), buffer);
276 continue;
277 }
278
279 spa_region *crop_region = nullptr;
280 if (s->user_options.crop) {
281 spa_meta_region *meta_crop_region = static_cast<spa_meta_region*>(spa_buffer_find_meta_data(buffer->buffer, SPA_META_VideoCrop, sizeof(*meta_crop_region)));
282 if (meta_crop_region != nullptr && spa_meta_region_is_valid(meta_crop_region))
283 crop_region = &meta_crop_region->region;
284 }
285
286 if(crop_region){
287 //Update desc so that we don't reallocate on each frame
288 //TODO: Figure what to do when we can't actually crop (MJPEG)
289 s->desc.width = crop_region->size.width;
290 s->desc.height = crop_region->size.height;
291 }
292
293 if(!next_frame || !video_desc_eq(video_desc_from_frame(next_frame.get()), s->desc)){
294 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "Desc changed, allocating new video_frame\n");
295 next_frame.reset(vf_alloc_desc_data(s->desc));
296 }
297
298
299 auto& raw_format = s->format.info.raw;
300
301 //copy_frame(s->pw.video_format(), buffer->buffer, next_frame.get(), s->desc.width, s->desc.height, crop_region);
302 pw_frame_to_uv_frame_memcpy(next_frame.get(), buffer->buffer, raw_format.format, raw_format.size, crop_region);
303
304 s->sending_frames.push(std::move(next_frame));
305 pw_stream_queue_buffer(s->stream.get(), buffer);
306 }
307
308 //LOG(LOG_LEVEL_DEBUG) << "[screen_pw]: from pw: "<< n_buffers_from_pw << "\t sending: "<<s->sending_frames.size_approx() << "\t blank: " << s->blank_frames.size_approx() << "\n";
309
310}
void ** state
struct video_desc video_desc_from_frame(const struct video_frame *frame)
Returns struct video_desc from video frame.
struct video_frame * vf_alloc_desc_data(struct video_desc desc)
void log_msg(int level, const char *format,...)
Definition debug.cpp:130
#define LOG_LEVEL_DEBUG
Definition kernels.cu:48
#define PROFILE_FUNC
static void pw_frame_to_uv_frame_memcpy(video_frame *dst, spa_buffer *src, spa_video_format fmt, spa_rectangle size, const spa_region *crop)
Definition pipewire.cpp:202
std::unique_ptr< video_frame, frame_deleter > unique_frame
Definition pipewire.cpp:78
bool video_desc_eq(struct video_desc a, struct video_desc b)
Compares two video descriptions.

References LOG, LOG_LEVEL_DEBUG, LOG_LEVEL_VERBOSE, log_msg(), MOD_NAME, PROFILE_FUNC, pw_frame_to_uv_frame_memcpy(), state, vf_alloc_desc_data(), video_desc_eq(), and video_desc_from_frame().

Here is the call graph for this function:

◆ on_remove_buffer()

static void on_remove_buffer ( void * ,
struct pw_buffer *  )
static

Definition at line 322 of file pipewire.cpp.

323{
324 LOG(LOG_LEVEL_VERBOSE) << MOD_NAME "pipewire: remove_buffer\n";
325}

References LOG, LOG_LEVEL_VERBOSE, and MOD_NAME.

◆ on_stream_param_changed()

static void on_stream_param_changed ( void * state,
uint32_t id,
const struct spa_pod * param )
static

Definition at line 127 of file pipewire.cpp.

127 {
128 auto s = static_cast<vcap_pw_state *>(state);
129 LOG(LOG_LEVEL_VERBOSE) << MOD_NAME "param changed:\n";
130
131 if (param == nullptr || id != SPA_PARAM_Format)
132 return;
133
134 int parse_format_ret = spa_format_parse(param, &s->format.media_type, &s->format.media_subtype);
135 assert(parse_format_ret > 0);
136
137 if(s->format.media_type != SPA_MEDIA_TYPE_video
138 || s->format.media_subtype != SPA_MEDIA_SUBTYPE_raw)
139 {
140 log_msg(LOG_LEVEL_ERROR, MOD_NAME "Format not video/raw!\n");
141 return;
142 }
143
144 auto& raw_format = s->format.info.raw;
145 spa_format_video_raw_parse(param, &raw_format);
146
147 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Got format: %s\n", spa_debug_type_find_name(spa_type_video_format, raw_format.format));
148
149 s->desc.width = raw_format.size.width;
150 s->desc.height = raw_format.size.height;
151 if(raw_format.framerate.num != 0){
152 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Got framerate: %d / %d\n", raw_format.framerate.num, raw_format.framerate.denom);
153 s->desc.fps = static_cast<double>(raw_format.framerate.num) / raw_format.framerate.denom;
154 } else {
155 //Variable framerate
156 log_msg(LOG_LEVEL_NOTICE, MOD_NAME "Got variable framerate: %d / %d\n", raw_format.max_framerate.num, raw_format.max_framerate.denom);
157 if(raw_format.max_framerate.num != 0){
158 s->desc.fps = static_cast<double>(raw_format.max_framerate.num) / raw_format.max_framerate.denom;
159 } else {
160 s->desc.fps = 60;
161 log_msg(LOG_LEVEL_WARNING, MOD_NAME "Invalid max framerate, using %f instead\n", s->desc.fps);
162 }
163 }
164 s->desc.color_spec = uv_codec_from_pw_fmt(raw_format.format);
165 s->desc.interlacing = PROGRESSIVE;
166 s->desc.tile_count = 1;
167
168 log_msg(LOG_LEVEL_VERBOSE, MOD_NAME "size: %dx%d\n", s->desc.width, s->desc.height);
169
170 int linesize = vc_get_linesize(s->desc.width, s->desc.color_spec);
171 int32_t size = linesize * s->desc.height;
172
173 uint8_t params_buffer[1024];
174
175 struct spa_pod_builder builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
176 const struct spa_pod *params[3] = {};
177 int n_params = 0;
178
179 params[n_params++] = static_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
180 SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
181 SPA_PARAM_BUFFERS_buffers,
182 SPA_POD_CHOICE_RANGE_Int(DEFAULT_BUFFERS_PW, MIN_BUFFERS_PW, MAX_BUFFERS_PW),
183 SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(1),
184 SPA_PARAM_BUFFERS_size, SPA_POD_Int(size),
185 SPA_PARAM_BUFFERS_stride, SPA_POD_Int(linesize),
186 SPA_PARAM_BUFFERS_dataType,
187 SPA_POD_CHOICE_FLAGS_Int((1 << SPA_DATA_MemPtr)))
188 );
189
190 if(s->user_options.crop) {
191 params[n_params++] = static_cast<spa_pod *>(spa_pod_builder_add_object(&builder,
192 SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
193 SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoCrop),
194 SPA_PARAM_META_size,
195 SPA_POD_Int(sizeof(struct spa_meta_region)))
196 );
197 }
198
199 pw_stream_update_params(s->stream.get(), params, n_params);
200}
int vc_get_linesize(unsigned int width, codec_t codec)
#define LOG_LEVEL_NOTICE
information that may be interesting
Definition debug.h:61
#define LOG_LEVEL_ERROR
general errors
Definition debug.h:59
#define LOG_LEVEL_WARNING
less severe errors
Definition debug.h:60
codec_t uv_codec_from_pw_fmt(spa_video_format fmt)
const char * param
Definition settings.cpp:195
@ PROGRESSIVE
progressive frame
Definition types.h:164
static constexpr int MIN_BUFFERS_PW
Definition pipewire.cpp:72
static constexpr int DEFAULT_BUFFERS_PW
Definition pipewire.cpp:71
static constexpr int MAX_BUFFERS_PW
Definition pipewire.cpp:73

References DEFAULT_BUFFERS_PW, LOG, LOG_LEVEL_ERROR, LOG_LEVEL_NOTICE, LOG_LEVEL_VERBOSE, LOG_LEVEL_WARNING, log_msg(), MAX_BUFFERS_PW, MIN_BUFFERS_PW, MOD_NAME, param, PROGRESSIVE, state, uv_codec_from_pw_fmt(), and vc_get_linesize().

Here is the call graph for this function:

◆ on_stream_state_changed()

static void on_stream_state_changed ( void * ,
enum pw_stream_state old,
enum pw_stream_state state,
const char * error )
static

Definition at line 117 of file pipewire.cpp.

117 {
118 LOG(LOG_LEVEL_INFO) << MOD_NAME "stream state changed \"" << pw_stream_state_as_string(old)
119 << "\" -> \""<<pw_stream_state_as_string(state)<<"\"\n";
120
121 if (error != nullptr) {
122 LOG(LOG_LEVEL_ERROR) << MOD_NAME "stream error: '"<< error << "'\n";
123 }
124}
#define LOG_LEVEL_INFO
normal reporting
Definition debug.h:62

References LOG, LOG_LEVEL_ERROR, LOG_LEVEL_INFO, MOD_NAME, and state.

◆ parse_params()

static int parse_params ( struct vidcap_params * params,
vcap_pw_state * s )
static

Definition at line 487 of file pipewire.cpp.

487 {
488 if(const char *fmt = vidcap_params_get_fmt(params)) {
489 std::istringstream params_stream(fmt);
490
491 std::string param;
492 while (std::getline(params_stream, param, ':')) {
493 if (param == "help") {
496 else
498 return VIDCAP_INIT_NOERR;
499 } else if (param == "cursor") {
500 s->user_options.show_cursor = true;
501 } else if (param == "nocrop") {
502 s->user_options.crop = false;
503 } else {
504 auto split_index = param.find('=');
505 if(split_index != std::string::npos && split_index != 0){
506 std::string name = param.substr(0, split_index);
507 std::string value = param.substr(split_index + 1);
508
509 if (name == "fps" || name == "FPS"){
510 std::istringstream is(value);
511 is >> s->user_options.fps;
512 continue;
513 }else if(name == "restore"){
514 s->user_options.restore_file = std::move(value);
515 continue;
516 } else if(name =="target"){
517 s->user_options.target = std::move(value);
518 continue;
519 }
520 }
521
522 LOG(LOG_LEVEL_ERROR) << MOD_NAME "invalid option: \"" << param << "\"\n";
523 return VIDCAP_INIT_FAIL;
524 }
525 }
526 }
527 return VIDCAP_INIT_OK;
528}
const char * fmt
#define VIDCAP_INIT_NOERR
state not initialized, other action performed (typically help)
#define VIDCAP_INIT_OK
initialization successful
#define VIDCAP_INIT_FAIL
error ocured
const char * name
Definition settings.cpp:193
enum vcap_pw_state::Mode mode
std::string target
Definition pipewire.cpp:112
struct vcap_pw_state::@71 user_options
uint32_t fps
Definition pipewire.cpp:110
std::string restore_file
Definition pipewire.cpp:109
static void show_screen_help()
Definition pipewire.cpp:462
static void show_generic_help()
Definition pipewire.cpp:476
const char * vidcap_params_get_fmt(const struct vidcap_params *params)

References vcap_pw_state::crop, fmt, vcap_pw_state::fps, LOG, LOG_LEVEL_ERROR, MOD_NAME, vcap_pw_state::mode, name, param, vcap_pw_state::restore_file, vcap_pw_state::Screen_capture, vcap_pw_state::show_cursor, show_generic_help(), show_screen_help(), vcap_pw_state::target, vcap_pw_state::user_options, VIDCAP_INIT_FAIL, VIDCAP_INIT_NOERR, VIDCAP_INIT_OK, and vidcap_params_get_fmt().

Referenced by vidcap_pw_init().

Here is the call graph for this function:

◆ pw_frame_to_uv_frame_memcpy()

static void pw_frame_to_uv_frame_memcpy ( video_frame * dst,
spa_buffer * src,
spa_video_format fmt,
spa_rectangle size,
const spa_region * crop )
static

Definition at line 202 of file pipewire.cpp.

202 {
203 auto offset = src->datas[0].chunk->offset;
204 auto chunk_size = src->datas[0].chunk->size;
205 auto stride = src->datas[0].chunk->stride;
206
207 auto width = size.width;
208 auto height = size.height;
209
210 unsigned start_x = 0;
211 unsigned start_y = 0;
212 if(crop){
213 width = crop->size.width;
214 height = crop->size.height;
215 start_x = crop->position.x;
216 start_y = crop->position.y;
217 }
218
219 if(stride == 0)
220 stride = chunk_size / size.height;
221
222 auto linesize = vc_get_linesize(width, dst->color_spec);
223 auto skip = vc_get_linesize(start_x, dst->color_spec);
224 bool swap_red_blue = fmt == SPA_VIDEO_FORMAT_BGRA || fmt == SPA_VIDEO_FORMAT_BGRx; //TODO
225 for(unsigned i = 0; i < height; i++){
226 auto src_p = static_cast<unsigned char *>(src->datas[0].data) + offset + skip + stride * (i + start_y);
227 auto dst_p = reinterpret_cast<unsigned char *>(dst->tiles[0].data) + linesize * i;
228 /* It would probably be better to have separate functions for
229 * pipweire to uv frame conversions like lavd has. For now,
230 * let's handle BGRA to RGBA like this.
231 */
232 if(swap_red_blue)
233 vc_copylineRGBA(dst_p, src_p, linesize, 16, 8, 0);
234 else
235 memcpy(dst_p, src_p, linesize);
236 }
237
238 dst->tiles[0].width = width;
239 dst->tiles[0].height = height;
240 dst->tiles[0].data_len = linesize * height;
241}
static __device__ const float offset
Definition cuda_dxt.cu:139
decoder_func_t vc_copylineRGBA
unsigned int width
Definition types.h:280
char * data
Raw tile data. Pointer must be at least 4B aligned.
Definition types.h:287
unsigned int data_len
length of the data
Definition types.h:288
unsigned int height
Definition types.h:281
struct tile tiles[FLEXIBLE_ARRAY_MEMBER]
Definition types.h:345
codec_t color_spec
Definition types.h:306

References video_frame::color_spec, tile::data, tile::data_len, fmt, tile::height, offset, video_frame::tiles, vc_copylineRGBA, vc_get_linesize(), and tile::width.

Referenced by on_process().

Here is the call graph for this function:

◆ REGISTER_MODULE()

REGISTER_MODULE ( pipewire ,
& vidcap_pw_info,
LIBRARY_CLASS_VIDEO_CAPTURE ,
VIDEO_CAPTURE_ABI_VERSION  )

◆ show_generic_help()

static void show_generic_help ( )
static

Definition at line 476 of file pipewire.cpp.

476 {
477 color_printf("Pipewire video capture.\n");
478 color_printf("Usage\n");
479 color_printf(TERM_BOLD TERM_FG_RED "\t-t pipewire" TERM_FG_RESET "[:fps=<fps>][:target=<device>]\n" TERM_RESET);
480 color_printf("\n");
481
482 color_printf("Devices:\n");
483 print_devices("Video/Source");
484}
int color_printf(const char *format,...)
#define TERM_BOLD
Definition color_out.h:48
#define TERM_FG_RED
Definition color_out.h:50
#define TERM_RESET
Definition color_out.h:47
#define TERM_FG_RESET
Definition color_out.h:59
void print_devices(std::string_view media_class)

References color_printf(), print_devices(), TERM_BOLD, TERM_FG_RED, TERM_FG_RESET, and TERM_RESET.

Referenced by parse_params().

Here is the call graph for this function:

◆ show_screen_help()

static void show_screen_help ( )
static

Definition at line 462 of file pipewire.cpp.

462 {
463 auto param = [](const char* name) -> std::ostream& {
464 col() << " " << SBOLD(name) << " - ";
465 return std::cout;
466 };
467
468 std::cout << "Screen capture using PipeWire and ScreenCast freedesktop portal API\n";
469 std::cout << "Usage: -t screen_pw[:cursor|:nocrop|:fps=<fps>|:restore=<token_file>]]\n";
470 param("cursor") << "make the cursor visible (default hidden)\n";
471 param("nocrop") << "when capturing a window do not crop out the empty background\n";
472 param("<fps>") << "prefered FPS passed to PipeWire (PipeWire may ignore it)\n";
473 param("<token_file>") << "restore the selected window/display from a file.\n\t\tIf not possible, display the selection dialog and save the token to the file specified.\n";
474}
#define SBOLD(x)
Definition color_out.h:80

References name, param, and SBOLD.

Referenced by parse_params().

◆ start_pipewire()

static int start_pipewire ( vcap_pw_state * s)
static

Definition at line 344 of file pipewire.cpp.

345{
346 const struct spa_pod *params[2] = {};
347 uint8_t params_buffer[1024];
348 struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
349
350 initialize_pw_common(s->pw, s->fd);
351
352 std::string node_name = "ultragrid_in_";
353 {
354 char buf[32];
355 snprintf(buf, sizeof(buf), "%ld", (long) getpid());
356 node_name += buf;
357 }
358
359 auto props = pw_properties_new(
360 PW_KEY_MEDIA_TYPE, "Video",
361 PW_KEY_MEDIA_CATEGORY, "Capture",
362 PW_KEY_MEDIA_ROLE, "Communication",
363 PW_KEY_APP_NAME, "UltraGrid",
364 PW_KEY_APP_ICON_NAME, "ultragrid",
365 PW_KEY_NODE_NAME, node_name.c_str(),
366 PW_KEY_NODE_DESCRIPTION, "UltraGrid capture",
367 nullptr);
368
369 if(!s->user_options.target.empty()){
370 pw_properties_set(props, STREAM_TARGET_PROPERTY_KEY, s->user_options.target.c_str());
371 }
372
374
375 s->stream.reset(pw_stream_new(s->pw.pipewire_core.get(),
376 s->mode == vcap_pw_state::Mode::Screen_capture ? "ug_screencapture" : "ug_videocap",
377 props));
378
379 assert(s->stream != nullptr);
380
381 pw_stream_add_listener(
382 s->stream.get(),
383 &s->stream_listener.get(),
385 s);
386
387 auto size_rect_def = SPA_RECTANGLE(1920, 1080);
388 auto size_rect_min = SPA_RECTANGLE(1, 1);
389 auto size_rect_max = SPA_RECTANGLE(3840, 2160);
390
391 auto framerate_def = SPA_FRACTION(s->user_options.fps > 0 ? s->user_options.fps : DEFAULT_EXPECTING_FPS, 1);
392 auto framerate_min = SPA_FRACTION(0, 1);
393 auto framerate_max = SPA_FRACTION(600, 1);
394
395 const int n_params = 1;
396 params[0] = static_cast<spa_pod *> (spa_pod_builder_add_object(
397 &pod_builder, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat,
398 SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_video),
399 SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_raw),
400 SPA_FORMAT_VIDEO_format,
401 SPA_POD_CHOICE_ENUM_Id(8,
402 SPA_VIDEO_FORMAT_UYVY,
403 SPA_VIDEO_FORMAT_UYVY,
404 SPA_VIDEO_FORMAT_RGB,
405 SPA_VIDEO_FORMAT_RGBA,
406 SPA_VIDEO_FORMAT_RGBx,
407 SPA_VIDEO_FORMAT_YUY2,
408 SPA_VIDEO_FORMAT_BGRA,
409 SPA_VIDEO_FORMAT_BGRx
410 ),
411 SPA_FORMAT_VIDEO_size,
412 SPA_POD_CHOICE_RANGE_Rectangle(
413 &size_rect_def,
414 &size_rect_min,
415 &size_rect_max),
416 SPA_FORMAT_VIDEO_framerate,
417 SPA_POD_CHOICE_RANGE_Fraction(
418 &framerate_def,
419 &framerate_min,
420 &framerate_max)
421 ));
422
423 auto flags = PW_STREAM_FLAG_MAP_BUFFERS |
424 PW_STREAM_FLAG_DONT_RECONNECT;
425
426 if(!s->user_options.target.empty()){
427 flags |= PW_STREAM_FLAG_AUTOCONNECT;
428 }
429
430 int res = pw_stream_connect(s->stream.get(),
431 PW_DIRECTION_INPUT,
432 s->node,
433 static_cast<pw_stream_flags>(flags),
434 params, n_params);
435 if (res < 0) {
436 fprintf(stderr, MOD_NAME "can't connect: %s\n", spa_strerror(res));
437 return -1;
438 }
439
440 pw_stream_set_active(s->stream.get(), true);
441 return 0;
442}
const char unsigned int flags
static const pw_stream_events stream_events
Definition pipewire.cpp:177
bool initialize_pw_common(pipewire_state_common &s, int fd)
#define STREAM_TARGET_PROPERTY_KEY
pw_thread_loop_uniq pipewire_loop
spa_hook & get()
pw_stream_uniq stream
Definition pipewire.cpp:98
pipewire_state_common pw
Definition pipewire.cpp:81
uint32_t node
Definition pipewire.cpp:96
spa_hook_uniq stream_listener
Definition pipewire.cpp:99
static constexpr int DEFAULT_EXPECTING_FPS
Definition pipewire.cpp:75

References DEFAULT_EXPECTING_FPS, vcap_pw_state::fd, flags, vcap_pw_state::fps, spa_hook_uniq::get(), initialize_pw_common(), MOD_NAME, vcap_pw_state::mode, vcap_pw_state::node, pipewire_state_common::pipewire_core, pipewire_state_common::pipewire_loop, vcap_pw_state::pw, vcap_pw_state::Screen_capture, vcap_pw_state::stream, stream_events, vcap_pw_state::stream_listener, STREAM_TARGET_PROPERTY_KEY, vcap_pw_state::target, and vcap_pw_state::user_options.

Referenced by vidcap_pw_init().

Here is the call graph for this function:

◆ vidcap_pw_init()

static int vidcap_pw_init ( struct vidcap_params * params,
void ** state )
static

Definition at line 573 of file pipewire.cpp.

574{
577 }
578
579 auto s = std::make_unique<vcap_pw_state>();
580
581 LOG(LOG_LEVEL_DEBUG) << MOD_NAME "init\n";
582
583 int params_ok = parse_params(params, s.get());
584 if(params_ok != VIDCAP_INIT_OK)
585 return params_ok;
586
587 for(int i = 0; i < QUEUE_SIZE; i++)
588 s->blank_frames.emplace_back(vf_alloc(1));
589
590 s->fd = -1;
591
592 LOG(LOG_LEVEL_DEBUG) << MOD_NAME "init ok\n";
593 start_pipewire(s.get());
594
595 *state = s.release();
596
597 return VIDCAP_INIT_OK;
598}
struct video_frame * vf_alloc(int count)
Allocates blank video frame.
#define VIDCAP_INIT_AUDIO_NOT_SUPPORTED
card does not support audio
static constexpr int QUEUE_SIZE
Definition pipewire.cpp:74
static int start_pipewire(vcap_pw_state *s)
Definition pipewire.cpp:344
static int parse_params(struct vidcap_params *params, vcap_pw_state *s)
Definition pipewire.cpp:487
unsigned int vidcap_params_get_flags(const struct vidcap_params *params)
#define VIDCAP_FLAG_AUDIO_ANY

References LOG, LOG_LEVEL_DEBUG, MOD_NAME, parse_params(), QUEUE_SIZE, start_pipewire(), state, vf_alloc(), VIDCAP_FLAG_AUDIO_ANY, VIDCAP_INIT_AUDIO_NOT_SUPPORTED, VIDCAP_INIT_OK, and vidcap_params_get_flags().

Here is the call graph for this function:

◆ vidcap_pw_probe()

static void vidcap_pw_probe ( struct device_info ** available_devices,
int * count,
void(** deleter )(void *) )
static

Definition at line 453 of file pipewire.cpp.

454{
455 *deleter = free;
456 *count = 1;
457 *available_devices = (struct device_info *) calloc(*count, sizeof(struct device_info));
458 // (*available_devices)[0].dev can be "" since screen cap. doesn't require parameters
459 snprintf((*available_devices)[0].name, sizeof (*available_devices)[0].name, "Generic PipeWire video capture");
460}
int void(** deleter)(void *))
int count
Definition hd-rum.c:44

References count, deleter, and name.

◆ vidcap_screen_pw_done()

static void vidcap_screen_pw_done ( void * state)
static

Definition at line 600 of file pipewire.cpp.

601{
602 auto s = static_cast<vcap_pw_state *>(state);
603
604 {
605 pipewire_thread_loop_lock_guard lock(s->pw.pipewire_loop.get());
606 pw_stream_disconnect(s->stream.get());
607 }
608
609 pw_thread_loop_stop(s->pw.pipewire_loop.get());
610 LOG(LOG_LEVEL_DEBUG) << MOD_NAME "done\n";
611 delete s;
612}

References LOG, LOG_LEVEL_DEBUG, MOD_NAME, and state.

◆ vidcap_screen_pw_grab()

static struct video_frame * vidcap_screen_pw_grab ( void * state,
struct audio_frame ** audio )
static

Definition at line 614 of file pipewire.cpp.

615{
617
618 assert(state != nullptr);
619 auto s = static_cast<vcap_pw_state *>(state);
620 *audio = nullptr;
621
622 if(s->in_flight_frame.get() != nullptr){
623 s->blank_frames.push_back(std::move(s->in_flight_frame));
624 }
625
626 using namespace std::chrono_literals;
627 s->sending_frames.timed_pop(s->in_flight_frame, 500ms);
628 return s->in_flight_frame.get();
629}
struct audio_frame ** audio

References audio, PROFILE_FUNC, and state.

◆ vidcap_screen_pw_probe()

static void vidcap_screen_pw_probe ( struct device_info ** available_devices,
int * count,
void(** deleter )(void *) )
static

Definition at line 444 of file pipewire.cpp.

445{
446 *deleter = free;
447 *count = 1;
448 *available_devices = (struct device_info *) calloc(*count, sizeof(struct device_info));
449 // (*available_devices)[0].dev can be "" since screen cap. doesn't require parameters
450 snprintf((*available_devices)[0].name, sizeof (*available_devices)[0].name, "Screen capture PipeWire");
451}

References count, deleter, and name.

Variable Documentation

◆ DEFAULT_BUFFERS_PW

int DEFAULT_BUFFERS_PW = 2
staticconstexpr

Definition at line 71 of file pipewire.cpp.

Referenced by on_stream_param_changed().

◆ DEFAULT_EXPECTING_FPS

int DEFAULT_EXPECTING_FPS = 30
staticconstexpr

Definition at line 75 of file pipewire.cpp.

Referenced by start_pipewire().

◆ MAX_BUFFERS_PW

int MAX_BUFFERS_PW = 10
staticconstexpr

Definition at line 73 of file pipewire.cpp.

Referenced by on_stream_param_changed().

◆ MIN_BUFFERS_PW

int MIN_BUFFERS_PW = 2
staticconstexpr

Definition at line 72 of file pipewire.cpp.

Referenced by on_stream_param_changed().

◆ QUEUE_SIZE

int QUEUE_SIZE = 3
staticconstexpr

Definition at line 74 of file pipewire.cpp.

Referenced by vidcap_pw_init().

◆ stream_events

const struct pw_stream_events stream_events
static
Initial value:
= {
.version = PW_VERSION_STREAM_EVENTS,
.destroy = nullptr,
.state_changed = on_stream_state_changed,
.control_info = nullptr,
.io_changed = nullptr,
.param_changed = on_stream_param_changed,
.add_buffer = on_add_buffer,
.remove_buffer = on_remove_buffer,
.process = on_process,
.drained = on_drained,
}
static void on_process(void *state)
Definition pipewire.cpp:83
static void on_remove_buffer(void *, struct pw_buffer *)
Definition pipewire.cpp:322
static void on_stream_param_changed(void *state, uint32_t id, const struct spa_pod *param)
Definition pipewire.cpp:127
static void on_stream_state_changed(void *, enum pw_stream_state old, enum pw_stream_state state, const char *error)
Definition pipewire.cpp:117
static void on_drained(void *)
Definition pipewire.cpp:312
static void on_add_buffer(void *, struct pw_buffer *)
Definition pipewire.cpp:317

Definition at line 327 of file pipewire.cpp.

327 {
328 .version = PW_VERSION_STREAM_EVENTS,
329 .destroy = nullptr,
330 .state_changed = on_stream_state_changed,
331 .control_info = nullptr,
332 .io_changed = nullptr,
333 .param_changed = on_stream_param_changed,
334 .add_buffer = on_add_buffer,
335 .remove_buffer = on_remove_buffer,
336 .process = on_process,
337 .drained = on_drained,
338#if PW_MAJOR > 0 || PW_MINOR > 3 || (PW_MINOR == 3 && PW_MICRO > 39)
339 .command = nullptr,
340 .trigger_done = nullptr,
341#endif
342};

◆ vidcap_pw_info

const struct video_capture_info vidcap_pw_info
static
Initial value:
= {
}
static void vidcap_screen_pw_done(void *state)
Definition pipewire.cpp:600
static void vidcap_pw_probe(struct device_info **available_devices, int *count, void(**deleter)(void *))
Definition pipewire.cpp:453
static struct video_frame * vidcap_screen_pw_grab(void *state, struct audio_frame **audio)
Definition pipewire.cpp:614
static int vidcap_pw_init(struct vidcap_params *params, void **state)
Definition pipewire.cpp:573

Definition at line 645 of file pipewire.cpp.