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
qavfscreencapture.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
3
4
#
include
<
QtFFmpegMediaPluginImpl
/
private
/
qavfscreencapture_p
.
h
>
5
6
#
include
<
QtGui
/
qscreen
.
h
>
7
8
#
include
<
QtFFmpegMediaPluginImpl
/
private
/
qavfsamplebufferdelegate_p
.
h
>
9
#
include
<
QtFFmpegMediaPluginImpl
/
private
/
qffmpegsurfacecapturegrabber_p
.
h
>
10
#
define
AVMediaType
XAVMediaType
11
#
include
<
QtFFmpegMediaPluginImpl
/
private
/
qffmpeghwaccel_p
.
h
>
12
#
undef
AVMediaType
13
14
#
include
<
QtMultimedia
/
private
/
qavfhelpers_p
.
h
>
15
16
#
define
AVMediaType
XAVMediaType
17
extern
"C"
{
18
#
include
<
libavutil
/
hwcontext_videotoolbox
.
h
>
19
#
include
<
libavutil
/
hwcontext
.
h
>
20
}
21
#
undef
AVMediaType
22
23
#
import
<
AppKit
/
NSScreen
.
h
>
24
25
#
import
<
dispatch
/
dispatch
.
h
>
26
27
namespace
{
28
29
const
auto
DefaultCVPixelFormat = kCVPixelFormatType_32BGRA;
30
31
CGDirectDisplayID findDisplayByName(
const
QString &name)
32
{
33
for
(NSScreen *screen in NSScreen.screens) {
34
if
(name == QString::fromNSString(screen.localizedName))
35
return
[screen.deviceDescription[@
"NSScreenNumber"
] unsignedIntValue];
36
}
37
return
kCGNullDirectDisplay;
38
}
39
}
40
41
QT_BEGIN_NAMESPACE
42
43
namespace
QFFmpeg
{
44
45
class
QAVFScreenCapture
::
Grabber
46
{
47
public
:
48
Grabber
(
QAVFScreenCapture
&
capture
,
QScreen
*
screen
,
CGDirectDisplayID
screenID
,
49
std
::
unique_ptr
<
HWAccel
>
hwAccel
)
50
{
51
m_captureSession
= [[
AVCaptureSession
alloc
]
init
];
52
53
m_sampleBufferDelegate
= [[
QAVFSampleBufferDelegate
alloc
]
54
initWithFrameHandler
:[&
capture
](
const
QVideoFrame
&
frame
) {
55
capture
.
onNewFrame
(
frame
);
56
}];
57
58
m_videoDataOutput
= [[
AVCaptureVideoDataOutput
alloc
]
init
];
59
60
NSDictionary
*
videoSettings
= [
NSDictionary
61
dictionaryWithObjectsAndKeys
:[
NSNumber
numberWithUnsignedInt
:
DefaultCVPixelFormat
],
62
kCVPixelBufferPixelFormatTypeKey
,
nil
];
63
64
[
m_videoDataOutput
setVideoSettings
:
videoSettings
];
65
[
m_videoDataOutput
setAlwaysDiscardsLateVideoFrames
:
true
];
66
67
// Configure video output
68
m_dispatchQueue
=
dispatch_queue_create
(
"vf_queue"
,
nullptr
);
69
[
m_videoDataOutput
setSampleBufferDelegate
:
m_sampleBufferDelegate
queue
:
m_dispatchQueue
];
70
71
[
m_captureSession
addOutput
:
m_videoDataOutput
];
72
73
[
m_sampleBufferDelegate
setHWAccel
:
std
::
move
(
hwAccel
)];
74
75
Q_ASSERT
(
screen
);
76
const
auto
frameRate
=
capture
.
frameRate
().
value_or
(
screen
->
refreshRate
());
77
[
m_sampleBufferDelegate
setVideoFormatFrameRate
:
frameRate
];
78
79
m_screenInput
= [[
AVCaptureScreenInput
alloc
]
initWithDisplayID
:
screenID
];
80
[
m_screenInput
setMinFrameDuration
:
CMTimeMake
(1,
static_cast
<
int32_t
>(
frameRate
))];
81
[
m_captureSession
addInput
:
m_screenInput
];
82
83
[
m_captureSession
startRunning
];
84
}
85
86
~
Grabber
()
87
{
88
if
(
m_captureSession
)
89
[
m_captureSession
stopRunning
];
90
91
if
(
m_dispatchQueue
) {
92
// Push a blocking job to the background frame thread,
93
// so we guarantee future frames are discarded. This
94
// causes the frameHandler to be destroyed, and the reference
95
// to this QAVFScreenCapture is cleared.
96
dispatch_sync
(
97
m_dispatchQueue
,
98
[
this
]() {
99
[
m_sampleBufferDelegate
discardFutureSamples
];
100
});
101
102
dispatch_release
(
m_dispatchQueue
);
103
}
104
105
[
m_sampleBufferDelegate
release
];
106
[
m_screenInput
release
];
107
[
m_videoDataOutput
release
];
108
[
m_captureSession
release
];
109
}
110
111
private
:
112
AVCaptureSession
*
m_captureSession
=
nullptr
;
113
AVCaptureScreenInput
*
m_screenInput
=
nullptr
;
114
AVCaptureVideoDataOutput
*
m_videoDataOutput
=
nullptr
;
115
QAVFSampleBufferDelegate
*
m_sampleBufferDelegate
=
nullptr
;
116
dispatch_queue_t
m_dispatchQueue
=
nullptr
;
117
};
118
119
QAVFScreenCapture
::
QAVFScreenCapture
() :
QPlatformSurfaceCapture
(
ScreenSource
{})
120
{
121
CGRequestScreenCaptureAccess
();
122
}
123
124
QAVFScreenCapture
::~
QAVFScreenCapture
()
125
{
126
resetCapture
();
127
}
128
129
bool
QAVFScreenCapture
::
setActiveInternal
(
bool
active
)
130
{
131
if
(
active
) {
132
if
(!
QAVFHelpers
::
checkMacOsScreenCapturePermissions
()) {
133
updateError
(
134
QPlatformSurfaceCapture
::
Error
::
CaptureFailed
,
135
QLatin1String
(
"Permissions denied"
));
136
return
false
;
137
}
138
139
auto
screen
=
source
<
ScreenSource
>();
140
141
if
(!
checkScreenWithError
(
screen
))
142
return
false
;
143
144
return
initScreenCapture
(
screen
);
145
}
else
{
146
resetCapture
();
147
}
148
149
return
true
;
150
}
151
152
void
QAVFScreenCapture
::
onNewFrame
(
const
QVideoFrame
&
frame
)
153
{
154
// Since writing of the format is supposed to be only from one thread,
155
// the read-only comparison without a mutex is thread-safe
156
if
(!
m_format
||
m_format
!=
frame
.
surfaceFormat
()) {
157
QMutexLocker
<
QMutex
>
locker
(&
m_formatMutex
);
158
159
m_format
=
frame
.
surfaceFormat
();
160
161
locker
.
unlock
();
162
163
m_waitForFormat
.
notify_one
();
164
}
165
166
emit
newVideoFrame
(
frame
);
167
}
168
169
QVideoFrameFormat
QAVFScreenCapture
::
frameFormat
()
const
170
{
171
if
(!
m_grabber
)
172
return
{};
173
174
QMutexLocker
<
QMutex
>
locker
(&
m_formatMutex
);
175
while
(!
m_format
)
176
m_waitForFormat
.
wait
(&
m_formatMutex
);
177
return
*
m_format
;
178
}
179
180
std
::
optional
<
int
>
QAVFScreenCapture
::
ffmpegHWPixelFormat
()
const
181
{
182
return
AV_PIX_FMT_VIDEOTOOLBOX
;
183
}
184
185
bool
QAVFScreenCapture
::
initScreenCapture
(
QScreen
*
screen
)
186
{
187
const
auto
screenID
=
findDisplayByName
(
screen
->
name
());
188
189
if
(
screenID
==
kCGNullDirectDisplay
) {
190
updateError
(
191
QPlatformSurfaceCapture
::
Error
::
InternalError
,
192
QLatin1String
(
"Screen exists but couldn't been found by name"
));
193
return
false
;
194
}
195
196
auto
hwAccel
=
HWAccel
::
create
(
AV_HWDEVICE_TYPE_VIDEOTOOLBOX
);
197
198
if
(!
hwAccel
) {
199
updateError
(
200
QPlatformSurfaceCapture
::
Error
::
CaptureFailed
,
201
QLatin1String
(
"Couldn't create videotoolbox hw acceleration"
));
202
return
false
;
203
}
204
205
hwAccel
->
createFramesContext
(
av_map_videotoolbox_format_to_pixfmt
(
DefaultCVPixelFormat
),
206
screen
->
size
() *
screen
->
devicePixelRatio
());
207
208
if
(!
hwAccel
->
hwFramesContextAsBuffer
()) {
209
updateError
(
210
QPlatformSurfaceCapture
::
Error
::
CaptureFailed
,
211
QLatin1String
(
"Couldn't create hw frames context"
));
212
return
false
;
213
}
214
215
m_grabber
=
std
::
make_unique
<
Grabber
>(*
this
,
screen
,
screenID
,
std
::
move
(
hwAccel
));
216
return
true
;
217
}
218
219
void
QAVFScreenCapture
::
resetCapture
()
220
{
221
m_grabber
.
reset
();
222
m_format
= {};
223
}
224
225
std
::
unique_ptr
<
QPlatformSurfaceCapture
>
makeQAvfScreenCapture
()
226
{
227
return
std::make_unique<QAVFScreenCapture>();
228
}
229
230
}
// namespace QFFmpeg
231
232
QT_END_NAMESPACE
233
234
#
include
"moc_qavfscreencapture_p.cpp"
QFFmpeg::QAVFScreenCapture::Grabber
Definition
qavfscreencapture.mm:46
QFFmpeg::QMacScreenCaptureStreamDelegate
QT_MANGLE_NAMESPACE(QMacScreenCaptureStreamDelegate) QMacScreenCaptureStreamDelegate
Definition
qmacscreencapturekit_p.h:46
QFFmpeg::makeQAvfScreenCapture
std::unique_ptr< QPlatformSurfaceCapture > makeQAvfScreenCapture()
Definition
qavfscreencapture.mm:225
qtmultimedia
src
plugins
multimedia
ffmpeg
darwin
qavfscreencapture.mm
Generated on
for Qt by
1.16.1