diff options
Diffstat (limited to 'src/pipewire_video.c')
-rw-r--r-- | src/pipewire_video.c | 121 |
1 files changed, 90 insertions, 31 deletions
diff --git a/src/pipewire_video.c b/src/pipewire_video.c index 023a2db..277004c 100644 --- a/src/pipewire_video.c +++ b/src/pipewire_video.c @@ -6,7 +6,7 @@ #include <spa/param/video/format-utils.h> #include <spa/debug/types.h> -#include <libdrm/drm_fourcc.h> +#include <drm_fourcc.h> #include <fcntl.h> #include <unistd.h> @@ -280,13 +280,21 @@ static void on_param_changed_cb(void *user_data, uint32_t id, const struct spa_p self->negotiated = true; } -static void on_state_changed_cb(void *user_data, enum pw_stream_state old, enum pw_stream_state state, const char *error) { - (void)old; +static void on_state_changed_cb(void *user_data, enum pw_stream_state prev_state, enum pw_stream_state new_state, const char *error) { gsr_pipewire_video *self = user_data; - fprintf(stderr, "gsr info: pipewire: stream %p state: \"%s\" (error: %s)\n", - (void*)self->stream, pw_stream_state_as_string(state), + fprintf(stderr, "gsr info: pipewire: stream %p previous state: \"%s\", new state: \"%s\" (error: %s)\n", + (void*)self->stream, pw_stream_state_as_string(prev_state), pw_stream_state_as_string(new_state), error ? error : "none"); + + pthread_mutex_lock(&self->mutex); + if(new_state == PW_STREAM_STATE_PAUSED) { + self->paused_start_secs = clock_get_monotonic_seconds(); + self->paused = true; + } else { + self->paused = false; + } + pthread_mutex_unlock(&self->mutex); } static const struct pw_stream_events stream_events = { @@ -346,19 +354,19 @@ static int64_t spa_video_format_to_drm_format(const enum spa_video_format format switch(format) { case SPA_VIDEO_FORMAT_RGBx: return DRM_FORMAT_XBGR8888; case SPA_VIDEO_FORMAT_BGRx: return DRM_FORMAT_XRGB8888; - case SPA_VIDEO_FORMAT_RGBA: return DRM_FORMAT_ABGR8888; - case SPA_VIDEO_FORMAT_BGRA: return DRM_FORMAT_ARGB8888; + // case SPA_VIDEO_FORMAT_RGBA: return DRM_FORMAT_ABGR8888; + //case SPA_VIDEO_FORMAT_BGRA: return DRM_FORMAT_ARGB8888; case SPA_VIDEO_FORMAT_RGB: return DRM_FORMAT_XBGR8888; case SPA_VIDEO_FORMAT_BGR: return DRM_FORMAT_XRGB8888; - case SPA_VIDEO_FORMAT_ARGB: return DRM_FORMAT_XRGB8888; - case SPA_VIDEO_FORMAT_ABGR: return DRM_FORMAT_XRGB8888; + //case SPA_VIDEO_FORMAT_ARGB: return DRM_FORMAT_XRGB8888; + //case SPA_VIDEO_FORMAT_ABGR: return DRM_FORMAT_XRGB8888; #if PW_CHECK_VERSION(0, 3, 41) case SPA_VIDEO_FORMAT_xRGB_210LE: return DRM_FORMAT_XRGB2101010; case SPA_VIDEO_FORMAT_xBGR_210LE: return DRM_FORMAT_XBGR2101010; - case SPA_VIDEO_FORMAT_ARGB_210LE: return DRM_FORMAT_ARGB2101010; - case SPA_VIDEO_FORMAT_ABGR_210LE: return DRM_FORMAT_ABGR2101010; + // case SPA_VIDEO_FORMAT_ARGB_210LE: return DRM_FORMAT_ARGB2101010; + // case SPA_VIDEO_FORMAT_ABGR_210LE: return DRM_FORMAT_ABGR2101010; #endif - default: break; + default: break; } return DRM_FORMAT_INVALID; } @@ -366,23 +374,23 @@ static int64_t spa_video_format_to_drm_format(const enum spa_video_format format #if PW_CHECK_VERSION(0, 3, 41) #define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS #else -#define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS 8 +#define GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS 4 #endif static const enum spa_video_format video_formats[GSR_PIPEWIRE_VIDEO_MAX_VIDEO_FORMATS] = { - SPA_VIDEO_FORMAT_BGRA, + // SPA_VIDEO_FORMAT_BGRA, SPA_VIDEO_FORMAT_BGRx, SPA_VIDEO_FORMAT_BGR, SPA_VIDEO_FORMAT_RGBx, - SPA_VIDEO_FORMAT_RGBA, + // SPA_VIDEO_FORMAT_RGBA, SPA_VIDEO_FORMAT_RGB, - SPA_VIDEO_FORMAT_ARGB, - SPA_VIDEO_FORMAT_ABGR, + // SPA_VIDEO_FORMAT_ARGB, + // SPA_VIDEO_FORMAT_ABGR, #if PW_CHECK_VERSION(0, 3, 41) SPA_VIDEO_FORMAT_xRGB_210LE, SPA_VIDEO_FORMAT_xBGR_210LE, - SPA_VIDEO_FORMAT_ARGB_210LE, - SPA_VIDEO_FORMAT_ABGR_210LE + // SPA_VIDEO_FORMAT_ARGB_210LE, + // SPA_VIDEO_FORMAT_ABGR_210LE #endif }; @@ -413,6 +421,7 @@ static void renegotiate_format(void *data, uint64_t expirations) { uint8_t params_buffer[4096]; struct spa_pod_builder pod_builder = SPA_POD_BUILDER_INIT(params_buffer, sizeof(params_buffer)); if (!gsr_pipewire_video_build_format_params(self, &pod_builder, params, &num_video_formats)) { + fprintf(stderr, "gsr error: renegotiate_format: failed to build formats\n"); pw_thread_loop_unlock(self->thread_loop); return; } @@ -470,6 +479,27 @@ static void gsr_pipewire_video_init_modifiers(gsr_pipewire_video *self) { spa_video_format_get_modifiers(self, self->supported_video_formats[i].format, self->modifiers + self->num_modifiers, GSR_PIPEWIRE_VIDEO_MAX_MODIFIERS - self->num_modifiers, &num_modifiers); self->supported_video_formats[i].modifiers_index = self->num_modifiers; self->supported_video_formats[i].modifiers_size = num_modifiers; + self->num_modifiers += num_modifiers; + } +} + +static void gsr_pipewire_video_format_remove_modifier(gsr_pipewire_video *self, gsr_video_format *video_format, uint64_t modifier) { + for(size_t i = 0; i < video_format->modifiers_size; ++i) { + if(self->modifiers[video_format->modifiers_index + i] != modifier) + continue; + + for(size_t j = i + 1; j < video_format->modifiers_size; ++j) { + self->modifiers[j - 1] = self->modifiers[j]; + } + --video_format->modifiers_size; + return; + } +} + +static void gsr_pipewire_video_remove_modifier(gsr_pipewire_video *self, uint64_t modifier) { + for(size_t i = 0; i < GSR_PIPEWIRE_VIDEO_NUM_VIDEO_FORMATS; i++) { + gsr_video_format *video_format = &self->supported_video_formats[i]; + gsr_pipewire_video_format_remove_modifier(self, video_format, modifier); } } @@ -509,6 +539,9 @@ static bool gsr_pipewire_video_setup_stream(gsr_pipewire_video *self) { // TODO: Error check pw_core_add_listener(self->core, &self->core_listener, &core_events, self); + self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, 0); + pw_thread_loop_wait(self->thread_loop); + gsr_pipewire_video_init_modifiers(self); // TODO: Cleanup? @@ -519,9 +552,6 @@ static bool gsr_pipewire_video_setup_stream(gsr_pipewire_video *self) { goto error; } - self->server_version_sync = pw_core_sync(self->core, PW_ID_CORE, 0); - pw_thread_loop_wait(self->thread_loop); - self->stream = pw_stream_new(self->core, "com.dec05eba.gpu_screen_recorder", pw_properties_new(PW_KEY_MEDIA_TYPE, "Video", PW_KEY_MEDIA_CATEGORY, "Capture", @@ -650,6 +680,7 @@ void gsr_pipewire_video_deinit(gsr_pipewire_video *self) { self->dmabuf_num_planes = 0; self->negotiated = false; + self->renegotiated = false; if(self->mutex_initialized) { pthread_mutex_destroy(&self->mutex); @@ -701,9 +732,19 @@ static EGLImage gsr_pipewire_video_create_egl_image_with_fallback(gsr_pipewire_v } else { image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, true); if(!image) { - fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifiers, trying without modifiers\n"); - self->no_modifiers_fallback = true; - image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, false); + if(self->renegotiated) { + fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifiers, trying without modifiers\n"); + self->no_modifiers_fallback = true; + image = gsr_pipewire_video_create_egl_image(self, fds, offsets, pitches, modifiers, false); + } else { + fprintf(stderr, "gsr error: gsr_pipewire_video_create_egl_image_with_fallback: failed to create egl image with modifiers, renegotiating with a different modifier\n"); + self->negotiated = false; + self->renegotiated = true; + gsr_pipewire_video_remove_modifier(self, self->format.info.raw.modifier); + pw_thread_loop_lock(self->thread_loop); + pw_loop_signal_event(pw_thread_loop_get_loop(self->thread_loop), self->reneg); + pw_thread_loop_unlock(self->thread_loop); + } } } return image; @@ -738,8 +779,6 @@ static void gsr_pipewire_video_update_cursor_texture(gsr_pipewire_video *self, g self->egl->glBindTexture(GL_TEXTURE_2D, texture_map.cursor_texture_id); // TODO: glTextureSubImage2D if same size self->egl->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, self->cursor.width, self->cursor.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, self->cursor.data); - self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); self->egl->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); self->egl->glBindTexture(GL_TEXTURE_2D, 0); @@ -764,12 +803,15 @@ bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map te } EGLImage image = gsr_pipewire_video_create_egl_image_with_fallback(self); - if(image) { - gsr_pipewire_video_bind_image_to_texture_with_fallback(self, texture_map, image); - *using_external_image = self->external_texture_fallback; - self->egl->eglDestroyImage(self->egl->egl_display, image); + if(!image) { + pthread_mutex_unlock(&self->mutex); + return false; } + gsr_pipewire_video_bind_image_to_texture_with_fallback(self, texture_map, image); + *using_external_image = self->external_texture_fallback; + self->egl->eglDestroyImage(self->egl->egl_display, image); + gsr_pipewire_video_update_cursor_texture(self, texture_map); region->x = 0; @@ -807,6 +849,9 @@ bool gsr_pipewire_video_map_texture(gsr_pipewire_video *self, gsr_texture_map te } bool gsr_pipewire_video_is_damaged(gsr_pipewire_video *self) { + if(!self->mutex_initialized) + return false; + bool damaged = false; pthread_mutex_lock(&self->mutex); damaged = self->damaged; @@ -815,7 +860,21 @@ bool gsr_pipewire_video_is_damaged(gsr_pipewire_video *self) { } void gsr_pipewire_video_clear_damage(gsr_pipewire_video *self) { + if(!self->mutex_initialized) + return; + pthread_mutex_lock(&self->mutex); self->damaged = false; pthread_mutex_unlock(&self->mutex); } + +bool gsr_pipewire_video_should_restart(gsr_pipewire_video *self) { + if(!self->mutex_initialized) + return false; + + bool should_restart = false; + pthread_mutex_lock(&self->mutex); + should_restart = self->paused && clock_get_monotonic_seconds() - self->paused_start_secs >= 3.0; + pthread_mutex_unlock(&self->mutex); + return should_restart; +} |