FFmpeg coverage


Directory: ../../../ffmpeg/
File: src/libavutil/hwcontext.c
Date: 2024-02-16 17:37:06
Exec Total Coverage
Lines: 0 505 0.0%
Functions: 0 25 0.0%
Branches: 0 282 0.0%

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 "config.h"
20
21 #include "avassert.h"
22 #include "buffer.h"
23 #include "common.h"
24 #include "hwcontext.h"
25 #include "hwcontext_internal.h"
26 #include "imgutils.h"
27 #include "log.h"
28 #include "mem.h"
29 #include "pixdesc.h"
30 #include "pixfmt.h"
31
32 static const HWContextType * const hw_table[] = {
33 #if CONFIG_CUDA
34 &ff_hwcontext_type_cuda,
35 #endif
36 #if CONFIG_D3D11VA
37 &ff_hwcontext_type_d3d11va,
38 #endif
39 #if CONFIG_D3D12VA
40 &ff_hwcontext_type_d3d12va,
41 #endif
42 #if CONFIG_LIBDRM
43 &ff_hwcontext_type_drm,
44 #endif
45 #if CONFIG_DXVA2
46 &ff_hwcontext_type_dxva2,
47 #endif
48 #if CONFIG_OPENCL
49 &ff_hwcontext_type_opencl,
50 #endif
51 #if CONFIG_QSV
52 &ff_hwcontext_type_qsv,
53 #endif
54 #if CONFIG_VAAPI
55 &ff_hwcontext_type_vaapi,
56 #endif
57 #if CONFIG_VDPAU
58 &ff_hwcontext_type_vdpau,
59 #endif
60 #if CONFIG_VIDEOTOOLBOX
61 &ff_hwcontext_type_videotoolbox,
62 #endif
63 #if CONFIG_MEDIACODEC
64 &ff_hwcontext_type_mediacodec,
65 #endif
66 #if CONFIG_VULKAN
67 &ff_hwcontext_type_vulkan,
68 #endif
69 NULL,
70 };
71
72 static const char *const hw_type_names[] = {
73 [AV_HWDEVICE_TYPE_CUDA] = "cuda",
74 [AV_HWDEVICE_TYPE_DRM] = "drm",
75 [AV_HWDEVICE_TYPE_DXVA2] = "dxva2",
76 [AV_HWDEVICE_TYPE_D3D11VA] = "d3d11va",
77 [AV_HWDEVICE_TYPE_D3D12VA] = "d3d12va",
78 [AV_HWDEVICE_TYPE_OPENCL] = "opencl",
79 [AV_HWDEVICE_TYPE_QSV] = "qsv",
80 [AV_HWDEVICE_TYPE_VAAPI] = "vaapi",
81 [AV_HWDEVICE_TYPE_VDPAU] = "vdpau",
82 [AV_HWDEVICE_TYPE_VIDEOTOOLBOX] = "videotoolbox",
83 [AV_HWDEVICE_TYPE_MEDIACODEC] = "mediacodec",
84 [AV_HWDEVICE_TYPE_VULKAN] = "vulkan",
85 };
86
87 enum AVHWDeviceType av_hwdevice_find_type_by_name(const char *name)
88 {
89 int type;
90 for (type = 0; type < FF_ARRAY_ELEMS(hw_type_names); type++) {
91 if (hw_type_names[type] && !strcmp(hw_type_names[type], name))
92 return type;
93 }
94 return AV_HWDEVICE_TYPE_NONE;
95 }
96
97 const char *av_hwdevice_get_type_name(enum AVHWDeviceType type)
98 {
99 if (type > AV_HWDEVICE_TYPE_NONE &&
100 type < FF_ARRAY_ELEMS(hw_type_names))
101 return hw_type_names[type];
102 else
103 return NULL;
104 }
105
106 enum AVHWDeviceType av_hwdevice_iterate_types(enum AVHWDeviceType prev)
107 {
108 enum AVHWDeviceType next;
109 int i, set = 0;
110 for (i = 0; hw_table[i]; i++) {
111 if (prev != AV_HWDEVICE_TYPE_NONE && hw_table[i]->type <= prev)
112 continue;
113 if (!set || hw_table[i]->type < next) {
114 next = hw_table[i]->type;
115 set = 1;
116 }
117 }
118 return set ? next : AV_HWDEVICE_TYPE_NONE;
119 }
120
121 static const AVClass hwdevice_ctx_class = {
122 .class_name = "AVHWDeviceContext",
123 .item_name = av_default_item_name,
124 .version = LIBAVUTIL_VERSION_INT,
125 };
126
127 static void hwdevice_ctx_free(void *opaque, uint8_t *data)
128 {
129 AVHWDeviceContext *ctx = (AVHWDeviceContext*)data;
130
131 /* uninit might still want access the hw context and the user
132 * free() callback might destroy it, so uninit has to be called first */
133 if (ctx->internal->hw_type->device_uninit)
134 ctx->internal->hw_type->device_uninit(ctx);
135
136 if (ctx->free)
137 ctx->free(ctx);
138
139 av_buffer_unref(&ctx->internal->source_device);
140
141 av_freep(&ctx->hwctx);
142 av_freep(&ctx->internal->priv);
143 av_freep(&ctx->internal);
144 av_freep(&ctx);
145 }
146
147 AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type)
148 {
149 AVHWDeviceContext *ctx;
150 AVBufferRef *buf;
151 const HWContextType *hw_type = NULL;
152 int i;
153
154 for (i = 0; hw_table[i]; i++) {
155 if (hw_table[i]->type == type) {
156 hw_type = hw_table[i];
157 break;
158 }
159 }
160 if (!hw_type)
161 return NULL;
162
163 ctx = av_mallocz(sizeof(*ctx));
164 if (!ctx)
165 return NULL;
166
167 ctx->internal = av_mallocz(sizeof(*ctx->internal));
168 if (!ctx->internal)
169 goto fail;
170
171 if (hw_type->device_priv_size) {
172 ctx->internal->priv = av_mallocz(hw_type->device_priv_size);
173 if (!ctx->internal->priv)
174 goto fail;
175 }
176
177 if (hw_type->device_hwctx_size) {
178 ctx->hwctx = av_mallocz(hw_type->device_hwctx_size);
179 if (!ctx->hwctx)
180 goto fail;
181 }
182
183 buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),
184 hwdevice_ctx_free, NULL,
185 AV_BUFFER_FLAG_READONLY);
186 if (!buf)
187 goto fail;
188
189 ctx->type = type;
190 ctx->av_class = &hwdevice_ctx_class;
191
192 ctx->internal->hw_type = hw_type;
193
194 return buf;
195
196 fail:
197 if (ctx->internal)
198 av_freep(&ctx->internal->priv);
199 av_freep(&ctx->internal);
200 av_freep(&ctx->hwctx);
201 av_freep(&ctx);
202 return NULL;
203 }
204
205 int av_hwdevice_ctx_init(AVBufferRef *ref)
206 {
207 AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data;
208 int ret;
209
210 if (ctx->internal->hw_type->device_init) {
211 ret = ctx->internal->hw_type->device_init(ctx);
212 if (ret < 0)
213 goto fail;
214 }
215
216 return 0;
217 fail:
218 if (ctx->internal->hw_type->device_uninit)
219 ctx->internal->hw_type->device_uninit(ctx);
220 return ret;
221 }
222
223 static const AVClass hwframe_ctx_class = {
224 .class_name = "AVHWFramesContext",
225 .item_name = av_default_item_name,
226 .version = LIBAVUTIL_VERSION_INT,
227 };
228
229 static void hwframe_ctx_free(void *opaque, uint8_t *data)
230 {
231 AVHWFramesContext *ctx = (AVHWFramesContext*)data;
232
233 if (ctx->internal->pool_internal)
234 av_buffer_pool_uninit(&ctx->internal->pool_internal);
235
236 if (ctx->internal->hw_type->frames_uninit)
237 ctx->internal->hw_type->frames_uninit(ctx);
238
239 if (ctx->free)
240 ctx->free(ctx);
241
242 av_buffer_unref(&ctx->internal->source_frames);
243
244 av_buffer_unref(&ctx->device_ref);
245
246 av_freep(&ctx->hwctx);
247 av_freep(&ctx->internal->priv);
248 av_freep(&ctx->internal);
249 av_freep(&ctx);
250 }
251
252 AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
253 {
254 AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref_in->data;
255 const HWContextType *hw_type = device_ctx->internal->hw_type;
256 AVHWFramesContext *ctx;
257 AVBufferRef *buf, *device_ref = NULL;
258
259 ctx = av_mallocz(sizeof(*ctx));
260 if (!ctx)
261 return NULL;
262
263 ctx->internal = av_mallocz(sizeof(*ctx->internal));
264 if (!ctx->internal)
265 goto fail;
266
267 if (hw_type->frames_priv_size) {
268 ctx->internal->priv = av_mallocz(hw_type->frames_priv_size);
269 if (!ctx->internal->priv)
270 goto fail;
271 }
272
273 if (hw_type->frames_hwctx_size) {
274 ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size);
275 if (!ctx->hwctx)
276 goto fail;
277 }
278
279 device_ref = av_buffer_ref(device_ref_in);
280 if (!device_ref)
281 goto fail;
282
283 buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),
284 hwframe_ctx_free, NULL,
285 AV_BUFFER_FLAG_READONLY);
286 if (!buf)
287 goto fail;
288
289 ctx->av_class = &hwframe_ctx_class;
290 ctx->device_ref = device_ref;
291 ctx->device_ctx = device_ctx;
292 ctx->format = AV_PIX_FMT_NONE;
293 ctx->sw_format = AV_PIX_FMT_NONE;
294
295 ctx->internal->hw_type = hw_type;
296
297 return buf;
298
299 fail:
300 if (device_ref)
301 av_buffer_unref(&device_ref);
302 if (ctx->internal)
303 av_freep(&ctx->internal->priv);
304 av_freep(&ctx->internal);
305 av_freep(&ctx->hwctx);
306 av_freep(&ctx);
307 return NULL;
308 }
309
310 static int hwframe_pool_prealloc(AVBufferRef *ref)
311 {
312 AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data;
313 AVFrame **frames;
314 int i, ret = 0;
315
316 frames = av_calloc(ctx->initial_pool_size, sizeof(*frames));
317 if (!frames)
318 return AVERROR(ENOMEM);
319
320 for (i = 0; i < ctx->initial_pool_size; i++) {
321 frames[i] = av_frame_alloc();
322 if (!frames[i])
323 goto fail;
324
325 ret = av_hwframe_get_buffer(ref, frames[i], 0);
326 if (ret < 0)
327 goto fail;
328 }
329
330 fail:
331 for (i = 0; i < ctx->initial_pool_size; i++)
332 av_frame_free(&frames[i]);
333 av_freep(&frames);
334
335 return ret;
336 }
337
338 int av_hwframe_ctx_init(AVBufferRef *ref)
339 {
340 AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data;
341 const enum AVPixelFormat *pix_fmt;
342 int ret;
343
344 if (ctx->internal->source_frames) {
345 /* A derived frame context is already initialised. */
346 return 0;
347 }
348
349 /* validate the pixel format */
350 for (pix_fmt = ctx->internal->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) {
351 if (*pix_fmt == ctx->format)
352 break;
353 }
354 if (*pix_fmt == AV_PIX_FMT_NONE) {
355 av_log(ctx, AV_LOG_ERROR,
356 "The hardware pixel format '%s' is not supported by the device type '%s'\n",
357 av_get_pix_fmt_name(ctx->format), ctx->internal->hw_type->name);
358 return AVERROR(ENOSYS);
359 }
360
361 /* validate the dimensions */
362 ret = av_image_check_size(ctx->width, ctx->height, 0, ctx);
363 if (ret < 0)
364 return ret;
365
366 /* format-specific init */
367 if (ctx->internal->hw_type->frames_init) {
368 ret = ctx->internal->hw_type->frames_init(ctx);
369 if (ret < 0)
370 goto fail;
371 }
372
373 if (ctx->internal->pool_internal && !ctx->pool)
374 ctx->pool = ctx->internal->pool_internal;
375
376 /* preallocate the frames in the pool, if requested */
377 if (ctx->initial_pool_size > 0) {
378 ret = hwframe_pool_prealloc(ref);
379 if (ret < 0)
380 goto fail;
381 }
382
383 return 0;
384 fail:
385 if (ctx->internal->hw_type->frames_uninit)
386 ctx->internal->hw_type->frames_uninit(ctx);
387 return ret;
388 }
389
390 int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref,
391 enum AVHWFrameTransferDirection dir,
392 enum AVPixelFormat **formats, int flags)
393 {
394 AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
395
396 if (!ctx->internal->hw_type->transfer_get_formats)
397 return AVERROR(ENOSYS);
398
399 return ctx->internal->hw_type->transfer_get_formats(ctx, dir, formats);
400 }
401
402 static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags)
403 {
404 AVHWFramesContext *ctx;
405 AVFrame *frame_tmp;
406 int ret = 0;
407
408 if (!src->hw_frames_ctx)
409 return AVERROR(EINVAL);
410 ctx = (AVHWFramesContext*)src->hw_frames_ctx->data;
411
412 frame_tmp = av_frame_alloc();
413 if (!frame_tmp)
414 return AVERROR(ENOMEM);
415
416 /* if the format is set, use that
417 * otherwise pick the first supported one */
418 if (dst->format >= 0) {
419 frame_tmp->format = dst->format;
420 } else {
421 enum AVPixelFormat *formats;
422
423 ret = av_hwframe_transfer_get_formats(src->hw_frames_ctx,
424 AV_HWFRAME_TRANSFER_DIRECTION_FROM,
425 &formats, 0);
426 if (ret < 0)
427 goto fail;
428 frame_tmp->format = formats[0];
429 av_freep(&formats);
430 }
431 frame_tmp->width = ctx->width;
432 frame_tmp->height = ctx->height;
433
434 ret = av_frame_get_buffer(frame_tmp, 0);
435 if (ret < 0)
436 goto fail;
437
438 ret = av_hwframe_transfer_data(frame_tmp, src, flags);
439 if (ret < 0)
440 goto fail;
441
442 frame_tmp->width = src->width;
443 frame_tmp->height = src->height;
444
445 av_frame_move_ref(dst, frame_tmp);
446
447 fail:
448 av_frame_free(&frame_tmp);
449 return ret;
450 }
451
452 int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)
453 {
454 AVHWFramesContext *ctx;
455 int ret;
456
457 if (!dst->buf[0])
458 return transfer_data_alloc(dst, src, flags);
459
460 /*
461 * Hardware -> Hardware Transfer.
462 * Unlike Software -> Hardware or Hardware -> Software, the transfer
463 * function could be provided by either the src or dst, depending on
464 * the specific combination of hardware.
465 */
466 if (src->hw_frames_ctx && dst->hw_frames_ctx) {
467 AVHWFramesContext *src_ctx =
468 (AVHWFramesContext*)src->hw_frames_ctx->data;
469 AVHWFramesContext *dst_ctx =
470 (AVHWFramesContext*)dst->hw_frames_ctx->data;
471
472 if (src_ctx->internal->source_frames) {
473 av_log(src_ctx, AV_LOG_ERROR,
474 "A device with a derived frame context cannot be used as "
475 "the source of a HW -> HW transfer.");
476 return AVERROR(ENOSYS);
477 }
478
479 if (dst_ctx->internal->source_frames) {
480 av_log(src_ctx, AV_LOG_ERROR,
481 "A device with a derived frame context cannot be used as "
482 "the destination of a HW -> HW transfer.");
483 return AVERROR(ENOSYS);
484 }
485
486 ret = src_ctx->internal->hw_type->transfer_data_from(src_ctx, dst, src);
487 if (ret == AVERROR(ENOSYS))
488 ret = dst_ctx->internal->hw_type->transfer_data_to(dst_ctx, dst, src);
489 if (ret < 0)
490 return ret;
491 } else {
492 if (src->hw_frames_ctx) {
493 ctx = (AVHWFramesContext*)src->hw_frames_ctx->data;
494
495 ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src);
496 if (ret < 0)
497 return ret;
498 } else if (dst->hw_frames_ctx) {
499 ctx = (AVHWFramesContext*)dst->hw_frames_ctx->data;
500
501 ret = ctx->internal->hw_type->transfer_data_to(ctx, dst, src);
502 if (ret < 0)
503 return ret;
504 } else {
505 return AVERROR(ENOSYS);
506 }
507 }
508 return 0;
509 }
510
511 int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
512 {
513 AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
514 int ret;
515
516 if (ctx->internal->source_frames) {
517 // This is a derived frame context, so we allocate in the source
518 // and map the frame immediately.
519 AVFrame *src_frame;
520
521 frame->format = ctx->format;
522 frame->hw_frames_ctx = av_buffer_ref(hwframe_ref);
523 if (!frame->hw_frames_ctx)
524 return AVERROR(ENOMEM);
525
526 src_frame = av_frame_alloc();
527 if (!src_frame)
528 return AVERROR(ENOMEM);
529
530 ret = av_hwframe_get_buffer(ctx->internal->source_frames,
531 src_frame, 0);
532 if (ret < 0) {
533 av_frame_free(&src_frame);
534 return ret;
535 }
536
537 ret = av_hwframe_map(frame, src_frame,
538 ctx->internal->source_allocation_map_flags);
539 if (ret) {
540 av_log(ctx, AV_LOG_ERROR, "Failed to map frame into derived "
541 "frame context: %d.\n", ret);
542 av_frame_free(&src_frame);
543 return ret;
544 }
545
546 // Free the source frame immediately - the mapped frame still
547 // contains a reference to it.
548 av_frame_free(&src_frame);
549
550 return 0;
551 }
552
553 if (!ctx->internal->hw_type->frames_get_buffer)
554 return AVERROR(ENOSYS);
555
556 if (!ctx->pool)
557 return AVERROR(EINVAL);
558
559 frame->hw_frames_ctx = av_buffer_ref(hwframe_ref);
560 if (!frame->hw_frames_ctx)
561 return AVERROR(ENOMEM);
562
563 ret = ctx->internal->hw_type->frames_get_buffer(ctx, frame);
564 if (ret < 0) {
565 av_buffer_unref(&frame->hw_frames_ctx);
566 return ret;
567 }
568
569 frame->extended_data = frame->data;
570
571 return 0;
572 }
573
574 void *av_hwdevice_hwconfig_alloc(AVBufferRef *ref)
575 {
576 AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data;
577 const HWContextType *hw_type = ctx->internal->hw_type;
578
579 if (hw_type->device_hwconfig_size == 0)
580 return NULL;
581
582 return av_mallocz(hw_type->device_hwconfig_size);
583 }
584
585 AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref,
586 const void *hwconfig)
587 {
588 AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data;
589 const HWContextType *hw_type = ctx->internal->hw_type;
590 AVHWFramesConstraints *constraints;
591
592 if (!hw_type->frames_get_constraints)
593 return NULL;
594
595 constraints = av_mallocz(sizeof(*constraints));
596 if (!constraints)
597 return NULL;
598
599 constraints->min_width = constraints->min_height = 0;
600 constraints->max_width = constraints->max_height = INT_MAX;
601
602 if (hw_type->frames_get_constraints(ctx, hwconfig, constraints) >= 0) {
603 return constraints;
604 } else {
605 av_hwframe_constraints_free(&constraints);
606 return NULL;
607 }
608 }
609
610 void av_hwframe_constraints_free(AVHWFramesConstraints **constraints)
611 {
612 if (*constraints) {
613 av_freep(&(*constraints)->valid_hw_formats);
614 av_freep(&(*constraints)->valid_sw_formats);
615 }
616 av_freep(constraints);
617 }
618
619 int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type,
620 const char *device, AVDictionary *opts, int flags)
621 {
622 AVBufferRef *device_ref = NULL;
623 AVHWDeviceContext *device_ctx;
624 int ret = 0;
625
626 device_ref = av_hwdevice_ctx_alloc(type);
627 if (!device_ref) {
628 ret = AVERROR(ENOMEM);
629 goto fail;
630 }
631 device_ctx = (AVHWDeviceContext*)device_ref->data;
632
633 if (!device_ctx->internal->hw_type->device_create) {
634 ret = AVERROR(ENOSYS);
635 goto fail;
636 }
637
638 ret = device_ctx->internal->hw_type->device_create(device_ctx, device,
639 opts, flags);
640 if (ret < 0)
641 goto fail;
642
643 ret = av_hwdevice_ctx_init(device_ref);
644 if (ret < 0)
645 goto fail;
646
647 *pdevice_ref = device_ref;
648 return 0;
649 fail:
650 av_buffer_unref(&device_ref);
651 *pdevice_ref = NULL;
652 return ret;
653 }
654
655 int av_hwdevice_ctx_create_derived_opts(AVBufferRef **dst_ref_ptr,
656 enum AVHWDeviceType type,
657 AVBufferRef *src_ref,
658 AVDictionary *options, int flags)
659 {
660 AVBufferRef *dst_ref = NULL, *tmp_ref;
661 AVHWDeviceContext *dst_ctx, *tmp_ctx;
662 int ret = 0;
663
664 tmp_ref = src_ref;
665 while (tmp_ref) {
666 tmp_ctx = (AVHWDeviceContext*)tmp_ref->data;
667 if (tmp_ctx->type == type) {
668 dst_ref = av_buffer_ref(tmp_ref);
669 if (!dst_ref) {
670 ret = AVERROR(ENOMEM);
671 goto fail;
672 }
673 goto done;
674 }
675 tmp_ref = tmp_ctx->internal->source_device;
676 }
677
678 dst_ref = av_hwdevice_ctx_alloc(type);
679 if (!dst_ref) {
680 ret = AVERROR(ENOMEM);
681 goto fail;
682 }
683 dst_ctx = (AVHWDeviceContext*)dst_ref->data;
684
685 tmp_ref = src_ref;
686 while (tmp_ref) {
687 tmp_ctx = (AVHWDeviceContext*)tmp_ref->data;
688 if (dst_ctx->internal->hw_type->device_derive) {
689 ret = dst_ctx->internal->hw_type->device_derive(dst_ctx,
690 tmp_ctx,
691 options,
692 flags);
693 if (ret == 0) {
694 dst_ctx->internal->source_device = av_buffer_ref(src_ref);
695 if (!dst_ctx->internal->source_device) {
696 ret = AVERROR(ENOMEM);
697 goto fail;
698 }
699 ret = av_hwdevice_ctx_init(dst_ref);
700 if (ret < 0)
701 goto fail;
702 goto done;
703 }
704 if (ret != AVERROR(ENOSYS))
705 goto fail;
706 }
707 tmp_ref = tmp_ctx->internal->source_device;
708 }
709
710 ret = AVERROR(ENOSYS);
711 goto fail;
712
713 done:
714 *dst_ref_ptr = dst_ref;
715 return 0;
716
717 fail:
718 av_buffer_unref(&dst_ref);
719 *dst_ref_ptr = NULL;
720 return ret;
721 }
722
723 int av_hwdevice_ctx_create_derived(AVBufferRef **dst_ref_ptr,
724 enum AVHWDeviceType type,
725 AVBufferRef *src_ref, int flags)
726 {
727 return av_hwdevice_ctx_create_derived_opts(dst_ref_ptr, type, src_ref,
728 NULL, flags);
729 }
730
731 static void ff_hwframe_unmap(void *opaque, uint8_t *data)
732 {
733 HWMapDescriptor *hwmap = (HWMapDescriptor*)data;
734 AVHWFramesContext *ctx = opaque;
735
736 if (hwmap->unmap)
737 hwmap->unmap(ctx, hwmap);
738
739 av_frame_free(&hwmap->source);
740
741 av_buffer_unref(&hwmap->hw_frames_ctx);
742
743 av_free(hwmap);
744 }
745
746 int ff_hwframe_map_create(AVBufferRef *hwframe_ref,
747 AVFrame *dst, const AVFrame *src,
748 void (*unmap)(AVHWFramesContext *ctx,
749 HWMapDescriptor *hwmap),
750 void *priv)
751 {
752 AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
753 HWMapDescriptor *hwmap;
754 int ret;
755
756 hwmap = av_mallocz(sizeof(*hwmap));
757 if (!hwmap) {
758 ret = AVERROR(ENOMEM);
759 goto fail;
760 }
761
762 hwmap->source = av_frame_alloc();
763 if (!hwmap->source) {
764 ret = AVERROR(ENOMEM);
765 goto fail;
766 }
767 ret = av_frame_ref(hwmap->source, src);
768 if (ret < 0)
769 goto fail;
770
771 hwmap->hw_frames_ctx = av_buffer_ref(hwframe_ref);
772 if (!hwmap->hw_frames_ctx) {
773 ret = AVERROR(ENOMEM);
774 goto fail;
775 }
776
777 hwmap->unmap = unmap;
778 hwmap->priv = priv;
779
780 dst->buf[0] = av_buffer_create((uint8_t*)hwmap, sizeof(*hwmap),
781 &ff_hwframe_unmap, ctx, 0);
782 if (!dst->buf[0]) {
783 ret = AVERROR(ENOMEM);
784 goto fail;
785 }
786
787 return 0;
788
789 fail:
790 if (hwmap) {
791 av_buffer_unref(&hwmap->hw_frames_ctx);
792 av_frame_free(&hwmap->source);
793 }
794 av_free(hwmap);
795 return ret;
796 }
797
798 int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
799 {
800 AVBufferRef *orig_dst_frames = dst->hw_frames_ctx;
801 enum AVPixelFormat orig_dst_fmt = dst->format;
802 AVHWFramesContext *src_frames, *dst_frames;
803 HWMapDescriptor *hwmap;
804 int ret;
805
806 if (src->hw_frames_ctx && dst->hw_frames_ctx) {
807 src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data;
808 dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data;
809
810 if ((src_frames == dst_frames &&
811 src->format == dst_frames->sw_format &&
812 dst->format == dst_frames->format) ||
813 (src_frames->internal->source_frames &&
814 src_frames->internal->source_frames->data ==
815 (uint8_t*)dst_frames)) {
816 // This is an unmap operation. We don't need to directly
817 // do anything here other than fill in the original frame,
818 // because the real unmap will be invoked when the last
819 // reference to the mapped frame disappears.
820 if (!src->buf[0]) {
821 av_log(src_frames, AV_LOG_ERROR, "Invalid mapping "
822 "found when attempting unmap.\n");
823 return AVERROR(EINVAL);
824 }
825 hwmap = (HWMapDescriptor*)src->buf[0]->data;
826 return av_frame_replace(dst, hwmap->source);
827 }
828 }
829
830 if (src->hw_frames_ctx) {
831 src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data;
832
833 if (src_frames->format == src->format &&
834 src_frames->internal->hw_type->map_from) {
835 ret = src_frames->internal->hw_type->map_from(src_frames,
836 dst, src, flags);
837 if (ret >= 0)
838 return ret;
839 else if (ret != AVERROR(ENOSYS))
840 goto fail;
841 }
842 }
843
844 if (dst->hw_frames_ctx) {
845 dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data;
846
847 if (dst_frames->format == dst->format &&
848 dst_frames->internal->hw_type->map_to) {
849 ret = dst_frames->internal->hw_type->map_to(dst_frames,
850 dst, src, flags);
851 if (ret >= 0)
852 return ret;
853 else if (ret != AVERROR(ENOSYS))
854 goto fail;
855 }
856 }
857
858 return AVERROR(ENOSYS);
859
860 fail:
861 // if the caller provided dst frames context, it should be preserved
862 // by this function
863 av_assert0(orig_dst_frames == NULL ||
864 orig_dst_frames == dst->hw_frames_ctx);
865
866 // preserve user-provided dst frame fields, but clean
867 // anything we might have set
868 dst->hw_frames_ctx = NULL;
869 av_frame_unref(dst);
870
871 dst->hw_frames_ctx = orig_dst_frames;
872 dst->format = orig_dst_fmt;
873
874 return ret;
875 }
876
877 int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx,
878 enum AVPixelFormat format,
879 AVBufferRef *derived_device_ctx,
880 AVBufferRef *source_frame_ctx,
881 int flags)
882 {
883 AVBufferRef *dst_ref = NULL;
884 AVHWFramesContext *dst = NULL;
885 AVHWFramesContext *src = (AVHWFramesContext*)source_frame_ctx->data;
886 int ret;
887
888 if (src->internal->source_frames) {
889 AVHWFramesContext *src_src =
890 (AVHWFramesContext*)src->internal->source_frames->data;
891 AVHWDeviceContext *dst_dev =
892 (AVHWDeviceContext*)derived_device_ctx->data;
893
894 if (src_src->device_ctx == dst_dev) {
895 // This is actually an unmapping, so we just return a
896 // reference to the source frame context.
897 *derived_frame_ctx =
898 av_buffer_ref(src->internal->source_frames);
899 if (!*derived_frame_ctx) {
900 ret = AVERROR(ENOMEM);
901 goto fail;
902 }
903 return 0;
904 }
905 }
906
907 dst_ref = av_hwframe_ctx_alloc(derived_device_ctx);
908 if (!dst_ref) {
909 ret = AVERROR(ENOMEM);
910 goto fail;
911 }
912
913 dst = (AVHWFramesContext*)dst_ref->data;
914
915 dst->format = format;
916 dst->sw_format = src->sw_format;
917 dst->width = src->width;
918 dst->height = src->height;
919
920 dst->internal->source_frames = av_buffer_ref(source_frame_ctx);
921 if (!dst->internal->source_frames) {
922 ret = AVERROR(ENOMEM);
923 goto fail;
924 }
925
926 dst->internal->source_allocation_map_flags =
927 flags & (AV_HWFRAME_MAP_READ |
928 AV_HWFRAME_MAP_WRITE |
929 AV_HWFRAME_MAP_OVERWRITE |
930 AV_HWFRAME_MAP_DIRECT);
931
932 ret = AVERROR(ENOSYS);
933 if (src->internal->hw_type->frames_derive_from)
934 ret = src->internal->hw_type->frames_derive_from(dst, src, flags);
935 if (ret == AVERROR(ENOSYS) &&
936 dst->internal->hw_type->frames_derive_to)
937 ret = dst->internal->hw_type->frames_derive_to(dst, src, flags);
938 if (ret == AVERROR(ENOSYS))
939 ret = 0;
940 if (ret)
941 goto fail;
942
943 *derived_frame_ctx = dst_ref;
944 return 0;
945
946 fail:
947 if (dst)
948 av_buffer_unref(&dst->internal->source_frames);
949 av_buffer_unref(&dst_ref);
950 return ret;
951 }
952
953 int ff_hwframe_map_replace(AVFrame *dst, const AVFrame *src)
954 {
955 HWMapDescriptor *hwmap = (HWMapDescriptor*)dst->buf[0]->data;
956 return av_frame_replace(hwmap->source, src);
957 }
958