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