Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qavfhelpers.mm
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
5#include <QtCore/qdebug.h>
6#include <QtCore/private/qcore_mac_p.h>
7
8#include <CoreMedia/CMFormatDescription.h>
9#include <CoreVideo/CoreVideo.h>
10
11namespace {
12
13using PixelFormat = QVideoFrameFormat::PixelFormat;
14using ColorRange = QVideoFrameFormat::ColorRange;
15
16// clang-format off
17constexpr std::tuple<CvPixelFormat, PixelFormat, ColorRange> PixelFormatMap[] = {
18 { kCVPixelFormatType_32ARGB, PixelFormat::Format_ARGB8888, ColorRange::ColorRange_Unknown },
19 { kCVPixelFormatType_32BGRA, PixelFormat::Format_BGRA8888, ColorRange::ColorRange_Unknown },
20 { kCVPixelFormatType_420YpCbCr8Planar, PixelFormat::Format_YUV420P, ColorRange::ColorRange_Unknown },
21 { kCVPixelFormatType_420YpCbCr8PlanarFullRange, PixelFormat::Format_YUV420P, ColorRange::ColorRange_Full },
22 { kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, PixelFormat::Format_NV12, ColorRange::ColorRange_Video },
23 { kCVPixelFormatType_420YpCbCr8BiPlanarFullRange, PixelFormat::Format_NV12, ColorRange::ColorRange_Full },
24 { kCVPixelFormatType_420YpCbCr10BiPlanarVideoRange, PixelFormat::Format_P010, ColorRange::ColorRange_Video },
25 { kCVPixelFormatType_420YpCbCr10BiPlanarFullRange, PixelFormat::Format_P010, ColorRange::ColorRange_Full },
26 { kCVPixelFormatType_422YpCbCr8, PixelFormat::Format_UYVY, ColorRange::ColorRange_Video },
27 { kCVPixelFormatType_422YpCbCr8_yuvs, PixelFormat::Format_YUYV, ColorRange::ColorRange_Video },
28 { kCVPixelFormatType_OneComponent8, PixelFormat::Format_Y8, ColorRange::ColorRange_Unknown },
29 { kCVPixelFormatType_OneComponent16, PixelFormat::Format_Y16, ColorRange::ColorRange_Unknown },
30
31 // The cases with kCMVideoCodecType_JPEG/kCMVideoCodecType_JPEG_OpenDML as cv pixel format should be investigated.
32 // Matching kCMVideoCodecType_JPEG_OpenDML to ColorRange_Full is a little hack to distinguish between
33 // kCMVideoCodecType_JPEG and kCMVideoCodecType_JPEG_OpenDML.
34 { kCMVideoCodecType_JPEG, PixelFormat::Format_Jpeg, ColorRange::ColorRange_Unknown },
35 { kCMVideoCodecType_JPEG_OpenDML, PixelFormat::Format_Jpeg, ColorRange::ColorRange_Full }
36};
37// clang-format on
38
39template<typename Type, typename... Args>
40Type findInPixelFormatMap(Type defaultValue, Args... args)
41{
42 auto checkElement = [&](const auto &element) {
43 return ((args == std::get<Args>(element)) && ...);
44 };
45
46 auto found = std::find_if(std::begin(PixelFormatMap), std::end(PixelFormatMap), checkElement);
47 return found == std::end(PixelFormatMap) ? defaultValue : std::get<Type>(*found);
48}
49
50}
51
52QT_BEGIN_NAMESPACE
53
54ColorRange QAVFHelpers::colorRangeForCVPixelFormat(CvPixelFormat cvPixelFormat)
55{
56 return findInPixelFormatMap(ColorRange::ColorRange_Unknown, cvPixelFormat);
57}
58
59PixelFormat QAVFHelpers::fromCVPixelFormat(CvPixelFormat cvPixelFormat)
60{
61 return findInPixelFormatMap(PixelFormat::Format_Invalid, cvPixelFormat);
62}
63
64CvPixelFormat QAVFHelpers::toCVPixelFormat(PixelFormat pixelFmt, ColorRange colorRange)
65{
66 return findInPixelFormatMap(CvPixelFormatInvalid, pixelFmt, colorRange);
67}
68
69QVideoFrameFormat QAVFHelpers::videoFormatForImageBuffer(CVImageBufferRef buffer, bool openGL)
70{
71 auto cvPixelFormat = CVPixelBufferGetPixelFormatType(buffer);
72 auto pixelFormat = fromCVPixelFormat(cvPixelFormat);
73 if (openGL) {
74 if (cvPixelFormat == kCVPixelFormatType_32BGRA)
75 pixelFormat = QVideoFrameFormat::Format_SamplerRect;
76 else
77 qWarning() << "Accelerated macOS OpenGL video supports BGRA only, got CV pixel format"
78 << cvPixelFormat;
79 }
80
81 QVideoFrameFormat format(QAVFHelpers::CVPixelBufferSize(buffer), pixelFormat);
82
83 auto colorSpace = QVideoFrameFormat::ColorSpace_Undefined;
84 auto colorTransfer = QVideoFrameFormat::ColorTransfer_Unknown;
85
86 if (auto cSpace =
87 QCFString(CVBufferCopyAttachment(buffer, kCVImageBufferYCbCrMatrixKey, nullptr))) {
88 if (CFEqual(cSpace, kCVImageBufferYCbCrMatrix_ITU_R_709_2)) {
89 colorSpace = QVideoFrameFormat::ColorSpace_BT709;
90 } else if (CFEqual(cSpace, kCVImageBufferYCbCrMatrix_ITU_R_601_4)
91 || CFEqual(cSpace, kCVImageBufferYCbCrMatrix_SMPTE_240M_1995)) {
92 colorSpace = QVideoFrameFormat::ColorSpace_BT601;
93 } else if (CFEqual(cSpace, kCVImageBufferYCbCrMatrix_ITU_R_2020)) {
94 colorSpace = QVideoFrameFormat::ColorSpace_BT2020;
95 }
96 }
97
98 if (auto cTransfer = QCFString(
99 CVBufferCopyAttachment(buffer, kCVImageBufferTransferFunctionKey, nullptr))) {
100
101 using QCFNumber = QCFType<CFNumberRef>;
102
103 if (CFEqual(cTransfer, kCVImageBufferTransferFunction_ITU_R_709_2)) {
104 colorTransfer = QVideoFrameFormat::ColorTransfer_BT709;
105 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_SMPTE_240M_1995)) {
106 colorTransfer = QVideoFrameFormat::ColorTransfer_BT601;
107 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_sRGB)) {
108 colorTransfer = QVideoFrameFormat::ColorTransfer_Gamma22;
109 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_UseGamma)) {
110 auto gamma =
111 QCFNumber(CVBufferCopyAttachment(buffer, kCVImageBufferGammaLevelKey, nullptr));
112 double g;
113 CFNumberGetValue(gamma, kCFNumberFloat32Type, &g);
114 // These are best fit values given what we have in our enum
115 if (g < 0.8)
116 ; // unknown
117 else if (g < 1.5)
118 colorTransfer = QVideoFrameFormat::ColorTransfer_Linear;
119 else if (g < 2.1)
120 colorTransfer = QVideoFrameFormat::ColorTransfer_BT709;
121 else if (g < 2.5)
122 colorTransfer = QVideoFrameFormat::ColorTransfer_Gamma22;
123 else if (g < 3.2)
124 colorTransfer = QVideoFrameFormat::ColorTransfer_Gamma28;
125 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_ITU_R_2020)) {
126 colorTransfer = QVideoFrameFormat::ColorTransfer_BT709;
127 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_ITU_R_2100_HLG)) {
128 colorTransfer = QVideoFrameFormat::ColorTransfer_STD_B67;
129 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ)) {
130 colorTransfer = QVideoFrameFormat::ColorTransfer_ST2084;
131 }
132 }
133
134 format.setColorRange(colorRangeForCVPixelFormat(cvPixelFormat));
135 format.setColorSpace(colorSpace);
136 format.setColorTransfer(colorTransfer);
137 return format;
138}
139
140std::chrono::microseconds QAVFHelpers::CMTimeToMicroseconds(const CMTime &time)
141{
142 if (!CMTIME_IS_NUMERIC(time) || time.timescale == 0)
143 return {};
144
145 return std::chrono::microseconds((time.value * 1'000'000) / time.timescale);
146}
147
148#if defined(Q_OS_MACOS)
149
150// Checks whether the current process has screen capturing permissions, without triggering
151// the system dialog.
152bool QAVFHelpers::checkMacOsScreenCapturePermissions()
153{
154 return CGPreflightScreenCaptureAccess();
155}
156
157void QAVFHelpers::requestMacOsScreenCapturePermissions()
158{
159 CGRequestScreenCaptureAccess();
160}
161
162#endif // Q_OS_MACOS
163
164QT_END_NAMESPACE