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 size_t width = CVPixelBufferGetWidth(buffer);
82 size_t height = CVPixelBufferGetHeight(buffer);
83
84 QVideoFrameFormat format(QSize(width, height), pixelFormat);
85
86 auto colorSpace = QVideoFrameFormat::ColorSpace_Undefined;
87 auto colorTransfer = QVideoFrameFormat::ColorTransfer_Unknown;
88
89 if (auto cSpace =
90 QCFString(CVBufferCopyAttachment(buffer, kCVImageBufferYCbCrMatrixKey, nullptr))) {
91 if (CFEqual(cSpace, kCVImageBufferYCbCrMatrix_ITU_R_709_2)) {
92 colorSpace = QVideoFrameFormat::ColorSpace_BT709;
93 } else if (CFEqual(cSpace, kCVImageBufferYCbCrMatrix_ITU_R_601_4)
94 || CFEqual(cSpace, kCVImageBufferYCbCrMatrix_SMPTE_240M_1995)) {
95 colorSpace = QVideoFrameFormat::ColorSpace_BT601;
96 } else if (CFEqual(cSpace, kCVImageBufferYCbCrMatrix_ITU_R_2020)) {
97 colorSpace = QVideoFrameFormat::ColorSpace_BT2020;
98 }
99 }
100
101 if (auto cTransfer = QCFString(
102 CVBufferCopyAttachment(buffer, kCVImageBufferTransferFunctionKey, nullptr))) {
103
104 using QCFNumber = QCFType<CFNumberRef>;
105
106 if (CFEqual(cTransfer, kCVImageBufferTransferFunction_ITU_R_709_2)) {
107 colorTransfer = QVideoFrameFormat::ColorTransfer_BT709;
108 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_SMPTE_240M_1995)) {
109 colorTransfer = QVideoFrameFormat::ColorTransfer_BT601;
110 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_sRGB)) {
111 colorTransfer = QVideoFrameFormat::ColorTransfer_Gamma22;
112 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_UseGamma)) {
113 auto gamma =
114 QCFNumber(CVBufferCopyAttachment(buffer, kCVImageBufferGammaLevelKey, nullptr));
115 double g;
116 CFNumberGetValue(gamma, kCFNumberFloat32Type, &g);
117 // These are best fit values given what we have in our enum
118 if (g < 0.8)
119 ; // unknown
120 else if (g < 1.5)
121 colorTransfer = QVideoFrameFormat::ColorTransfer_Linear;
122 else if (g < 2.1)
123 colorTransfer = QVideoFrameFormat::ColorTransfer_BT709;
124 else if (g < 2.5)
125 colorTransfer = QVideoFrameFormat::ColorTransfer_Gamma22;
126 else if (g < 3.2)
127 colorTransfer = QVideoFrameFormat::ColorTransfer_Gamma28;
128 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_ITU_R_2020)) {
129 colorTransfer = QVideoFrameFormat::ColorTransfer_BT709;
130 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_ITU_R_2100_HLG)) {
131 colorTransfer = QVideoFrameFormat::ColorTransfer_STD_B67;
132 } else if (CFEqual(cTransfer, kCVImageBufferTransferFunction_SMPTE_ST_2084_PQ)) {
133 colorTransfer = QVideoFrameFormat::ColorTransfer_ST2084;
134 }
135 }
136
137 format.setColorRange(colorRangeForCVPixelFormat(cvPixelFormat));
138 format.setColorSpace(colorSpace);
139 format.setColorTransfer(colorTransfer);
140 return format;
141}
142
143QT_END_NAMESPACE