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
qffmpeghwaccel_videotoolbox.mm
Go to the documentation of this file.
1// Copyright (C) 2021 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
3
4#include <QtFFmpegMediaPluginImpl/private/qffmpeghwaccel_videotoolbox_p.h>
5
6#if !defined(Q_OS_DARWIN)
7#error "Configuration error"
8#endif
9
10#include <QtCore/qloggingcategory.h>
11
12#include <QtFFmpegMediaPluginImpl/private/qffmpegvideobuffer_p.h>
13
14#include <QtGui/qopenglcontext.h>
15#include <QtGui/rhi/qrhi.h>
16
17#include <QtMultimedia/private/qavfhelpers_p.h>
18#include <QtMultimedia/private/qvideotexturehelper_p.h>
19#include <QtMultimedia/qvideoframeformat.h>
20
21#include <CoreVideo/CVMetalTexture.h>
22#include <CoreVideo/CVMetalTextureCache.h>
23
24#ifdef Q_OS_MACOS
25#import <AppKit/AppKit.h>
26#endif
27#ifdef Q_OS_IOS
28#import <OpenGLES/EAGL.h>
29#endif
30#import <Metal/Metal.h>
31
33
34Q_STATIC_LOGGING_CATEGORY(qLcVideotoolbox, "qt.multimedia.ffmpeg.videotoolbox");
35
36namespace QFFmpeg
37{
38
39namespace {
40
41class VideoToolBoxTextureHandles : public QVideoFrameTexturesHandles
42{
43public:
44 ~VideoToolBoxTextureHandles();
45 quint64 textureHandle(QRhi &, int plane) override;
46
47 TextureConverterBackendPtr parentConverterBackend; // ensures the backend is deleted after the texture
48
49 QRhi *rhi = nullptr;
50 QCFType<CVMetalTextureRef> m_cvMetalTexture[3] = {};
51
52#if defined(Q_OS_MACOS)
53 QCFType<CVOpenGLTextureRef> m_cvOpenGLTexture;
54#elif defined(Q_OS_IOS)
55 QCFType<CVOpenGLESTextureRef> m_cvOpenGLESTexture;
56#endif
57
58 QAVFHelpers::QSharedCVPixelBuffer m_buffer;
59};
60}
61
63{
65 return ret->rhi ? ret : nullptr;
66}
67
70{
71 if (!rhi)
72 return;
73
74 if (rhi->backend() == QRhi::Metal) {
75 const auto *metal = static_cast<const QRhiMetalNativeHandles *>(rhi->nativeHandles());
76
77 // Create a Metal Core Video texture cache from the pixel buffer.
82 nil,
84 nil,
87 qCWarning(qLcVideotoolbox) << "Metal texture cache creation failed";
88 rhi = nullptr;
89 }
90
93
94 } else if (rhi->backend() == QRhi::OpenGLES2) {
95#if QT_CONFIG(opengl)
96#ifdef Q_OS_MACOS
97 const auto *gl = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
98
99 // Create an OpenGL CoreVideo texture cache from the pixel buffer.
106 nullptr,
107 reinterpret_cast<CGLContextObj>(nsGLContext.CGLContextObj),
109 nil,
111 if (cvReturn != kCVReturnSuccess) {
112 qCWarning(qLcVideotoolbox) << "OpenGL texture cache creation failed";
113 rhi = nullptr;
114 }
115
118
119#endif
120#ifdef Q_OS_IOS
121 // Create an OpenGL CoreVideo texture cache from the pixel buffer.
125 nullptr,
127 nullptr,
129 if (cvReturn != kCVReturnSuccess) {
130 qCWarning(qLcVideotoolbox) << "OpenGLES texture cache creation failed";
131 rhi = nullptr;
132 }
133
136
137#endif
138#else
139 rhi = nullptr;
140#endif // QT_CONFIG(opengl)
141 }
142}
143
145{
147}
148
150{
151 m_cvMetalTextureCache = nullptr;
152#if defined(Q_OS_MACOS)
153 m_cvOpenGLTextureCache = nullptr;
154#elif defined(Q_OS_IOS)
155 m_cvOpenGLESTextureCache = nullptr;
156#endif
157}
158
160{
161 switch (f) {
162 default:
163 case QRhiTexture::UnknownFormat:
164 return MTLPixelFormatInvalid;
165 case QRhiTexture::RGBA8:
166 return MTLPixelFormatRGBA8Unorm;
167 case QRhiTexture::BGRA8:
168 return MTLPixelFormatBGRA8Unorm;
169 case QRhiTexture::R8:
170 case QRhiTexture::RED_OR_ALPHA8:
171 return MTLPixelFormatR8Unorm;
172 case QRhiTexture::RG8:
173 return MTLPixelFormatRG8Unorm;
174 case QRhiTexture::R16:
175 return MTLPixelFormatR16Unorm;
176 case QRhiTexture::RG16:
177 return MTLPixelFormatRG16Unorm;
178
179 case QRhiTexture::RGBA16F:
180 return MTLPixelFormatRGBA16Float;
181 case QRhiTexture::RGBA32F:
182 return MTLPixelFormatRGBA32Float;
183 case QRhiTexture::R16F:
184 return MTLPixelFormatR16Float;
185 case QRhiTexture::R32F:
186 return MTLPixelFormatR32Float;
187 }
188}
189
192 QVideoFrameTexturesHandlesUPtr /*oldHandles*/)
193{
194 if (!rhi)
195 return nullptr;
196
197 bool needsConversion = false;
199 if (needsConversion) {
200 return nullptr;
201 }
202
203 auto cvPixelBufferRef = reinterpret_cast<CVPixelBufferRef>(frame->data[3]);
205
212
215
216 if (rhi->backend() == QRhi::Metal) {
217 // First check that all planes have pixel-formats that we can handle,
218 // before we create any Metal textures.
219 for (int plane = 0; plane < bufferPlanes; ++plane) {
223 return nullptr;
224 }
225
226 for (int plane = 0; plane < bufferPlanes; ++plane) {
231
232 // Tested to be valid in prior loop.
235
236 // Create a CoreVideo pixel buffer backed Metal texture image from the texture cache.
242 nil,
244 width, height,
245 plane,
247 if (ret != kCVReturnSuccess) {
248 qCWarning(qLcVideotoolbox) << "Metal texture creation failed" << ret;
249 return nullptr;
250 }
251
254
255 }
256 } else if (rhi->backend() == QRhi::OpenGLES2) {
257#if QT_CONFIG(opengl)
258#ifdef Q_OS_MACOS
261 // Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
266 nil,
268 if (cvret != kCVReturnSuccess) {
269 qCWarning(qLcVideotoolbox) << "OpenGL texture creation failed" << cvret;
270 return nullptr;
271 }
272
276
277#endif
278#ifdef Q_OS_IOS
281 // Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
286 nil,
288 GL_RGBA,
291 GL_RGBA,
293 0,
295 if (cvret != kCVReturnSuccess) {
296 qCWarning(qLcVideotoolbox) << "OpenGL ES texture creation failed" << cvret;
297 return nullptr;
298 }
299
302
303#endif
304#endif
305 }
306
307 return textureHandles;
308}
309
310VideoToolBoxTextureHandles::~VideoToolBoxTextureHandles()
311{
312}
313
314quint64 VideoToolBoxTextureHandles::textureHandle(QRhi &, int plane)
315{
316 if (rhi->backend() == QRhi::Metal)
317 return m_cvMetalTexture[plane] ? qint64(CVMetalTextureGetTexture(m_cvMetalTexture[plane])) : 0;
318#if QT_CONFIG(opengl)
319 Q_ASSERT(plane == 0);
320#ifdef Q_OS_MACOS
321 return CVOpenGLTextureGetName(m_cvOpenGLTexture);
322#endif
323#ifdef Q_OS_IOS
324 return CVOpenGLESTextureGetName(m_cvOpenGLESTexture);
325#endif
326#endif
327 return 0;
328}
329
330}
331
332QT_END_NAMESPACE
static MTLPixelFormat rhiTextureFormatToMetalFormat(QRhiTexture::Format f)
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)