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 <stdint.h>
22 #include <string.h>
23
24 #include <VideoToolbox/VideoToolbox.h>
25
35
37 /**
38 * The public AVVTFramesContext. See hwcontext_videotoolbox.h for it.
39 */
43
44 static const struct {
53 #ifdef kCFCoreFoundationVersionNumber10_7
54 { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
false,
AV_PIX_FMT_NV12 },
55 { kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
true,
AV_PIX_FMT_NV12 },
57 #endif
58 #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
61 #endif
62 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
63 { kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange,
false,
AV_PIX_FMT_NV16 },
64 { kCVPixelFormatType_422YpCbCr8BiPlanarFullRange,
true,
AV_PIX_FMT_NV16 },
65 #endif
66 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
67 { kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange,
false,
AV_PIX_FMT_P210 },
68 { kCVPixelFormatType_422YpCbCr10BiPlanarFullRange,
true,
AV_PIX_FMT_P210 },
69 #endif
70 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
71 { kCVPixelFormatType_422YpCbCr16BiPlanarVideoRange,
false,
AV_PIX_FMT_P216 },
72 #endif
73 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
74 { kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange,
false,
AV_PIX_FMT_NV24 },
75 { kCVPixelFormatType_444YpCbCr8BiPlanarFullRange,
true,
AV_PIX_FMT_NV24 },
76 #endif
77 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
78 { kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange,
false,
AV_PIX_FMT_P410 },
79 { kCVPixelFormatType_444YpCbCr10BiPlanarFullRange,
true,
AV_PIX_FMT_P410 },
80 #endif
81 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
82 { kCVPixelFormatType_444YpCbCr16BiPlanarVideoRange,
false,
AV_PIX_FMT_P416 },
83 #endif
84 };
85
87 #ifdef kCFCoreFoundationVersionNumber10_7
90 #endif
93 #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
95 #endif
96 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
98 #endif
99 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
101 #endif
102 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
104 #endif
105 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
107 #endif
108 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
110 #endif
111 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
113 #endif
115 };
116
118 const void *hwconfig,
120 {
122
127
131
135
138
139 return 0;
140 }
141
143 {
148 }
150 }
151
154 {
158
159 // Don't care if unspecified
162
165 }
166 }
167
168 return 0;
169 }
170
172 {
174 }
175
177 {
179 }
180
182 {
185 CVReturn err;
187 uint32_t cv_pixfmt;
188 CFMutableDictionaryRef attributes, iosurface_properties;
189
190 attributes = CFDictionaryCreateMutable(
192 2,
193 &kCFTypeDictionaryKeyCallBacks,
194 &kCFTypeDictionaryValueCallBacks);
195
197 pixfmt = CFNumberCreate(
NULL, kCFNumberSInt32Type, &cv_pixfmt);
198 CFDictionarySetValue(
199 attributes,
200 kCVPixelBufferPixelFormatTypeKey,
203
204 iosurface_properties = CFDictionaryCreateMutable(
206 0,
207 &kCFTypeDictionaryKeyCallBacks,
208 &kCFTypeDictionaryValueCallBacks);
209 CFDictionarySetValue(attributes, kCVPixelBufferIOSurfacePropertiesKey, iosurface_properties);
210 CFRelease(iosurface_properties);
211
212 w = CFNumberCreate(
NULL, kCFNumberSInt32Type, &
ctx->width);
213 h = CFNumberCreate(
NULL, kCFNumberSInt32Type, &
ctx->height);
214 CFDictionarySetValue(attributes, kCVPixelBufferWidthKey,
w);
215 CFDictionarySetValue(attributes, kCVPixelBufferHeightKey,
h);
218
219 err = CVPixelBufferPoolCreate(
222 attributes,
224 CFRelease(attributes);
225
226 if (err == kCVReturnSuccess)
227 return 0;
228
231 }
232
234 {
235 CVPixelBufferRelease((CVPixelBufferRef)
data);
236 }
237
239 {
240 CVPixelBufferRef pixbuf;
242 CVReturn err;
245
246 err = CVPixelBufferPoolCreatePixelBuffer(
249 &pixbuf
250 );
251 if (err != kCVReturnSuccess) {
254 }
255
258 if (!buf) {
259 CVPixelBufferRelease(pixbuf);
261 }
262 return buf;
263 }
264
266 {
269 CVPixelBufferPoolRelease(fctx->
pool);
271 }
272 }
273
275 {
277
280 break;
281 }
286 }
287
293 }
294
298
299 return 0;
300 }
301
303 {
307
312
313 return 0;
314 }
315
319 {
321 if (!fmts)
323
324 fmts[0] =
ctx->sw_format;
326
328 return 0;
329 }
330
332 {
333 CVPixelBufferRef pixbuf = (CVPixelBufferRef)hwmap->
source->
data[3];
334
335 CVPixelBufferUnlockBaseAddress(pixbuf, (uintptr_t)hwmap->
priv);
336 }
337
340 {
341 CFMutableDictionaryRef par =
NULL;
344
346 return 0;
347
350 0xFFFFFFFF);
351
352 num = CFNumberCreate(kCFAllocatorDefault,
353 kCFNumberIntType,
355
356 den = CFNumberCreate(kCFAllocatorDefault,
357 kCFNumberIntType,
359
360 par = CFDictionaryCreateMutable(kCFAllocatorDefault,
361 2,
362 &kCFCopyStringDictionaryKeyCallBacks,
363 &kCFTypeDictionaryValueCallBacks);
364
365 if (!par || !num || !den) {
366 if (par) CFRelease(par);
367 if (num) CFRelease(num);
368 if (den) CFRelease(den);
370 }
371
372 CFDictionarySetValue(
373 par,
374 kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
375 num);
376 CFDictionarySetValue(
377 par,
378 kCVImageBufferPixelAspectRatioVerticalSpacingKey,
379 den);
380
381 CVBufferSetAttachment(
382 pixbuf,
383 kCVImageBufferPixelAspectRatioKey,
384 par,
385 kCVAttachmentMode_ShouldPropagate
386 );
387
388 CFRelease(par);
389 CFRelease(num);
390 CFRelease(den);
391
392 return 0;
393 }
394
396 {
397 switch (loc) {
399 return kCVImageBufferChromaLocation_Left;
401 return kCVImageBufferChromaLocation_Center;
403 return kCVImageBufferChromaLocation_Top;
405 return kCVImageBufferChromaLocation_Bottom;
407 return kCVImageBufferChromaLocation_TopLeft;
409 return kCVImageBufferChromaLocation_BottomLeft;
410 default:
412 }
413 }
414
417 {
419
420 if (loc) {
421 CVBufferSetAttachment(
422 pixbuf,
423 kCVImageBufferChromaLocationTopFieldKey,
424 loc,
425 kCVAttachmentMode_ShouldPropagate);
426 }
427
428 return 0;
429 }
430
432 {
436 #if HAVE_KCVIMAGEBUFFERYCBCRMATRIX_ITU_R_2020
437 if (__builtin_available(macOS 10.11, iOS 9, *))
439 #endif
440 return CFSTR("ITU_R_2020");
443 return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
445 return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
447 return kCVImageBufferYCbCrMatrix_SMPTE_240M_1995;
448 default:
449 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
450 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
451 return CVYCbCrMatrixGetStringForIntegerCodePoint(
space);
452 #endif
455 }
456 }
457
459 {
460 switch (pri) {
462 #if HAVE_KCVIMAGEBUFFERCOLORPRIMARIES_ITU_R_2020
463 if (__builtin_available(macOS 10.11, iOS 9, *))
465 #endif
466 return CFSTR("ITU_R_2020");
468 return kCVImageBufferColorPrimaries_ITU_R_709_2;
470 return kCVImageBufferColorPrimaries_SMPTE_C;
472 return kCVImageBufferColorPrimaries_EBU_3213;
473 default:
474 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
475 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
476 return CVColorPrimariesGetStringForIntegerCodePoint(pri);
477 #endif
480 }
481 }
482
484 {
485
486 switch (trc) {
488 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_2084_PQ
489 if (__builtin_available(macOS 10.13, iOS 11, *))
490 return kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ;
491 #endif
492 return CFSTR("SMPTE_ST_2084_PQ");
495 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2020
496 if (__builtin_available(macOS 10.11, iOS 9, *))
498 #endif
499 return CFSTR("ITU_R_2020");
501 return kCVImageBufferTransferFunction_ITU_R_709_2;
503 return kCVImageBufferTransferFunction_SMPTE_240M_1995;
505 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_428_1
506 if (__builtin_available(macOS 10.12, iOS 10, *))
507 return kCVImageBufferTransferFunction_SMPTE_ST_428_1;
508 #endif
509 return CFSTR("SMPTE_ST_428_1");
511 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
512 if (__builtin_available(macOS 10.13, iOS 11, *))
513 return kCVImageBufferTransferFunction_ITU_R_2100_HLG;
514 #endif
515 return CFSTR("ITU_R_2100_HLG");
517 return kCVImageBufferTransferFunction_UseGamma;
519 return kCVImageBufferTransferFunction_UseGamma;
520 default:
521 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
522 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
523 return CVTransferFunctionGetStringForIntegerCodePoint(trc);
524 #endif
527 }
528 }
529
532 {
533 CFStringRef colormatrix =
NULL, colorpri =
NULL, colortrc =
NULL;
534 Float32 gamma = 0;
535
539
543
547
549 gamma = 2.2;
551 gamma = 2.8;
552
553 if (colormatrix) {
554 CVBufferSetAttachment(
555 pixbuf,
556 kCVImageBufferYCbCrMatrixKey,
557 colormatrix,
558 kCVAttachmentMode_ShouldPropagate);
559 }
560 if (colorpri) {
561 CVBufferSetAttachment(
562 pixbuf,
563 kCVImageBufferColorPrimariesKey,
564 colorpri,
565 kCVAttachmentMode_ShouldPropagate);
566 }
567 if (colortrc) {
568 CVBufferSetAttachment(
569 pixbuf,
570 kCVImageBufferTransferFunctionKey,
571 colortrc,
572 kCVAttachmentMode_ShouldPropagate);
573 }
574 if (gamma != 0) {
575 CFNumberRef gamma_level = CFNumberCreate(
NULL, kCFNumberFloat32Type, &gamma);
576 CVBufferSetAttachment(
577 pixbuf,
578 kCVImageBufferGammaLevelKey,
579 gamma_level,
580 kCVAttachmentMode_ShouldPropagate);
581 CFRelease(gamma_level);
582 }
583
584 return 0;
585 }
586
589 {
600 return 0;
601 }
602
605 {
607 }
608
611 {
612 CVPixelBufferRef pixbuf = (CVPixelBufferRef)
src->data[3];
613 OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
614 CVReturn err;
615 uint32_t map_flags = 0;
619
625 }
626
627 if (CVPixelBufferGetWidth(pixbuf) !=
ctx->width ||
628 CVPixelBufferGetHeight(pixbuf) !=
ctx->height) {
631 }
632
634 map_flags = kCVPixelBufferLock_ReadOnly;
635
636 err = CVPixelBufferLockBaseAddress(pixbuf, map_flags);
637 if (err != kCVReturnSuccess) {
640 }
641
642 if (CVPixelBufferIsPlanar(pixbuf)) {
643 int planes = CVPixelBufferGetPlaneCount(pixbuf);
645 dst->
data[
i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf,
i);
646 dst->
linesize[
i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf,
i);
647 }
648 } else {
649 dst->
data[0] = CVPixelBufferGetBaseAddress(pixbuf);
650 dst->
linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
651 }
652
654 (void *)(uintptr_t)map_flags);
656 goto unlock;
657
658 return 0;
659
660 unlock:
661 CVPixelBufferUnlockBaseAddress(pixbuf, map_flags);
663 }
664
667 {
669 int err;
670
673
678
680 if (err)
682
685
687 if (err)
689
690 err = 0;
693 return err;
694 }
695
698 {
700 int err;
701
704
708 map->format =
src->format;
709
711 if (err)
713
715 map->height =
src->height;
716
718 if (err)
720
722 if (err)
724
725 err = 0;
728 return err;
729 }
730
733 {
734 int err;
735
740
742 if (err)
743 return err;
744
747
749 if (err)
750 return err;
751
752 return 0;
753 }
754
757 {
758 if (device && device[0]) {
761 }
762
763 return 0;
764 }
765
768 .name = "videotoolbox",
769
771
781
783 };