1
0
mirror of https://github.com/mpv-player/mpv synced 2025-03-24 12:22:25 +00:00

vd_lavc, vaapi: move hw device creation to generic code

hw_vaapi.c didn't do much interesting anymore. Other than the function
to create a device for decoding with vaapi-copy, everything can be done
by generic code. Other libavcodec hwaccels are planned to provide the
same API as vaapi. It will be possible to drop the other hw_ files in
the future. They will use this generic code instead.
This commit is contained in:
wm4 2017-02-20 08:39:55 +01:00
parent 6e2d3d9919
commit 6aa4efd1e3
9 changed files with 104 additions and 161 deletions

View File

@ -1,142 +0,0 @@
/*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stddef.h>
#include <assert.h>
#include <libavcodec/avcodec.h>
#include <libavutil/common.h>
#include <libavutil/hwcontext.h>
#include <libavutil/hwcontext_vaapi.h>
#include "config.h"
#include "lavc.h"
#include "common/common.h"
#include "common/av_common.h"
#include "video/fmt-conversion.h"
#include "video/vaapi.h"
#include "video/mp_image_pool.h"
#include "video/hwdec.h"
#include "video/filter/vf.h"
struct priv {
struct mp_log *log;
struct mp_vaapi_ctx *ctx;
};
static void uninit(struct lavc_ctx *ctx)
{
struct priv *p = ctx->hwdec_priv;
if (!p)
return;
va_destroy(p->ctx);
talloc_free(p);
ctx->hwdec_priv = NULL;
ctx->hwdec_dev = NULL;
}
static int init(struct lavc_ctx *ctx, bool direct)
{
struct priv *p = talloc_ptrtype(NULL, p);
*p = (struct priv) {
.log = mp_log_new(p, ctx->log, "vaapi"),
};
if (direct) {
ctx->hwdec_dev = hwdec_devices_get(ctx->hwdec_devs, HWDEC_VAAPI);
} else {
p->ctx = va_create_standalone(ctx->log, false);
if (!p->ctx) {
talloc_free(p);
return -1;
}
ctx->hwdec_dev = &p->ctx->hwctx;
}
ctx->hwdec_priv = p;
if (!ctx->hwdec_dev->av_device_ref)
return -1;
return 0;
}
static int init_direct(struct lavc_ctx *ctx)
{
return init(ctx, true);
}
static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
if (!hwdec_devices_load(ctx->hwdec_devs, HWDEC_VAAPI))
return HWDEC_ERR_NO_CTX;
return 0;
}
static int probe_copy(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
struct mp_vaapi_ctx *dummy = va_create_standalone(ctx->log, true);
if (!dummy)
return HWDEC_ERR_NO_CTX;
bool emulated = va_guess_if_emulated(dummy);
va_destroy(dummy);
if (emulated)
return HWDEC_ERR_EMULATED;
return 0;
}
static int init_copy(struct lavc_ctx *ctx)
{
return init(ctx, false);
}
const struct vd_lavc_hwdec mp_vd_lavc_vaapi = {
.type = HWDEC_VAAPI,
.image_format = IMGFMT_VAAPI,
.probe = probe,
.init = init_direct,
.uninit = uninit,
.generic_hwaccel = true,
.static_pool = true,
.pixfmt_map = (const enum AVPixelFormat[][2]) {
{AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010},
{AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12},
{AV_PIX_FMT_NONE}
},
};
const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy = {
.type = HWDEC_VAAPI_COPY,
.copying = true,
.image_format = IMGFMT_VAAPI,
.probe = probe_copy,
.init = init_copy,
.uninit = uninit,
.generic_hwaccel = true,
.static_pool = true,
.pixfmt_map = (const enum AVPixelFormat[][2]) {
{AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010},
{AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12},
{AV_PIX_FMT_NONE}
},
};

View File

@ -327,11 +327,12 @@ static int init(struct lavc_ctx *ctx, bool direct)
if (direct) {
p->ctx = hwdec_devices_get(ctx->hwdec_devs, HWDEC_VAAPI)->ctx;
} else {
p->ctx = va_create_standalone(ctx->log, false);
if (!p->ctx) {
struct mp_hwdec_ctx *hwctx = va_create_standalone(NULL, ctx->log, false);
if (!hwctx) {
talloc_free(p);
return -1;
}
p->ctx = hwctx->ctx;
p->own_ctx = true;
}
@ -368,9 +369,10 @@ static int probe(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
static int probe_copy(struct lavc_ctx *ctx, struct vd_lavc_hwdec *hwdec,
const char *codec)
{
struct mp_vaapi_ctx *dummy = va_create_standalone(ctx->log, true);
if (!dummy)
struct mp_hwdec_ctx *hwctx = va_create_standalone(NULL, ctx->log, true);
if (!hwctx)
return HWDEC_ERR_NO_CTX;
struct mp_vaapi_ctx *dummy = hwctx->ctx;
bool emulated = va_guess_if_emulated(dummy);
va_destroy(dummy);
if (!hwdec_check_codec_support(codec, profiles))

View File

@ -19,6 +19,8 @@
// This value does not yet include HWDEC_DELAY_QUEUE_COUNT.
#define HWDEC_EXTRA_SURFACES 4
struct mpv_global;
typedef struct lavc_ctx {
struct mp_log *log;
struct MPOpts *opts;
@ -95,9 +97,11 @@ struct vd_lavc_hwdec {
struct mp_image *(*allocate_image)(struct lavc_ctx *ctx, int w, int h);
// Process the image returned by the libavcodec decoder.
struct mp_image *(*process_image)(struct lavc_ctx *ctx, struct mp_image *img);
// Optional; if a special hardware decoder is needed (instead of "hwaccel").
const char *(*get_codec)(struct lavc_ctx *ctx, const char *codec);
// Suffix for libavcodec decoder. If non-NULL, get_codec() is overridden
// For copy hwdecs. If probing is true, don't log errors if unavailable.
// The returned device must be freed with mp_hwdec_ctx->destroy.
struct mp_hwdec_ctx *(*create_dev)(struct mpv_global *global,
struct mp_log *log, bool probing);
// Suffix for libavcodec decoder. If non-NULL, the codec is overridden
// with hwdec_find_decoder.
// Intuitively, this will force the corresponding wrapper decoder.
const char *lavc_suffix;

View File

@ -129,8 +129,6 @@ extern const struct vd_lavc_hwdec mp_vd_lavc_vdpau;
extern const struct vd_lavc_hwdec mp_vd_lavc_vdpau_copy;
extern const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox;
extern const struct vd_lavc_hwdec mp_vd_lavc_videotoolbox_copy;
extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi;
extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy;
extern const struct vd_lavc_hwdec mp_vd_lavc_dxva2;
extern const struct vd_lavc_hwdec mp_vd_lavc_dxva2_copy;
extern const struct vd_lavc_hwdec mp_vd_lavc_d3d11va;
@ -172,6 +170,41 @@ static const struct vd_lavc_hwdec mp_vd_lavc_crystalhd = {
.copying = true,
};
#if HAVE_VAAPI_HWACCEL
#if HAVE_VAAPI_HWACCEL_NEW
const struct vd_lavc_hwdec mp_vd_lavc_vaapi = {
.type = HWDEC_VAAPI,
.image_format = IMGFMT_VAAPI,
.generic_hwaccel = true,
.static_pool = true,
.pixfmt_map = (const enum AVPixelFormat[][2]) {
{AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010},
{AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12},
{AV_PIX_FMT_NONE}
},
};
#include "video/vaapi.h"
const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy = {
.type = HWDEC_VAAPI_COPY,
.copying = true,
.image_format = IMGFMT_VAAPI,
.generic_hwaccel = true,
.static_pool = true,
.create_dev = va_create_standalone,
.pixfmt_map = (const enum AVPixelFormat[][2]) {
{AV_PIX_FMT_YUV420P10, AV_PIX_FMT_P010},
{AV_PIX_FMT_YUV420P, AV_PIX_FMT_NV12},
{AV_PIX_FMT_NONE}
},
};
#else
extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi;
extern const struct vd_lavc_hwdec mp_vd_lavc_vaapi_copy;
#endif
#endif
static const struct vd_lavc_hwdec *const hwdec_list[] = {
#if HAVE_RPI
&mp_vd_lavc_rpi,
@ -309,13 +342,37 @@ static bool hwdec_is_wrapper(struct vd_lavc_hwdec *hwdec, const char *decoder)
return bstr_endswith0(bstr0(decoder), hwdec->lavc_suffix);
}
static struct mp_hwdec_ctx *hwdec_create_dev(struct dec_video *vd,
struct vd_lavc_hwdec *hwdec,
bool autoprobe)
{
if (hwdec->create_dev)
return hwdec->create_dev(vd->global, vd->log, autoprobe);
if (vd->hwdec_devs) {
hwdec_devices_request(vd->hwdec_devs, hwdec->type);
return hwdec_devices_get(vd->hwdec_devs, hwdec->type);
}
return NULL;
}
static int hwdec_probe(struct dec_video *vd, struct vd_lavc_hwdec *hwdec,
const char *codec)
const char *codec, bool autoprobe)
{
vd_ffmpeg_ctx *ctx = vd->priv;
int r = 0;
if (hwdec->probe)
r = hwdec->probe(ctx, hwdec, codec);
if (hwdec->generic_hwaccel) {
assert(!hwdec->probe && !hwdec->init && !hwdec->init_decoder &&
!hwdec->uninit && !hwdec->allocate_image && !hwdec->process_image);
struct mp_hwdec_ctx *dev = hwdec_create_dev(vd, hwdec, autoprobe);
if (!dev)
return hwdec->copying ? -1 : HWDEC_ERR_NO_CTX;
if (dev->emulated)
r = HWDEC_ERR_EMULATED;
if (hwdec->create_dev && dev->destroy)
dev->destroy(dev);
}
if (r >= 0) {
if (hwdec->lavc_suffix && !hwdec_find_decoder(codec, hwdec->lavc_suffix))
return HWDEC_ERR_NO_CODEC;
@ -333,7 +390,7 @@ static struct vd_lavc_hwdec *probe_hwdec(struct dec_video *vd, bool autoprobe,
MP_VERBOSE(vd, "Requested hardware decoder not compiled.\n");
return NULL;
}
int r = hwdec_probe(vd, hwdec, codec);
int r = hwdec_probe(vd, hwdec, codec, autoprobe);
if (r == HWDEC_ERR_EMULATED) {
if (autoprobe)
return NULL;
@ -421,8 +478,6 @@ static void reinit(struct dec_video *vd)
if (hwdec) {
const char *orig_decoder = decoder;
if (hwdec->get_codec)
decoder = hwdec->get_codec(ctx, decoder);
if (hwdec->lavc_suffix)
decoder = hwdec_find_decoder(codec, hwdec->lavc_suffix);
MP_VERBOSE(vd, "Trying hardware decoding.\n");
@ -505,6 +560,11 @@ static void init_avctx(struct dec_video *vd, const char *decoder,
avctx->get_buffer2 = get_buffer2_hwdec;
if (ctx->hwdec->init && ctx->hwdec->init(ctx) < 0)
goto error;
if (ctx->hwdec->generic_hwaccel) {
ctx->hwdec_dev = hwdec_create_dev(vd, ctx->hwdec, false);
if (!ctx->hwdec_dev)
goto error;
}
ctx->max_delay_queue = ctx->hwdec->delay_queue;
ctx->hw_probing = true;
} else {
@ -584,6 +644,11 @@ static void uninit_avctx(struct dec_video *vd)
av_freep(&ctx->avctx->extradata);
}
if (ctx->hwdec_dev && ctx->hwdec && ctx->hwdec->generic_hwaccel &&
ctx->hwdec_dev->destroy)
ctx->hwdec_dev->destroy(ctx->hwdec_dev);
ctx->hwdec_dev = NULL;
if (ctx->hwdec && ctx->hwdec->uninit)
ctx->hwdec->uninit(ctx);
ctx->hwdec = NULL;

View File

@ -72,8 +72,6 @@ void hwdec_devices_set_loader(struct mp_hwdec_devices *devs,
devs->load_api_ctx = load_api_ctx;
}
// Cause VO to lazily load the requested device, and will block until this is
// done (even if not available).
void hwdec_devices_request(struct mp_hwdec_devices *devs, enum hwdec_type type)
{
if (devs->load_api && !hwdec_devices_get_first(devs))

View File

@ -53,6 +53,9 @@ struct mp_hwdec_ctx {
// List of IMGFMT_s, terminated with 0. NULL if N/A.
int *supported_formats;
// Hint to generic code: it's using a wrapper API
bool emulated;
// Optional. Legacy. (New code should use AVHWFramesContext and
// mp_image_hw_download().)
// Allocates a software image from the pool, downloads the hw image from
@ -62,6 +65,9 @@ struct mp_hwdec_ctx {
struct mp_image *(*download_image)(struct mp_hwdec_ctx *ctx,
struct mp_image *mpi,
struct mp_image_pool *swpool);
// Optional. Do not set for VO-bound devices.
void (*destroy)(struct mp_hwdec_ctx *ctx);
};
// Used to communicate hardware decoder device handles from VO to video decoder.

View File

@ -210,6 +210,8 @@ struct mp_vaapi_ctx *va_initialize(VADisplay *display, struct mp_log *plog,
// libva drivers (such as the vdpau wraper). So don't error out on failure.
open_lavu_vaapi_device(res);
res->hwctx.emulated = va_guess_if_emulated(res);
return res;
error:
@ -716,7 +718,13 @@ static const struct va_native_display *const native_displays[] = {
NULL
};
struct mp_vaapi_ctx *va_create_standalone(struct mp_log *plog, bool probing)
static void va_destroy_ctx(struct mp_hwdec_ctx *ctx)
{
va_destroy(ctx->ctx);
}
struct mp_hwdec_ctx *va_create_standalone(struct mpv_global *global,
struct mp_log *plog, bool probing)
{
for (int n = 0; native_displays[n]; n++) {
VADisplay *display = NULL;
@ -731,7 +739,8 @@ struct mp_vaapi_ctx *va_create_standalone(struct mp_log *plog, bool probing)
}
ctx->native_ctx = native_ctx;
ctx->destroy_native_ctx = native_displays[n]->destroy;
return ctx;
ctx->hwctx.destroy = va_destroy_ctx;
return &ctx->hwctx;
}
}
return NULL;

View File

@ -73,6 +73,8 @@ void va_surface_init_subformat(struct mp_image *mpi);
bool va_guess_if_emulated(struct mp_vaapi_ctx *ctx);
struct mp_vaapi_ctx *va_create_standalone(struct mp_log *plog, bool probing);
struct mpv_global;
struct mp_hwdec_ctx *va_create_standalone(struct mpv_global *global,
struct mp_log *plog, bool probing);
#endif

View File

@ -309,7 +309,6 @@ def build(ctx):
( "video/decode/hw_cuda.c", "cuda-hwaccel" ),
( "video/decode/hw_dxva2.c", "d3d-hwaccel" ),
( "video/decode/hw_d3d11va.c", "d3d-hwaccel" ),
( "video/decode/hw_vaapi.c", "vaapi-hwaccel-new" ),
( "video/decode/hw_vaapi_old.c", "vaapi-hwaccel-old" ),
( "video/decode/hw_vdpau.c", "vdpau-hwaccel" ),
( "video/decode/hw_videotoolbox.c", "videotoolbox-hwaccel" ),