2 * This file is part of FFmpeg.
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.
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.
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
24 #include <VideoToolbox/VideoToolbox.h>
27 #include "buffer_internal.h"
29 #include "hwcontext.h"
30 #include "hwcontext_internal.h"
31 #include "hwcontext_videotoolbox.h"
36 typedef struct VTFramesContext {
37 CVPixelBufferPoolRef pool;
43 enum AVPixelFormat pix_fmt;
45 { kCVPixelFormatType_420YpCbCr8Planar, false, AV_PIX_FMT_YUV420P },
46 { kCVPixelFormatType_422YpCbCr8, false, AV_PIX_FMT_UYVY422 },
47 { kCVPixelFormatType_32BGRA, true, AV_PIX_FMT_BGRA },
48 #ifdef kCFCoreFoundationVersionNumber10_7
49 { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, false, AV_PIX_FMT_NV12 },
50 { kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, true, AV_PIX_FMT_NV12 },
51 { kCVPixelFormatType_4444AYpCbCr16, false, AV_PIX_FMT_AYUV64 },
53 #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
54 { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange, false, AV_PIX_FMT_P010 },
55 { kCVPixelFormatType_420YpCbCr10BiPlanarFullRange, true, AV_PIX_FMT_P010 },
57 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
58 { kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange, false, AV_PIX_FMT_NV16 },
59 { kCVPixelFormatType_422YpCbCr8BiPlanarFullRange, true, AV_PIX_FMT_NV16 },
61 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
62 { kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange, false, AV_PIX_FMT_P210 },
63 { kCVPixelFormatType_422YpCbCr10BiPlanarFullRange, true, AV_PIX_FMT_P210 },
65 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
66 { kCVPixelFormatType_422YpCbCr16BiPlanarVideoRange, false, AV_PIX_FMT_P216 },
68 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
69 { kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange, false, AV_PIX_FMT_NV24 },
70 { kCVPixelFormatType_444YpCbCr8BiPlanarFullRange, true, AV_PIX_FMT_NV24 },
72 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
73 { kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange, false, AV_PIX_FMT_P410 },
74 { kCVPixelFormatType_444YpCbCr10BiPlanarFullRange, true, AV_PIX_FMT_P410 },
76 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
77 { kCVPixelFormatType_444YpCbCr16BiPlanarVideoRange, false, AV_PIX_FMT_P416 },
81 static const enum AVPixelFormat supported_formats[] = {
82 #ifdef kCFCoreFoundationVersionNumber10_7
88 #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
91 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
94 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
97 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
100 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
103 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
106 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
112 static int vt_frames_get_constraints(AVHWDeviceContext *ctx,
113 const void *hwconfig,
114 AVHWFramesConstraints *constraints)
118 constraints->valid_sw_formats = av_malloc_array(FF_ARRAY_ELEMS(supported_formats) + 1,
119 sizeof(*constraints->valid_sw_formats));
120 if (!constraints->valid_sw_formats)
121 return AVERROR(ENOMEM);
123 for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++)
124 constraints->valid_sw_formats[i] = supported_formats[i];
125 constraints->valid_sw_formats[FF_ARRAY_ELEMS(supported_formats)] = AV_PIX_FMT_NONE;
127 constraints->valid_hw_formats = av_malloc_array(2, sizeof(*constraints->valid_hw_formats));
128 if (!constraints->valid_hw_formats)
129 return AVERROR(ENOMEM);
131 constraints->valid_hw_formats[0] = AV_PIX_FMT_VIDEOTOOLBOX;
132 constraints->valid_hw_formats[1] = AV_PIX_FMT_NONE;
137 enum AVPixelFormat av_map_videotoolbox_format_to_pixfmt(uint32_t cv_fmt)
140 for (i = 0; i < FF_ARRAY_ELEMS(cv_pix_fmts); i++) {
141 if (cv_pix_fmts[i].cv_fmt == cv_fmt)
142 return cv_pix_fmts[i].pix_fmt;
144 return AV_PIX_FMT_NONE;
147 uint32_t av_map_videotoolbox_format_from_pixfmt(enum AVPixelFormat pix_fmt)
149 return av_map_videotoolbox_format_from_pixfmt2(pix_fmt, false);
152 uint32_t av_map_videotoolbox_format_from_pixfmt2(enum AVPixelFormat pix_fmt, bool full_range)
155 for (i = 0; i < FF_ARRAY_ELEMS(cv_pix_fmts); i++) {
156 if (cv_pix_fmts[i].pix_fmt == pix_fmt && cv_pix_fmts[i].full_range == full_range)
157 return cv_pix_fmts[i].cv_fmt;
162 static int vt_pool_alloc(AVHWFramesContext *ctx)
164 VTFramesContext *fctx = ctx->internal->priv;
166 CFNumberRef w, h, pixfmt;
168 CFMutableDictionaryRef attributes, iosurface_properties;
170 attributes = CFDictionaryCreateMutable(
173 &kCFTypeDictionaryKeyCallBacks,
174 &kCFTypeDictionaryValueCallBacks);
176 cv_pixfmt = av_map_videotoolbox_format_from_pixfmt(ctx->sw_format);
177 pixfmt = CFNumberCreate(NULL, kCFNumberSInt32Type, &cv_pixfmt);
178 CFDictionarySetValue(
180 kCVPixelBufferPixelFormatTypeKey,
184 iosurface_properties = CFDictionaryCreateMutable(
187 &kCFTypeDictionaryKeyCallBacks,
188 &kCFTypeDictionaryValueCallBacks);
189 CFDictionarySetValue(attributes, kCVPixelBufferIOSurfacePropertiesKey, iosurface_properties);
190 CFRelease(iosurface_properties);
192 w = CFNumberCreate(NULL, kCFNumberSInt32Type, &ctx->width);
193 h = CFNumberCreate(NULL, kCFNumberSInt32Type, &ctx->height);
194 CFDictionarySetValue(attributes, kCVPixelBufferWidthKey, w);
195 CFDictionarySetValue(attributes, kCVPixelBufferHeightKey, h);
199 err = CVPixelBufferPoolCreate(
204 CFRelease(attributes);
206 if (err == kCVReturnSuccess)
209 av_log(ctx, AV_LOG_ERROR, "Error creating CVPixelBufferPool: %d\n", err);
210 return AVERROR_EXTERNAL;
213 static void videotoolbox_buffer_release(void *opaque, uint8_t *data)
215 CVPixelBufferRelease((CVPixelBufferRef)data);
218 static AVBufferRef *vt_pool_alloc_buffer(void *opaque, size_t size)
220 CVPixelBufferRef pixbuf;
223 AVHWFramesContext *ctx = opaque;
224 VTFramesContext *fctx = ctx->internal->priv;
226 err = CVPixelBufferPoolCreatePixelBuffer(
231 if (err != kCVReturnSuccess) {
232 av_log(ctx, AV_LOG_ERROR, "Failed to create pixel buffer from pool: %d\n", err);
236 buf = av_buffer_create((uint8_t *)pixbuf, size,
237 videotoolbox_buffer_release, NULL, 0);
239 CVPixelBufferRelease(pixbuf);
245 static void vt_frames_uninit(AVHWFramesContext *ctx)
247 VTFramesContext *fctx = ctx->internal->priv;
249 CVPixelBufferPoolRelease(fctx->pool);
254 static int vt_frames_init(AVHWFramesContext *ctx)
258 for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) {
259 if (ctx->sw_format == supported_formats[i])
262 if (i == FF_ARRAY_ELEMS(supported_formats)) {
263 av_log(ctx, AV_LOG_ERROR, "Pixel format '%s' is not supported\n",
264 av_get_pix_fmt_name(ctx->sw_format));
265 return AVERROR(ENOSYS);
269 ctx->internal->pool_internal = av_buffer_pool_init2(
270 sizeof(CVPixelBufferRef), ctx, vt_pool_alloc_buffer, NULL);
271 if (!ctx->internal->pool_internal)
272 return AVERROR(ENOMEM);
275 ret = vt_pool_alloc(ctx);
282 static int vt_get_buffer(AVHWFramesContext *ctx, AVFrame *frame)
284 frame->buf[0] = av_buffer_pool_get(ctx->pool);
286 return AVERROR(ENOMEM);
288 frame->data[3] = frame->buf[0]->data;
289 frame->format = AV_PIX_FMT_VIDEOTOOLBOX;
290 frame->width = ctx->width;
291 frame->height = ctx->height;
296 static int vt_transfer_get_formats(AVHWFramesContext *ctx,
297 enum AVHWFrameTransferDirection dir,
298 enum AVPixelFormat **formats)
300 enum AVPixelFormat *fmts = av_malloc_array(2, sizeof(*fmts));
302 return AVERROR(ENOMEM);
304 fmts[0] = ctx->sw_format;
305 fmts[1] = AV_PIX_FMT_NONE;
311 static void vt_unmap(AVHWFramesContext *ctx, HWMapDescriptor *hwmap)
313 CVPixelBufferRef pixbuf = (CVPixelBufferRef)hwmap->source->data[3];
315 CVPixelBufferUnlockBaseAddress(pixbuf, (uintptr_t)hwmap->priv);
318 static int vt_pixbuf_set_par(void *log_ctx,
319 CVPixelBufferRef pixbuf, const AVFrame *src)
321 CFMutableDictionaryRef par = NULL;
322 CFNumberRef num = NULL, den = NULL;
323 AVRational avpar = src->sample_aspect_ratio;
328 av_reduce(&avpar.num, &avpar.den,
329 avpar.num, avpar.den,
332 num = CFNumberCreate(kCFAllocatorDefault,
336 den = CFNumberCreate(kCFAllocatorDefault,
340 par = CFDictionaryCreateMutable(kCFAllocatorDefault,
342 &kCFCopyStringDictionaryKeyCallBacks,
343 &kCFTypeDictionaryValueCallBacks);
345 if (!par || !num || !den) {
346 if (par) CFRelease(par);
347 if (num) CFRelease(num);
348 if (den) CFRelease(den);
349 return AVERROR(ENOMEM);
352 CFDictionarySetValue(
354 kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
356 CFDictionarySetValue(
358 kCVImageBufferPixelAspectRatioVerticalSpacingKey,
361 CVBufferSetAttachment(
363 kCVImageBufferPixelAspectRatioKey,
365 kCVAttachmentMode_ShouldPropagate
375 CFStringRef av_map_videotoolbox_chroma_loc_from_av(enum AVChromaLocation loc)
378 case AVCHROMA_LOC_LEFT:
379 return kCVImageBufferChromaLocation_Left;
380 case AVCHROMA_LOC_CENTER:
381 return kCVImageBufferChromaLocation_Center;
382 case AVCHROMA_LOC_TOP:
383 return kCVImageBufferChromaLocation_Top;
384 case AVCHROMA_LOC_BOTTOM:
385 return kCVImageBufferChromaLocation_Bottom;
386 case AVCHROMA_LOC_TOPLEFT:
387 return kCVImageBufferChromaLocation_TopLeft;
388 case AVCHROMA_LOC_BOTTOMLEFT:
389 return kCVImageBufferChromaLocation_BottomLeft;
395 static int vt_pixbuf_set_chromaloc(void *log_ctx,
396 CVPixelBufferRef pixbuf, const AVFrame *src)
398 CFStringRef loc = av_map_videotoolbox_chroma_loc_from_av(src->chroma_location);
401 CVBufferSetAttachment(
403 kCVImageBufferChromaLocationTopFieldKey,
405 kCVAttachmentMode_ShouldPropagate);
411 CFStringRef av_map_videotoolbox_color_matrix_from_av(enum AVColorSpace space)
414 case AVCOL_SPC_BT2020_CL:
415 case AVCOL_SPC_BT2020_NCL:
416 #if HAVE_KCVIMAGEBUFFERYCBCRMATRIX_ITU_R_2020
417 if (__builtin_available(macOS 10.11, iOS 9, *))
418 return kCVImageBufferYCbCrMatrix_ITU_R_2020;
420 return CFSTR("ITU_R_2020");
421 case AVCOL_SPC_BT470BG:
422 case AVCOL_SPC_SMPTE170M:
423 return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
424 case AVCOL_SPC_BT709:
425 return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
426 case AVCOL_SPC_SMPTE240M:
427 return kCVImageBufferYCbCrMatrix_SMPTE_240M_1995;
429 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
430 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
431 return CVYCbCrMatrixGetStringForIntegerCodePoint(space);
433 case AVCOL_SPC_UNSPECIFIED:
438 CFStringRef av_map_videotoolbox_color_primaries_from_av(enum AVColorPrimaries pri)
441 case AVCOL_PRI_BT2020:
442 #if HAVE_KCVIMAGEBUFFERCOLORPRIMARIES_ITU_R_2020
443 if (__builtin_available(macOS 10.11, iOS 9, *))
444 return kCVImageBufferColorPrimaries_ITU_R_2020;
446 return CFSTR("ITU_R_2020");
447 case AVCOL_PRI_BT709:
448 return kCVImageBufferColorPrimaries_ITU_R_709_2;
449 case AVCOL_PRI_SMPTE170M:
450 return kCVImageBufferColorPrimaries_SMPTE_C;
451 case AVCOL_PRI_BT470BG:
452 return kCVImageBufferColorPrimaries_EBU_3213;
454 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
455 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
456 return CVColorPrimariesGetStringForIntegerCodePoint(pri);
458 case AVCOL_PRI_UNSPECIFIED:
463 CFStringRef av_map_videotoolbox_color_trc_from_av(enum AVColorTransferCharacteristic trc)
467 case AVCOL_TRC_SMPTE2084:
468 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_2084_PQ
469 if (__builtin_available(macOS 10.13, iOS 11, *))
470 return kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ;
472 return CFSTR("SMPTE_ST_2084_PQ");
473 case AVCOL_TRC_BT2020_10:
474 case AVCOL_TRC_BT2020_12:
475 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2020
476 if (__builtin_available(macOS 10.11, iOS 9, *))
477 return kCVImageBufferTransferFunction_ITU_R_2020;
479 return CFSTR("ITU_R_2020");
480 case AVCOL_TRC_BT709:
481 return kCVImageBufferTransferFunction_ITU_R_709_2;
482 case AVCOL_TRC_SMPTE240M:
483 return kCVImageBufferTransferFunction_SMPTE_240M_1995;
484 case AVCOL_TRC_SMPTE428:
485 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_428_1
486 if (__builtin_available(macOS 10.12, iOS 10, *))
487 return kCVImageBufferTransferFunction_SMPTE_ST_428_1;
489 return CFSTR("SMPTE_ST_428_1");
490 case AVCOL_TRC_ARIB_STD_B67:
491 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
492 if (__builtin_available(macOS 10.13, iOS 11, *))
493 return kCVImageBufferTransferFunction_ITU_R_2100_HLG;
495 return CFSTR("ITU_R_2100_HLG");
496 case AVCOL_TRC_GAMMA22:
497 return kCVImageBufferTransferFunction_UseGamma;
498 case AVCOL_TRC_GAMMA28:
499 return kCVImageBufferTransferFunction_UseGamma;
501 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
502 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
503 return CVTransferFunctionGetStringForIntegerCodePoint(trc);
505 case AVCOL_TRC_UNSPECIFIED:
510 static int vt_pixbuf_set_colorspace(void *log_ctx,
511 CVPixelBufferRef pixbuf, const AVFrame *src)
513 CFStringRef colormatrix = NULL, colorpri = NULL, colortrc = NULL;
516 colormatrix = av_map_videotoolbox_color_matrix_from_av(src->colorspace);
517 if (!colormatrix && src->colorspace != AVCOL_SPC_UNSPECIFIED)
518 av_log(log_ctx, AV_LOG_WARNING, "Color space %s is not supported.\n", av_color_space_name(src->colorspace));
520 colorpri = av_map_videotoolbox_color_primaries_from_av(src->color_primaries);
521 if (!colorpri && src->color_primaries != AVCOL_PRI_UNSPECIFIED)
522 av_log(log_ctx, AV_LOG_WARNING, "Color primaries %s is not supported.\n", av_color_primaries_name(src->color_primaries));
524 colortrc = av_map_videotoolbox_color_trc_from_av(src->color_trc);
525 if (!colortrc && src->color_trc != AVCOL_TRC_UNSPECIFIED)
526 av_log(log_ctx, AV_LOG_WARNING, "Color transfer function %s is not supported.\n", av_color_transfer_name(src->color_trc));
528 if (src->color_trc == AVCOL_TRC_GAMMA22)
530 else if (src->color_trc == AVCOL_TRC_GAMMA28)
534 CVBufferSetAttachment(
536 kCVImageBufferYCbCrMatrixKey,
538 kCVAttachmentMode_ShouldPropagate);
541 CVBufferSetAttachment(
543 kCVImageBufferColorPrimariesKey,
545 kCVAttachmentMode_ShouldPropagate);
548 CVBufferSetAttachment(
550 kCVImageBufferTransferFunctionKey,
552 kCVAttachmentMode_ShouldPropagate);
555 CFNumberRef gamma_level = CFNumberCreate(NULL, kCFNumberFloat32Type, &gamma);
556 CVBufferSetAttachment(
558 kCVImageBufferGammaLevelKey,
560 kCVAttachmentMode_ShouldPropagate);
561 CFRelease(gamma_level);
567 static int vt_pixbuf_set_attachments(void *log_ctx,
568 CVPixelBufferRef pixbuf, const AVFrame *src)
571 ret = vt_pixbuf_set_par(log_ctx, pixbuf, src);
574 ret = vt_pixbuf_set_colorspace(log_ctx, pixbuf, src);
577 ret = vt_pixbuf_set_chromaloc(log_ctx, pixbuf, src);
583 int av_vt_pixbuf_set_attachments(void *log_ctx,
584 CVPixelBufferRef pixbuf, const AVFrame *src)
586 return vt_pixbuf_set_attachments(log_ctx, pixbuf, src);
589 static int vt_map_frame(AVHWFramesContext *ctx, AVFrame *dst, const AVFrame *src,
592 CVPixelBufferRef pixbuf = (CVPixelBufferRef)src->data[3];
593 OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
595 uint32_t map_flags = 0;
598 enum AVPixelFormat format;
600 format = av_map_videotoolbox_format_to_pixfmt(pixel_format);
601 if (dst->format != format) {
602 av_log(ctx, AV_LOG_ERROR, "Unsupported or mismatching pixel format: %s\n",
603 av_fourcc2str(pixel_format));
604 return AVERROR_UNKNOWN;
607 if (CVPixelBufferGetWidth(pixbuf) != ctx->width ||
608 CVPixelBufferGetHeight(pixbuf) != ctx->height) {
609 av_log(ctx, AV_LOG_ERROR, "Inconsistent frame dimensions.\n");
610 return AVERROR_UNKNOWN;
613 if (flags == AV_HWFRAME_MAP_READ)
614 map_flags = kCVPixelBufferLock_ReadOnly;
616 err = CVPixelBufferLockBaseAddress(pixbuf, map_flags);
617 if (err != kCVReturnSuccess) {
618 av_log(ctx, AV_LOG_ERROR, "Error locking the pixel buffer.\n");
619 return AVERROR_UNKNOWN;
622 if (CVPixelBufferIsPlanar(pixbuf)) {
623 int planes = CVPixelBufferGetPlaneCount(pixbuf);
624 for (i = 0; i < planes; i++) {
625 dst->data[i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf, i);
626 dst->linesize[i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf, i);
629 dst->data[0] = CVPixelBufferGetBaseAddress(pixbuf);
630 dst->linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
633 ret = ff_hwframe_map_create(src->hw_frames_ctx, dst, src, vt_unmap,
634 (void *)(uintptr_t)map_flags);
641 CVPixelBufferUnlockBaseAddress(pixbuf, map_flags);
645 static int vt_transfer_data_from(AVHWFramesContext *hwfc,
646 AVFrame *dst, const AVFrame *src)
651 if (dst->width > hwfc->width || dst->height > hwfc->height)
652 return AVERROR(EINVAL);
654 map = av_frame_alloc();
656 return AVERROR(ENOMEM);
657 map->format = dst->format;
659 err = vt_map_frame(hwfc, map, src, AV_HWFRAME_MAP_READ);
663 map->width = dst->width;
664 map->height = dst->height;
666 err = av_frame_copy(dst, map);
676 static int vt_transfer_data_to(AVHWFramesContext *hwfc,
677 AVFrame *dst, const AVFrame *src)
682 if (src->width > hwfc->width || src->height > hwfc->height)
683 return AVERROR(EINVAL);
685 map = av_frame_alloc();
687 return AVERROR(ENOMEM);
688 map->format = src->format;
690 err = vt_map_frame(hwfc, map, dst, AV_HWFRAME_MAP_WRITE | AV_HWFRAME_MAP_OVERWRITE);
694 map->width = src->width;
695 map->height = src->height;
697 err = av_frame_copy(map, src);
701 err = vt_pixbuf_set_attachments(hwfc, (CVPixelBufferRef)dst->data[3], src);
711 static int vt_map_from(AVHWFramesContext *hwfc, AVFrame *dst,
712 const AVFrame *src, int flags)
716 if (dst->format == AV_PIX_FMT_NONE)
717 dst->format = hwfc->sw_format;
718 else if (dst->format != hwfc->sw_format)
719 return AVERROR(ENOSYS);
721 err = vt_map_frame(hwfc, dst, src, flags);
725 dst->width = src->width;
726 dst->height = src->height;
728 err = av_frame_copy_props(dst, src);
735 static int vt_device_create(AVHWDeviceContext *ctx, const char *device,
736 AVDictionary *opts, int flags)
738 if (device && device[0]) {
739 av_log(ctx, AV_LOG_ERROR, "Device selection unsupported.\n");
740 return AVERROR_UNKNOWN;
746 const HWContextType ff_hwcontext_type_videotoolbox = {
747 .type = AV_HWDEVICE_TYPE_VIDEOTOOLBOX,
748 .name = "videotoolbox",
750 .frames_priv_size = sizeof(VTFramesContext),
752 .device_create = vt_device_create,
753 .frames_init = vt_frames_init,
754 .frames_get_buffer = vt_get_buffer,
755 .frames_get_constraints = vt_frames_get_constraints,
756 .frames_uninit = vt_frames_uninit,
757 .transfer_get_formats = vt_transfer_get_formats,
758 .transfer_data_to = vt_transfer_data_to,
759 .transfer_data_from = vt_transfer_data_from,
760 .map_from = vt_map_from,
762 .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_VIDEOTOOLBOX, AV_PIX_FMT_NONE },