1
mirror of https://github.com/mpv-player/mpv synced 2024-08-04 14:59:58 +02:00
mpv/video/hwdec.c
wm4 eb8957cea1 vd_lavc: rewrite how --hwdec is handled
Change it from explicit metadata about every hwaccel method to trying to
get it from libavcodec. As shown by add_all_hwdec_methods(), this is a
quite bumpy road, and a bit worse than expected.

This will probably cause a bunch of regressions. In particular I didn't
check all the strange decoder wrappers, which all cause some sort of
special cases each. You're volunteering for beta testing by using this
commit.

One interesting thing is that we completely get rid of mp_hwdec_ctx in
vd_lavc.c, and that HWDEC_* mostly goes away (some filters still use it,
and the VO hwdec interops still have a lot of code to set it up, so it's
not going away completely for now).
2017-12-01 21:11:43 +01:00

156 lines
4.0 KiB
C

#include <pthread.h>
#include <assert.h>
#include <libavutil/hwcontext.h>
#include "config.h"
#include "hwdec.h"
struct mp_hwdec_devices {
pthread_mutex_t lock;
struct mp_hwdec_ctx **hwctxs;
int num_hwctxs;
void (*load_api)(void *ctx);
void *load_api_ctx;
};
struct mp_hwdec_devices *hwdec_devices_create(void)
{
struct mp_hwdec_devices *devs = talloc_zero(NULL, struct mp_hwdec_devices);
pthread_mutex_init(&devs->lock, NULL);
return devs;
}
void hwdec_devices_destroy(struct mp_hwdec_devices *devs)
{
if (!devs)
return;
assert(!devs->num_hwctxs); // must have been hwdec_devices_remove()ed
assert(!devs->load_api); // must have been unset
pthread_mutex_destroy(&devs->lock);
talloc_free(devs);
}
struct mp_hwdec_ctx *hwdec_devices_get(struct mp_hwdec_devices *devs,
enum hwdec_type type)
{
struct mp_hwdec_ctx *res = NULL;
pthread_mutex_lock(&devs->lock);
for (int n = 0; n < devs->num_hwctxs; n++) {
if (devs->hwctxs[n]->type == type) {
res = devs->hwctxs[n];
break;
}
}
pthread_mutex_unlock(&devs->lock);
return res;
}
struct AVBufferRef *hwdec_devices_get_lavc(struct mp_hwdec_devices *devs,
int av_hwdevice_type)
{
AVBufferRef *res = NULL;
pthread_mutex_lock(&devs->lock);
for (int n = 0; n < devs->num_hwctxs; n++) {
struct mp_hwdec_ctx *dev = devs->hwctxs[n];
if (dev->av_device_ref) {
AVHWDeviceContext *hwctx = (void *)dev->av_device_ref->data;
if (hwctx->type == av_hwdevice_type) {
if (dev->av_device_ref)
res = av_buffer_ref(dev->av_device_ref);
break;
}
}
}
pthread_mutex_unlock(&devs->lock);
return res;
}
struct mp_hwdec_ctx *hwdec_devices_get_first(struct mp_hwdec_devices *devs)
{
pthread_mutex_lock(&devs->lock);
struct mp_hwdec_ctx *res = devs->num_hwctxs ? devs->hwctxs[0] : NULL;
pthread_mutex_unlock(&devs->lock);
return res;
}
void hwdec_devices_add(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx)
{
pthread_mutex_lock(&devs->lock);
MP_TARRAY_APPEND(devs, devs->hwctxs, devs->num_hwctxs, ctx);
pthread_mutex_unlock(&devs->lock);
}
void hwdec_devices_remove(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx)
{
pthread_mutex_lock(&devs->lock);
for (int n = 0; n < devs->num_hwctxs; n++) {
if (devs->hwctxs[n] == ctx) {
MP_TARRAY_REMOVE_AT(devs->hwctxs, devs->num_hwctxs, n);
break;
}
}
pthread_mutex_unlock(&devs->lock);
}
void hwdec_devices_set_loader(struct mp_hwdec_devices *devs,
void (*load_api)(void *ctx), void *load_api_ctx)
{
devs->load_api = load_api;
devs->load_api_ctx = load_api_ctx;
}
void hwdec_devices_request_all(struct mp_hwdec_devices *devs)
{
if (devs->load_api && !hwdec_devices_get_first(devs))
devs->load_api(devs->load_api_ctx);
}
void *hwdec_devices_load(struct mp_hwdec_devices *devs, enum hwdec_type type)
{
if (!devs)
return NULL;
hwdec_devices_request_all(devs);
struct mp_hwdec_ctx *hwctx = hwdec_devices_get(devs, type);
return hwctx ? hwctx->ctx : NULL;
}
char *hwdec_devices_get_names(struct mp_hwdec_devices *devs)
{
char *res = NULL;
for (int n = 0; n < devs->num_hwctxs; n++) {
if (res)
ta_xstrdup_append(&res, ",");
ta_xstrdup_append(&res, devs->hwctxs[n]->driver_name);
}
return res;
}
static const struct hwcontext_fns *const hwcontext_fns[] = {
#if HAVE_D3D_HWACCEL
&hwcontext_fns_d3d11,
#endif
#if HAVE_D3D9_HWACCEL
&hwcontext_fns_dxva2,
#endif
#if HAVE_VAAPI
&hwcontext_fns_vaapi,
#endif
#if HAVE_VDPAU
&hwcontext_fns_vdpau,
#endif
NULL,
};
const struct hwcontext_fns *hwdec_get_hwcontext_fns(int av_hwdevice_type)
{
for (int n = 0; hwcontext_fns[n]; n++) {
if (hwcontext_fns[n]->av_hwdevice_type == av_hwdevice_type)
return hwcontext_fns[n];
}
return NULL;
}