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