0
0
mirror of https://github.com/obsproject/obs-studio.git synced 2024-09-20 04:42:18 +02:00

linux-pipewire: Reject invalid buffers

PipeWire supports two flags to signal an invalid buffer:
SPA_META_HEADER_FLAG_CORRUPTED signals that the whole buffer is invalid
and should not be used
SPA_CHUNK_FLAG_CORRUPTED signals that one single buffer plane is invalid

Skipping a buffer because of size 0 was moved to only the SHM case.
For DMA-BUFs the size of a single plane is not relevant and should be
ignored [1].

Compatibility note:
GNOME pre 43 sets the chunk size to 0 when a buffer copy failed.
Luckily GNOME doesn't use the META_Header and thus we can detect if we
should use the new or old style of invalid buffer detection.
This workaround should be dropped when reasonable.

[1] https://docs.pipewire.org/page_dma_buf.html
This commit is contained in:
columbarius 2021-09-18 23:42:38 +02:00 committed by Georges Basile Stavracas Neto
parent 8e96d47cd3
commit e0a4d8628d

View File

@ -454,11 +454,12 @@ static void on_process_cb(void *user_data)
obs_pipewire_data *obs_pw = user_data;
struct spa_meta_cursor *cursor;
uint32_t drm_format;
struct spa_meta_header *header;
struct spa_meta_region *region;
struct spa_buffer *buffer;
struct pw_buffer *b;
bool swap_red_blue = false;
bool has_buffer;
bool has_buffer = true;
/* Find the most recent buffer */
b = NULL;
@ -478,10 +479,19 @@ static void on_process_cb(void *user_data)
}
buffer = b->buffer;
has_buffer = buffer->datas[0].chunk->size != 0;
header = spa_buffer_find_meta_data(buffer, SPA_META_Header,
sizeof(*header));
if (header && (header->flags & SPA_META_HEADER_FLAG_CORRUPTED) > 0) {
blog(LOG_ERROR, "[pipewire] buffer is corrupt");
pw_stream_queue_buffer(obs_pw->stream, b);
return;
} else if (!header) {
has_buffer = buffer->datas[0].chunk->size != 0;
}
obs_enter_graphics();
// Workaround for mutter behaviour pre GNOME 43
if (!has_buffer)
goto read_metadata;
@ -492,6 +502,7 @@ static void on_process_cb(void *user_data)
uint64_t modifiers[planes];
int fds[planes];
bool use_modifiers;
bool corrupt = false;
blog(LOG_DEBUG,
"[pipewire] DMA-BUF info: fd:%ld, stride:%d, offset:%u, size:%dx%d",
@ -514,6 +525,14 @@ static void on_process_cb(void *user_data)
offsets[plane] = buffer->datas[plane].chunk->offset;
strides[plane] = buffer->datas[plane].chunk->stride;
modifiers[plane] = obs_pw->format.info.raw.modifier;
corrupt |= (buffer->datas[plane].chunk->flags &
SPA_CHUNK_FLAG_CORRUPTED) > 0;
}
if (corrupt) {
blog(LOG_ERROR,
"[pipewire] buffer contains corrupted data");
goto read_metadata;
}
g_clear_pointer(&obs_pw->texture, gs_texture_destroy);
@ -547,6 +566,19 @@ static void on_process_cb(void *user_data)
goto read_metadata;
}
if ((buffer->datas[0].chunk->flags & SPA_CHUNK_FLAG_CORRUPTED) >
0) {
blog(LOG_ERROR,
"[pipewire] buffer contains corrupted data");
goto read_metadata;
}
if (buffer->datas[0].chunk->size == 0) {
blog(LOG_ERROR,
"[pipewire] buffer contains empty data");
goto read_metadata;
}
g_clear_pointer(&obs_pw->texture, gs_texture_destroy);
obs_pw->texture = gs_texture_create(
obs_pw->format.info.raw.size.width,
@ -626,7 +658,7 @@ static void on_param_changed_cb(void *user_data, uint32_t id,
{
obs_pipewire_data *obs_pw = user_data;
struct spa_pod_builder pod_builder;
const struct spa_pod *params[3];
const struct spa_pod *params[4];
uint32_t buffer_types;
uint8_t params_buffer[1024];
int result;
@ -695,7 +727,14 @@ static void on_param_changed_cb(void *user_data, uint32_t id,
&pod_builder, SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
SPA_PARAM_BUFFERS_dataType, SPA_POD_Int(buffer_types));
pw_stream_update_params(obs_pw->stream, params, 3);
/* Meta header */
params[3] = 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);
obs_pw->negotiated = true;
}