[PATCH weston 1/2] vaapi-recorder: Encode frames in a separate thread
Kristian Høgsberg
hoegsberg at gmail.com
Wed Sep 11 11:55:52 PDT 2013
On Fri, Sep 06, 2013 at 05:49:37PM +0300, Ander Conselvan de Oliveira wrote:
> Previously, vaapi_recorder_frame() would wait until the encoded
> contents for a frame is written to the output file descriptor. This
> delayed the repainting of the next frame, and affected frame rate
> when capturing with high resolutions. Instead, wait only if there is
> and attempted to encode two frames at the same time.
>
> Increases framerate from 30 to 60 fps when capturing at 1920x1200 on
> my SandryBridge system, although there are periodic slowdowns due to
> disk writes.
Thanks Ander, both committed.
Kristian
> ---
> src/compositor-drm.c | 2 -
> src/vaapi-recorder.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++---
> 2 files changed, 96 insertions(+), 7 deletions(-)
>
> diff --git a/src/compositor-drm.c b/src/compositor-drm.c
> index eb3ec61..7f6ffbc 100644
> --- a/src/compositor-drm.c
> +++ b/src/compositor-drm.c
> @@ -2471,8 +2471,6 @@ recorder_frame_notify(struct wl_listener *listener, void *data)
> }
>
> vaapi_recorder_frame(output->recorder, fd, output->current->stride / 4);
> -
> - close(fd);
> }
>
> static void *
> diff --git a/src/vaapi-recorder.c b/src/vaapi-recorder.c
> index c0210f0..e9127da 100644
> --- a/src/vaapi-recorder.c
> +++ b/src/vaapi-recorder.c
> @@ -47,11 +47,13 @@
> #include <stdint.h>
> #include <string.h>
> #include <unistd.h>
> +#include <assert.h>
>
> #include <sys/types.h>
> #include <sys/stat.h>
> #include <fcntl.h>
>
> +#include <pthread.h>
>
> #include <va/va.h>
> #include <va/va_drm.h>
> @@ -89,6 +91,16 @@ struct vaapi_recorder {
> int width, height;
> int frame_count;
>
> + int destroying;
> + pthread_t worker_thread;
> + pthread_mutex_t mutex;
> + pthread_cond_t input_cond;
> +
> + struct {
> + int valid;
> + int prime_fd, stride;
> + } input;
> +
> VADisplay va_dpy;
>
> /* video post processing is used for colorspace conversion */
> @@ -116,6 +128,9 @@ struct vaapi_recorder {
> } encoder;
> };
>
> +static void *
> +worker_thread_function(void *);
> +
> /* bistream code used for writing the packed headers */
>
> #define BITSTREAM_ALLOCATE_STEPPING 4096
> @@ -886,6 +901,33 @@ vpp_destroy(struct vaapi_recorder *r)
> vaDestroyConfig(r->va_dpy, r->vpp.cfg);
> }
>
> +static int
> +setup_worker_thread(struct vaapi_recorder *r)
> +{
> + pthread_mutex_init(&r->mutex, NULL);
> + pthread_cond_init(&r->input_cond, NULL);
> + pthread_create(&r->worker_thread, NULL, worker_thread_function, r);
> +
> + return 1;
> +}
> +
> +static void
> +destroy_worker_thread(struct vaapi_recorder *r)
> +{
> + pthread_mutex_lock(&r->mutex);
> +
> + /* Make sure the worker thread finishes */
> + r->destroying = 1;
> + pthread_cond_signal(&r->input_cond);
> +
> + pthread_mutex_unlock(&r->mutex);
> +
> + pthread_join(r->worker_thread, NULL);
> +
> + pthread_mutex_destroy(&r->mutex);
> + pthread_cond_destroy(&r->input_cond);
> +}
> +
> struct vaapi_recorder *
> vaapi_recorder_create(int drm_fd, int width, int height, const char *filename)
> {
> @@ -904,9 +946,12 @@ vaapi_recorder_create(int drm_fd, int width, int height, const char *filename)
> flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
> r->output_fd = open(filename, flags, 0644);
>
> - if (r->output_fd < 0)
> + if (setup_worker_thread(r) < 0)
> goto err_free;
>
> + if (r->output_fd < 0)
> + goto err_thread;
> +
> r->va_dpy = vaGetDisplayDRM(drm_fd);
> if (!r->va_dpy) {
> weston_log("failed to create VA display\n");
> @@ -936,6 +981,8 @@ err_va_dpy:
> vaTerminate(r->va_dpy);
> err_fd:
> close(r->output_fd);
> +err_thread:
> + destroy_worker_thread(r);
> err_free:
> free(r);
>
> @@ -945,6 +992,8 @@ err_free:
> void
> vaapi_recorder_destroy(struct vaapi_recorder *r)
> {
> + destroy_worker_thread(r);
> +
> encoder_destroy(r);
> vpp_destroy(r);
>
> @@ -1033,20 +1082,22 @@ convert_rgb_to_yuv(struct vaapi_recorder *r, VASurfaceID rgb_surface)
> return status;
> }
>
> -void
> -vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd,
> - int stride)
> +static void
> +recorder_frame(struct vaapi_recorder *r)
> {
> VASurfaceID rgb_surface;
> VAStatus status;
>
> - status = create_surface_from_fd(r, prime_fd, stride, &rgb_surface);
> + status = create_surface_from_fd(r, r->input.prime_fd,
> + r->input.stride, &rgb_surface);
> if (status != VA_STATUS_SUCCESS) {
> weston_log("[libva recorder] "
> "failed to create surface from bo\n");
> return;
> }
>
> + close(r->input.prime_fd);
> +
> status = convert_rgb_to_yuv(r, rgb_surface);
> if (status != VA_STATUS_SUCCESS) {
> weston_log("[libva recorder] "
> @@ -1059,4 +1110,44 @@ vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd,
> vaDestroySurfaces(r->va_dpy, &rgb_surface, 1);
> }
>
> +static void *
> +worker_thread_function(void *data)
> +{
> + struct vaapi_recorder *r = data;
> +
> + pthread_mutex_lock(&r->mutex);
> +
> + while (!r->destroying) {
> + if (!r->input.valid)
> + pthread_cond_wait(&r->input_cond, &r->mutex);
> +
> + /* If the thread is awaken by destroy_worker_thread(),
> + * there might not be valid input */
> + if (!r->input.valid)
> + continue;
> +
> + recorder_frame(r);
> + r->input.valid = 0;
> + }
> +
> + pthread_mutex_unlock(&r->mutex);
> +
> + return NULL;
> +}
> +
> +void
> +vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd, int stride)
> +{
> + pthread_mutex_lock(&r->mutex);
> +
> + /* The mutex is never released while encoding, so this point should
> + * never be reached if input.valid is true. */
> + assert(!r->input.valid);
>
> + r->input.prime_fd = prime_fd;
> + r->input.stride = stride;
> + r->input.valid = 1;
> + pthread_cond_signal(&r->input_cond);
> +
> + pthread_mutex_unlock(&r->mutex);
> +}
> --
> 1.8.1.2
>
> _______________________________________________
> wayland-devel mailing list
> wayland-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/wayland-devel
More information about the wayland-devel
mailing list