Revision control

++ // Copyright (C) 2024 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++
++ #include "capturesessionfixture_p.h"
++ #include <QtTest/qtest.h>
++
++ QT_BEGIN_NAMESPACE
++
++ using namespace std::chrono;
++
++ CaptureSessionFixture::CaptureSessionFixture(StreamType streamType) : m_streamType{ streamType } { }
++
++ CaptureSessionFixture::~CaptureSessionFixture()
++ {
++ if (!m_recorder.actualLocation().isEmpty())
++ QFile::remove(m_recorder.actualLocation().toLocalFile());
++ }
++
++ void CaptureSessionFixture::setVideoSink(QVideoSink *videoSink)
++ {
++ m_videoSink = videoSink;
++ }
++
++ void CaptureSessionFixture::start(RunMode mode, AutoStop autoStop,
++ std::optional<QIODevice *> outputDevice)
++ {
++ if (hasVideo()) {
++ m_session.setVideoFrameInput(&m_videoInput);
++
++ QObject::connect(&m_videoGenerator, &VideoGenerator::frameCreated, //
++ &m_videoInput, &QVideoFrameInput::sendVideoFrame);
++
++ if (autoStop == AutoStop::EmitEmpty) {
++ m_recorder.setAutoStop(true);
++ m_videoGenerator.emitEmptyFrameOnStop();
++ }
++ }
++
++ if (hasAudio()) {
++ m_session.setAudioBufferInput(&m_audioInput);
++
++ QObject::connect(&m_audioGenerator, &AudioGenerator::audioBufferCreated, //
++ &m_audioInput, &QAudioBufferInput::sendAudioBuffer);
++
++ if (autoStop == AutoStop::EmitEmpty) {
++ m_recorder.setAutoStop(true);
++ m_audioGenerator.emitEmptyBufferOnStop();
++ }
++ }
++
++ if (mode == RunMode::Pull) {
++ if (hasVideo())
++ QObject::connect(&m_videoInput, &QVideoFrameInput::readyToSendVideoFrame, //
++ &m_videoGenerator, &VideoGenerator::nextFrame);
++
++ if (hasAudio())
++ QObject::connect(&m_audioInput, &QAudioBufferInput::readyToSendAudioBuffer, //
++ &m_audioGenerator, &AudioGenerator::nextBuffer);
++ }
++
++ m_session.setRecorder(&m_recorder);
++ m_recorder.setQuality(QMediaRecorder::VeryHighQuality);
++
++ if (outputDevice)
++ m_recorder.setOutputDevice(*outputDevice);
++
++ if (!outputDevice && m_recorder.outputLocation().isEmpty()) {
++ // Create a temporary file.
++ // The file name is not available without opening.
++ if (!m_tempFile.open()) {
++ qWarning("Failed to open file: %s (%s)",
++ qPrintable(m_tempFile.fileName()), qPrintable(m_tempFile.errorString()));
++ } else {
++ m_tempFile.close();
++
++ m_recorder.setOutputLocation(QUrl::fromLocalFile(m_tempFile.fileName()));
++ }
++ }
++ // else: outputLocation has been already set
++
++ m_recorder.record();
++
++ // HACK: Add sink after starting recording because setting the video sink will
++ // emit ready signals and start the processing chain. TODO: Fix this
++ if (m_videoSink)
++ m_session.setVideoSink(m_videoSink);
++ }
++
++ bool CaptureSessionFixture::waitForRecorderStopped(std::chrono::milliseconds duration)
++ {
++ // StoppedState is emitted when media is finalized.
++ const bool stopped = QTest::qWaitFor(
++ [&] { //
++ return recorderStateChanged.contains(
++ QList<QVariant>{ QMediaRecorder::RecorderState::StoppedState });
++ },
++ duration);
++
++ if (!stopped)
++ return false;
++
++ return m_recorder.recorderState() == QMediaRecorder::StoppedState;
++ }
++
++ bool CaptureSessionFixture::hasAudio() const
++ {
++ return m_streamType == StreamType::Audio || m_streamType == StreamType::AudioAndVideo;
++ }
++
++ bool CaptureSessionFixture::hasVideo() const
++ {
++ return m_streamType == StreamType::Video || m_streamType == StreamType::AudioAndVideo;
++ }
++
++ QT_END_NAMESPACE