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>
31 constexpr int BufferSizeFactor = 2;
32 constexpr int BufferSizeExceeding = 4096;
34 return input
.bufferSize() * BufferSizeFactor + BufferSizeExceeding;
39 connect(
this, &QFFmpegMediaCaptureSession::primaryActiveVideoSourceChanged,
this,
40 &QFFmpegMediaCaptureSession::updateVideoFrameConnection);
52 if (setVideoSource(m_camera, camera))
58 return m_screenCapture;
63 if (setVideoSource(m_screenCapture, screenCapture))
64 emit screenCaptureChanged();
69 return m_windowCapture;
74 if (setVideoSource(m_windowCapture, windowCapture))
75 emit windowCaptureChanged();
80 return m_videoFrameInput;
85 if (setVideoSource(m_videoFrameInput, input))
86 emit videoFrameInputChanged();
91 return m_imageCapture;
96 if (m_imageCapture == imageCapture)
100 m_imageCapture->setCaptureSession(
nullptr);
105 m_imageCapture->setCaptureSession(
this);
107 emit imageCaptureChanged();
113 if (m_mediaRecorder == r)
122 emit encoderChanged();
127 return m_mediaRecorder;
132 qCDebug(qLcFFmpegMediaCaptureSession)
133 <<
"set audio input:" << (input ? input->device.description() :
"null");
135 auto ffmpegAudioInput =
dynamic_cast<QFFmpegAudioInput *>(input);
136 Q_ASSERT(!!input == !!ffmpegAudioInput);
138 if (m_audioInput == ffmpegAudioInput)
142 m_audioInput->q->disconnect(
this);
144 m_audioInput = ffmpegAudioInput;
147 connect(m_audioInput->q, &QAudioInput::deviceChanged,
this,
148 &QFFmpegMediaCaptureSession::updateAudioSink);
156 m_audioBufferInput = input;
162 m_audioSink->reset();
166 if (!m_audioInput || !m_audioOutput)
169 auto format = m_audioInput->device.preferredFormat();
171 if (!m_audioOutput->device.isFormatSupported(format))
172 qWarning() <<
"Audio source format" << format <<
"is not compatible with the audio output";
174 m_audioSink = std::make_unique<QAudioSink>(m_audioOutput->device, format);
176 m_audioBufferSize = preferredAudioSinkBufferSize(*m_audioInput);
177 m_audioSink->setBufferSize(m_audioBufferSize);
179 qCDebug(qLcFFmpegMediaCaptureSession)
180 <<
"Create audiosink, format:" << format <<
"bufferSize:" << m_audioSink->bufferSize()
181 <<
"output device:" << m_audioOutput->device.description();
183 m_audioIODevice = m_audioSink->start();
184 if (m_audioIODevice) {
185 auto writeToDevice = [
this](
const QAudioBuffer &buffer) {
186 if (m_audioBufferSize < preferredAudioSinkBufferSize(*m_audioInput)) {
187 qCDebug(qLcFFmpegMediaCaptureSession)
188 <<
"Recreate audiosink due to small buffer size:" << m_audioBufferSize;
194 m_audioIODevice->write(buffer.data<
const char>(), buffer.byteCount());
196 if (written < buffer.byteCount())
198 <<
"Not all bytes written:" << written <<
"vs" << buffer.byteCount();
200 connect(m_audioInput, &QFFmpegAudioInput::newAudioBuffer, m_audioSink.get(), writeToDevice);
202 qWarning() <<
"Failed to start audiosink push mode";
211 m_audioSink->setVolume(m_audioOutput->muted ? 0.f : m_audioOutput->volume);
221 if (std::exchange(m_videoSink, sink) == sink)
224 updateVideoFrameConnection();
229 qCDebug(qLcFFmpegMediaCaptureSession)
230 <<
"set audio output:" << (output ? output->device.description() :
"null");
232 if (m_audioOutput == output)
236 m_audioOutput->q->disconnect(
this);
238 m_audioOutput = output;
241 connect(m_audioOutput->q, &QAudioOutput::deviceChanged,
this,
242 &QFFmpegMediaCaptureSession::updateAudioSink);
243 connect(m_audioOutput->q, &QAudioOutput::volumeChanged,
this,
244 &QFFmpegMediaCaptureSession::updateVolume);
245 connect(m_audioOutput->q, &QAudioOutput::mutedChanged,
this,
246 &QFFmpegMediaCaptureSession::updateVolume);
254 disconnect(m_videoFrameConnection);
256 if (m_primaryActiveVideoSource && m_videoSink) {
260 m_videoFrameConnection =
261 connect(m_primaryActiveVideoSource, &QPlatformVideoSource::newVideoFrame,
262 m_videoSink, &QVideoSink::setVideoFrame);
268 auto sources = activeVideoSources();
269 auto source = sources.empty() ?
nullptr : sources.front();
270 if (std::exchange(m_primaryActiveVideoSource, source) != source)
271 emit primaryActiveVideoSourceChanged();
274template<
typename VideoSource>
276 VideoSource *newSource)
278 if (source == newSource)
281 if (
auto prevSource = std::exchange(source, newSource)) {
282 prevSource->setCaptureSession(
nullptr);
283 prevSource->disconnect(
this);
287 source->setCaptureSession(
this);
288 connect(source, &QPlatformVideoSource::activeChanged,
this,
289 &QFFmpegMediaCaptureSession::updatePrimaryActiveVideoSource);
290 connect(source, &QObject::destroyed,
this,
291 &QFFmpegMediaCaptureSession::updatePrimaryActiveVideoSource, Qt::QueuedConnection);
294 updatePrimaryActiveVideoSource();
301 return m_primaryActiveVideoSource;
306 std::vector<QPlatformAudioBufferInputBase *> result;
308 result.push_back(m_audioInput);
310 if (m_audioBufferInput)
311 result.push_back(m_audioBufferInput);
318#include "moc_qffmpegmediacapturesession_p.cpp"
Combined button and popup list for selecting options.
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_STATIC_LOGGING_CATEGORY(name,...)