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
qffmpegaudioinput.cpp
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
#
include
"qffmpegaudioinput_p.h"
4
5
#
include
<
QtCore
/
qatomic
.
h
>
6
#
include
<
QtCore
/
qdebug
.
h
>
7
#
include
<
QtCore
/
qiodevice
.
h
>
8
#
include
<
QtCore
/
qmetaobject
.
h
>
9
#
include
<
QtMultimedia
/
qaudiobuffer
.
h
>
10
#
include
<
QtMultimedia
/
qaudiosource
.
h
>
11
12
QT_BEGIN_NAMESPACE
13
14
namespace
QFFmpeg
{
15
16
class
AudioSourceIO
:
public
QIODevice
17
{
18
Q_OBJECT
19
public
:
20
AudioSourceIO
(
QFFmpegAudioInput
*
audioInput
) :
m_input
(
audioInput
)
21
{
22
m_muted
=
m_input
->
muted
;
23
m_volume
=
m_input
->
volume
;
24
updateVolume
();
25
open
(
QIODevice
::
WriteOnly
);
26
}
27
28
~
AudioSourceIO
()
override
29
{
30
// QAudioSource may invoke QIODevice::writeData in the destructor.
31
// Let's reset the audio source to get around the case.
32
if
(
m_audioSource
)
33
m_audioSource
->
reset
();
34
}
35
36
void
setDevice
(
const
QAudioDevice
&
device
)
37
{
38
Q_ASSERT
(!
thread
()->
isCurrentThread
());
39
QMutexLocker
locker
(&
m_mutex
);
40
if
(
m_device
==
device
)
41
return
;
42
m_device
=
device
;
43
QMetaObject
::
invokeMethod
(
this
, [
this
] {
44
QMutexLocker
locker
(&
m_mutex
);
45
updateSource
(
locker
);
46
});
47
}
48
void
setBufferSize
(
int
bufferSize
)
49
{
50
m_bufferSize
.
storeRelease
((
bufferSize
> 0 &&
m_format
.
isValid
())
51
?
m_format
.
bytesForFrames
(
bufferSize
)
52
:
DefaultAudioInputBufferSize
);
53
}
54
void
setRunning
(
bool
r
) {
55
Q_ASSERT
(!
thread
()->
isCurrentThread
());
56
QMutexLocker
locker
(&
m_mutex
);
57
if
(
m_running
==
r
)
58
return
;
59
m_running
=
r
;
60
QMetaObject
::
invokeMethod
(
this
, &
AudioSourceIO
::
updateRunning
);
61
}
62
63
void
setVolume
(
float
vol
) {
64
Q_ASSERT
(!
thread
()->
isCurrentThread
());
65
QMutexLocker
locker
(&
m_mutex
);
66
m_volume
=
vol
;
67
QMetaObject
::
invokeMethod
(
this
, &
AudioSourceIO
::
updateVolume
);
68
}
69
void
setMuted
(
bool
muted
) {
70
Q_ASSERT
(!
thread
()->
isCurrentThread
());
71
QMutexLocker
locker
(&
m_mutex
);
72
m_muted
=
muted
;
73
QMetaObject
::
invokeMethod
(
this
, &
AudioSourceIO
::
updateVolume
);
74
}
75
76
int
bufferSize
()
const
{
return
m_bufferSize
.
loadAcquire
(); }
77
78
protected
:
79
qint64
readData
(
char
*,
qint64
)
override
80
{
81
return
0;
82
}
83
qint64
writeData
(
const
char
*
data
,
qint64
len
)
override
84
{
85
Q_ASSERT
(
m_audioSource
);
86
87
int
l
=
len
;
88
while
(
len
> 0) {
89
const
auto
bufferSize
=
m_bufferSize
.
loadAcquire
();
90
91
while
(
m_pcm
.
size
() >
bufferSize
) {
92
// bufferSize has been reduced. Send data until m_pcm
93
// can hold more data.
94
sendBuffer
(
m_pcm
.
first
(
bufferSize
));
95
m_pcm
.
remove
(0,
bufferSize
);
96
}
97
98
// Size of m_pcm is always <= bufferSize
99
int
toAppend
=
qMin
(
len
,
bufferSize
-
m_pcm
.
size
());
100
m_pcm
.
append
(
data
,
toAppend
);
101
data
+=
toAppend
;
102
len
-=
toAppend
;
103
if
(
m_pcm
.
size
() ==
bufferSize
) {
104
sendBuffer
(
m_pcm
);
105
m_pcm
.
clear
();
106
}
107
}
108
109
return
l
;
110
}
111
112
private
Q_SLOTS
:
113
void
updateVolume
()
114
{
115
if
(
m_audioSource
)
116
m_audioSource
->
setVolume
(
m_muted
? 0. :
m_volume
);
117
}
118
void
updateRunning
()
119
{
120
QMutexLocker
locker
(&
m_mutex
);
121
if
(
m_running
) {
122
if
(!
m_audioSource
)
123
updateSource
(
locker
);
124
else
125
m_audioSource
->
start
(
this
);
126
}
else
{
127
m_audioSource
->
stop
();
128
}
129
}
130
131
private
:
132
void
updateSource
(
const
QMutexLocker
<
QMutex
> &
guard
)
133
{
134
Q_ASSERT
(
guard
.
mutex
() == &
m_mutex
);
135
m_format
=
m_device
.
preferredFormat
();
136
if
(
std
::
exchange
(
m_audioSource
,
nullptr
))
137
m_pcm
.
clear
();
138
139
m_audioSource
=
std
::
make_unique
<
QAudioSource
>(
m_device
,
m_format
);
140
updateVolume
();
141
if
(
m_running
)
142
m_audioSource
->
start
(
this
);
143
}
144
145
void
sendBuffer
(
const
QByteArray
&
pcmData
)
146
{
147
QAudioFormat
fmt
=
m_audioSource
->
format
();
148
qint64
time
=
fmt
.
durationForBytes
(
m_processed
);
149
QAudioBuffer
buffer
(
pcmData
,
fmt
,
time
);
150
emit
m_input
->
newAudioBuffer
(
buffer
);
151
m_processed
+=
pcmData
.
size
();
152
}
153
154
QMutex
m_mutex
;
155
QAudioDevice m_device;
156
float
m_volume = 1.;
157
bool
m_muted =
false
;
158
bool
m_running =
false
;
159
160
QFFmpegAudioInput
*m_input =
nullptr
;
161
std::unique_ptr<QAudioSource> m_audioSource;
162
QAudioFormat m_format;
163
QAtomicInt m_bufferSize =
DefaultAudioInputBufferSize
;
164
qint64 m_processed = 0;
165
QByteArray m_pcm;
166
};
167
168
}
// namespace QFFmpeg
169
170
QFFmpegAudioInput
::QFFmpegAudioInput(QAudioInput *qq)
171
: QPlatformAudioInput(qq)
172
{
173
qRegisterMetaType<QAudioBuffer>();
174
175
m_inputThread = std::make_unique<QThread>();
176
m_inputThread->setObjectName(QStringLiteral(
"QFFmpegAudioInputThread"
));
177
m_audioIO =
new
QFFmpeg::AudioSourceIO(
this
);
178
m_audioIO->moveToThread(m_inputThread.get());
179
m_inputThread->start();
180
}
181
182
QFFmpegAudioInput
::~
QFFmpegAudioInput
()
183
{
184
// Ensure that COM is uninitialized by nested QWindowsResampler
185
// on the same thread that initialized it.
186
m_audioIO->deleteLater();
187
m_inputThread->exit();
188
m_inputThread->wait();
189
}
190
191
void
QFFmpegAudioInput
::
setAudioDevice
(
const
QAudioDevice &device)
192
{
193
m_audioIO->setDevice(device);
194
}
195
196
void
QFFmpegAudioInput
::
setMuted
(
bool
muted)
197
{
198
m_audioIO->setMuted(muted);
199
}
200
201
void
QFFmpegAudioInput
::
setVolume
(
float
volume)
202
{
203
m_audioIO->setVolume(volume);
204
}
205
206
void
QFFmpegAudioInput
::
setBufferSize
(
int
bufferSize)
207
{
208
m_audioIO->setBufferSize(bufferSize);
209
}
210
211
int
QFFmpegAudioInput
::
bufferSize
()
const
212
{
213
return
m_audioIO->bufferSize();
214
}
215
216
void
QFFmpegAudioInput
::
connectNotify
(
const
QMetaMethod &signal)
217
{
218
// threading considerations:
219
// AudioSourceIO::setRunning doesn't reenter
220
// the internal QObject's mutex of the audio input instance
221
if
(signal == QMetaMethod::fromSignal(&QFFmpegAudioInput::newAudioBuffer))
222
m_audioIO->setRunning(
true
);
223
}
224
225
void
QFFmpegAudioInput
::
disconnectNotify
(
const
QMetaMethod &signal)
226
{
227
if
(!signal.isValid()
228
|| signal == QMetaMethod::fromSignal(&QFFmpegAudioInput::newAudioBuffer)) {
229
auto
stopIOifNeeded = [
this
]() {
230
// if the signal disconnectNotify is not
231
if
(!isSignalConnected(QMetaMethod::fromSignal(&QFFmpegAudioInput::newAudioBuffer)))
232
m_audioIO->setRunning(
false
);
233
};
234
235
// threading considerations:
236
// QMetaObject::invokeMethod doesn't reenter
237
// the internal QObject's mutex of the audio input instance.
238
// Instead, QMetaObject::invokeMethod locks ThreadData::postEventMutex
239
240
// postpone update to avoid redundant QAudioSource restarts upon reconnection
241
QMetaObject::invokeMethod(
this
, stopIOifNeeded, Qt::QueuedConnection);
242
}
243
}
244
245
QT_END_NAMESPACE
246
247
#
include
"moc_qffmpegaudioinput_p.cpp"
248
249
#
include
"qffmpegaudioinput.moc"
QFFmpegAudioInput
Definition
qffmpegaudioinput_p.h:31
QFFmpegAudioInput::setAudioDevice
void setAudioDevice(const QAudioDevice &) override
Definition
qffmpegaudioinput.cpp:191
QFFmpegAudioInput::setVolume
void setVolume(float) override
Definition
qffmpegaudioinput.cpp:201
QFFmpegAudioInput::setMuted
void setMuted(bool) override
Definition
qffmpegaudioinput.cpp:196
QFFmpegAudioInput::setBufferSize
void setBufferSize(int bufferSize)
Definition
qffmpegaudioinput.cpp:206
QFFmpegAudioInput::bufferSize
int bufferSize() const
Definition
qffmpegaudioinput.cpp:211
QFFmpegAudioInput::connectNotify
void connectNotify(const QMetaMethod &signal) override
Definition
qffmpegaudioinput.cpp:216
QFFmpegAudioInput::disconnectNotify
void disconnectNotify(const QMetaMethod &signal) override
Definition
qffmpegaudioinput.cpp:225
QFFmpegAudioInput::~QFFmpegAudioInput
~QFFmpegAudioInput() override
Definition
qffmpegaudioinput.cpp:182
QFFmpeg::AudioSourceIO
Definition
qffmpegaudioinput.cpp:17
QFFmpeg::AvioWriteBufferType
std::conditional_t< QT_FFMPEG_AVIO_WRITE_CONST, const uint8_t *, uint8_t * > AvioWriteBufferType
Definition
qffmpegioutils_p.h:29
QPlatformGraphicsBufferHelper
\inmodule QtGui
qtmultimedia
src
plugins
multimedia
ffmpeg
qffmpegaudioinput.cpp
Generated on
for Qt by
1.14.0