Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
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
32
QT_BEGIN_NAMESPACE
33
34
Q_STATIC_LOGGING_CATEGORY
(qLcVideotoolbox,
"qt.multimedia.ffmpeg.videotoolbox"
);
35
36
namespace
QFFmpeg
37
{
38
39
namespace
{
40
41
class
VideoToolBoxTextureHandles :
public
QVideoFrameTexturesHandles
42
{
43
public
:
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
62
std
::
shared_ptr
<
VideoToolBoxTextureConverter
>
VideoToolBoxTextureConverter
::
create
(
QRhi
*
rhi
)
63
{
64
auto
ret
=
std
::
shared_ptr
<
VideoToolBoxTextureConverter
>(
new
VideoToolBoxTextureConverter
(
rhi
));
65
return
ret
->
rhi
?
ret
:
nullptr
;
66
}
67
68
VideoToolBoxTextureConverter
::
VideoToolBoxTextureConverter
(
QRhi
*
targetRhi
)
69
:
TextureConverterBackend
(
targetRhi
)
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.
78
Q_ASSERT
(!
m_cvMetalTextureCache
);
79
CVMetalTextureCacheRef
outCvMetalTexCacheRef
=
nullptr
;
80
CVReturn
cvReturn
=
CVMetalTextureCacheCreate
(
81
kCFAllocatorDefault
,
82
nil
,
83
(
id
<
MTLDevice
>)
metal
->
dev
,
84
nil
,
85
&
outCvMetalTexCacheRef
);
86
if
(
cvReturn
!=
kCVReturnSuccess
) {
87
qCWarning
(
qLcVideotoolbox
) <<
"Metal texture cache creation failed"
;
88
rhi
=
nullptr
;
89
}
90
91
Q_ASSERT
(
outCvMetalTexCacheRef
);
92
m_cvMetalTextureCache
=
QCFType
<
CVMetalTextureCacheRef
>{
outCvMetalTexCacheRef
};
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.
100
NSOpenGLContext
*
nsGLContext
=
101
gl
->
context
->
nativeInterface
<
QNativeInterface
::
QCocoaGLContext
>()->
nativeContext
();
102
CGLPixelFormatObj
nsGLPixelFormat
=
nsGLContext
.
pixelFormat
.
CGLPixelFormatObj
;
103
CVOpenGLTextureCacheRef
outCvGlTexCacheRef
=
nullptr
;
104
CVReturn
cvReturn
=
CVOpenGLTextureCacheCreate
(
105
kCFAllocatorDefault
,
106
nullptr
,
107
reinterpret_cast
<
CGLContextObj
>(
nsGLContext
.
CGLContextObj
),
108
nsGLPixelFormat
,
109
nil
,
110
&
outCvGlTexCacheRef
);
111
if
(
cvReturn
!=
kCVReturnSuccess
) {
112
qCWarning
(
qLcVideotoolbox
) <<
"OpenGL texture cache creation failed"
;
113
rhi
=
nullptr
;
114
}
115
116
Q_ASSERT
(
outCvGlTexCacheRef
);
117
m_cvOpenGLTextureCache
=
QCFType
<
CVOpenGLTextureCacheRef
>{
outCvGlTexCacheRef
};
118
119
#
endif
120
#
ifdef
Q_OS_IOS
121
// Create an OpenGL CoreVideo texture cache from the pixel buffer.
122
CVOpenGLESTextureCacheRef
outCvGlEsTexCacheRef
=
nullptr
;
123
CVReturn
cvReturn
=
CVOpenGLESTextureCacheCreate
(
124
kCFAllocatorDefault
,
125
nullptr
,
126
[
EAGLContext
currentContext
],
127
nullptr
,
128
&
outCvGlEsTexCacheRef
);
129
if
(
cvReturn
!=
kCVReturnSuccess
) {
130
qCWarning
(
qLcVideotoolbox
) <<
"OpenGLES texture cache creation failed"
;
131
rhi
=
nullptr
;
132
}
133
134
Q_ASSERT
(
outCvGlEsTexCacheRef
);
135
m_cvOpenGLESTextureCache
=
QCFType
<
CVOpenGLESTextureCacheRef
>{
outCvGlEsTexCacheRef
};
136
137
#
endif
138
#
else
139
rhi
=
nullptr
;
140
#
endif
// QT_CONFIG(opengl)
141
}
142
}
143
144
VideoToolBoxTextureConverter
::~
VideoToolBoxTextureConverter
()
145
{
146
freeTextureCaches
();
147
}
148
149
void
VideoToolBoxTextureConverter
::
freeTextureCaches
()
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
159
static
MTLPixelFormat
rhiTextureFormatToMetalFormat
(QRhiTexture::Format f)
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
190
QVideoFrameTexturesHandlesUPtr
191
VideoToolBoxTextureConverter
::
createTextureHandles
(
AVFrame
*
frame
)
192
{
193
if
(!
rhi
)
194
return
nullptr
;
195
196
bool
needsConversion
=
false
;
197
QVideoFrameFormat
::
PixelFormat
pixelFormat
=
QFFmpegVideoBuffer
::
toQtPixelFormat
(
HWAccel
::
format
(
frame
), &
needsConversion
);
198
if
(
needsConversion
) {
199
return
nullptr
;
200
}
201
202
auto
cvPixelBufferRef
=
reinterpret_cast
<
CVPixelBufferRef
>(
frame
->
data
[3]);
203
Q_ASSERT
(
cvPixelBufferRef
);
204
205
auto
textureHandles
=
std
::
make_unique
<
VideoToolBoxTextureHandles
>();
206
textureHandles
->
parentConverterBackend
=
shared_from_this
();
207
textureHandles
->
m_buffer
=
QAVFHelpers
::
QSharedCVPixelBuffer
(
208
cvPixelBufferRef
,
209
QAVFHelpers
::
QSharedCVPixelBuffer
::
RefMode
::
NeedsRef
);
210
textureHandles
->
rhi
=
rhi
;
211
212
auto
*
textureDescription
=
QVideoTextureHelper
::
textureDescription
(
pixelFormat
);
213
const
int
bufferPlanes
=
textureDescription
->
nplanes
;
214
215
if
(
rhi
->
backend
() ==
QRhi
::
Metal
) {
216
// First check that all planes have pixel-formats that we can handle,
217
// before we create any Metal textures.
218
for
(
int
plane
= 0;
plane
<
bufferPlanes
; ++
plane
) {
219
const
MTLPixelFormat
metalPixelFormatForPlane
=
220
rhiTextureFormatToMetalFormat
(
textureDescription
->
rhiTextureFormat
(
plane
,
rhi
));
221
if
(
metalPixelFormatForPlane
==
MTLPixelFormatInvalid
)
222
return
nullptr
;
223
}
224
225
for
(
int
plane
= 0;
plane
<
bufferPlanes
; ++
plane
) {
226
size_t
width
=
CVPixelBufferGetWidth
(
textureHandles
->
m_buffer
.
get
());
227
size_t
height
=
CVPixelBufferGetHeight
(
textureHandles
->
m_buffer
.
get
());
228
width
=
textureDescription
->
widthForPlane
(
width
,
plane
);
229
height
=
textureDescription
->
heightForPlane
(
height
,
plane
);
230
231
// Tested to be valid in prior loop.
232
const
MTLPixelFormat
metalPixelFormatForPlane
=
233
rhiTextureFormatToMetalFormat
(
textureDescription
->
rhiTextureFormat
(
plane
,
rhi
));
234
235
// Create a CoreVideo pixel buffer backed Metal texture image from the texture cache.
236
CVMetalTextureRef
outCvMetalTexRef
=
nullptr
;
237
auto
ret
=
CVMetalTextureCacheCreateTextureFromImage
(
238
kCFAllocatorDefault
,
239
m_cvMetalTextureCache
,
240
textureHandles
->
m_buffer
.
get
(),
241
nil
,
242
metalPixelFormatForPlane
,
243
width
,
height
,
244
plane
,
245
&
outCvMetalTexRef
);
246
if
(
ret
!=
kCVReturnSuccess
) {
247
qCWarning
(
qLcVideotoolbox
) <<
"Metal texture creation failed"
<<
ret
;
248
return
nullptr
;
249
}
250
251
Q_ASSERT
(
outCvMetalTexRef
);
252
textureHandles
->
m_cvMetalTexture
[
plane
] =
QCFType
<
CVMetalTextureRef
>{
outCvMetalTexRef
};
253
254
}
255
}
else
if
(
rhi
->
backend
() ==
QRhi
::
OpenGLES2
) {
256
#
if
QT_CONFIG
(
opengl
)
257
#
ifdef
Q_OS_MACOS
258
CVOpenGLTextureCacheFlush
(
m_cvOpenGLTextureCache
, 0);
259
CVOpenGLTextureRef
outCvGlTexRef
=
nullptr
;
260
// Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
261
const
CVReturn
cvret
=
CVOpenGLTextureCacheCreateTextureFromImage
(
262
kCFAllocatorDefault
,
263
m_cvOpenGLTextureCache
,
264
textureHandles
->
m_buffer
.
get
(),
265
nil
,
266
&
outCvGlTexRef
);
267
if
(
cvret
!=
kCVReturnSuccess
) {
268
qCWarning
(
qLcVideotoolbox
) <<
"OpenGL texture creation failed"
<<
cvret
;
269
return
nullptr
;
270
}
271
272
Q_ASSERT
(
outCvGlTexRef
);
273
Q_ASSERT
(
CVOpenGLTextureGetTarget
(
outCvGlTexRef
) ==
GL_TEXTURE_RECTANGLE
);
274
textureHandles
->
m_cvOpenGLTexture
=
QCFType
<
CVOpenGLTextureRef
>{
outCvGlTexRef
};
275
276
#
endif
277
#
ifdef
Q_OS_IOS
278
CVOpenGLESTextureCacheFlush
(
m_cvOpenGLESTextureCache
, 0);
279
CVOpenGLESTextureRef
outCvGlTexRef
=
nullptr
;
280
// Create a CVPixelBuffer-backed OpenGL texture image from the texture cache.
281
const
CVReturn
cvret
=
CVOpenGLESTextureCacheCreateTextureFromImage
(
282
kCFAllocatorDefault
,
283
m_cvOpenGLESTextureCache
,
284
textureHandles
->
m_buffer
.
get
(),
285
nil
,
286
GL_TEXTURE_2D
,
287
GL_RGBA
,
288
CVPixelBufferGetWidth
(
textureHandles
->
m_buffer
.
get
()),
289
CVPixelBufferGetHeight
(
textureHandles
->
m_buffer
.
get
()),
290
GL_RGBA
,
291
GL_UNSIGNED_BYTE
,
292
0,
293
&
outCvGlTexRef
);
294
if
(
cvret
!=
kCVReturnSuccess
) {
295
qCWarning
(
qLcVideotoolbox
) <<
"OpenGL ES texture creation failed"
<<
cvret
;
296
return
nullptr
;
297
}
298
299
Q_ASSERT
(
outCvGlTexRef
);
300
textureHandles
->
m_cvOpenGLESTexture
=
QCFType
<
CVOpenGLESTextureRef
>{
outCvGlTexRef
};
301
302
#
endif
303
#
endif
304
}
305
306
return
textureHandles
;
307
}
308
309
VideoToolBoxTextureHandles::~VideoToolBoxTextureHandles()
310
{
311
}
312
313
quint64 VideoToolBoxTextureHandles::textureHandle(QRhi &,
int
plane)
314
{
315
if
(rhi->backend() == QRhi::Metal)
316
return
m_cvMetalTexture[plane] ? qint64(CVMetalTextureGetTexture(m_cvMetalTexture[plane])) : 0;
317
#
if
QT_CONFIG
(
opengl
)
318
Q_ASSERT(plane == 0);
319
#
ifdef
Q_OS_MACOS
320
return
CVOpenGLTextureGetName(m_cvOpenGLTexture);
321
#
endif
322
#
ifdef
Q_OS_IOS
323
return
CVOpenGLESTextureGetName(m_cvOpenGLESTexture);
324
#
endif
325
#
endif
326
return
0;
327
}
328
329
}
330
331
QT_END_NAMESPACE
QFFmpeg
Definition
qandroidcacertificates.cpp:26
QFFmpeg::rhiTextureFormatToMetalFormat
static MTLPixelFormat rhiTextureFormatToMetalFormat(QRhiTexture::Format f)
Definition
qffmpeghwaccel_videotoolbox.mm:159
Q_STATIC_LOGGING_CATEGORY
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)
qtmultimedia
src
plugins
multimedia
ffmpeg
darwin
qffmpeghwaccel_videotoolbox.mm
Generated on
for Qt by
1.18.0