summaryrefslogtreecommitdiffstats
path: root/video/hwdec.c
blob: b3c21317917dc9ffa5b202bca6bb722e5a4dbd9c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#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_by_lavc(struct mp_hwdec_devices *devs,
                                               int av_hwdevice_type)
{
    struct mp_hwdec_ctx *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) {
                res = dev;
                break;
            }
        }
    }
    pthread_mutex_unlock(&devs->lock);
    return res;
}

struct AVBufferRef *hwdec_devices_get_lavc(struct mp_hwdec_devices *devs,
                                           int av_hwdevice_type)
{
    struct mp_hwdec_ctx *ctx = hwdec_devices_get_by_lavc(devs, av_hwdevice_type);
    if (!ctx)
        return NULL;
    return av_buffer_ref(ctx->av_device_ref);
}

struct mp_hwdec_ctx *hwdec_devices_get_first(struct mp_hwdec_devices *devs)
{
    return hwdec_devices_get_n(devs, 0);
}

struct mp_hwdec_ctx *hwdec_devices_get_n(struct mp_hwdec_devices *devs, int n)
{
    pthread_mutex_lock(&devs->lock);
    struct mp_hwdec_ctx *res = n < devs->num_hwctxs ? devs->hwctxs[n] : 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);
}

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;
}