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:
parent
6e2d3d9919
commit
6aa4efd1e3
@ -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}
|
||||
},
|
||||
};
|
@ -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))
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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" ),
|
||||
|
Loading…
Reference in New Issue
Block a user