Commit | Line | Data |
---|---|---|
89923e41 AK |
1 | /* |
2 | * This file is part of Libav. | |
3 | * | |
4 | * Libav 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 | * Libav 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 Libav; if not, write to the Free Software | |
16 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
17 | */ | |
18 | ||
19 | #include "config.h" | |
20 | ||
21 | #include "buffer.h" | |
22 | #include "common.h" | |
23 | #include "hwcontext.h" | |
24 | #include "hwcontext_internal.h" | |
25 | #include "imgutils.h" | |
26 | #include "log.h" | |
27 | #include "mem.h" | |
28 | #include "pixdesc.h" | |
29 | #include "pixfmt.h" | |
30 | ||
31 | static const HWContextType *hw_table[] = { | |
ad884d10 AK |
32 | #if CONFIG_CUDA |
33 | &ff_hwcontext_type_cuda, | |
34 | #endif | |
551c6775 MT |
35 | #if CONFIG_VAAPI |
36 | &ff_hwcontext_type_vaapi, | |
37 | #endif | |
a001ce31 AK |
38 | #if CONFIG_VDPAU |
39 | &ff_hwcontext_type_vdpau, | |
40 | #endif | |
89923e41 AK |
41 | NULL, |
42 | }; | |
43 | ||
44 | static const AVClass hwdevice_ctx_class = { | |
45 | .class_name = "AVHWDeviceContext", | |
46 | .item_name = av_default_item_name, | |
47 | .version = LIBAVUTIL_VERSION_INT, | |
48 | }; | |
49 | ||
50 | static void hwdevice_ctx_free(void *opaque, uint8_t *data) | |
51 | { | |
52 | AVHWDeviceContext *ctx = (AVHWDeviceContext*)data; | |
53 | ||
54 | /* uninit might still want access the hw context and the user | |
55 | * free() callback might destroy it, so uninit has to be called first */ | |
56 | if (ctx->internal->hw_type->device_uninit) | |
57 | ctx->internal->hw_type->device_uninit(ctx); | |
58 | ||
59 | if (ctx->free) | |
60 | ctx->free(ctx); | |
61 | ||
62 | av_freep(&ctx->hwctx); | |
63 | av_freep(&ctx->internal->priv); | |
64 | av_freep(&ctx->internal); | |
65 | av_freep(&ctx); | |
66 | } | |
67 | ||
68 | AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type) | |
69 | { | |
70 | AVHWDeviceContext *ctx; | |
71 | AVBufferRef *buf; | |
72 | const HWContextType *hw_type = NULL; | |
73 | int i; | |
74 | ||
75 | for (i = 0; hw_table[i]; i++) { | |
76 | if (hw_table[i]->type == type) { | |
77 | hw_type = hw_table[i]; | |
78 | break; | |
79 | } | |
80 | } | |
81 | if (!hw_type) | |
82 | return NULL; | |
83 | ||
84 | ctx = av_mallocz(sizeof(*ctx)); | |
85 | if (!ctx) | |
86 | return NULL; | |
87 | ||
88 | ctx->internal = av_mallocz(sizeof(*ctx->internal)); | |
89 | if (!ctx->internal) | |
90 | goto fail; | |
91 | ||
92 | if (hw_type->device_priv_size) { | |
93 | ctx->internal->priv = av_mallocz(hw_type->device_priv_size); | |
94 | if (!ctx->internal->priv) | |
95 | goto fail; | |
96 | } | |
97 | ||
98 | if (hw_type->device_hwctx_size) { | |
99 | ctx->hwctx = av_mallocz(hw_type->device_hwctx_size); | |
100 | if (!ctx->hwctx) | |
101 | goto fail; | |
102 | } | |
103 | ||
104 | buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), | |
105 | hwdevice_ctx_free, NULL, | |
106 | AV_BUFFER_FLAG_READONLY); | |
107 | if (!buf) | |
108 | goto fail; | |
109 | ||
110 | ctx->type = type; | |
111 | ctx->av_class = &hwdevice_ctx_class; | |
112 | ||
113 | ctx->internal->hw_type = hw_type; | |
114 | ||
115 | return buf; | |
116 | ||
117 | fail: | |
118 | if (ctx->internal) | |
119 | av_freep(&ctx->internal->priv); | |
120 | av_freep(&ctx->internal); | |
121 | av_freep(&ctx->hwctx); | |
122 | av_freep(&ctx); | |
123 | return NULL; | |
124 | } | |
125 | ||
126 | int av_hwdevice_ctx_init(AVBufferRef *ref) | |
127 | { | |
128 | AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; | |
129 | int ret; | |
130 | ||
131 | if (ctx->internal->hw_type->device_init) { | |
132 | ret = ctx->internal->hw_type->device_init(ctx); | |
133 | if (ret < 0) | |
134 | goto fail; | |
135 | } | |
136 | ||
137 | return 0; | |
138 | fail: | |
139 | if (ctx->internal->hw_type->device_uninit) | |
140 | ctx->internal->hw_type->device_uninit(ctx); | |
141 | return ret; | |
142 | } | |
143 | ||
144 | static const AVClass hwframe_ctx_class = { | |
145 | .class_name = "AVHWFramesContext", | |
146 | .item_name = av_default_item_name, | |
147 | .version = LIBAVUTIL_VERSION_INT, | |
148 | }; | |
149 | ||
150 | static void hwframe_ctx_free(void *opaque, uint8_t *data) | |
151 | { | |
152 | AVHWFramesContext *ctx = (AVHWFramesContext*)data; | |
153 | ||
154 | if (ctx->internal->pool_internal) | |
155 | av_buffer_pool_uninit(&ctx->internal->pool_internal); | |
156 | ||
157 | if (ctx->internal->hw_type->frames_uninit) | |
158 | ctx->internal->hw_type->frames_uninit(ctx); | |
159 | ||
160 | if (ctx->free) | |
161 | ctx->free(ctx); | |
162 | ||
163 | av_buffer_unref(&ctx->device_ref); | |
164 | ||
165 | av_freep(&ctx->hwctx); | |
166 | av_freep(&ctx->internal->priv); | |
167 | av_freep(&ctx->internal); | |
168 | av_freep(&ctx); | |
169 | } | |
170 | ||
171 | AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in) | |
172 | { | |
173 | AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref_in->data; | |
174 | const HWContextType *hw_type = device_ctx->internal->hw_type; | |
175 | AVHWFramesContext *ctx; | |
176 | AVBufferRef *buf, *device_ref = NULL;; | |
177 | ||
178 | ctx = av_mallocz(sizeof(*ctx)); | |
179 | if (!ctx) | |
180 | return NULL; | |
181 | ||
182 | ctx->internal = av_mallocz(sizeof(*ctx->internal)); | |
183 | if (!ctx->internal) | |
184 | goto fail; | |
185 | ||
186 | if (hw_type->frames_priv_size) { | |
187 | ctx->internal->priv = av_mallocz(hw_type->frames_priv_size); | |
188 | if (!ctx->internal->priv) | |
189 | goto fail; | |
190 | } | |
191 | ||
192 | if (hw_type->frames_hwctx_size) { | |
193 | ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size); | |
194 | if (!ctx->hwctx) | |
195 | goto fail; | |
196 | } | |
197 | ||
198 | device_ref = av_buffer_ref(device_ref_in); | |
199 | if (!device_ref) | |
200 | goto fail; | |
201 | ||
202 | buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx), | |
203 | hwframe_ctx_free, NULL, | |
204 | AV_BUFFER_FLAG_READONLY); | |
205 | if (!buf) | |
206 | goto fail; | |
207 | ||
208 | ctx->av_class = &hwframe_ctx_class; | |
209 | ctx->device_ref = device_ref; | |
210 | ctx->device_ctx = device_ctx; | |
211 | ctx->format = AV_PIX_FMT_NONE; | |
212 | ||
213 | ctx->internal->hw_type = hw_type; | |
214 | ||
215 | return buf; | |
216 | ||
217 | fail: | |
218 | if (device_ref) | |
219 | av_buffer_unref(&device_ref); | |
220 | if (ctx->internal) | |
221 | av_freep(&ctx->internal->priv); | |
222 | av_freep(&ctx->internal); | |
223 | av_freep(&ctx->hwctx); | |
224 | av_freep(&ctx); | |
225 | return NULL; | |
226 | } | |
227 | ||
228 | static int hwframe_pool_prealloc(AVBufferRef *ref) | |
229 | { | |
230 | AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; | |
231 | AVFrame **frames; | |
232 | int i, ret = 0; | |
233 | ||
234 | frames = av_mallocz_array(ctx->initial_pool_size, sizeof(*frames)); | |
235 | if (!frames) | |
236 | return AVERROR(ENOMEM); | |
237 | ||
238 | for (i = 0; i < ctx->initial_pool_size; i++) { | |
239 | frames[i] = av_frame_alloc(); | |
240 | if (!frames[i]) | |
241 | goto fail; | |
242 | ||
243 | ret = av_hwframe_get_buffer(ref, frames[i], 0); | |
244 | if (ret < 0) | |
245 | goto fail; | |
246 | } | |
247 | ||
248 | fail: | |
249 | for (i = 0; i < ctx->initial_pool_size; i++) | |
250 | av_frame_free(&frames[i]); | |
251 | av_freep(&frames); | |
252 | ||
253 | return ret; | |
254 | } | |
255 | ||
256 | int av_hwframe_ctx_init(AVBufferRef *ref) | |
257 | { | |
258 | AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data; | |
259 | const enum AVPixelFormat *pix_fmt; | |
260 | int ret; | |
261 | ||
262 | /* validate the pixel format */ | |
263 | for (pix_fmt = ctx->internal->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) { | |
264 | if (*pix_fmt == ctx->format) | |
265 | break; | |
266 | } | |
267 | if (*pix_fmt == AV_PIX_FMT_NONE) { | |
268 | av_log(ctx, AV_LOG_ERROR, | |
269 | "The hardware pixel format '%s' is not supported by the device type '%s'\n", | |
270 | av_get_pix_fmt_name(ctx->format), ctx->internal->hw_type->name); | |
271 | return AVERROR(ENOSYS); | |
272 | } | |
273 | ||
274 | /* validate the dimensions */ | |
275 | ret = av_image_check_size(ctx->width, ctx->height, 0, ctx); | |
276 | if (ret < 0) | |
277 | return ret; | |
278 | ||
279 | /* format-specific init */ | |
280 | if (ctx->internal->hw_type->frames_init) { | |
281 | ret = ctx->internal->hw_type->frames_init(ctx); | |
282 | if (ret < 0) | |
283 | goto fail; | |
284 | } | |
285 | ||
286 | if (ctx->internal->pool_internal && !ctx->pool) | |
287 | ctx->pool = ctx->internal->pool_internal; | |
288 | ||
289 | /* preallocate the frames in the pool, if requested */ | |
290 | if (ctx->initial_pool_size > 0) { | |
291 | ret = hwframe_pool_prealloc(ref); | |
292 | if (ret < 0) | |
293 | goto fail; | |
294 | } | |
295 | ||
296 | return 0; | |
297 | fail: | |
298 | if (ctx->internal->hw_type->frames_uninit) | |
299 | ctx->internal->hw_type->frames_uninit(ctx); | |
300 | return ret; | |
301 | } | |
302 | ||
303 | int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref, | |
304 | enum AVHWFrameTransferDirection dir, | |
305 | enum AVPixelFormat **formats, int flags) | |
306 | { | |
307 | AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; | |
308 | ||
309 | if (!ctx->internal->hw_type->transfer_get_formats) | |
310 | return AVERROR(ENOSYS); | |
311 | ||
312 | return ctx->internal->hw_type->transfer_get_formats(ctx, dir, formats); | |
313 | } | |
314 | ||
315 | static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags) | |
316 | { | |
317 | AVFrame *frame_tmp; | |
318 | int ret = 0; | |
319 | ||
320 | frame_tmp = av_frame_alloc(); | |
321 | if (!frame_tmp) | |
322 | return AVERROR(ENOMEM); | |
323 | ||
324 | /* if the format is set, use that | |
325 | * otherwise pick the first supported one */ | |
326 | if (dst->format >= 0) { | |
327 | frame_tmp->format = dst->format; | |
328 | } else { | |
329 | enum AVPixelFormat *formats; | |
330 | ||
331 | ret = av_hwframe_transfer_get_formats(src->hw_frames_ctx, | |
332 | AV_HWFRAME_TRANSFER_DIRECTION_FROM, | |
333 | &formats, 0); | |
334 | if (ret < 0) | |
335 | goto fail; | |
336 | frame_tmp->format = formats[0]; | |
337 | av_freep(&formats); | |
338 | } | |
339 | frame_tmp->width = src->width; | |
340 | frame_tmp->height = src->height; | |
341 | ||
342 | ret = av_frame_get_buffer(frame_tmp, 32); | |
343 | if (ret < 0) | |
344 | goto fail; | |
345 | ||
346 | ret = av_hwframe_transfer_data(frame_tmp, src, flags); | |
347 | if (ret < 0) | |
348 | goto fail; | |
349 | ||
350 | av_frame_move_ref(dst, frame_tmp); | |
351 | ||
352 | fail: | |
353 | av_frame_free(&frame_tmp); | |
354 | return ret; | |
355 | } | |
356 | ||
357 | int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags) | |
358 | { | |
359 | AVHWFramesContext *ctx; | |
360 | int ret; | |
361 | ||
362 | if (!dst->buf[0]) | |
363 | return transfer_data_alloc(dst, src, flags); | |
364 | ||
365 | if (src->hw_frames_ctx) { | |
366 | ctx = (AVHWFramesContext*)src->hw_frames_ctx->data; | |
367 | ||
368 | ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src); | |
369 | if (ret < 0) | |
370 | return ret; | |
371 | } else if (dst->hw_frames_ctx) { | |
372 | ctx = (AVHWFramesContext*)dst->hw_frames_ctx->data; | |
373 | ||
374 | ret = ctx->internal->hw_type->transfer_data_to(ctx, dst, src); | |
375 | if (ret < 0) | |
376 | return ret; | |
377 | } else | |
378 | return AVERROR(ENOSYS); | |
379 | ||
380 | return 0; | |
381 | } | |
382 | ||
383 | int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags) | |
384 | { | |
385 | AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data; | |
386 | int ret; | |
387 | ||
388 | if (!ctx->internal->hw_type->frames_get_buffer) | |
389 | return AVERROR(ENOSYS); | |
390 | ||
391 | if (!ctx->pool) | |
392 | return AVERROR(EINVAL); | |
393 | ||
394 | frame->hw_frames_ctx = av_buffer_ref(hwframe_ref); | |
395 | if (!frame->hw_frames_ctx) | |
396 | return AVERROR(ENOMEM); | |
397 | ||
398 | ret = ctx->internal->hw_type->frames_get_buffer(ctx, frame); | |
399 | if (ret < 0) { | |
400 | av_buffer_unref(&frame->hw_frames_ctx); | |
401 | return ret; | |
402 | } | |
403 | ||
404 | return 0; | |
405 | } | |
b1f01e85 MT |
406 | |
407 | void *av_hwdevice_hwconfig_alloc(AVBufferRef *ref) | |
408 | { | |
409 | AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; | |
410 | const HWContextType *hw_type = ctx->internal->hw_type; | |
411 | ||
412 | if (hw_type->device_hwconfig_size == 0) | |
413 | return NULL; | |
414 | ||
415 | return av_mallocz(hw_type->device_hwconfig_size); | |
416 | } | |
417 | ||
418 | AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref, | |
419 | const void *hwconfig) | |
420 | { | |
421 | AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data; | |
422 | const HWContextType *hw_type = ctx->internal->hw_type; | |
423 | AVHWFramesConstraints *constraints; | |
424 | ||
425 | if (!hw_type->frames_get_constraints) | |
426 | return NULL; | |
427 | ||
428 | constraints = av_mallocz(sizeof(*constraints)); | |
429 | if (!constraints) | |
430 | return NULL; | |
431 | ||
432 | constraints->min_width = constraints->min_height = 0; | |
433 | constraints->max_width = constraints->max_height = INT_MAX; | |
434 | ||
435 | if (hw_type->frames_get_constraints(ctx, hwconfig, constraints) >= 0) { | |
436 | return constraints; | |
437 | } else { | |
438 | av_hwframe_constraints_free(&constraints); | |
439 | return NULL; | |
440 | } | |
441 | } | |
442 | ||
443 | void av_hwframe_constraints_free(AVHWFramesConstraints **constraints) | |
444 | { | |
445 | if (*constraints) { | |
446 | av_freep(&(*constraints)->valid_hw_formats); | |
447 | av_freep(&(*constraints)->valid_sw_formats); | |
448 | } | |
449 | av_freep(constraints); | |
450 | } |