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
39
40 static const struct {
48 #ifdef kCFCoreFoundationVersionNumber10_7
49 { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange,
false,
AV_PIX_FMT_NV12 },
50 { kCVPixelFormatType_420YpCbCr8BiPlanarFullRange,
true,
AV_PIX_FMT_NV12 },
52 #endif
53 #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
56 #endif
57 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
58 { kCVPixelFormatType_422YpCbCr8BiPlanarVideoRange,
false,
AV_PIX_FMT_NV16 },
59 { kCVPixelFormatType_422YpCbCr8BiPlanarFullRange,
true,
AV_PIX_FMT_NV16 },
60 #endif
61 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
62 { kCVPixelFormatType_422YpCbCr10BiPlanarVideoRange,
false,
AV_PIX_FMT_P210 },
63 { kCVPixelFormatType_422YpCbCr10BiPlanarFullRange,
true,
AV_PIX_FMT_P210 },
64 #endif
65 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
66 { kCVPixelFormatType_422YpCbCr16BiPlanarVideoRange,
false,
AV_PIX_FMT_P216 },
67 #endif
68 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
69 { kCVPixelFormatType_444YpCbCr8BiPlanarVideoRange,
false,
AV_PIX_FMT_NV24 },
70 { kCVPixelFormatType_444YpCbCr8BiPlanarFullRange,
true,
AV_PIX_FMT_NV24 },
71 #endif
72 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
73 { kCVPixelFormatType_444YpCbCr10BiPlanarVideoRange,
false,
AV_PIX_FMT_P410 },
74 { kCVPixelFormatType_444YpCbCr10BiPlanarFullRange,
true,
AV_PIX_FMT_P410 },
75 #endif
76 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
77 { kCVPixelFormatType_444YpCbCr16BiPlanarVideoRange,
false,
AV_PIX_FMT_P416 },
78 #endif
79 };
80
82 #ifdef kCFCoreFoundationVersionNumber10_7
85 #endif
88 #if HAVE_KCVPIXELFORMATTYPE_420YPCBCR10BIPLANARVIDEORANGE
90 #endif
91 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR8BIPLANARVIDEORANGE
93 #endif
94 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR10BIPLANARVIDEORANGE
96 #endif
97 #if HAVE_KCVPIXELFORMATTYPE_422YPCBCR16BIPLANARVIDEORANGE
99 #endif
100 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR8BIPLANARVIDEORANGE
102 #endif
103 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR10BIPLANARVIDEORANGE
105 #endif
106 #if HAVE_KCVPIXELFORMATTYPE_444YPCBCR16BIPLANARVIDEORANGE
108 #endif
110 };
111
113 const void *hwconfig,
115 {
117
122
126
130
133
134 return 0;
135 }
136
138 {
143 }
145 }
146
148 {
150 }
151
153 {
158 }
159 return 0;
160 }
161
163 {
165 CVReturn err;
167 uint32_t cv_pixfmt;
168 CFMutableDictionaryRef attributes, iosurface_properties;
169
170 attributes = CFDictionaryCreateMutable(
172 2,
173 &kCFTypeDictionaryKeyCallBacks,
174 &kCFTypeDictionaryValueCallBacks);
175
177 pixfmt = CFNumberCreate(
NULL, kCFNumberSInt32Type, &cv_pixfmt);
178 CFDictionarySetValue(
179 attributes,
180 kCVPixelBufferPixelFormatTypeKey,
183
184 iosurface_properties = CFDictionaryCreateMutable(
186 0,
187 &kCFTypeDictionaryKeyCallBacks,
188 &kCFTypeDictionaryValueCallBacks);
189 CFDictionarySetValue(attributes, kCVPixelBufferIOSurfacePropertiesKey, iosurface_properties);
190 CFRelease(iosurface_properties);
191
192 w = CFNumberCreate(
NULL, kCFNumberSInt32Type, &
ctx->width);
193 h = CFNumberCreate(
NULL, kCFNumberSInt32Type, &
ctx->height);
194 CFDictionarySetValue(attributes, kCVPixelBufferWidthKey,
w);
195 CFDictionarySetValue(attributes, kCVPixelBufferHeightKey,
h);
198
199 err = CVPixelBufferPoolCreate(
202 attributes,
204 CFRelease(attributes);
205
206 if (err == kCVReturnSuccess)
207 return 0;
208
211 }
212
214 {
215 CVPixelBufferRelease((CVPixelBufferRef)
data);
216 }
217
219 {
220 CVPixelBufferRef pixbuf;
222 CVReturn err;
225
226 err = CVPixelBufferPoolCreatePixelBuffer(
229 &pixbuf
230 );
231 if (err != kCVReturnSuccess) {
234 }
235
238 if (!buf) {
239 CVPixelBufferRelease(pixbuf);
241 }
242 return buf;
243 }
244
246 {
249 CVPixelBufferPoolRelease(fctx->
pool);
251 }
252 }
253
255 {
257
260 break;
261 }
266 }
267
271 if (!
ctx->internal->pool_internal)
273 }
274
278
279 return 0;
280 }
281
283 {
287
292
293 return 0;
294 }
295
299 {
301 if (!fmts)
303
304 fmts[0] =
ctx->sw_format;
306
308 return 0;
309 }
310
312 {
313 CVPixelBufferRef pixbuf = (CVPixelBufferRef)hwmap->
source->
data[3];
314
315 CVPixelBufferUnlockBaseAddress(pixbuf, (uintptr_t)hwmap->
priv);
316 }
317
320 {
321 CFMutableDictionaryRef par =
NULL;
324
326 return 0;
327
330 0xFFFFFFFF);
331
332 num = CFNumberCreate(kCFAllocatorDefault,
333 kCFNumberIntType,
335
336 den = CFNumberCreate(kCFAllocatorDefault,
337 kCFNumberIntType,
339
340 par = CFDictionaryCreateMutable(kCFAllocatorDefault,
341 2,
342 &kCFCopyStringDictionaryKeyCallBacks,
343 &kCFTypeDictionaryValueCallBacks);
344
345 if (!par || !num || !den) {
346 if (par) CFRelease(par);
347 if (num) CFRelease(num);
348 if (den) CFRelease(den);
350 }
351
352 CFDictionarySetValue(
353 par,
354 kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
355 num);
356 CFDictionarySetValue(
357 par,
358 kCVImageBufferPixelAspectRatioVerticalSpacingKey,
359 den);
360
361 CVBufferSetAttachment(
362 pixbuf,
363 kCVImageBufferPixelAspectRatioKey,
364 par,
365 kCVAttachmentMode_ShouldPropagate
366 );
367
368 CFRelease(par);
369 CFRelease(num);
370 CFRelease(den);
371
372 return 0;
373 }
374
376 {
377 switch (loc) {
379 return kCVImageBufferChromaLocation_Left;
381 return kCVImageBufferChromaLocation_Center;
383 return kCVImageBufferChromaLocation_Top;
385 return kCVImageBufferChromaLocation_Bottom;
387 return kCVImageBufferChromaLocation_TopLeft;
389 return kCVImageBufferChromaLocation_BottomLeft;
390 default:
392 }
393 }
394
397 {
399
400 if (loc) {
401 CVBufferSetAttachment(
402 pixbuf,
403 kCVImageBufferChromaLocationTopFieldKey,
404 loc,
405 kCVAttachmentMode_ShouldPropagate);
406 }
407
408 return 0;
409 }
410
412 {
416 #if HAVE_KCVIMAGEBUFFERYCBCRMATRIX_ITU_R_2020
417 if (__builtin_available(macOS 10.11, iOS 9, *))
419 #endif
420 return CFSTR("ITU_R_2020");
423 return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
425 return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
427 return kCVImageBufferYCbCrMatrix_SMPTE_240M_1995;
428 default:
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);
432 #endif
435 }
436 }
437
439 {
440 switch (pri) {
442 #if HAVE_KCVIMAGEBUFFERCOLORPRIMARIES_ITU_R_2020
443 if (__builtin_available(macOS 10.11, iOS 9, *))
445 #endif
446 return CFSTR("ITU_R_2020");
448 return kCVImageBufferColorPrimaries_ITU_R_709_2;
450 return kCVImageBufferColorPrimaries_SMPTE_C;
452 return kCVImageBufferColorPrimaries_EBU_3213;
453 default:
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);
457 #endif
460 }
461 }
462
464 {
465
466 switch (trc) {
468 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_2084_PQ
469 if (__builtin_available(macOS 10.13, iOS 11, *))
470 return kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ;
471 #endif
472 return CFSTR("SMPTE_ST_2084_PQ");
475 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2020
476 if (__builtin_available(macOS 10.11, iOS 9, *))
478 #endif
479 return CFSTR("ITU_R_2020");
481 return kCVImageBufferTransferFunction_ITU_R_709_2;
483 return kCVImageBufferTransferFunction_SMPTE_240M_1995;
485 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_428_1
486 if (__builtin_available(macOS 10.12, iOS 10, *))
487 return kCVImageBufferTransferFunction_SMPTE_ST_428_1;
488 #endif
489 return CFSTR("SMPTE_ST_428_1");
491 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
492 if (__builtin_available(macOS 10.13, iOS 11, *))
493 return kCVImageBufferTransferFunction_ITU_R_2100_HLG;
494 #endif
495 return CFSTR("ITU_R_2100_HLG");
497 return kCVImageBufferTransferFunction_UseGamma;
499 return kCVImageBufferTransferFunction_UseGamma;
500 default:
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);
504 #endif
507 }
508 }
509
512 {
513 CFStringRef colormatrix =
NULL, colorpri =
NULL, colortrc =
NULL;
514 Float32 gamma = 0;
515
519
523
527
529 gamma = 2.2;
531 gamma = 2.8;
532
533 if (colormatrix) {
534 CVBufferSetAttachment(
535 pixbuf,
536 kCVImageBufferYCbCrMatrixKey,
537 colormatrix,
538 kCVAttachmentMode_ShouldPropagate);
539 }
540 if (colorpri) {
541 CVBufferSetAttachment(
542 pixbuf,
543 kCVImageBufferColorPrimariesKey,
544 colorpri,
545 kCVAttachmentMode_ShouldPropagate);
546 }
547 if (colortrc) {
548 CVBufferSetAttachment(
549 pixbuf,
550 kCVImageBufferTransferFunctionKey,
551 colortrc,
552 kCVAttachmentMode_ShouldPropagate);
553 }
554 if (gamma != 0) {
555 CFNumberRef gamma_level = CFNumberCreate(
NULL, kCFNumberFloat32Type, &gamma);
556 CVBufferSetAttachment(
557 pixbuf,
558 kCVImageBufferGammaLevelKey,
559 gamma_level,
560 kCVAttachmentMode_ShouldPropagate);
561 CFRelease(gamma_level);
562 }
563
564 return 0;
565 }
566
569 {
580 return 0;
581 }
582
585 {
587 }
588
591 {
592 CVPixelBufferRef pixbuf = (CVPixelBufferRef)
src->data[3];
593 OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
594 CVReturn err;
595 uint32_t map_flags = 0;
599
605 }
606
607 if (CVPixelBufferGetWidth(pixbuf) !=
ctx->width ||
608 CVPixelBufferGetHeight(pixbuf) !=
ctx->height) {
611 }
612
614 map_flags = kCVPixelBufferLock_ReadOnly;
615
616 err = CVPixelBufferLockBaseAddress(pixbuf, map_flags);
617 if (err != kCVReturnSuccess) {
620 }
621
622 if (CVPixelBufferIsPlanar(pixbuf)) {
623 int planes = CVPixelBufferGetPlaneCount(pixbuf);
625 dst->
data[
i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf,
i);
626 dst->
linesize[
i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf,
i);
627 }
628 } else {
629 dst->
data[0] = CVPixelBufferGetBaseAddress(pixbuf);
630 dst->
linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
631 }
632
634 (void *)(uintptr_t)map_flags);
636 goto unlock;
637
638 return 0;
639
640 unlock:
641 CVPixelBufferUnlockBaseAddress(pixbuf, map_flags);
643 }
644
647 {
649 int err;
650
653
658
660 if (err)
662
665
667 if (err)
669
670 err = 0;
673 return err;
674 }
675
678 {
680 int err;
681
684
688 map->format =
src->format;
689
691 if (err)
693
695 map->height =
src->height;
696
698 if (err)
700
702 if (err)
704
705 err = 0;
708 return err;
709 }
710
713 {
714 int err;
715
720
722 if (err)
723 return err;
724
727
729 if (err)
730 return err;
731
732 return 0;
733 }
734
737 {
738 if (device && device[0]) {
741 }
742
743 return 0;
744 }
745
748 .name = "videotoolbox",
749
751
761
763 };