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/qvideotexturehelper_p.h>
18#include <QtMultimedia/qvideoframeformat.h>
19
20#include <CoreVideo/CVMetalTexture.h>
21#include <CoreVideo/CVMetalTextureCache.h>
22
23#ifdef Q_OS_MACOS
24#import <AppKit/AppKit.h>
25#endif
26#ifdef Q_OS_IOS
27#import <OpenGLES/EAGL.h>
28#endif
29#import <Metal/Metal.h>
30
32
33Q_STATIC_LOGGING_CATEGORY(qLcVideotoolbox, "qt.multimedia.ffmpeg.videotoolbox");
34
35namespace QFFmpeg
36{
37
38namespace {
39CVMetalTextureCacheRef &mtc(void *&cache) { return reinterpret_cast<CVMetalTextureCacheRef &>(cache); }
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 CVMetalTextureRef cvMetalTexture[3] = {};
51
52#if defined(Q_OS_MACOS)
53 CVOpenGLTextureRef cvOpenGLTexture = nullptr;
54#elif defined(Q_OS_IOS)
55 CVOpenGLESTextureRef cvOpenGLESTexture = nullptr;
56#endif
57
58 CVImageBufferRef m_buffer = nullptr;
59};
60}
61
64{
65 if (!rhi)
66 return;
67
68 if (rhi->backend() == QRhi::Metal) {
69 const auto *metal = static_cast<const QRhiMetalNativeHandles *>(rhi->nativeHandles());
70
71 // Create a Metal Core Video texture cache from the pixel buffer.
75 nil,
77 nil,
79 qWarning() << "Metal texture cache creation failed";
80 rhi = nullptr;
81 }
82 } else if (rhi->backend() == QRhi::OpenGLES2) {
83#if QT_CONFIG(opengl)
84#ifdef Q_OS_MACOS
85 const auto *gl = static_cast<const QRhiGles2NativeHandles *>(rhi->nativeHandles());
86
89
90 // Create an OpenGL CoreVideo texture cache from the pixel buffer.
93 nullptr,
94 reinterpret_cast<CGLContextObj>(nsGLContext.CGLContextObj),
96 nil,
98 qWarning() << "OpenGL texture cache creation failed";
99 rhi = nullptr;
100 }
101#endif
102#ifdef Q_OS_IOS
103 // Create an OpenGL CoreVideo texture cache from the pixel buffer.
106 nullptr,
108 nullptr,
110 qWarning() << "OpenGL texture cache creation failed";
111 rhi = nullptr;
112 }
113#endif
114#else
115 rhi = nullptr;
116#endif // QT_CONFIG(opengl)
117 }
118}
119
121{
123}
124
126{
129 cvMetalTextureCache = nullptr;
130#if defined(Q_OS_MACOS)
133 cvOpenGLTextureCache = nullptr;
134#elif defined(Q_OS_IOS)
137 cvOpenGLESTextureCache = nullptr;
138#endif
139}
140
142{
143 switch (f) {
144 default:
145 case QRhiTexture::UnknownFormat:
146 return MTLPixelFormatInvalid;
147 case QRhiTexture::RGBA8:
148 return MTLPixelFormatRGBA8Unorm;
149 case QRhiTexture::BGRA8:
150 return MTLPixelFormatBGRA8Unorm;
151 case QRhiTexture::R8:
152 case QRhiTexture::RED_OR_ALPHA8:
153 return MTLPixelFormatR8Unorm;
154 case QRhiTexture::RG8:
155 return MTLPixelFormatRG8Unorm;
156 case QRhiTexture::R16:
157 return MTLPixelFormatR16Unorm;
158 case QRhiTexture::RG16:
159 return MTLPixelFormatRG16Unorm;
160
161 case QRhiTexture::RGBA16F:
162 return MTLPixelFormatRGBA16Float;
163 case QRhiTexture::RGBA32F:
164 return MTLPixelFormatRGBA32Float;
165 case QRhiTexture::R16F:
166 return MTLPixelFormatR16Float;
167 case QRhiTexture::R32F:
168 return MTLPixelFormatR32Float;
169 }
170}
171
174 QVideoFrameTexturesHandlesUPtr /*oldHandles*/)
175{
176 if (!rhi)
177 return nullptr;
178
179 bool needsConversion = false;
181 if (needsConversion) {
182 // qDebug() << "XXXXXXXXXXXX pixel format needs conversion" << pixelFormat << HWAccel::format(frame);
183 return nullptr;
184 }
185
187
193
196 // qDebug() << "XXXXX createTextureHandles" << pixelFormat << bufferPlanes << buffer;
197
198 if (rhi->backend() == QRhi::Metal) {
199 // First check that all planes have pixel-formats that we can handle,
200 // before we create any Metal textures.
201 for (int plane = 0; plane < bufferPlanes; ++plane) {
205 return nullptr;
206 }
207
208 for (int plane = 0; plane < bufferPlanes; ++plane) {
213
214 // Tested to be valid in prior loop.
217
218 // Create a CoreVideo pixel buffer backed Metal texture image from the texture cache.
222 buffer, nil,
224 width, height,
225 plane,
227
228 if (ret != kCVReturnSuccess)
229 qWarning() << "texture creation failed" << ret;
230// auto t = CVMetalTextureGetTexture(textureHandles->cvMetalTexture[plane]);
231// qDebug() << " metal texture for plane" << plane << "is" << quint64(textureHandles->cvMetalTexture[plane]) << width << height;
232// qDebug() << " " << t.iosurfacePlane << t.pixelFormat << t.width << t.height;
233 }
234 } else if (rhi->backend() == QRhi::OpenGLES2) {
235#if QT_CONFIG(opengl)
236#ifdef Q_OS_MACOS
238 // Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
242 buffer,
243 nil,
245 if (cvret != kCVReturnSuccess) {
246 qCWarning(qLcVideotoolbox) << "OpenGL texture creation failed" << cvret;
247 return nullptr;
248 }
249
251#endif
252#ifdef Q_OS_IOS
254 // Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
258 buffer,
259 nil,
261 GL_RGBA,
264 GL_RGBA,
266 0,
268 if (cvret != kCVReturnSuccess) {
269 qCWarning(qLcVideotoolbox) << "OpenGL ES texture creation failed" << cvret;
270 return nullptr;
271 }
272#endif
273#endif
274 }
275
276 return textureHandles;
277}
278
279VideoToolBoxTextureHandles::~VideoToolBoxTextureHandles()
280{
281 for (int i = 0; i < 4; ++i)
282 if (cvMetalTexture[i])
283 CFRelease(cvMetalTexture[i]);
284#if defined(Q_OS_MACOS)
285 if (cvOpenGLTexture)
286 CVOpenGLTextureRelease(cvOpenGLTexture);
287#elif defined(Q_OS_IOS)
288 if (cvOpenGLESTexture)
289 CFRelease(cvOpenGLESTexture);
290#endif
291 CVPixelBufferRelease(m_buffer);
292}
293
294quint64 VideoToolBoxTextureHandles::textureHandle(QRhi &, int plane)
295{
296 if (rhi->backend() == QRhi::Metal)
297 return cvMetalTexture[plane] ? qint64(CVMetalTextureGetTexture(cvMetalTexture[plane])) : 0;
298#if QT_CONFIG(opengl)
299 Q_ASSERT(plane == 0);
300#ifdef Q_OS_MACOS
301 return CVOpenGLTextureGetName(cvOpenGLTexture);
302#endif
303#ifdef Q_OS_IOS
304 return CVOpenGLESTextureGetName(cvOpenGLESTexture);
305#endif
306#endif
307}
308
309}
310
311QT_END_NAMESPACE
static MTLPixelFormat rhiTextureFormatToMetalFormat(QRhiTexture::Format f)
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType
Q_STATIC_LOGGING_CATEGORY(lcAccessibilityCore, "qt.accessibility.core")