summaryrefslogtreecommitdiffstats
path: root/video
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2013-09-22 22:47:50 +0200
committerwm4 <wm4@nowhere>2013-09-25 13:53:42 +0200
commit641e94cd27eb3b0b152ac5003d371793904609c8 (patch)
treeb1abe1207dc7a43a3b79cdadc0b56e8e73237cfc /video
parent7c3f1ffc44b532590e661315b42fea5b6d1ae40c (diff)
downloadmpv-641e94cd27eb3b0b152ac5003d371793904609c8.tar.bz2
mpv-641e94cd27eb3b0b152ac5003d371793904609c8.tar.xz
vaapi: allow GPU read-back with --hwdec=vaapi-copy
This code is actually quite inefficient: it reuses the (slow, simple) screenshot code. It uses an inefficient method to read the image (vaGetImage() instead of vaDeriveImage()), allocates new memory for each frame that is read, and it tries all image formats again each time. Also, in my tests it always picked NV12 as image format, which is not ideal if you actually want to filter the video, and vo_xv can't handle this format without conversion either. However, a user confirmed that it worked for him, so everything is fine.
Diffstat (limited to 'video')
-rw-r--r--video/decode/lavc.h1
-rw-r--r--video/decode/vaapi.c108
-rw-r--r--video/decode/vd_lavc.c2
3 files changed, 108 insertions, 3 deletions
diff --git a/video/decode/lavc.h b/video/decode/lavc.h
index 681f151ad0..32b827b964 100644
--- a/video/decode/lavc.h
+++ b/video/decode/lavc.h
@@ -18,6 +18,7 @@ enum hwdec_type {
HWDEC_VDA = 2,
HWDEC_CRYSTALHD = 3,
HWDEC_VAAPI = 4,
+ HWDEC_VAAPI_COPY = 5,
};
typedef struct lavc_ctx {
diff --git a/video/decode/vaapi.c b/video/decode/vaapi.c
index 8bec94d950..82c46de81e 100644
--- a/video/decode/vaapi.c
+++ b/video/decode/vaapi.c
@@ -25,6 +25,8 @@
#include <libavcodec/vaapi.h>
#include <libavutil/common.h>
+#include <X11/Xlib.h>
+
#include "lavc.h"
#include "mpvcore/mp_common.h"
#include "mpvcore/av_common.h"
@@ -54,6 +56,7 @@
struct priv {
struct mp_vaapi_ctx *ctx;
VADisplay display;
+ Display *x11_display;
// libavcodec shared struct
struct vaapi_context *va_context;
@@ -64,6 +67,8 @@ struct priv {
struct va_surface_pool *pool;
int rt_format;
+
+ bool printed_readback_warning;
};
struct profile_entry {
@@ -342,6 +347,38 @@ static struct mp_image *allocate_image(struct lavc_ctx *ctx, int format,
return NULL;
}
+
+static void destroy_va_dummy_ctx(struct priv *p)
+{
+ if (p->x11_display)
+ XCloseDisplay(p->x11_display);
+ p->x11_display = NULL;
+ va_destroy(p->ctx);
+ p->ctx = NULL;
+}
+
+// Creates a "private" VADisplay, disconnected from the VO. We just create a
+// new X connection, because that's simpler. (We could also pass the X
+// connection along with struct mp_hwdec_info, if we wanted.)
+static bool create_va_dummy_ctx(struct priv *p)
+{
+ p->x11_display = XOpenDisplay(NULL);
+ if (!p->x11_display)
+ goto destroy_ctx;
+ VADisplay *display = vaGetDisplay(p->x11_display);
+ if (!display)
+ goto destroy_ctx;
+ p->ctx = va_initialize(display);
+ if (!p->ctx) {
+ vaTerminate(display);
+ goto destroy_ctx;
+ }
+ return true;
+destroy_ctx:
+ destroy_va_dummy_ctx(p);
+ return false;
+}
+
static void uninit(struct lavc_ctx *ctx)
{
struct priv *p = ctx->hwdec_priv;
@@ -350,21 +387,31 @@ static void uninit(struct lavc_ctx *ctx)
return;
destroy_decoder(ctx);
-
va_surface_pool_release(p->pool);
+
+ if (p->x11_display)
+ destroy_va_dummy_ctx(p);
+
talloc_free(p);
ctx->hwdec_priv = NULL;
}
-static int init(struct lavc_ctx *ctx)
+static int init_with_vactx(struct lavc_ctx *ctx, struct mp_vaapi_ctx *vactx)
{
struct priv *p = talloc_ptrtype(NULL, p);
*p = (struct priv) {
- .ctx = ctx->hwdec_info->vaapi_ctx,
+ .ctx = vactx,
.va_context = &p->va_context_storage,
.rt_format = VA_RT_FORMAT_YUV420
};
+ if (!p->ctx)
+ create_va_dummy_ctx(p);
+ if (!p->ctx) {
+ talloc_free(p);
+ return -1;
+ }
+
p->display = p->ctx->display;
p->pool = va_surface_pool_alloc(p->display, p->rt_format);
@@ -378,6 +425,12 @@ static int init(struct lavc_ctx *ctx)
return 0;
}
+static int init(struct lavc_ctx *ctx)
+{
+ if (!ctx->hwdec_info->vaapi_ctx)
+ return -1;
+ return init_with_vactx(ctx, ctx->hwdec_info->vaapi_ctx);
+}
static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
const char *decoder)
@@ -389,6 +442,44 @@ static int probe(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
return 0;
}
+static int probe_copy(struct vd_lavc_hwdec *hwdec, struct mp_hwdec_info *info,
+ const char *decoder)
+{
+ struct priv dummy = {0};
+ if (!create_va_dummy_ctx(&dummy))
+ return HWDEC_ERR_NO_CTX;
+ destroy_va_dummy_ctx(&dummy);
+ if (!find_codec(mp_codec_to_av_codec_id(decoder)))
+ return HWDEC_ERR_NO_CODEC;
+ return 0;
+}
+
+static int init_copy(struct lavc_ctx *ctx)
+{
+ return init_with_vactx(ctx, NULL);
+}
+
+static struct mp_image *copy_image(struct lavc_ctx *ctx, struct mp_image *img)
+{
+ struct priv *p = ctx->hwdec_priv;
+
+ struct va_surface *surface = va_surface_in_mp_image(img);
+ if (surface) {
+ struct mp_image *simg =
+ va_surface_download(surface, p->ctx->image_formats);
+ if (simg) {
+ if (!p->printed_readback_warning) {
+ mp_msg(MSGT_VO, MSGL_WARN, "[vaapi] Using GPU readback. This "
+ "is usually inefficient.\n");
+ p->printed_readback_warning = true;
+ }
+ talloc_free(img);
+ return simg;
+ }
+ }
+ return img;
+}
+
const struct vd_lavc_hwdec mp_vd_lavc_vaapi = {
.type = HWDEC_VAAPI,
.image_formats = (const int[]) {IMGFMT_VAAPI, IMGFMT_VAAPI_MPEG2_IDCT,
@@ -398,3 +489,14 @@ const struct vd_lavc_hwdec mp_vd_lavc_vaapi = {
.uninit = uninit,
.allocate_image = allocate_image,
};
+
+const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy = {
+ .type = HWDEC_VAAPI_COPY,
+ .image_formats = (const int[]) {IMGFMT_VAAPI, IMGFMT_VAAPI_MPEG2_IDCT,
+ IMGFMT_VAAPI_MPEG2_MOCO, 0},
+ .probe = probe_copy,
+ .init = init_copy,
+ .uninit = uninit,
+ .allocate_image = allocate_image,
+ .process_image = copy_image,
+};
diff --git a/video/decode/vd_lavc.c b/video/decode/vd_lavc.c
index c658d92a35..7fbf9d8401 100644
--- a/video/decode/vd_lavc.c
+++ b/video/decode/vd_lavc.c
@@ -86,6 +86,7 @@ const struct vd_lavc_hwdec mp_vd_lavc_vdpau;
const struct vd_lavc_hwdec mp_vd_lavc_vdpau_old;
const struct vd_lavc_hwdec mp_vd_lavc_vda;
const struct vd_lavc_hwdec mp_vd_lavc_vaapi;
+const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy;
static const struct vd_lavc_hwdec mp_vd_lavc_crystalhd = {
.type = HWDEC_CRYSTALHD,
@@ -114,6 +115,7 @@ static const struct vd_lavc_hwdec *hwdec_list[] = {
&mp_vd_lavc_crystalhd,
#if CONFIG_VAAPI
&mp_vd_lavc_vaapi,
+ &mp_vd_lavc_vaapi_copy,
#endif
NULL
};