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 {
216 }
217
219 {
222 CVPixelBufferPoolRelease(fctx->
pool);
224 }
225 }
226
228 {
230
233 break;
234 }
239 }
240
241 // create a dummy pool so av_hwframe_get_buffer doesn't EINVAL
244 if (!
ctx->internal->pool_internal)
246 }
247
251
252 return 0;
253 }
254
256 {
257 CVPixelBufferRelease((CVPixelBufferRef)
data);
258 }
259
261 {
263
264 if (
ctx->pool &&
ctx->pool->size != 0) {
268 } else {
269 CVPixelBufferRef pixbuf;
271 CVReturn err;
272
273 err = CVPixelBufferPoolCreatePixelBuffer(
276 &pixbuf
277 );
278 if (err != kCVReturnSuccess) {
281 }
282
284 if (!buf) {
285 CVPixelBufferRelease(pixbuf);
287 }
289 }
290
295
296 return 0;
297 }
298
302 {
304 if (!fmts)
306
307 fmts[0] =
ctx->sw_format;
309
311 return 0;
312 }
313
315 {
316 CVPixelBufferRef pixbuf = (CVPixelBufferRef)hwmap->
source->
data[3];
317
318 CVPixelBufferUnlockBaseAddress(pixbuf, (uintptr_t)hwmap->
priv);
319 }
320
323 {
324 CFMutableDictionaryRef par =
NULL;
327
329 return 0;
330
333 0xFFFFFFFF);
334
335 num = CFNumberCreate(kCFAllocatorDefault,
336 kCFNumberIntType,
338
339 den = CFNumberCreate(kCFAllocatorDefault,
340 kCFNumberIntType,
342
343 par = CFDictionaryCreateMutable(kCFAllocatorDefault,
344 2,
345 &kCFCopyStringDictionaryKeyCallBacks,
346 &kCFTypeDictionaryValueCallBacks);
347
348 if (!par || !num || !den) {
349 if (par) CFRelease(par);
350 if (num) CFRelease(num);
351 if (den) CFRelease(den);
353 }
354
355 CFDictionarySetValue(
356 par,
357 kCVImageBufferPixelAspectRatioHorizontalSpacingKey,
358 num);
359 CFDictionarySetValue(
360 par,
361 kCVImageBufferPixelAspectRatioVerticalSpacingKey,
362 den);
363
364 CVBufferSetAttachment(
365 pixbuf,
366 kCVImageBufferPixelAspectRatioKey,
367 par,
368 kCVAttachmentMode_ShouldPropagate
369 );
370
371 CFRelease(par);
372 CFRelease(num);
373 CFRelease(den);
374
375 return 0;
376 }
377
379 {
380 switch (loc) {
382 return kCVImageBufferChromaLocation_Left;
384 return kCVImageBufferChromaLocation_Center;
386 return kCVImageBufferChromaLocation_Top;
388 return kCVImageBufferChromaLocation_Bottom;
390 return kCVImageBufferChromaLocation_TopLeft;
392 return kCVImageBufferChromaLocation_BottomLeft;
393 default:
395 }
396 }
397
400 {
402
403 if (loc) {
404 CVBufferSetAttachment(
405 pixbuf,
406 kCVImageBufferChromaLocationTopFieldKey,
407 loc,
408 kCVAttachmentMode_ShouldPropagate);
409 }
410
411 return 0;
412 }
413
415 {
419 #if HAVE_KCVIMAGEBUFFERYCBCRMATRIX_ITU_R_2020
420 if (__builtin_available(macOS 10.11, iOS 9, *))
422 #endif
423 return CFSTR("ITU_R_2020");
426 return kCVImageBufferYCbCrMatrix_ITU_R_601_4;
428 return kCVImageBufferYCbCrMatrix_ITU_R_709_2;
430 return kCVImageBufferYCbCrMatrix_SMPTE_240M_1995;
431 default:
432 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
433 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
434 return CVYCbCrMatrixGetStringForIntegerCodePoint(
space);
435 #endif
438 }
439 }
440
442 {
443 switch (pri) {
445 #if HAVE_KCVIMAGEBUFFERCOLORPRIMARIES_ITU_R_2020
446 if (__builtin_available(macOS 10.11, iOS 9, *))
448 #endif
449 return CFSTR("ITU_R_2020");
451 return kCVImageBufferColorPrimaries_ITU_R_709_2;
453 return kCVImageBufferColorPrimaries_SMPTE_C;
455 return kCVImageBufferColorPrimaries_EBU_3213;
456 default:
457 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
458 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
459 return CVColorPrimariesGetStringForIntegerCodePoint(pri);
460 #endif
463 }
464 }
465
467 {
468
469 switch (trc) {
471 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_2084_PQ
472 if (__builtin_available(macOS 10.13, iOS 11, *))
473 return kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ;
474 #endif
475 return CFSTR("SMPTE_ST_2084_PQ");
478 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2020
479 if (__builtin_available(macOS 10.11, iOS 9, *))
481 #endif
482 return CFSTR("ITU_R_2020");
484 return kCVImageBufferTransferFunction_ITU_R_709_2;
486 return kCVImageBufferTransferFunction_SMPTE_240M_1995;
488 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_SMPTE_ST_428_1
489 if (__builtin_available(macOS 10.12, iOS 10, *))
490 return kCVImageBufferTransferFunction_SMPTE_ST_428_1;
491 #endif
492 return CFSTR("SMPTE_ST_428_1");
494 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
495 if (__builtin_available(macOS 10.13, iOS 11, *))
496 return kCVImageBufferTransferFunction_ITU_R_2100_HLG;
497 #endif
498 return CFSTR("ITU_R_2100_HLG");
500 return kCVImageBufferTransferFunction_UseGamma;
502 return kCVImageBufferTransferFunction_UseGamma;
503 default:
504 #if HAVE_KCVIMAGEBUFFERTRANSFERFUNCTION_ITU_R_2100_HLG
505 if (__builtin_available(macOS 10.13, iOS 11, tvOS 11, watchOS 4, *))
506 return CVTransferFunctionGetStringForIntegerCodePoint(trc);
507 #endif
510 }
511 }
512
515 {
516 CFStringRef colormatrix =
NULL, colorpri =
NULL, colortrc =
NULL;
517 Float32 gamma = 0;
518
522
526
530
532 gamma = 2.2;
534 gamma = 2.8;
535
536 if (colormatrix) {
537 CVBufferSetAttachment(
538 pixbuf,
539 kCVImageBufferYCbCrMatrixKey,
540 colormatrix,
541 kCVAttachmentMode_ShouldPropagate);
542 }
543 if (colorpri) {
544 CVBufferSetAttachment(
545 pixbuf,
546 kCVImageBufferColorPrimariesKey,
547 colorpri,
548 kCVAttachmentMode_ShouldPropagate);
549 }
550 if (colortrc) {
551 CVBufferSetAttachment(
552 pixbuf,
553 kCVImageBufferTransferFunctionKey,
554 colortrc,
555 kCVAttachmentMode_ShouldPropagate);
556 }
557 if (gamma != 0) {
558 CFNumberRef gamma_level = CFNumberCreate(
NULL, kCFNumberFloat32Type, &gamma);
559 CVBufferSetAttachment(
560 pixbuf,
561 kCVImageBufferGammaLevelKey,
562 gamma_level,
563 kCVAttachmentMode_ShouldPropagate);
564 CFRelease(gamma_level);
565 }
566
567 return 0;
568 }
569
572 {
583 return 0;
584 }
585
588 {
590 }
591
594 {
595 CVPixelBufferRef pixbuf = (CVPixelBufferRef)
src->data[3];
596 OSType pixel_format = CVPixelBufferGetPixelFormatType(pixbuf);
597 CVReturn err;
598 uint32_t map_flags = 0;
602
608 }
609
610 if (CVPixelBufferGetWidth(pixbuf) !=
ctx->width ||
611 CVPixelBufferGetHeight(pixbuf) !=
ctx->height) {
614 }
615
617 map_flags = kCVPixelBufferLock_ReadOnly;
618
619 err = CVPixelBufferLockBaseAddress(pixbuf, map_flags);
620 if (err != kCVReturnSuccess) {
623 }
624
625 if (CVPixelBufferIsPlanar(pixbuf)) {
626 int planes = CVPixelBufferGetPlaneCount(pixbuf);
628 dst->
data[
i] = CVPixelBufferGetBaseAddressOfPlane(pixbuf,
i);
629 dst->
linesize[
i] = CVPixelBufferGetBytesPerRowOfPlane(pixbuf,
i);
630 }
631 } else {
632 dst->
data[0] = CVPixelBufferGetBaseAddress(pixbuf);
633 dst->
linesize[0] = CVPixelBufferGetBytesPerRow(pixbuf);
634 }
635
637 (void *)(uintptr_t)map_flags);
639 goto unlock;
640
641 return 0;
642
643 unlock:
644 CVPixelBufferUnlockBaseAddress(pixbuf, map_flags);
646 }
647
650 {
652 int err;
653
656
661
663 if (err)
665
668
670 if (err)
672
673 err = 0;
676 return err;
677 }
678
681 {
683 int err;
684
687
691 map->format =
src->format;
692
694 if (err)
696
698 map->height =
src->height;
699
701 if (err)
703
705 if (err)
707
708 err = 0;
711 return err;
712 }
713
716 {
717 if (device && device[0]) {
720 }
721
722 return 0;
723 }
724
727 .name = "videotoolbox",
728
730
739
741 };