mirror of
https://github.com/obsproject/obs-studio.git
synced 2024-09-20 04:42:18 +02:00
linux-pipewire: Read buffer transformation from PipeWire
PipeWire allows since 0.3.62 [1] to attach metadata to a buffer describing a transformation of the buffercontent. Clients should then undo that transformation to import it correctly. We can enable this feature using macro guards and runtime server version checks on supported systems. [1] https://gitlab.freedesktop.org/pipewire/pipewire/-/merge_requests/1423
This commit is contained in:
parent
2a2d8fc1bb
commit
8abc3528cf
@ -30,11 +30,30 @@
|
||||
#include <libdrm/drm_fourcc.h>
|
||||
#include <pipewire/pipewire.h>
|
||||
#include <spa/param/video/format-utils.h>
|
||||
#include <spa/buffer/meta.h>
|
||||
#include <spa/debug/format.h>
|
||||
#include <spa/debug/types.h>
|
||||
#include <spa/param/video/type-info.h>
|
||||
#include <spa/utils/result.h>
|
||||
|
||||
#if !PW_CHECK_VERSION(0, 3, 62)
|
||||
enum spa_meta_videotransform_value {
|
||||
SPA_META_TRANSFORMATION_None = 0, /**< no transform */
|
||||
SPA_META_TRANSFORMATION_90, /**< 90 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_180, /**< 180 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_270, /**< 270 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_Flipped, /**< 180 degree flipped around the vertical axis. Equivalent
|
||||
* to a reflexion through the vertical line splitting the
|
||||
* bufffer in two equal sized parts */
|
||||
SPA_META_TRANSFORMATION_Flipped90, /**< flip then rotate around 90 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_Flipped180, /**< flip then rotate around 180 degree counter-clockwise */
|
||||
SPA_META_TRANSFORMATION_Flipped270, /**< flip then rotate around 270 degree counter-clockwise */
|
||||
};
|
||||
|
||||
#define SPA_META_VideoTransform 8
|
||||
|
||||
#endif
|
||||
|
||||
#define CURSOR_META_SIZE(width, height) \
|
||||
(sizeof(struct spa_meta_cursor) + sizeof(struct spa_meta_bitmap) + \
|
||||
width * height * 4)
|
||||
@ -71,6 +90,8 @@ struct _obs_pipewire {
|
||||
|
||||
struct spa_video_info format;
|
||||
|
||||
enum spa_meta_videotransform_value transform;
|
||||
|
||||
struct {
|
||||
bool valid;
|
||||
int x, y;
|
||||
@ -454,6 +475,7 @@ static void on_process_cb(void *user_data)
|
||||
uint32_t drm_format;
|
||||
struct spa_meta_header *header;
|
||||
struct spa_meta_region *region;
|
||||
struct spa_meta_videotransform *video_transform;
|
||||
struct spa_buffer *buffer;
|
||||
struct pw_buffer *b;
|
||||
bool swap_red_blue = false;
|
||||
@ -605,6 +627,14 @@ static void on_process_cb(void *user_data)
|
||||
obs_pw->crop.valid = false;
|
||||
}
|
||||
|
||||
/* Video Transform */
|
||||
video_transform = spa_buffer_find_meta_data(
|
||||
buffer, SPA_META_VideoTransform, sizeof(*video_transform));
|
||||
if (video_transform)
|
||||
obs_pw->transform = video_transform->transform;
|
||||
else
|
||||
obs_pw->transform = SPA_META_TRANSFORMATION_None;
|
||||
|
||||
read_metadata:
|
||||
|
||||
/* Cursor */
|
||||
@ -656,7 +686,8 @@ static void on_param_changed_cb(void *user_data, uint32_t id,
|
||||
{
|
||||
obs_pipewire *obs_pw = user_data;
|
||||
struct spa_pod_builder pod_builder;
|
||||
const struct spa_pod *params[4];
|
||||
const struct spa_pod *params[5];
|
||||
uint32_t n_params = 0;
|
||||
uint32_t buffer_types;
|
||||
uint8_t params_buffer[1024];
|
||||
int result;
|
||||
@ -705,14 +736,14 @@ static void on_param_changed_cb(void *user_data, uint32_t id,
|
||||
/* Video crop */
|
||||
pod_builder =
|
||||
SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer));
|
||||
params[0] = spa_pod_builder_add_object(
|
||||
params[n_params++] = spa_pod_builder_add_object(
|
||||
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_VideoCrop),
|
||||
SPA_PARAM_META_size,
|
||||
SPA_POD_Int(sizeof(struct spa_meta_region)));
|
||||
|
||||
/* Cursor */
|
||||
params[1] = spa_pod_builder_add_object(
|
||||
params[n_params++] = spa_pod_builder_add_object(
|
||||
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Cursor),
|
||||
SPA_PARAM_META_size,
|
||||
@ -721,18 +752,29 @@ static void on_param_changed_cb(void *user_data, uint32_t id,
|
||||
CURSOR_META_SIZE(1024, 1024)));
|
||||
|
||||
/* Buffer options */
|
||||
params[2] = spa_pod_builder_add_object(
|
||||
params[n_params++] = spa_pod_builder_add_object(
|
||||
&pod_builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
|
||||
SPA_PARAM_BUFFERS_dataType, SPA_POD_Int(buffer_types));
|
||||
|
||||
/* Meta header */
|
||||
params[3] = spa_pod_builder_add_object(
|
||||
params[n_params++] = spa_pod_builder_add_object(
|
||||
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||
SPA_PARAM_META_type, SPA_POD_Id(SPA_META_Header),
|
||||
SPA_PARAM_META_size,
|
||||
SPA_POD_Int(sizeof(struct spa_meta_header)));
|
||||
|
||||
pw_stream_update_params(obs_pw->stream, params, 4);
|
||||
#if PW_CHECK_VERSION(0, 3, 62)
|
||||
if (check_pw_version(&obs_pw->server_version, 0, 3, 62)) {
|
||||
/* Video transformation */
|
||||
params[n_params++] = spa_pod_builder_add_object(
|
||||
&pod_builder, SPA_TYPE_OBJECT_ParamMeta, SPA_PARAM_Meta,
|
||||
SPA_PARAM_META_type,
|
||||
SPA_POD_Id(SPA_META_VideoTransform),
|
||||
SPA_PARAM_META_size,
|
||||
SPA_POD_Int(sizeof(struct spa_meta_videotransform)));
|
||||
}
|
||||
#endif
|
||||
pw_stream_update_params(obs_pw->stream, params, n_params);
|
||||
|
||||
obs_pw->negotiated = true;
|
||||
}
|
||||
@ -911,10 +953,20 @@ uint32_t obs_pipewire_get_width(obs_pipewire *obs_pw)
|
||||
if (!obs_pw->negotiated)
|
||||
return 0;
|
||||
|
||||
if (obs_pw->crop.valid)
|
||||
return obs_pw->crop.width;
|
||||
else
|
||||
return obs_pw->format.info.raw.size.width;
|
||||
switch (obs_pw->transform) {
|
||||
case SPA_META_TRANSFORMATION_Flipped:
|
||||
case SPA_META_TRANSFORMATION_None:
|
||||
case SPA_META_TRANSFORMATION_Flipped180:
|
||||
case SPA_META_TRANSFORMATION_180:
|
||||
return obs_pw->crop.valid ? obs_pw->crop.width
|
||||
: obs_pw->format.info.raw.size.width;
|
||||
case SPA_META_TRANSFORMATION_Flipped90:
|
||||
case SPA_META_TRANSFORMATION_90:
|
||||
case SPA_META_TRANSFORMATION_Flipped270:
|
||||
case SPA_META_TRANSFORMATION_270:
|
||||
return obs_pw->crop.valid ? obs_pw->crop.height
|
||||
: obs_pw->format.info.raw.size.height;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t obs_pipewire_get_height(obs_pipewire *obs_pw)
|
||||
@ -922,14 +974,30 @@ uint32_t obs_pipewire_get_height(obs_pipewire *obs_pw)
|
||||
if (!obs_pw->negotiated)
|
||||
return 0;
|
||||
|
||||
if (obs_pw->crop.valid)
|
||||
return obs_pw->crop.height;
|
||||
else
|
||||
return obs_pw->format.info.raw.size.height;
|
||||
switch (obs_pw->transform) {
|
||||
case SPA_META_TRANSFORMATION_Flipped:
|
||||
case SPA_META_TRANSFORMATION_None:
|
||||
case SPA_META_TRANSFORMATION_Flipped180:
|
||||
case SPA_META_TRANSFORMATION_180:
|
||||
return obs_pw->crop.valid ? obs_pw->crop.height
|
||||
: obs_pw->format.info.raw.size.height;
|
||||
case SPA_META_TRANSFORMATION_Flipped90:
|
||||
case SPA_META_TRANSFORMATION_90:
|
||||
case SPA_META_TRANSFORMATION_Flipped270:
|
||||
case SPA_META_TRANSFORMATION_270:
|
||||
return obs_pw->crop.valid ? obs_pw->crop.width
|
||||
: obs_pw->format.info.raw.size.width;
|
||||
}
|
||||
}
|
||||
|
||||
void obs_pipewire_video_render(obs_pipewire *obs_pw, gs_effect_t *effect)
|
||||
{
|
||||
double rot = 0;
|
||||
int flip = 0;
|
||||
double offset_x = 0;
|
||||
double offset_y = 0;
|
||||
bool has_crop;
|
||||
|
||||
gs_eparam_t *image;
|
||||
|
||||
if (!obs_pw->texture)
|
||||
@ -938,13 +1006,58 @@ void obs_pipewire_video_render(obs_pipewire *obs_pw, gs_effect_t *effect)
|
||||
image = gs_effect_get_param_by_name(effect, "image");
|
||||
gs_effect_set_texture(image, obs_pw->texture);
|
||||
|
||||
if (has_effective_crop(obs_pw)) {
|
||||
gs_draw_sprite_subregion(obs_pw->texture, 0, obs_pw->crop.x,
|
||||
has_crop = has_effective_crop(obs_pw);
|
||||
|
||||
switch (obs_pw->transform) {
|
||||
case SPA_META_TRANSFORMATION_Flipped:
|
||||
flip = GS_FLIP_U;
|
||||
/* fallthrough */
|
||||
case SPA_META_TRANSFORMATION_None:
|
||||
rot = 0;
|
||||
break;
|
||||
case SPA_META_TRANSFORMATION_Flipped90:
|
||||
flip = GS_FLIP_V;
|
||||
/* fallthrough */
|
||||
case SPA_META_TRANSFORMATION_90:
|
||||
rot = 90;
|
||||
offset_x = 0;
|
||||
offset_y = has_crop ? obs_pw->crop.height
|
||||
: obs_pw->format.info.raw.size.height;
|
||||
break;
|
||||
case SPA_META_TRANSFORMATION_Flipped180:
|
||||
flip = GS_FLIP_U;
|
||||
/* fallthrough */
|
||||
case SPA_META_TRANSFORMATION_180:
|
||||
rot = 180;
|
||||
offset_x = has_crop ? obs_pw->crop.width
|
||||
: obs_pw->format.info.raw.size.width;
|
||||
offset_y = has_crop ? obs_pw->crop.height
|
||||
: obs_pw->format.info.raw.size.height;
|
||||
break;
|
||||
case SPA_META_TRANSFORMATION_Flipped270:
|
||||
flip = GS_FLIP_V;
|
||||
/* fallthrough */
|
||||
case SPA_META_TRANSFORMATION_270:
|
||||
rot = 270;
|
||||
offset_x = has_crop ? obs_pw->crop.width
|
||||
: obs_pw->format.info.raw.size.width;
|
||||
offset_y = 0;
|
||||
break;
|
||||
}
|
||||
if (rot != 0) {
|
||||
gs_matrix_push();
|
||||
gs_matrix_rotaa4f(0.0f, 0.0f, 1.0f, RAD(rot));
|
||||
gs_matrix_translate3f(-offset_x, -offset_y, 0.0f);
|
||||
}
|
||||
if (has_crop) {
|
||||
gs_draw_sprite_subregion(obs_pw->texture, flip, obs_pw->crop.x,
|
||||
obs_pw->crop.y, obs_pw->crop.width,
|
||||
obs_pw->crop.height);
|
||||
} else {
|
||||
gs_draw_sprite(obs_pw->texture, 0, 0, 0);
|
||||
gs_draw_sprite(obs_pw->texture, flip, 0, 0);
|
||||
}
|
||||
if (rot != 0)
|
||||
gs_matrix_pop();
|
||||
|
||||
if (obs_pw->cursor.visible && obs_pw->cursor.valid &&
|
||||
obs_pw->cursor.texture) {
|
||||
|
Loading…
Reference in New Issue
Block a user