FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/fftools/ffmpeg_hw.c
Date: 2026-09-25 02:02:46
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 1796 HWDevice *hw_device_get_by_type(enum AVHWDeviceType type)
29 {
30 1796 HWDevice *found = NULL;
31 int i;
32
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1796 times.
1796 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 1796 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 8837 void hw_device_free_all(void)
287 {
288 int i;
289
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 8837 times.
8837 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 8837 av_freep(&hw_devices);
295 8837 nb_hw_devices = 0;
296 8837 }
297
298 16556 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 16556 times.
16556 if (filter_hw_device)
303 ✗ return filter_hw_device->device_ref;
304
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 16556 times.
16556 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 16556 return NULL;
319 }
320