6#include <QtCore/qloggingcategory.h>
8#include <QtFFmpegMediaPluginImpl/private/qffmpegaudioinput_p.h>
9#include <QtFFmpegMediaPluginImpl/private/qffmpegimagecapture_p.h>
10#include <QtFFmpegMediaPluginImpl/private/qffmpegmediarecorder_p.h>
12#include <QtMultimedia/private/qmultimedia_ranges_p.h>
13#include <QtMultimedia/private/qplatformaudioinput_p.h>
14#include <QtMultimedia/private/qplatformaudiobufferinput_p.h>
15#include <QtMultimedia/private/qplatformaudiooutput_p.h>
16#include <QtMultimedia/private/qplatformcamera_p.h>
17#include <QtMultimedia/private/qplatformsurfacecapture_p.h>
18#include <QtMultimedia/private/qplatformvideoframeinput_p.h>
19#include <QtMultimedia/qaudiobuffer.h>
20#include <QtMultimedia/qaudiooutput.h>
21#include <QtMultimedia/qaudiosink.h>
22#include <QtMultimedia/qvideosink.h>
28using namespace Qt::StringLiterals;
29namespace ranges = QtMultimediaPrivate::ranges;
37 constexpr int BufferSizeFactor = 2;
38 constexpr int BufferSizeExceeding = 4096;
40 return input.bufferSize() * BufferSizeFactor + BufferSizeExceeding;
47 &QFFmpegMediaCaptureSession::primaryActiveVideoSourceChanged,
50 updateVideoFrameConnection(
nullptr);
63 if (setVideoSource(m_camera, camera))
69 return m_screenCapture;
74 if (setVideoSource(m_screenCapture, screenCapture))
75 emit screenCaptureChanged();
80 return m_windowCapture;
85 if (setVideoSource(m_windowCapture, windowCapture))
86 emit windowCaptureChanged();
91 return m_videoFrameInput;
96 if (setVideoSource(m_videoFrameInput, input))
97 emit videoFrameInputChanged();
102 return m_imageCapture;
107 if (m_imageCapture == imageCapture)
111 m_imageCapture->setCaptureSession(
nullptr);
116 m_imageCapture->setCaptureSession(
this);
118 emit imageCaptureChanged();
124 if (m_mediaRecorder == r)
128 m_mediaRecorder->setCaptureSession(
nullptr);
131 m_mediaRecorder->setCaptureSession(
this);
133 emit encoderChanged();
138 return m_mediaRecorder;
143 qCDebug(qLcFFmpegMediaCaptureSession)
144 <<
"set audio input:" << (input ? input->device.description() : u"null"_s);
147 Q_ASSERT(!!input == !!ffmpegAudioInput);
149 if (m_audioInput == ffmpegAudioInput)
153 m_audioInput->q->disconnect(
this);
155 m_audioInput = ffmpegAudioInput;
158 connect(m_audioInput->q, &QAudioInput::deviceChanged,
this,
159 &QFFmpegMediaCaptureSession::updateAudioSink);
167 m_audioBufferInput = input;
173 m_audioSink->reset();
177 if (!m_audioInput || !m_audioOutput)
180 auto format = m_audioInput->device.preferredFormat();
182 if (!m_audioOutput->device.isFormatSupported(format))
183 qWarning() <<
"Audio source format" << format <<
"is not compatible with the audio output";
185 m_audioSink = std::make_unique<QAudioSink>(m_audioOutput->device, format);
187 m_audioBufferSize = preferredAudioSinkBufferSize(*m_audioInput);
188 m_audioSink->setBufferSize(m_audioBufferSize);
190 qCDebug(qLcFFmpegMediaCaptureSession)
191 <<
"Create audiosink, format:" << format <<
"bufferSize:" << m_audioSink->bufferSize()
192 <<
"output device:" << m_audioOutput->device.description();
194 m_audioIODevice = m_audioSink->start();
195 if (m_audioIODevice) {
196 auto writeToDevice = [
this](
const QAudioBuffer &buffer) {
197 if (m_audioBufferSize < preferredAudioSinkBufferSize(*m_audioInput)) {
198 qCDebug(qLcFFmpegMediaCaptureSession)
199 <<
"Recreate audiosink due to small buffer size:" << m_audioBufferSize;
205 m_audioIODevice->write(buffer.data<
const char>(), buffer.byteCount());
207 if (written < buffer.byteCount())
208 qCWarning(qLcFFmpegMediaCaptureSession)
209 <<
"Not all bytes written:" << written <<
"vs" << buffer.byteCount();
211 connect(m_audioInput, &QFFmpegAudioInput::newAudioBuffer, m_audioSink.get(), writeToDevice);
213 qWarning() <<
"Failed to start audiosink push mode";
222 m_audioSink->setVolume(m_audioOutput->muted ? 0.f : m_audioOutput->volume);
232 if (std::exchange(m_videoSink, sink) == sink)
235 updateVideoFrameConnection(
nullptr);
240 qCDebug(qLcFFmpegMediaCaptureSession)
241 <<
"set audio output:" << (output ? output->device.description() : u"null"_s);
243 if (m_audioOutput == output)
247 m_audioOutput->q->disconnect(
this);
249 m_audioOutput = output;
252 connect(m_audioOutput->q, &QAudioOutput::deviceChanged,
this,
253 &QFFmpegMediaCaptureSession::updateAudioSink);
254 connect(m_audioOutput->q, &QAudioOutput::volumeChanged,
this,
256 connect(m_audioOutput->q, &QAudioOutput::mutedChanged,
this,
269 updateVideoFrameConnection(&source);
276 updateVideoFrameConnection(
nullptr);
281QPlatformVideoSource *
285 const std::array<QPlatformVideoSource *, 4> sourcesByPriority{
286 videoFrameInput(), camera(), screenCapture(), windowCapture()
289 auto it = ranges::find_if(
291 [&](QPlatformVideoSource *item) {
292 return item && (item == pendingActiveSource || item->isActive());
294 if (it != sourcesByPriority.end())
302 QPlatformVideoSource *source = primaryVideoSource(pendingActiveSource);
304 if (m_videoSinkConnection.source == source && m_videoSinkConnection.sink == m_videoSink)
307 disconnect(m_videoSinkConnection.connection);
308 m_videoSinkConnection = {};
310 if (source && m_videoSink) {
313 m_videoSinkConnection.source = source;
314 m_videoSinkConnection.sink = m_videoSink;
315 m_videoSinkConnection.connection = connect(
317 &QPlatformVideoSource::newVideoFrame,
319 &QVideoSink::setVideoFrame);
325 QPlatformVideoSource *source = primaryVideoSource(
nullptr);
326 if (std::exchange(m_primaryActiveVideoSource, source) != source)
327 emit primaryActiveVideoSourceChanged();
330template<
typename VideoSource>
332 VideoSource *newSource)
334 if (source == newSource)
337 if (
auto prevSource = std::exchange(source, newSource)) {
338 prevSource->setCaptureSession(
nullptr);
339 prevSource->disconnect(
this);
343 source->setCaptureSession(
this);
344 connect(source, &QPlatformVideoSource::activeChanged,
this,
346 connect(source, &QObject::destroyed,
this,
350 updatePrimaryActiveVideoSource();
357 return m_primaryActiveVideoSource;
362 std::vector<QAudioBufferSource *> result;
364 result.push_back(m_audioInput);
366 if (m_audioBufferInput)
367 result.push_back(m_audioBufferInput);
374#include "moc_qffmpegmediacapturesession_p.cpp"
QT_BEGIN_NAMESPACE Q_STATIC_LOGGING_CATEGORY(lcSynthesizedIterableAccess, "qt.iterable.synthesized", QtWarningMsg)