1 #include <pthread.h>
2 #include <assert.h>
3
4 #include <libavutil/hwcontext.h>
5
6 #include "config.h"
7
8 #include "hwdec.h"
9
10 struct mp_hwdec_devices {
11 pthread_mutex_t lock;
12
13 struct mp_hwdec_ctx **hwctxs;
14 int num_hwctxs;
15
16 void (*load_api)(void *ctx);
17 void *load_api_ctx;
18 };
19
hwdec_devices_create(void)20 struct mp_hwdec_devices *hwdec_devices_create(void)
21 {
22 struct mp_hwdec_devices *devs = talloc_zero(NULL, struct mp_hwdec_devices);
23 pthread_mutex_init(&devs->lock, NULL);
24 return devs;
25 }
26
hwdec_devices_destroy(struct mp_hwdec_devices * devs)27 void hwdec_devices_destroy(struct mp_hwdec_devices *devs)
28 {
29 if (!devs)
30 return;
31 assert(!devs->num_hwctxs); // must have been hwdec_devices_remove()ed
32 assert(!devs->load_api); // must have been unset
33 pthread_mutex_destroy(&devs->lock);
34 talloc_free(devs);
35 }
36
hwdec_devices_get_by_lavc(struct mp_hwdec_devices * devs,int av_hwdevice_type)37 struct mp_hwdec_ctx *hwdec_devices_get_by_lavc(struct mp_hwdec_devices *devs,
38 int av_hwdevice_type)
39 {
40 struct mp_hwdec_ctx *res = NULL;
41 pthread_mutex_lock(&devs->lock);
42 for (int n = 0; n < devs->num_hwctxs; n++) {
43 struct mp_hwdec_ctx *dev = devs->hwctxs[n];
44 if (dev->av_device_ref) {
45 AVHWDeviceContext *hwctx = (void *)dev->av_device_ref->data;
46 if (hwctx->type == av_hwdevice_type) {
47 res = dev;
48 break;
49 }
50 }
51 }
52 pthread_mutex_unlock(&devs->lock);
53 return res;
54 }
55
hwdec_devices_get_lavc(struct mp_hwdec_devices * devs,int av_hwdevice_type)56 struct AVBufferRef *hwdec_devices_get_lavc(struct mp_hwdec_devices *devs,
57 int av_hwdevice_type)
58 {
59 struct mp_hwdec_ctx *ctx = hwdec_devices_get_by_lavc(devs, av_hwdevice_type);
60 if (!ctx)
61 return NULL;
62 return av_buffer_ref(ctx->av_device_ref);
63 }
64
hwdec_devices_get_first(struct mp_hwdec_devices * devs)65 struct mp_hwdec_ctx *hwdec_devices_get_first(struct mp_hwdec_devices *devs)
66 {
67 return hwdec_devices_get_n(devs, 0);
68 }
69
hwdec_devices_get_n(struct mp_hwdec_devices * devs,int n)70 struct mp_hwdec_ctx *hwdec_devices_get_n(struct mp_hwdec_devices *devs, int n)
71 {
72 pthread_mutex_lock(&devs->lock);
73 struct mp_hwdec_ctx *res = n < devs->num_hwctxs ? devs->hwctxs[n] : NULL;
74 pthread_mutex_unlock(&devs->lock);
75 return res;
76 }
77
hwdec_devices_add(struct mp_hwdec_devices * devs,struct mp_hwdec_ctx * ctx)78 void hwdec_devices_add(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx)
79 {
80 pthread_mutex_lock(&devs->lock);
81 MP_TARRAY_APPEND(devs, devs->hwctxs, devs->num_hwctxs, ctx);
82 pthread_mutex_unlock(&devs->lock);
83 }
84
hwdec_devices_remove(struct mp_hwdec_devices * devs,struct mp_hwdec_ctx * ctx)85 void hwdec_devices_remove(struct mp_hwdec_devices *devs, struct mp_hwdec_ctx *ctx)
86 {
87 pthread_mutex_lock(&devs->lock);
88 for (int n = 0; n < devs->num_hwctxs; n++) {
89 if (devs->hwctxs[n] == ctx) {
90 MP_TARRAY_REMOVE_AT(devs->hwctxs, devs->num_hwctxs, n);
91 break;
92 }
93 }
94 pthread_mutex_unlock(&devs->lock);
95 }
96
hwdec_devices_set_loader(struct mp_hwdec_devices * devs,void (* load_api)(void * ctx),void * load_api_ctx)97 void hwdec_devices_set_loader(struct mp_hwdec_devices *devs,
98 void (*load_api)(void *ctx), void *load_api_ctx)
99 {
100 devs->load_api = load_api;
101 devs->load_api_ctx = load_api_ctx;
102 }
103
hwdec_devices_request_all(struct mp_hwdec_devices * devs)104 void hwdec_devices_request_all(struct mp_hwdec_devices *devs)
105 {
106 if (devs->load_api && !hwdec_devices_get_first(devs))
107 devs->load_api(devs->load_api_ctx);
108 }
109
hwdec_devices_get_names(struct mp_hwdec_devices * devs)110 char *hwdec_devices_get_names(struct mp_hwdec_devices *devs)
111 {
112 char *res = NULL;
113 for (int n = 0; n < devs->num_hwctxs; n++) {
114 if (res)
115 ta_xstrdup_append(&res, ",");
116 ta_xstrdup_append(&res, devs->hwctxs[n]->driver_name);
117 }
118 return res;
119 }
120
121 static const struct hwcontext_fns *const hwcontext_fns[] = {
122 #if HAVE_CUDA_HWACCEL
123 &hwcontext_fns_cuda,
124 #endif
125 #if HAVE_D3D_HWACCEL
126 &hwcontext_fns_d3d11,
127 #endif
128 #if HAVE_D3D9_HWACCEL
129 &hwcontext_fns_dxva2,
130 #endif
131 #if HAVE_VAAPI
132 &hwcontext_fns_vaapi,
133 #endif
134 #if HAVE_VDPAU
135 &hwcontext_fns_vdpau,
136 #endif
137 NULL,
138 };
139
hwdec_get_hwcontext_fns(int av_hwdevice_type)140 const struct hwcontext_fns *hwdec_get_hwcontext_fns(int av_hwdevice_type)
141 {
142 for (int n = 0; hwcontext_fns[n]; n++) {
143 if (hwcontext_fns[n]->av_hwdevice_type == av_hwdevice_type)
144 return hwcontext_fns[n];
145 }
146 return NULL;
147 }
148