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
const
auto
frameRate
=
std
::
min
(
screen
->
refreshRate
(),
MaxScreenCaptureFrameRate
);
74
[
m_sampleBufferDelegate
setVideoFormatFrameRate
:
frameRate
];
75
76
m_screenInput
= [[
AVCaptureScreenInput
alloc
]
initWithDisplayID
:
screenID
];
77
[
m_screenInput
setMinFrameDuration
:
CMTimeMake
(1,
static_cast
<
int32_t
>(
frameRate
))];
78
[
m_captureSession
addInput
:
m_screenInput
];
79
80
[
m_captureSession
startRunning
];
81
}
82
83
~
Grabber
()
84
{
85
if
(
m_captureSession
)
86
[
m_captureSession
stopRunning
];
87
88
if
(
m_dispatchQueue
) {
89
// Push a blocking job to the background frame thread,
90
// so we guarantee future frames are discarded. This
91
// causes the frameHandler to be destroyed, and the reference
92
// to this QAVFScreenCapture is cleared.
93
dispatch_sync
(
94
m_dispatchQueue
,
95
[
this
]() {
96
[
m_sampleBufferDelegate
discardFutureSamples
];
97
});
98
99
dispatch_release
(
m_dispatchQueue
);
100
}
101
102
[
m_sampleBufferDelegate
release
];
103
[
m_screenInput
release
];
104
[
m_videoDataOutput
release
];
105
[
m_captureSession
release
];
106
}
107
108
private
:
109
AVCaptureSession
*
m_captureSession
=
nullptr
;
110
AVCaptureScreenInput
*
m_screenInput
=
nullptr
;
111
AVCaptureVideoDataOutput
*
m_videoDataOutput
=
nullptr
;
112
QAVFSampleBufferDelegate
*
m_sampleBufferDelegate
=
nullptr
;
113
dispatch_queue_t
m_dispatchQueue
=
nullptr
;
114
};
115
116
QAVFScreenCapture
::
QAVFScreenCapture
() :
QPlatformSurfaceCapture
(
ScreenSource
{})
117
{
118
CGRequestScreenCaptureAccess
();
119
}
120
121
QAVFScreenCapture
::~
QAVFScreenCapture
()
122
{
123
resetCapture
();
124
}
125
126
bool
QAVFScreenCapture
::
setActiveInternal
(
bool
active
)
127
{
128
if
(
active
) {
129
if
(!
CGPreflightScreenCaptureAccess
()) {
130
updateError
(
CaptureFailed
,
QLatin1String
(
"Permissions denied"
));
131
return
false
;
132
}
133
134
auto
screen
=
source
<
ScreenSource
>();
135
136
if
(!
checkScreenWithError
(
screen
))
137
return
false
;
138
139
return
initScreenCapture
(
screen
);
140
}
else
{
141
resetCapture
();
142
}
143
144
return
true
;
145
}
146
147
void
QAVFScreenCapture
::
onNewFrame
(
const
QVideoFrame
&
frame
)
148
{
149
// Since writing of the format is supposed to be only from one thread,
150
// the read-only comparison without a mutex is thread-safe
151
if
(!
m_format
||
m_format
!=
frame
.
surfaceFormat
()) {
152
QMutexLocker
<
QMutex
>
locker
(&
m_formatMutex
);
153
154
m_format
=
frame
.
surfaceFormat
();
155
156
locker
.
unlock
();
157
158
m_waitForFormat
.
notify_one
();
159
}
160
161
emit
newVideoFrame
(
frame
);
162
}
163
164
QVideoFrameFormat
QAVFScreenCapture
::
frameFormat
()
const
165
{
166
if
(!
m_grabber
)
167
return
{};
168
169
QMutexLocker
<
QMutex
>
locker
(&
m_formatMutex
);
170
while
(!
m_format
)
171
m_waitForFormat
.
wait
(&
m_formatMutex
);
172
return
*
m_format
;
173
}
174
175
std
::
optional
<
int
>
QAVFScreenCapture
::
ffmpegHWPixelFormat
()
const
176
{
177
return
AV_PIX_FMT_VIDEOTOOLBOX
;
178
}
179
180
bool
QAVFScreenCapture
::
initScreenCapture
(
QScreen
*
screen
)
181
{
182
const
auto
screenID
=
findDisplayByName
(
screen
->
name
());
183
184
if
(
screenID
==
kCGNullDirectDisplay
) {
185
updateError
(
InternalError
,
QLatin1String
(
"Screen exists but couldn't been found by name"
));
186
return
false
;
187
}
188
189
auto
hwAccel
=
HWAccel
::
create
(
AV_HWDEVICE_TYPE_VIDEOTOOLBOX
);
190
191
if
(!
hwAccel
) {
192
updateError
(
CaptureFailed
,
QLatin1String
(
"Couldn't create videotoolbox hw acceleration"
));
193
return
false
;
194
}
195
196
hwAccel
->
createFramesContext
(
av_map_videotoolbox_format_to_pixfmt
(
DefaultCVPixelFormat
),
197
screen
->
size
() *
screen
->
devicePixelRatio
());
198
199
if
(!
hwAccel
->
hwFramesContextAsBuffer
()) {
200
updateError
(
CaptureFailed
,
QLatin1String
(
"Couldn't create hw frames context"
));
201
return
false
;
202
}
203
204
m_grabber
=
std
::
make_unique
<
Grabber
>(*
this
,
screen
,
screenID
,
std
::
move
(
hwAccel
));
205
return
true
;
206
}
207
208
void
QAVFScreenCapture
::
resetCapture
()
209
{
210
m_grabber
.
reset
();
211
m_format
= {};
212
}
213
214
std
::
unique_ptr
<
QPlatformSurfaceCapture
>
makeQAvfScreenCapture
()
215
{
216
return
std::make_unique<QAVFScreenCapture>();
217
}
218
219
}
// namespace QFFmpeg
220
221
QT_END_NAMESPACE
222
223
#
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:214
qtmultimedia
src
plugins
multimedia
ffmpeg
darwin
qavfscreencapture.mm
Generated on
for Qt by
1.16.1