6#include "private/qplatformaudioinput_p.h"
7#include "private/qplatformaudiooutput_p.h"
8#include "private/qplatformsurfacecapture_p.h"
9#include "private/qplatformaudiobufferinput_p.h"
10#include "private/qplatformvideoframeinput_p.h"
11#include "private/qplatformcamera_p.h"
21#include <qloggingcategory.h>
25using namespace Qt::StringLiterals;
33 constexpr int BufferSizeFactor = 2;
34 constexpr int BufferSizeExceeding = 4096;
36 return input
.bufferSize() * BufferSizeFactor + BufferSizeExceeding;
41 connect(
this, &QFFmpegMediaCaptureSession::primaryActiveVideoSourceChanged,
this,
42 &QFFmpegMediaCaptureSession::updateVideoFrameConnection);
54 if (setVideoSource(m_camera, camera))
60 return m_screenCapture;
65 if (setVideoSource(m_screenCapture, screenCapture))
66 emit screenCaptureChanged();
71 return m_windowCapture;
76 if (setVideoSource(m_windowCapture, windowCapture))
77 emit windowCaptureChanged();
82 return m_videoFrameInput;
87 if (setVideoSource(m_videoFrameInput, input))
88 emit videoFrameInputChanged();
93 return m_imageCapture;
98 if (m_imageCapture == imageCapture)
102 m_imageCapture->setCaptureSession(
nullptr);
107 m_imageCapture->setCaptureSession(
this);
109 emit imageCaptureChanged();
115 if (m_mediaRecorder == r)
124 emit encoderChanged();
129 return m_mediaRecorder;
134 qCDebug(qLcFFmpegMediaCaptureSession)
135 <<
"set audio input:" << (input ? input->device.description() : u"null"_s);
138 Q_ASSERT(!!input == !!ffmpegAudioInput);
140 if (m_audioInput == ffmpegAudioInput)
144 m_audioInput->q->disconnect(
this);
146 m_audioInput = ffmpegAudioInput;
149 connect(m_audioInput->q, &QAudioInput::deviceChanged,
this,
150 &QFFmpegMediaCaptureSession::updateAudioSink);
158 m_audioBufferInput = input;
164 m_audioSink->reset();
168 if (!m_audioInput || !m_audioOutput)
171 auto format = m_audioInput->device.preferredFormat();
173 if (!m_audioOutput->device.isFormatSupported(format))
174 qWarning() <<
"Audio source format" << format <<
"is not compatible with the audio output";
176 m_audioSink = std::make_unique<QAudioSink>(m_audioOutput->device, format);
178 m_audioBufferSize = preferredAudioSinkBufferSize(*m_audioInput);
179 m_audioSink->setBufferSize(m_audioBufferSize);
181 qCDebug(qLcFFmpegMediaCaptureSession)
182 <<
"Create audiosink, format:" << format <<
"bufferSize:" << m_audioSink->bufferSize()
183 <<
"output device:" << m_audioOutput->device.description();
185 m_audioIODevice = m_audioSink->start();
186 if (m_audioIODevice) {
187 auto writeToDevice = [
this](
const QAudioBuffer &buffer) {
188 if (m_audioBufferSize < preferredAudioSinkBufferSize(*m_audioInput)) {
189 qCDebug(qLcFFmpegMediaCaptureSession)
190 <<
"Recreate audiosink due to small buffer size:" << m_audioBufferSize;
196 m_audioIODevice->write(buffer.data<
const char>(), buffer.byteCount());
198 if (written < buffer.byteCount())
200 <<
"Not all bytes written:" << written <<
"vs" << buffer.byteCount();
202 connect(m_audioInput, &QFFmpegAudioInput::newAudioBuffer, m_audioSink.get(), writeToDevice);
204 qWarning() <<
"Failed to start audiosink push mode";
213 m_audioSink->setVolume(m_audioOutput->muted ? 0.f : m_audioOutput->volume);
223 if (std::exchange(m_videoSink, sink) == sink)
226 updateVideoFrameConnection();
231 qCDebug(qLcFFmpegMediaCaptureSession)
232 <<
"set audio output:" << (output ? output->device.description() : u"null"_s);
234 if (m_audioOutput == output)
238 m_audioOutput->q->disconnect(
this);
240 m_audioOutput = output;
243 connect(m_audioOutput->q, &QAudioOutput::deviceChanged,
this,
244 &QFFmpegMediaCaptureSession::updateAudioSink);
245 connect(m_audioOutput->q, &QAudioOutput::volumeChanged,
this,
246 &QFFmpegMediaCaptureSession::updateVolume);
247 connect(m_audioOutput->q, &QAudioOutput::mutedChanged,
this,
248 &QFFmpegMediaCaptureSession::updateVolume);
256 disconnect(m_videoFrameConnection);
258 if (m_primaryActiveVideoSource && m_videoSink) {
262 m_videoFrameConnection =
263 connect(m_primaryActiveVideoSource, &QPlatformVideoSource::newVideoFrame,
264 m_videoSink, &QVideoSink::setVideoFrame);
270 auto sources = activeVideoSources();
271 auto source = sources.empty() ?
nullptr : sources.front();
272 if (std::exchange(m_primaryActiveVideoSource, source) != source)
273 emit primaryActiveVideoSourceChanged();
276template<
typename VideoSource>
278 VideoSource *newSource)
280 if (source == newSource)
283 if (
auto prevSource = std::exchange(source, newSource)) {
284 prevSource->setCaptureSession(
nullptr);
285 prevSource->disconnect(
this);
289 source->setCaptureSession(
this);
290 connect(source, &QPlatformVideoSource::activeChanged,
this,
291 &QFFmpegMediaCaptureSession::updatePrimaryActiveVideoSource);
292 connect(source, &QObject::destroyed,
this,
293 &QFFmpegMediaCaptureSession::updatePrimaryActiveVideoSource, Qt::QueuedConnection);
296 updatePrimaryActiveVideoSource();
303 return m_primaryActiveVideoSource;
308 std::vector<QAudioBufferSource *> result;
310 result.push_back(m_audioInput);
312 if (m_audioBufferInput)
313 result.push_back(m_audioBufferInput);
320#include "moc_qffmpegmediacapturesession_p.cpp"
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)