FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/fftools/ffmpeg_hw.c
Date: 2024-11-20 23:03:26
Exec Total Coverage
Lines: 13 170 7.6%
Functions: 3 8 37.5%
Branches: 4 86 4.7%

Line Branch Exec Source
1 /*
2 * This file is part of FFmpeg.
3 *
4 * FFmpeg is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
8 *
9 * FFmpeg is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with FFmpeg; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18
19 #include <string.h>
20
21 #include "libavutil/mem.h"
22
23 #include "ffmpeg.h"
24
25 static int nb_hw_devices;
26 static HWDevice **hw_devices;
27
28 1700 HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
29 {
30 1700 HWDevice *found = NULL;
31 int i;
32
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1700 times.
1700 for (i = 0; i < nb_hw_devices; i++) {
33 if (hw_devices[i]->type == type) {
34 if (found)
35 return NULL;
36 found = hw_devices[i];
37 }
38 }
39 1700 return found;
40 }
41
42 HWDevice *hw_device_get_by_name(const char *name)
43 {
44 int i;
45 for (i = 0; i < nb_hw_devices; i++) {
46 if (!strcmp(hw_devices[i]->name, name))
47 return hw_devices[i];
48 }
49 return NULL;
50 }
51
52 static HWDevice *hw_device_add(void)
53 {
54 int err;
55 err = av_reallocp_array(&hw_devices, nb_hw_devices + 1,
56 sizeof(*hw_devices));
57 if (err) {
58 nb_hw_devices = 0;
59 return NULL;
60 }
61 hw_devices[nb_hw_devices] = av_mallocz(sizeof(HWDevice));
62 if (!hw_devices[nb_hw_devices])
63 return NULL;
64 return hw_devices[nb_hw_devices++];
65 }
66
67 static char *hw_device_default_name(enum AVHWDeviceType type)
68 {
69 // Make an automatic name of the form "type%d". We arbitrarily
70 // limit at 1000 anonymous devices of the same type - there is
71 // probably something else very wrong if you get to this limit.
72 const char *type_name = av_hwdevice_get_type_name(type);
73 char *name;
74 size_t index_pos;
75 int index, index_limit = 1000;
76 index_pos = strlen(type_name);
77 name = av_malloc(index_pos + 4);
78 if (!name)
79 return NULL;
80 for (index = 0; index < index_limit; index++) {
81 snprintf(name, index_pos + 4, "%s%d", type_name, index);
82 if (!hw_device_get_by_name(name))
83 break;
84 }
85 if (index >= index_limit) {
86 av_freep(&name);
87 return NULL;
88 }
89 return name;
90 }
91
92 int hw_device_init_from_string(const char *arg, HWDevice **dev_out)
93 {
94 // "type=name"
95 // "type=name,key=value,key2=value2"
96 // "type=name:device,key=value,key2=value2"
97 // "type:device,key=value,key2=value2"
98 // -> av_hwdevice_ctx_create()
99 // "type=name@name"
100 // "type@name"
101 // -> av_hwdevice_ctx_create_derived()
102
103 AVDictionary *options = NULL;
104 const char *type_name = NULL, *name = NULL, *device = NULL;
105 enum AVHWDeviceType type;
106 HWDevice *dev, *src;
107 AVBufferRef *device_ref = NULL;
108 int err;
109 const char *errmsg, *p, *q;
110 size_t k;
111
112 k = strcspn(arg, ":=@");
113 p = arg + k;
114
115 type_name = av_strndup(arg, k);
116 if (!type_name) {
117 err = AVERROR(ENOMEM);
118 goto fail;
119 }
120 type = av_hwdevice_find_type_by_name(type_name);
121 if (type == AV_HWDEVICE_TYPE_NONE) {
122 errmsg = "unknown device type";
123 goto invalid;
124 }
125
126 if (*p == '=') {
127 k = strcspn(p + 1, ":@,");
128
129 name = av_strndup(p + 1, k);
130 if (!name) {
131 err = AVERROR(ENOMEM);
132 goto fail;
133 }
134 if (hw_device_get_by_name(name)) {
135 errmsg = "named device already exists";
136 goto invalid;
137 }
138
139 p += 1 + k;
140 } else {
141 name = hw_device_default_name(type);
142 if (!name) {
143 err = AVERROR(ENOMEM);
144 goto fail;
145 }
146 }
147
148 if (!*p) {
149 // New device with no parameters.
150 err = av_hwdevice_ctx_create(&device_ref, type,
151 NULL, NULL, 0);
152 if (err < 0)
153 goto fail;
154
155 } else if (*p == ':') {
156 // New device with some parameters.
157 ++p;
158 q = strchr(p, ',');
159 if (q) {
160 if (q - p > 0) {
161 device = av_strndup(p, q - p);
162 if (!device) {
163 err = AVERROR(ENOMEM);
164 goto fail;
165 }
166 }
167 err = av_dict_parse_string(&options, q + 1, "=", ",", 0);
168 if (err < 0) {
169 errmsg = "failed to parse options";
170 goto invalid;
171 }
172 }
173
174 err = av_hwdevice_ctx_create(&device_ref, type,
175 q ? device : p[0] ? p : NULL,
176 options, 0);
177 if (err < 0)
178 goto fail;
179
180 } else if (*p == '@') {
181 // Derive from existing device.
182
183 src = hw_device_get_by_name(p + 1);
184 if (!src) {
185 errmsg = "invalid source device name";
186 goto invalid;
187 }
188
189 err = av_hwdevice_ctx_create_derived(&device_ref, type,
190 src->device_ref, 0);
191 if (err < 0)
192 goto fail;
193 } else if (*p == ',') {
194 err = av_dict_parse_string(&options, p + 1, "=", ",", 0);
195
196 if (err < 0) {
197 errmsg = "failed to parse options";
198 goto invalid;
199 }
200
201 err = av_hwdevice_ctx_create(&device_ref, type,
202 NULL, options, 0);
203 if (err < 0)
204 goto fail;
205 } else {
206 errmsg = "parse error";
207 goto invalid;
208 }
209
210 dev = hw_device_add();
211 if (!dev) {
212 err = AVERROR(ENOMEM);
213 goto fail;
214 }
215
216 dev->name = name;
217 dev->type = type;
218 dev->device_ref = device_ref;
219
220 if (dev_out)
221 *dev_out = dev;
222
223 name = NULL;
224 err = 0;
225 done:
226 av_freep(&type_name);
227 av_freep(&name);
228 av_freep(&device);
229 av_dict_free(&options);
230 return err;
231 invalid:
232 av_log(NULL, AV_LOG_ERROR,
233 "Invalid device specification \"%s\": %s\n", arg, errmsg);
234 err = AVERROR(EINVAL);
235 goto done;
236 fail:
237 av_log(NULL, AV_LOG_ERROR,
238 "Device creation failed: %d.\n", err);
239 av_buffer_unref(&device_ref);
240 goto done;
241 }
242
243 int hw_device_init_from_type(enum AVHWDeviceType type,
244 const char *device,
245 HWDevice **dev_out)
246 {
247 AVBufferRef *device_ref = NULL;
248 HWDevice *dev;
249 char *name;
250 int err;
251
252 name = hw_device_default_name(type);
253 if (!name) {
254 err = AVERROR(ENOMEM);
255 goto fail;
256 }
257
258 err = av_hwdevice_ctx_create(&device_ref, type, device, NULL, 0);
259 if (err < 0) {
260 av_log(NULL, AV_LOG_ERROR,
261 "Device creation failed: %d.\n", err);
262 goto fail;
263 }
264
265 dev = hw_device_add();
266 if (!dev) {
267 err = AVERROR(ENOMEM);
268 goto fail;
269 }
270
271 dev->name = name;
272 dev->type = type;
273 dev->device_ref = device_ref;
274
275 if (dev_out)
276 *dev_out = dev;
277
278 return 0;
279
280 fail:
281 av_freep(&name);
282 av_buffer_unref(&device_ref);
283 return err;
284 }
285
286 7915 void hw_device_free_all(void)
287 {
288 int i;
289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7915 times.
7915 for (i = 0; i < nb_hw_devices; i++) {
290 av_freep(&hw_devices[i]->name);
291 av_buffer_unref(&hw_devices[i]->device_ref);
292 av_freep(&hw_devices[i]);
293 }
294 7915 av_freep(&hw_devices);
295 7915 nb_hw_devices = 0;
296 7915 }
297
298 15120 AVBufferRef *hw_device_for_filter(void)
299 {
300 // Pick the last hardware device if the user doesn't pick the device for
301 // filters explicitly with the filter_hw_device option.
302
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15120 times.
15120 if (filter_hw_device)
303 return filter_hw_device->device_ref;
304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 15120 times.
15120 else if (nb_hw_devices > 0) {
305 HWDevice *dev = hw_devices[nb_hw_devices - 1];
306
307 if (nb_hw_devices > 1)
308 av_log(NULL, AV_LOG_WARNING, "There are %d hardware devices. device "
309 "%s of type %s is picked for filters by default. Set hardware "
310 "device explicitly with the filter_hw_device option if device "
311 "%s is not usable for filters.\n",
312 nb_hw_devices, dev->name,
313 av_hwdevice_get_type_name(dev->type), dev->name);
314
315 return dev->device_ref;
316 }
317
318 15120 return NULL;
319 }
320