summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2017-09-29 17:54:21 +0200
committerwm4 <wm4@nowhere>2017-09-29 18:17:51 +0200
commitd462a2a32139ea48b63d884d5e991584babbe76a (patch)
tree6120aeaea62e9262b4cc6d2ce9356a9e346a64a4
parent1f79b2652924cec703627edc92abff4d349aec26 (diff)
downloadmpv-d462a2a32139ea48b63d884d5e991584babbe76a.tar.bz2
mpv-d462a2a32139ea48b63d884d5e991584babbe76a.tar.xz
vf_vavpp: use libavutil hw frames API for frame pool and upload
Another step to get rid of the legacy crap in vaapi.c. (Most is still kept, because it's in use by vo_vaapi.c.)
-rw-r--r--video/filter/vf_vavpp.c108
-rw-r--r--video/mp_image_pool.c34
-rw-r--r--video/mp_image_pool.h2
-rw-r--r--video/vaapi.c21
-rw-r--r--video/vaapi.h3
5 files changed, 119 insertions, 49 deletions
diff --git a/video/filter/vf_vavpp.c b/video/filter/vf_vavpp.c
index 4b225aa466..32d650dc77 100644
--- a/video/filter/vf_vavpp.c
+++ b/video/filter/vf_vavpp.c
@@ -20,10 +20,13 @@
#include <va/va.h>
#include <va/va_vpp.h>
+#include <libavutil/hwcontext.h>
+
#include "config.h"
#include "options/options.h"
#include "vf.h"
#include "refqueue.h"
+#include "video/fmt-conversion.h"
#include "video/vaapi.h"
#include "video/hwdec.h"
#include "video/mp_image_pool.h"
@@ -64,8 +67,9 @@ struct vf_priv_s {
VADisplay display;
struct mp_vaapi_ctx *va;
struct pipeline pipe;
- struct mp_image_pool *pool;
- int current_rt_format;
+ AVBufferRef *hw_pool;
+ int *in_formats;
+ int num_in_formats;
struct mp_refqueue *queue;
};
@@ -156,6 +160,28 @@ nodeint:
mp_refqueue_set_mode(p->queue, 0);
}
+static struct mp_image *alloc_out(struct vf_instance *vf)
+{
+ struct vf_priv_s *p = vf->priv;
+
+ AVFrame *av_frame = av_frame_alloc();
+ if (!av_frame)
+ abort();
+ if (av_hwframe_get_buffer(p->hw_pool, av_frame, 0) < 0) {
+ MP_ERR(vf, "Failed to allocate frame from hw pool.\n");
+ av_frame_free(&av_frame);
+ return NULL;
+ }
+ struct mp_image *img = mp_image_from_av_frame(av_frame);
+ av_frame_free(&av_frame);
+ if (!img) {
+ MP_ERR(vf, "Unknown error.\n");
+ return NULL;
+ }
+ mp_image_set_size(img, vf->fmt_in.w, vf->fmt_in.h);
+ return img;
+}
+
static struct mp_image *render(struct vf_instance *vf)
{
struct vf_priv_s *p = vf->priv;
@@ -167,15 +193,13 @@ static struct mp_image *render(struct vf_instance *vf)
VABufferID buffer = VA_INVALID_ID;
VASurfaceID in_id = va_surface_id(in);
- if (!p->pipe.filters || in_id == VA_INVALID_ID)
+ if (!p->pipe.filters || in_id == VA_INVALID_ID || !p->hw_pool)
goto cleanup;
- int r_w, r_h;
- va_surface_get_uncropped_size(in, &r_w, &r_h);
- img = mp_image_pool_get(p->pool, IMGFMT_VAAPI, r_w, r_h);
+ img = alloc_out(vf);
if (!img)
goto cleanup;
- mp_image_set_size(img, in->w, in->h);
+
mp_image_copy_attributes(img, in);
unsigned int flags = va_get_colorspace_flag(p->params.color.space);
@@ -264,11 +288,10 @@ cleanup:
static struct mp_image *upload(struct vf_instance *vf, struct mp_image *in)
{
- struct vf_priv_s *p = vf->priv;
- struct mp_image *out = mp_image_pool_get(p->pool, IMGFMT_VAAPI, in->w, in->h);
+ struct mp_image *out = alloc_out(vf);
if (!out)
return NULL;
- if (va_surface_upload(out, in) < 0) {
+ if (!mp_image_hw_upload(out, in)) {
talloc_free(out);
return NULL;
}
@@ -323,23 +346,39 @@ static int reconfig(struct vf_instance *vf, struct mp_image_params *in,
struct vf_priv_s *p = vf->priv;
flush_frames(vf);
- talloc_free(p->pool);
- p->pool = NULL;
+ av_buffer_unref(&p->hw_pool);
p->params = *in;
+ *out = *in;
- p->current_rt_format = VA_RT_FORMAT_YUV420;
- p->pool = mp_image_pool_new(20);
- va_pool_set_allocator(p->pool, p->va, p->current_rt_format);
+ int src_w = in->w;
+ int src_h = in->h;
- struct mp_image *probe = mp_image_pool_get(p->pool, IMGFMT_VAAPI, in->w, in->h);
- if (!probe)
+ if (in->imgfmt == IMGFMT_VAAPI) {
+ if (!vf->in_hwframes_ref)
+ return -1;
+ AVHWFramesContext *hw_frames = (void *)vf->in_hwframes_ref->data;
+ // VAAPI requires the full surface size to match for input and output.
+ src_w = hw_frames->width;
+ src_h = hw_frames->height;
+ } else {
+ out->imgfmt = IMGFMT_VAAPI;
+ out->hw_subfmt = IMGFMT_NV12;
+ }
+
+ p->hw_pool = av_hwframe_ctx_alloc(p->va->av_device_ref);
+ if (!p->hw_pool)
return -1;
- va_surface_init_subformat(probe);
- *out = *in;
- out->imgfmt = probe->params.imgfmt;
- out->hw_subfmt = probe->params.hw_subfmt;
- talloc_free(probe);
+ AVHWFramesContext *hw_frames = (void *)p->hw_pool->data;
+ hw_frames->format = AV_PIX_FMT_VAAPI;
+ hw_frames->sw_format = imgfmt2pixfmt(out->hw_subfmt);
+ hw_frames->width = src_w;
+ hw_frames->height = src_h;
+ if (av_hwframe_ctx_init(p->hw_pool) < 0) {
+ MP_ERR(vf, "Failed to initialize libavutil vaapi frames pool.\n");
+ av_buffer_unref(&p->hw_pool);
+ return -1;
+ }
return 0;
}
@@ -353,7 +392,7 @@ static void uninit(struct vf_instance *vf)
vaDestroyContext(p->display, p->context);
if (p->config != VA_INVALID_ID)
vaDestroyConfig(p->display, p->config);
- talloc_free(p->pool);
+ av_buffer_unref(&p->hw_pool);
flush_frames(vf);
mp_refqueue_free(p->queue);
}
@@ -361,7 +400,12 @@ static void uninit(struct vf_instance *vf)
static int query_format(struct vf_instance *vf, unsigned int imgfmt)
{
struct vf_priv_s *p = vf->priv;
- if (imgfmt == IMGFMT_VAAPI || va_image_format_from_imgfmt(p->va, imgfmt))
+
+ bool supported = false;
+ for (int n = 0; n < p->num_in_formats; n++)
+ supported |= imgfmt == p->in_formats[n];
+
+ if (imgfmt == IMGFMT_VAAPI || supported)
return vf_next_query_format(vf, IMGFMT_VAAPI);
return 0;
}
@@ -469,9 +513,23 @@ static int vf_open(vf_instance_t *vf)
p->queue = mp_refqueue_alloc();
p->va = hwdec_devices_load(vf->hwdec_devs, HWDEC_VAAPI);
- if (!p->va)
+ if (!p->va || !p->va->av_device_ref) {
+ uninit(vf);
return 0;
+ }
p->display = p->va->display;
+
+ AVBufferRef *device_ref = (void *)p->va->av_device_ref;
+ AVHWFramesConstraints *constraints =
+ av_hwdevice_get_hwframe_constraints(device_ref, NULL);
+ const enum AVPixelFormat *fmts = constraints->valid_sw_formats;
+ for (int n = 0; fmts && fmts[n] != AV_PIX_FMT_NONE; n++) {
+ int mpfmt = pixfmt2imgfmt(fmts[n]);
+ if (mpfmt)
+ MP_TARRAY_APPEND(p, p->in_formats, p->num_in_formats, mpfmt);
+ }
+ av_hwframe_constraints_free(&constraints);
+
if (initialize(vf))
return true;
uninit(vf);
diff --git a/video/mp_image_pool.c b/video/mp_image_pool.c
index 9a848af925..e993b4e096 100644
--- a/video/mp_image_pool.c
+++ b/video/mp_image_pool.c
@@ -309,3 +309,37 @@ struct mp_image *mp_image_hw_download(struct mp_image *src,
}
return dst;
}
+
+bool mp_image_hw_upload(struct mp_image *hw_img, struct mp_image *src)
+{
+ if (hw_img->w != src->w || hw_img->h != src->h)
+ return false;
+
+ if (!hw_img->hwctx || src->hwctx)
+ return false;
+
+ bool ok = false;
+ AVFrame *dstav = NULL;
+ AVFrame *srcav = NULL;
+
+ // This means the destination image will not be "writable", which would be
+ // a pain if Libav enforced this - fortunately it doesn't care. We can
+ // transfer data to it even if there are multiple refs.
+ dstav = mp_image_to_av_frame(hw_img);
+ if (!dstav)
+ goto done;
+
+ srcav = mp_image_to_av_frame(src);
+ if (!srcav)
+ goto done;
+
+ ok = av_hwframe_transfer_data(dstav, srcav, 0) >= 0;
+
+done:
+ av_frame_unref(srcav);
+ av_frame_unref(dstav);
+
+ if (ok)
+ mp_image_copy_attributes(hw_img, src);
+ return ok;
+}
diff --git a/video/mp_image_pool.h b/video/mp_image_pool.h
index 95e4ae57be..5f570bc6f6 100644
--- a/video/mp_image_pool.h
+++ b/video/mp_image_pool.h
@@ -29,4 +29,6 @@ bool mp_image_pool_make_writeable(struct mp_image_pool *pool,
struct mp_image *mp_image_hw_download(struct mp_image *img,
struct mp_image_pool *swpool);
+bool mp_image_hw_upload(struct mp_image *hw_img, struct mp_image *src);
+
#endif
diff --git a/video/vaapi.c b/video/vaapi.c
index f977b054e4..3bf63f3b54 100644
--- a/video/vaapi.c
+++ b/video/vaapi.c
@@ -287,27 +287,6 @@ static struct va_surface *va_surface_in_mp_image(struct mp_image *mpi)
(struct va_surface*)mpi->planes[0] : NULL;
}
-int va_surface_rt_format(struct mp_image *mpi)
-{
- struct va_surface *surface = va_surface_in_mp_image(mpi);
- return surface ? surface->rt_format : 0;
-}
-
-// Return the real size of the underlying surface. (HW decoding might allocate
-// padded surfaces for example.)
-void va_surface_get_uncropped_size(struct mp_image *mpi, int *out_w, int *out_h)
-{
- if (mpi->hwctx) {
- AVHWFramesContext *fctx = (void *)mpi->hwctx->data;
- *out_w = fctx->width;
- *out_h = fctx->height;
- } else {
- struct va_surface *s = va_surface_in_mp_image(mpi);
- *out_w = s ? s->w : 0;
- *out_h = s ? s->h : 0;
- }
-}
-
static void release_va_surface(void *arg)
{
struct va_surface *surface = arg;
diff --git a/video/vaapi.h b/video/vaapi.h
index d21e3a34ee..58f8ee96f0 100644
--- a/video/vaapi.h
+++ b/video/vaapi.h
@@ -56,13 +56,10 @@ VAImageFormat * va_image_format_from_imgfmt(struct mp_vaapi_ctx *ctx, i
bool va_image_map(struct mp_vaapi_ctx *ctx, VAImage *image, struct mp_image *mpi);
bool va_image_unmap(struct mp_vaapi_ctx *ctx, VAImage *image);
-void va_surface_get_uncropped_size(struct mp_image *mpi, int *out_w, int *out_h);
-
void va_pool_set_allocator(struct mp_image_pool *pool, struct mp_vaapi_ctx *ctx,
int rt_format);
VASurfaceID va_surface_id(struct mp_image *mpi);
-int va_surface_rt_format(struct mp_image *mpi);
struct mp_image *va_surface_download(struct mp_image *src,
struct mp_image_pool *pool);