]> git.sesse.net Git - ffmpeg/blob - libavutil/hwcontext.c
configure: Simplify and fix avfoundation indev handling
[ffmpeg] / libavutil / hwcontext.c
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[] = {
32 #if CONFIG_CUDA
33     &ff_hwcontext_type_cuda,
34 #endif
35 #if CONFIG_DXVA2
36     &ff_hwcontext_type_dxva2,
37 #endif
38 #if CONFIG_LIBMFX
39     &ff_hwcontext_type_qsv,
40 #endif
41 #if CONFIG_VAAPI
42     &ff_hwcontext_type_vaapi,
43 #endif
44 #if CONFIG_VDPAU
45     &ff_hwcontext_type_vdpau,
46 #endif
47     NULL,
48 };
49
50 static const AVClass hwdevice_ctx_class = {
51     .class_name = "AVHWDeviceContext",
52     .item_name  = av_default_item_name,
53     .version    = LIBAVUTIL_VERSION_INT,
54 };
55
56 static void hwdevice_ctx_free(void *opaque, uint8_t *data)
57 {
58     AVHWDeviceContext *ctx = (AVHWDeviceContext*)data;
59
60     /* uninit might still want access the hw context and the user
61      * free() callback might destroy it, so uninit has to be called first */
62     if (ctx->internal->hw_type->device_uninit)
63         ctx->internal->hw_type->device_uninit(ctx);
64
65     if (ctx->free)
66         ctx->free(ctx);
67
68     av_freep(&ctx->hwctx);
69     av_freep(&ctx->internal->priv);
70     av_freep(&ctx->internal);
71     av_freep(&ctx);
72 }
73
74 AVBufferRef *av_hwdevice_ctx_alloc(enum AVHWDeviceType type)
75 {
76     AVHWDeviceContext *ctx;
77     AVBufferRef *buf;
78     const HWContextType *hw_type = NULL;
79     int i;
80
81     for (i = 0; hw_table[i]; i++) {
82         if (hw_table[i]->type == type) {
83             hw_type = hw_table[i];
84             break;
85         }
86     }
87     if (!hw_type)
88         return NULL;
89
90     ctx = av_mallocz(sizeof(*ctx));
91     if (!ctx)
92         return NULL;
93
94     ctx->internal = av_mallocz(sizeof(*ctx->internal));
95     if (!ctx->internal)
96         goto fail;
97
98     if (hw_type->device_priv_size) {
99         ctx->internal->priv = av_mallocz(hw_type->device_priv_size);
100         if (!ctx->internal->priv)
101             goto fail;
102     }
103
104     if (hw_type->device_hwctx_size) {
105         ctx->hwctx = av_mallocz(hw_type->device_hwctx_size);
106         if (!ctx->hwctx)
107             goto fail;
108     }
109
110     buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),
111                            hwdevice_ctx_free, NULL,
112                            AV_BUFFER_FLAG_READONLY);
113     if (!buf)
114         goto fail;
115
116     ctx->type     = type;
117     ctx->av_class = &hwdevice_ctx_class;
118
119     ctx->internal->hw_type = hw_type;
120
121     return buf;
122
123 fail:
124     if (ctx->internal)
125         av_freep(&ctx->internal->priv);
126     av_freep(&ctx->internal);
127     av_freep(&ctx->hwctx);
128     av_freep(&ctx);
129     return NULL;
130 }
131
132 int av_hwdevice_ctx_init(AVBufferRef *ref)
133 {
134     AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data;
135     int ret;
136
137     if (ctx->internal->hw_type->device_init) {
138         ret = ctx->internal->hw_type->device_init(ctx);
139         if (ret < 0)
140             goto fail;
141     }
142
143     return 0;
144 fail:
145     if (ctx->internal->hw_type->device_uninit)
146         ctx->internal->hw_type->device_uninit(ctx);
147     return ret;
148 }
149
150 static const AVClass hwframe_ctx_class = {
151     .class_name = "AVHWFramesContext",
152     .item_name  = av_default_item_name,
153     .version    = LIBAVUTIL_VERSION_INT,
154 };
155
156 static void hwframe_ctx_free(void *opaque, uint8_t *data)
157 {
158     AVHWFramesContext *ctx = (AVHWFramesContext*)data;
159
160     if (ctx->internal->source_frames) {
161         av_buffer_unref(&ctx->internal->source_frames);
162
163     } else {
164         if (ctx->internal->pool_internal)
165             av_buffer_pool_uninit(&ctx->internal->pool_internal);
166
167         if (ctx->internal->hw_type->frames_uninit)
168             ctx->internal->hw_type->frames_uninit(ctx);
169
170         if (ctx->free)
171             ctx->free(ctx);
172     }
173
174     av_buffer_unref(&ctx->device_ref);
175
176     av_freep(&ctx->hwctx);
177     av_freep(&ctx->internal->priv);
178     av_freep(&ctx->internal);
179     av_freep(&ctx);
180 }
181
182 AVBufferRef *av_hwframe_ctx_alloc(AVBufferRef *device_ref_in)
183 {
184     AVHWDeviceContext *device_ctx = (AVHWDeviceContext*)device_ref_in->data;
185     const HWContextType  *hw_type = device_ctx->internal->hw_type;
186     AVHWFramesContext *ctx;
187     AVBufferRef *buf, *device_ref = NULL;;
188
189     ctx = av_mallocz(sizeof(*ctx));
190     if (!ctx)
191         return NULL;
192
193     ctx->internal = av_mallocz(sizeof(*ctx->internal));
194     if (!ctx->internal)
195         goto fail;
196
197     if (hw_type->frames_priv_size) {
198         ctx->internal->priv = av_mallocz(hw_type->frames_priv_size);
199         if (!ctx->internal->priv)
200             goto fail;
201     }
202
203     if (hw_type->frames_hwctx_size) {
204         ctx->hwctx = av_mallocz(hw_type->frames_hwctx_size);
205         if (!ctx->hwctx)
206             goto fail;
207     }
208
209     device_ref = av_buffer_ref(device_ref_in);
210     if (!device_ref)
211         goto fail;
212
213     buf = av_buffer_create((uint8_t*)ctx, sizeof(*ctx),
214                            hwframe_ctx_free, NULL,
215                            AV_BUFFER_FLAG_READONLY);
216     if (!buf)
217         goto fail;
218
219     ctx->av_class   = &hwframe_ctx_class;
220     ctx->device_ref = device_ref;
221     ctx->device_ctx = device_ctx;
222     ctx->format     = AV_PIX_FMT_NONE;
223     ctx->sw_format  = AV_PIX_FMT_NONE;
224
225     ctx->internal->hw_type = hw_type;
226
227     return buf;
228
229 fail:
230     if (device_ref)
231         av_buffer_unref(&device_ref);
232     if (ctx->internal)
233         av_freep(&ctx->internal->priv);
234     av_freep(&ctx->internal);
235     av_freep(&ctx->hwctx);
236     av_freep(&ctx);
237     return NULL;
238 }
239
240 static int hwframe_pool_prealloc(AVBufferRef *ref)
241 {
242     AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data;
243     AVFrame **frames;
244     int i, ret = 0;
245
246     frames = av_mallocz_array(ctx->initial_pool_size, sizeof(*frames));
247     if (!frames)
248         return AVERROR(ENOMEM);
249
250     for (i = 0; i < ctx->initial_pool_size; i++) {
251         frames[i] = av_frame_alloc();
252         if (!frames[i])
253             goto fail;
254
255         ret = av_hwframe_get_buffer(ref, frames[i], 0);
256         if (ret < 0)
257             goto fail;
258     }
259
260 fail:
261     for (i = 0; i < ctx->initial_pool_size; i++)
262         av_frame_free(&frames[i]);
263     av_freep(&frames);
264
265     return ret;
266 }
267
268 int av_hwframe_ctx_init(AVBufferRef *ref)
269 {
270     AVHWFramesContext *ctx = (AVHWFramesContext*)ref->data;
271     const enum AVPixelFormat *pix_fmt;
272     int ret;
273
274     if (ctx->internal->source_frames) {
275         /* A derived frame context is already initialised. */
276         return 0;
277     }
278
279     /* validate the pixel format */
280     for (pix_fmt = ctx->internal->hw_type->pix_fmts; *pix_fmt != AV_PIX_FMT_NONE; pix_fmt++) {
281         if (*pix_fmt == ctx->format)
282             break;
283     }
284     if (*pix_fmt == AV_PIX_FMT_NONE) {
285         av_log(ctx, AV_LOG_ERROR,
286                "The hardware pixel format '%s' is not supported by the device type '%s'\n",
287                av_get_pix_fmt_name(ctx->format), ctx->internal->hw_type->name);
288         return AVERROR(ENOSYS);
289     }
290
291     /* validate the dimensions */
292     ret = av_image_check_size(ctx->width, ctx->height, 0, ctx);
293     if (ret < 0)
294         return ret;
295
296     /* format-specific init */
297     if (ctx->internal->hw_type->frames_init) {
298         ret = ctx->internal->hw_type->frames_init(ctx);
299         if (ret < 0)
300             goto fail;
301     }
302
303     if (ctx->internal->pool_internal && !ctx->pool)
304         ctx->pool = ctx->internal->pool_internal;
305
306     /* preallocate the frames in the pool, if requested */
307     if (ctx->initial_pool_size > 0) {
308         ret = hwframe_pool_prealloc(ref);
309         if (ret < 0)
310             goto fail;
311     }
312
313     return 0;
314 fail:
315     if (ctx->internal->hw_type->frames_uninit)
316         ctx->internal->hw_type->frames_uninit(ctx);
317     return ret;
318 }
319
320 int av_hwframe_transfer_get_formats(AVBufferRef *hwframe_ref,
321                                     enum AVHWFrameTransferDirection dir,
322                                     enum AVPixelFormat **formats, int flags)
323 {
324     AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
325
326     if (!ctx->internal->hw_type->transfer_get_formats)
327         return AVERROR(ENOSYS);
328
329     return ctx->internal->hw_type->transfer_get_formats(ctx, dir, formats);
330 }
331
332 static int transfer_data_alloc(AVFrame *dst, const AVFrame *src, int flags)
333 {
334     AVHWFramesContext *ctx = (AVHWFramesContext*)src->hw_frames_ctx->data;
335     AVFrame *frame_tmp;
336     int ret = 0;
337
338     frame_tmp = av_frame_alloc();
339     if (!frame_tmp)
340         return AVERROR(ENOMEM);
341
342     /* if the format is set, use that
343      * otherwise pick the first supported one */
344     if (dst->format >= 0) {
345         frame_tmp->format = dst->format;
346     } else {
347         enum AVPixelFormat *formats;
348
349         ret = av_hwframe_transfer_get_formats(src->hw_frames_ctx,
350                                               AV_HWFRAME_TRANSFER_DIRECTION_FROM,
351                                               &formats, 0);
352         if (ret < 0)
353             goto fail;
354         frame_tmp->format = formats[0];
355         av_freep(&formats);
356     }
357     frame_tmp->width  = ctx->width;
358     frame_tmp->height = ctx->height;
359
360     ret = av_frame_get_buffer(frame_tmp, 32);
361     if (ret < 0)
362         goto fail;
363
364     ret = av_hwframe_transfer_data(frame_tmp, src, flags);
365     if (ret < 0)
366         goto fail;
367
368     frame_tmp->width  = src->width;
369     frame_tmp->height = src->height;
370
371     av_frame_move_ref(dst, frame_tmp);
372
373 fail:
374     av_frame_free(&frame_tmp);
375     return ret;
376 }
377
378 int av_hwframe_transfer_data(AVFrame *dst, const AVFrame *src, int flags)
379 {
380     AVHWFramesContext *ctx;
381     int ret;
382
383     if (!dst->buf[0])
384         return transfer_data_alloc(dst, src, flags);
385
386     if (src->hw_frames_ctx) {
387         ctx = (AVHWFramesContext*)src->hw_frames_ctx->data;
388
389         ret = ctx->internal->hw_type->transfer_data_from(ctx, dst, src);
390         if (ret < 0)
391             return ret;
392     } else if (dst->hw_frames_ctx) {
393         ctx = (AVHWFramesContext*)dst->hw_frames_ctx->data;
394
395         ret = ctx->internal->hw_type->transfer_data_to(ctx, dst, src);
396         if (ret < 0)
397             return ret;
398     } else
399         return AVERROR(ENOSYS);
400
401     return 0;
402 }
403
404 int av_hwframe_get_buffer(AVBufferRef *hwframe_ref, AVFrame *frame, int flags)
405 {
406     AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
407     int ret;
408
409     if (ctx->internal->source_frames) {
410         // This is a derived frame context, so we allocate in the source
411         // and map the frame immediately.
412         AVFrame *src_frame;
413
414         src_frame = av_frame_alloc();
415         if (!src_frame)
416             return AVERROR(ENOMEM);
417
418         ret = av_hwframe_get_buffer(ctx->internal->source_frames,
419                                     src_frame, 0);
420         if (ret < 0)
421             return ret;
422
423         ret = av_hwframe_map(frame, src_frame, 0);
424         if (ret) {
425             av_log(ctx, AV_LOG_ERROR, "Failed to map frame into derived "
426                    "frame context: %d.\n", ret);
427             av_frame_free(&src_frame);
428             return ret;
429         }
430
431         // Free the source frame immediately - the mapped frame still
432         // contains a reference to it.
433         av_frame_free(&src_frame);
434
435         return 0;
436     }
437
438     if (!ctx->internal->hw_type->frames_get_buffer)
439         return AVERROR(ENOSYS);
440
441     if (!ctx->pool)
442         return AVERROR(EINVAL);
443
444     frame->hw_frames_ctx = av_buffer_ref(hwframe_ref);
445     if (!frame->hw_frames_ctx)
446         return AVERROR(ENOMEM);
447
448     ret = ctx->internal->hw_type->frames_get_buffer(ctx, frame);
449     if (ret < 0) {
450         av_buffer_unref(&frame->hw_frames_ctx);
451         return ret;
452     }
453
454     return 0;
455 }
456
457 void *av_hwdevice_hwconfig_alloc(AVBufferRef *ref)
458 {
459     AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data;
460     const HWContextType  *hw_type = ctx->internal->hw_type;
461
462     if (hw_type->device_hwconfig_size == 0)
463         return NULL;
464
465     return av_mallocz(hw_type->device_hwconfig_size);
466 }
467
468 AVHWFramesConstraints *av_hwdevice_get_hwframe_constraints(AVBufferRef *ref,
469                                                            const void *hwconfig)
470 {
471     AVHWDeviceContext *ctx = (AVHWDeviceContext*)ref->data;
472     const HWContextType  *hw_type = ctx->internal->hw_type;
473     AVHWFramesConstraints *constraints;
474
475     if (!hw_type->frames_get_constraints)
476         return NULL;
477
478     constraints = av_mallocz(sizeof(*constraints));
479     if (!constraints)
480         return NULL;
481
482     constraints->min_width = constraints->min_height = 0;
483     constraints->max_width = constraints->max_height = INT_MAX;
484
485     if (hw_type->frames_get_constraints(ctx, hwconfig, constraints) >= 0) {
486         return constraints;
487     } else {
488         av_hwframe_constraints_free(&constraints);
489         return NULL;
490     }
491 }
492
493 void av_hwframe_constraints_free(AVHWFramesConstraints **constraints)
494 {
495     if (*constraints) {
496         av_freep(&(*constraints)->valid_hw_formats);
497         av_freep(&(*constraints)->valid_sw_formats);
498     }
499     av_freep(constraints);
500 }
501
502 int av_hwdevice_ctx_create(AVBufferRef **pdevice_ref, enum AVHWDeviceType type,
503                            const char *device, AVDictionary *opts, int flags)
504 {
505     AVBufferRef *device_ref = NULL;
506     AVHWDeviceContext *device_ctx;
507     int ret = 0;
508
509     device_ref = av_hwdevice_ctx_alloc(type);
510     if (!device_ref) {
511         ret = AVERROR(ENOMEM);
512         goto fail;
513     }
514     device_ctx = (AVHWDeviceContext*)device_ref->data;
515
516     if (!device_ctx->internal->hw_type->device_create) {
517         ret = AVERROR(ENOSYS);
518         goto fail;
519     }
520
521     ret = device_ctx->internal->hw_type->device_create(device_ctx, device,
522                                                        opts, flags);
523     if (ret < 0)
524         goto fail;
525
526     ret = av_hwdevice_ctx_init(device_ref);
527     if (ret < 0)
528         goto fail;
529
530     *pdevice_ref = device_ref;
531     return 0;
532 fail:
533     av_buffer_unref(&device_ref);
534     *pdevice_ref = NULL;
535     return ret;
536 }
537
538 static void ff_hwframe_unmap(void *opaque, uint8_t *data)
539 {
540     HWMapDescriptor *hwmap = (HWMapDescriptor*)data;
541     AVHWFramesContext *ctx = opaque;
542
543     if (hwmap->unmap)
544         hwmap->unmap(ctx, hwmap);
545
546     av_frame_free(&hwmap->source);
547
548     av_buffer_unref(&hwmap->hw_frames_ctx);
549
550     av_free(hwmap);
551 }
552
553 int ff_hwframe_map_create(AVBufferRef *hwframe_ref,
554                           AVFrame *dst, const AVFrame *src,
555                           void (*unmap)(AVHWFramesContext *ctx,
556                                         HWMapDescriptor *hwmap),
557                           void *priv)
558 {
559     AVHWFramesContext *ctx = (AVHWFramesContext*)hwframe_ref->data;
560     HWMapDescriptor *hwmap;
561     int ret;
562
563     hwmap = av_mallocz(sizeof(*hwmap));
564     if (!hwmap) {
565         ret = AVERROR(ENOMEM);
566         goto fail;
567     }
568
569     hwmap->source = av_frame_alloc();
570     if (!hwmap->source) {
571         ret = AVERROR(ENOMEM);
572         goto fail;
573     }
574     ret = av_frame_ref(hwmap->source, src);
575     if (ret < 0)
576         goto fail;
577
578     hwmap->hw_frames_ctx = av_buffer_ref(hwframe_ref);
579     if (!hwmap->hw_frames_ctx) {
580         ret = AVERROR(ENOMEM);
581         goto fail;
582     }
583
584     hwmap->unmap = unmap;
585     hwmap->priv  = priv;
586
587     dst->buf[0] = av_buffer_create((uint8_t*)hwmap, sizeof(*hwmap),
588                                    &ff_hwframe_unmap, ctx, 0);
589     if (!dst->buf[0]) {
590         ret = AVERROR(ENOMEM);
591         goto fail;
592     }
593
594     return 0;
595
596 fail:
597     if (hwmap) {
598         av_buffer_unref(&hwmap->hw_frames_ctx);
599         av_frame_free(&hwmap->source);
600     }
601     av_free(hwmap);
602     return ret;
603 }
604
605 int av_hwframe_map(AVFrame *dst, const AVFrame *src, int flags)
606 {
607     AVHWFramesContext *src_frames, *dst_frames;
608     HWMapDescriptor *hwmap;
609     int ret;
610
611     if (src->hw_frames_ctx && dst->hw_frames_ctx) {
612         src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data;
613         dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data;
614
615         if ((src_frames == dst_frames &&
616              src->format == dst_frames->sw_format &&
617              dst->format == dst_frames->format) ||
618             (src_frames->internal->source_frames &&
619              src_frames->internal->source_frames->data ==
620              (uint8_t*)dst_frames)) {
621             // This is an unmap operation.  We don't need to directly
622             // do anything here other than fill in the original frame,
623             // because the real unmap will be invoked when the last
624             // reference to the mapped frame disappears.
625             if (!src->buf[0]) {
626                 av_log(src_frames, AV_LOG_ERROR, "Invalid mapping "
627                        "found when attempting unmap.\n");
628                 return AVERROR(EINVAL);
629             }
630             hwmap = (HWMapDescriptor*)src->buf[0]->data;
631             av_frame_unref(dst);
632             return av_frame_ref(dst, hwmap->source);
633         }
634     }
635
636     if (src->hw_frames_ctx) {
637         src_frames = (AVHWFramesContext*)src->hw_frames_ctx->data;
638
639         if (src_frames->format == src->format &&
640             src_frames->internal->hw_type->map_from) {
641             ret = src_frames->internal->hw_type->map_from(src_frames,
642                                                           dst, src, flags);
643             if (ret != AVERROR(ENOSYS))
644                 return ret;
645         }
646     }
647
648     if (dst->hw_frames_ctx) {
649         dst_frames = (AVHWFramesContext*)dst->hw_frames_ctx->data;
650
651         if (dst_frames->format == dst->format &&
652             dst_frames->internal->hw_type->map_to) {
653             ret = dst_frames->internal->hw_type->map_to(dst_frames,
654                                                         dst, src, flags);
655             if (ret != AVERROR(ENOSYS))
656                 return ret;
657         }
658     }
659
660     return AVERROR(ENOSYS);
661 }
662
663 int av_hwframe_ctx_create_derived(AVBufferRef **derived_frame_ctx,
664                                   enum AVPixelFormat format,
665                                   AVBufferRef *derived_device_ctx,
666                                   AVBufferRef *source_frame_ctx,
667                                   int flags)
668 {
669     AVBufferRef   *dst_ref = NULL;
670     AVHWFramesContext *dst = NULL;
671     AVHWFramesContext *src = (AVHWFramesContext*)source_frame_ctx->data;
672     int ret;
673
674     if (src->internal->source_frames) {
675         AVHWFramesContext *src_src =
676             (AVHWFramesContext*)src->internal->source_frames->data;
677         AVHWDeviceContext *dst_dev =
678             (AVHWDeviceContext*)derived_device_ctx->data;
679
680         if (src_src->device_ctx == dst_dev) {
681             // This is actually an unmapping, so we just return a
682             // reference to the source frame context.
683             *derived_frame_ctx =
684                 av_buffer_ref(src->internal->source_frames);
685             if (!*derived_frame_ctx) {
686                 ret = AVERROR(ENOMEM);
687                 goto fail;
688             }
689             return 0;
690         }
691     }
692
693     dst_ref = av_hwframe_ctx_alloc(derived_device_ctx);
694     if (!dst_ref) {
695         ret = AVERROR(ENOMEM);
696         goto fail;
697     }
698
699     dst = (AVHWFramesContext*)dst_ref->data;
700
701     dst->format    = format;
702     dst->sw_format = src->sw_format;
703     dst->width     = src->width;
704     dst->height    = src->height;
705
706     dst->internal->source_frames = av_buffer_ref(source_frame_ctx);
707     if (!dst->internal->source_frames) {
708         ret = AVERROR(ENOMEM);
709         goto fail;
710     }
711
712     ret = av_hwframe_ctx_init(dst_ref);
713     if (ret)
714         goto fail;
715
716     *derived_frame_ctx = dst_ref;
717     return 0;
718
719 fail:
720     if (dst)
721         av_buffer_unref(&dst->internal->source_frames);
722     av_buffer_unref(&dst_ref);
723     return ret;
724 }