Revision control

++ // Copyright (C) 2021 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
++
++ #include "qwindowsmediaencoder_p.h"
++
++ #include <common/mfmetadata_p.h>
++ #include <mediacapture/qwindowsmediacapture_p.h>
++ #include <mediacapture/qwindowsmediadevicesession_p.h>
++
++ #include <QtMultimedia/private/qmediarecorder_p.h>
++ #include <QtMultimedia/private/qmediastoragelocation_p.h>
++ #include <QtCore/qurl.h>
++ #include <QtCore/private/qcomptr_p.h>
++
++ #include <mferror.h>
++ #include <shobjidl.h>
++
++ QT_BEGIN_NAMESPACE
++
++ QWindowsMediaEncoder::QWindowsMediaEncoder(QMediaRecorder *parent)
++ : QObject(parent),
++ QPlatformMediaRecorder(parent)
++ {
++ }
++
++ bool QWindowsMediaEncoder::isLocationWritable(const QUrl &location) const
++ {
++ return location.scheme() == u"file" || location.scheme().isEmpty();
++ }
++
++ QMediaRecorder::RecorderState QWindowsMediaEncoder::state() const
++ {
++ return m_state;
++ }
++
++ qint64 QWindowsMediaEncoder::duration() const
++ {
++ return m_duration;
++ }
++
++ void QWindowsMediaEncoder::record(QMediaEncoderSettings &settings)
++ {
++ if (!m_captureService || !m_mediaDeviceSession) {
++ qWarning() << Q_FUNC_INFO << "Encoder is not set to a capture session";
++ return;
++ }
++ if (m_state != QMediaRecorder::StoppedState)
++ return;
++
++ m_sessionWasActive = m_mediaDeviceSession->isActive() || m_mediaDeviceSession->isActivating();
++
++ if (!m_sessionWasActive) {
++
++ m_mediaDeviceSession->setActive(true);
++
++ if (!m_mediaDeviceSession->isActivating()) {
++ updateError(QMediaRecorder::ResourceError,
++ QMediaRecorderPrivate::msgFailedStartRecording());
++ return;
++ }
++ }
++
++ const auto audioOnly = settings.videoCodec() == QMediaFormat::VideoCodec::Unspecified;
++ m_fileName = QMediaStorageLocation::generateFileName(outputLocation().toLocalFile(),
++ audioOnly ? QStandardPaths::MusicLocation
++ : QStandardPaths::MoviesLocation,
++ settings.preferredSuffix());
++
++ QMediaRecorder::Error ec = m_mediaDeviceSession->startRecording(settings, m_fileName, audioOnly);
++ if (ec == QMediaRecorder::NoError) {
++ m_state = QMediaRecorder::RecordingState;
++
++ actualLocationChanged(QUrl::fromLocalFile(m_fileName));
++ stateChanged(m_state);
++
++ } else {
++ updateError(ec, QMediaRecorderPrivate::msgFailedStartRecording());
++ }
++ }
++
++ void QWindowsMediaEncoder::pause()
++ {
++ if (!m_mediaDeviceSession || m_state != QMediaRecorder::RecordingState)
++ return;
++
++ if (m_mediaDeviceSession->pauseRecording()) {
++ m_state = QMediaRecorder::PausedState;
++ stateChanged(m_state);
++ } else {
++ updateError(QMediaRecorder::FormatError, tr("Failed to pause recording"));
++ }
++ }
++
++ void QWindowsMediaEncoder::resume()
++ {
++ if (!m_mediaDeviceSession || m_state != QMediaRecorder::PausedState)
++ return;
++
++ if (m_mediaDeviceSession->resumeRecording()) {
++ m_state = QMediaRecorder::RecordingState;
++ stateChanged(m_state);
++ } else {
++ updateError(QMediaRecorder::FormatError, tr("Failed to resume recording"));
++ }
++ }
++
++ void QWindowsMediaEncoder::stop()
++ {
++ if (m_mediaDeviceSession && m_state != QMediaRecorder::StoppedState) {
++ m_mediaDeviceSession->stopRecording();
++ if (!m_sessionWasActive)
++ m_mediaDeviceSession->setActive(false);
++ }
++ }
++
++
++
++ void QWindowsMediaEncoder::setCaptureSession(QPlatformMediaCaptureSession *session)
++ {
++ QWindowsMediaCaptureService *captureSession = static_cast<QWindowsMediaCaptureService *>(session);
++ if (m_captureService == captureSession)
++ return;
++
++ if (m_captureService)
++ stop();
++
++ m_captureService = captureSession;
++ if (!m_captureService) {
++ m_mediaDeviceSession = nullptr;
++ return;
++ }
++
++ m_mediaDeviceSession = m_captureService->session();
++ Q_ASSERT(m_mediaDeviceSession);
++
++ connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::recordingStarted, this, &QWindowsMediaEncoder::onRecordingStarted);
++ connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::recordingStopped, this, &QWindowsMediaEncoder::onRecordingStopped);
++ connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::streamingError, this, &QWindowsMediaEncoder::onStreamingError);
++ connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::recordingError, this, &QWindowsMediaEncoder::onRecordingError);
++ connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::durationChanged, this, &QWindowsMediaEncoder::onDurationChanged);
++ connect(m_captureService, &QWindowsMediaCaptureService::cameraChanged, this, &QWindowsMediaEncoder::onCameraChanged);
++ onCameraChanged();
++ }
++
++ void QWindowsMediaEncoder::setMetaData(const QMediaMetaData &metaData)
++ {
++ m_metaData = metaData;
++ }
++
++ QMediaMetaData QWindowsMediaEncoder::metaData() const
++ {
++ return m_metaData;
++ }
++
++ void QWindowsMediaEncoder::saveMetadata()
++ {
++ if (!m_metaData.isEmpty()) {
++
++ const QString nativeFileName = QDir::toNativeSeparators(m_fileName);
++
++ ComPtr<IPropertyStore> store;
++
++ if (SUCCEEDED(SHGetPropertyStoreFromParsingName(reinterpret_cast<LPCWSTR>(nativeFileName.utf16()),
++ nullptr, GPS_READWRITE, IID_PPV_ARGS(&store)))) {
++
++ MFMetaData::toNative(m_metaData, store.Get());
++
++ store->Commit();
++ }
++ }
++ }
++
++ void QWindowsMediaEncoder::onDurationChanged(qint64 duration)
++ {
++ m_duration = duration;
++ durationChanged(m_duration);
++ }
++
++ void QWindowsMediaEncoder::onStreamingError(HRESULT errorCode)
++ {
++ if (errorCode == MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED)
++ updateError(QMediaRecorder::ResourceError, tr("Camera is no longer present"));
++ else if (errorCode == MF_E_AUDIO_RECORDING_DEVICE_INVALIDATED)
++ updateError(QMediaRecorder::ResourceError, tr("Audio input is no longer present"));
++ else
++ updateError(QMediaRecorder::ResourceError, tr("Streaming error"));
++
++ if (m_state != QMediaRecorder::StoppedState) {
++ m_mediaDeviceSession->stopRecording();
++ if (!m_sessionWasActive)
++ m_mediaDeviceSession->setActive(false);
++ }
++ }
++
++ void QWindowsMediaEncoder::onRecordingError(HRESULT errorCode)
++ {
++ Q_UNUSED(errorCode);
++ updateError(QMediaRecorder::ResourceError, tr("Recording error"));
++
++ auto lastState = m_state;
++ m_state = QMediaRecorder::StoppedState;
++ if (m_state != lastState)
++ stateChanged(m_state);
++ }
++
++ void QWindowsMediaEncoder::onCameraChanged()
++ {
++ }
++
++ void QWindowsMediaEncoder::onRecordingStarted()
++ {
++ }
++
++ void QWindowsMediaEncoder::onRecordingStopped()
++ {
++ saveMetadata();
++
++ auto lastState = m_state;
++ m_state = QMediaRecorder::StoppedState;
++ if (m_state != lastState)
++ stateChanged(m_state);
++ }
++
++ QT_END_NAMESPACE
++
++ #include "moc_qwindowsmediaencoder_p.cpp"