setup electron app with boilerplate
This commit is contained in:
@@ -0,0 +1,339 @@
|
||||
#include "mediahandler.h"
|
||||
#include <QPermission>
|
||||
#include <QMediaCaptureSession>
|
||||
#include <QApplication>
|
||||
#include <QCameraDevice>
|
||||
#include <QCameraFormat>
|
||||
#include <QMediaRecorder>
|
||||
#include <QMediaFormat>
|
||||
#include <QMimeType>
|
||||
#include <QAudioInput>
|
||||
#include <QCamera>
|
||||
#include <QUrl>
|
||||
|
||||
MediaHandler::MediaHandler(QObject *parent) : QObject{parent},
|
||||
m_captureSession{nullptr},
|
||||
m_audioInput{nullptr},
|
||||
m_camera{nullptr},
|
||||
m_videoSink{nullptr},
|
||||
m_recorder{nullptr}
|
||||
{
|
||||
}
|
||||
|
||||
MediaHandler::~MediaHandler()
|
||||
{
|
||||
}
|
||||
|
||||
MediaHandler::State MediaHandler::state() const
|
||||
{
|
||||
return m_state;
|
||||
}
|
||||
|
||||
MediaHandler::CaptureMode MediaHandler::captureMode() const
|
||||
{
|
||||
return m_captureMode;
|
||||
}
|
||||
|
||||
QVideoSink *MediaHandler::videoSink() const
|
||||
{
|
||||
return m_videoSink;
|
||||
}
|
||||
|
||||
void MediaHandler::startPreview(QVideoSink *sink)
|
||||
{
|
||||
if (m_state != OFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pendingRecord = false;
|
||||
startCapture(sink);
|
||||
}
|
||||
|
||||
void MediaHandler::startRecording(QVideoSink *sink)
|
||||
{
|
||||
if (m_state == RECORDING || m_state == PREPARING)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_state == ON)
|
||||
{
|
||||
m_cancelledRecording = false;
|
||||
m_recorder->record();
|
||||
return;
|
||||
}
|
||||
|
||||
// OFF
|
||||
m_pendingRecord = true;
|
||||
startCapture(sink);
|
||||
}
|
||||
|
||||
void MediaHandler::startCapture(QVideoSink *sink)
|
||||
{
|
||||
setState(PREPARING);
|
||||
|
||||
// microphone permission (always needed)
|
||||
QMicrophonePermission microphonePermission;
|
||||
switch (qApp->checkPermission(microphonePermission))
|
||||
{
|
||||
case Qt::PermissionStatus::Undetermined:
|
||||
qApp->requestPermission(microphonePermission, this, [this, sink]() {
|
||||
startCapture(sink);
|
||||
});
|
||||
return;
|
||||
case Qt::PermissionStatus::Denied:
|
||||
qDebug("Microphone permission is not granted!");
|
||||
setState(OFF);
|
||||
emit micPermissionDenied();
|
||||
return;
|
||||
case Qt::PermissionStatus::Granted:
|
||||
qDebug("Mic permission granted.");
|
||||
break;
|
||||
}
|
||||
|
||||
// camera permission (skip for AUDIO_ONLY)
|
||||
if (m_captureMode != AUDIO_ONLY)
|
||||
{
|
||||
QCameraPermission cameraPermission;
|
||||
switch (qApp->checkPermission(cameraPermission))
|
||||
{
|
||||
case Qt::PermissionStatus::Undetermined:
|
||||
qApp->requestPermission(cameraPermission, this, [this, sink]() {
|
||||
startCapture(sink);
|
||||
});
|
||||
return;
|
||||
case Qt::PermissionStatus::Denied:
|
||||
qDebug("Camera permission is not granted!");
|
||||
setState(OFF);
|
||||
emit cameraPermissionDenied();
|
||||
return;
|
||||
case Qt::PermissionStatus::Granted:
|
||||
qDebug("Camera permission granted.");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Create capture session and audio input
|
||||
if (!m_captureSession)
|
||||
{
|
||||
m_captureSession = new QMediaCaptureSession{this};
|
||||
}
|
||||
|
||||
// TODO: handle QMediaDevices:audioInputsChanged()
|
||||
if (!m_audioInput)
|
||||
{
|
||||
m_audioInput = new QAudioInput{this};
|
||||
m_captureSession->setAudioInput(m_audioInput);
|
||||
}
|
||||
|
||||
// Camera setup (skip for AUDIO_ONLY)
|
||||
// TODO: handle QMediaDevices:videoInputsChanged()
|
||||
if (m_captureMode != AUDIO_ONLY)
|
||||
{
|
||||
if (!m_camera)
|
||||
{
|
||||
QCameraDevice cameraDevice = QMediaDevices::defaultVideoInput();
|
||||
if (cameraDevice.videoFormats().empty())
|
||||
{
|
||||
setState(OFF);
|
||||
emit errorOccurred("Unable to find suitable camera formats");
|
||||
return;
|
||||
}
|
||||
QCameraFormat cameraFormat = cameraDevice.videoFormats().at(0);
|
||||
for (auto format : cameraDevice.videoFormats())
|
||||
{
|
||||
qDebug() << "Format: " << format.resolution();
|
||||
qDebug() << "framerate: " << format.minFrameRate() << " " << format.maxFrameRate();
|
||||
if (format.isNull())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (format.resolution().width() == 1280 && format.resolution().height() == 720)
|
||||
{
|
||||
cameraFormat = format;
|
||||
}
|
||||
}
|
||||
|
||||
m_camera = new QCamera(cameraDevice);
|
||||
m_camera->setCameraFormat(cameraFormat);
|
||||
connect(m_camera, &QCamera::activeChanged, this, [this](bool active) {
|
||||
if (active)
|
||||
{
|
||||
setState(ON);
|
||||
if (m_pendingRecord)
|
||||
{
|
||||
m_pendingRecord = false;
|
||||
m_cancelledRecording = false;
|
||||
m_recorder->record();
|
||||
}
|
||||
}
|
||||
});
|
||||
connect(m_camera, &QCamera::errorOccurred, this, [this](QCamera::Error error, const QString &message) {
|
||||
if (error != QCamera::NoError)
|
||||
{
|
||||
stop();
|
||||
emit errorOccurred(message);
|
||||
}
|
||||
});
|
||||
m_captureSession->setCamera(m_camera);
|
||||
}
|
||||
|
||||
m_videoSink = sink;
|
||||
m_captureSession->setVideoSink(m_videoSink);
|
||||
}
|
||||
else
|
||||
{
|
||||
// AUDIO_ONLY: no camera
|
||||
m_captureSession->setCamera(nullptr);
|
||||
m_captureSession->setVideoSink(nullptr);
|
||||
m_videoSink = nullptr;
|
||||
}
|
||||
|
||||
// Recorder setup
|
||||
if (!m_recorder)
|
||||
{
|
||||
QMediaFormat mediaFormat{QMediaFormat::MPEG4};
|
||||
mediaFormat.setAudioCodec(QMediaFormat::AudioCodec::AAC);
|
||||
if (m_captureMode != AUDIO_ONLY)
|
||||
{
|
||||
mediaFormat.setVideoCodec(QMediaFormat::VideoCodec::H264);
|
||||
}
|
||||
if (!mediaFormat.isSupported(QMediaFormat::Encode))
|
||||
{
|
||||
setState(OFF);
|
||||
emit errorOccurred("Unsupported codec");
|
||||
return;
|
||||
}
|
||||
|
||||
m_recorder = new QMediaRecorder(this);
|
||||
m_captureSession->setRecorder(m_recorder);
|
||||
m_recorder->setQuality(QMediaRecorder::HighQuality);
|
||||
m_recorder->setAutoStop(true);
|
||||
m_recorder->setMediaFormat(mediaFormat);
|
||||
|
||||
connect(m_recorder, &QMediaRecorder::recorderStateChanged, this, [this](QMediaRecorder::RecorderState state) {
|
||||
switch (state)
|
||||
{
|
||||
case QMediaRecorder::StoppedState:
|
||||
if (m_state == RECORDING)
|
||||
{
|
||||
setState(ON);
|
||||
}
|
||||
if (!m_cancelledRecording)
|
||||
{
|
||||
qint64 duration = m_recorder->duration();
|
||||
QString mimeType = m_recorder->mediaFormat().mimeType().name();
|
||||
qDebug() << "Recording location " << m_recorder->actualLocation().toString();
|
||||
emit recordingComplete(m_recorder->actualLocation(), duration, mimeType);
|
||||
}
|
||||
m_cancelledRecording = false;
|
||||
break;
|
||||
case QMediaRecorder::PausedState:
|
||||
break;
|
||||
case QMediaRecorder::RecordingState:
|
||||
setState(RECORDING);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (m_captureMode != AUDIO_ONLY)
|
||||
{
|
||||
m_camera->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
// AUDIO_ONLY: no async camera startup, go straight to ON
|
||||
setState(ON);
|
||||
if (m_pendingRecord)
|
||||
{
|
||||
m_pendingRecord = false;
|
||||
m_cancelledRecording = false;
|
||||
m_recorder->record();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MediaHandler::stop()
|
||||
{
|
||||
if (m_state == OFF)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_pendingRecord = false;
|
||||
|
||||
if (m_state == RECORDING && m_recorder)
|
||||
{
|
||||
m_cancelledRecording = true;
|
||||
m_recorder->stop();
|
||||
}
|
||||
|
||||
if (m_camera)
|
||||
{
|
||||
m_camera->stop();
|
||||
delete m_camera;
|
||||
m_camera = nullptr;
|
||||
}
|
||||
|
||||
if (m_captureSession)
|
||||
{
|
||||
m_captureSession->setVideoSink(nullptr);
|
||||
}
|
||||
|
||||
m_videoSink = nullptr;
|
||||
|
||||
if (m_recorder)
|
||||
{
|
||||
delete m_recorder;
|
||||
m_recorder = nullptr;
|
||||
}
|
||||
|
||||
setState(OFF);
|
||||
}
|
||||
|
||||
void MediaHandler::recordStop()
|
||||
{
|
||||
if (m_state != RECORDING)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_cancelledRecording = false;
|
||||
m_recorder->stop();
|
||||
}
|
||||
|
||||
void MediaHandler::recordCancel()
|
||||
{
|
||||
if (m_state != RECORDING)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_cancelledRecording = true;
|
||||
m_recorder->stop();
|
||||
}
|
||||
|
||||
void MediaHandler::setCaptureMode(CaptureMode newMode)
|
||||
{
|
||||
if (m_captureMode == newMode)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_captureMode = newMode;
|
||||
emit captureModeChanged();
|
||||
}
|
||||
|
||||
void MediaHandler::setState(State state)
|
||||
{
|
||||
if (m_state == state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_state = state;
|
||||
emit stateChanged();
|
||||
}
|
||||
Reference in New Issue
Block a user