Revision control

Copy as Markdown

// 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 "qwindowsimagecapture_p.h"
#include <mediacapture/qwindowsmediacapture_p.h>
#include <mediacapture/qwindowsmediadevicesession_p.h>
#include <QtMultimedia/private/qmediastoragelocation_p.h>
#include <QtGui/qimagewriter.h>
#include <QtConcurrent/qtconcurrentrun.h>
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
QWindowsImageCapture::QWindowsImageCapture(QImageCapture *parent)
: QPlatformImageCapture(parent)
{
}
QWindowsImageCapture::~QWindowsImageCapture() = default;
bool QWindowsImageCapture::isReadyForCapture() const
{
if (!m_mediaDeviceSession)
return false;
return !m_capturing && m_mediaDeviceSession->isActive() && !m_mediaDeviceSession->activeCamera().isNull();
}
int QWindowsImageCapture::capture(const QString &fileName)
{
auto ext = writerFormat(m_settings.format());
auto path = QMediaStorageLocation::generateFileName(fileName, QStandardPaths::PicturesLocation, ext);
return doCapture(path);
}
int QWindowsImageCapture::captureToBuffer()
{
return doCapture(QString());
}
int QWindowsImageCapture::doCapture(const QString &fileName)
{
if (!isReadyForCapture())
return -1;
m_fileName = fileName;
m_capturing = true;
return m_captureId;
}
QImageEncoderSettings QWindowsImageCapture::imageSettings() const
{
return m_settings;
}
void QWindowsImageCapture::setImageSettings(const QImageEncoderSettings &settings)
{
m_settings = settings;
}
void QWindowsImageCapture::setCaptureSession(QPlatformMediaCaptureSession *session)
{
QWindowsMediaCaptureService *captureService = static_cast<QWindowsMediaCaptureService *>(session);
if (m_captureService == captureService)
return;
auto readyForCapture = isReadyForCapture();
if (m_mediaDeviceSession)
disconnect(m_mediaDeviceSession, nullptr, this, nullptr);
m_captureService = captureService;
if (!m_captureService) {
if (readyForCapture)
Q_EMIT readyForCaptureChanged(false);
m_mediaDeviceSession = nullptr;
return;
}
m_mediaDeviceSession = m_captureService->session();
Q_ASSERT(m_mediaDeviceSession);
if (isReadyForCapture() != readyForCapture)
Q_EMIT readyForCaptureChanged(isReadyForCapture());
connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::readyForCaptureChanged,
this, &QWindowsImageCapture::readyForCaptureChanged);
connect(m_mediaDeviceSession, &QWindowsMediaDeviceSession::videoFrameChanged,
this, &QWindowsImageCapture::handleVideoFrameChanged);
}
void QWindowsImageCapture::handleVideoFrameChanged(const QVideoFrame &frame)
{
if (m_capturing) {
QImage image = frame.toImage();
QSize size = m_settings.resolution();
if (size.isValid() && image.size() != size) {
image = image.scaled(size, Qt::KeepAspectRatioByExpanding);
if (image.size() != size) {
int xoff = (image.size().width() - size.width()) / 2;
int yoff = (image.size().height() - size.height()) / 2;
image = image.copy(xoff, yoff, size.width(), size.height());
}
}
Q_EMIT imageExposed(m_captureId);
Q_EMIT imageAvailable(m_captureId, frame);
Q_EMIT imageCaptured(m_captureId, image);
QMediaMetaData metaData = this->metaData();
metaData.insert(QMediaMetaData::Date, QDateTime::currentDateTime());
metaData.insert(QMediaMetaData::Resolution, size);
Q_EMIT imageMetadataAvailable(m_captureId, metaData);
if (!m_fileName.isEmpty()) {
(void)QtConcurrent::run(&QWindowsImageCapture::saveImage, this,
m_captureId, m_fileName, image, metaData, m_settings);
}
++m_captureId;
m_capturing = false;
}
}
void QWindowsImageCapture::saveImage(int captureId, const QString &fileName,
const QImage &image, const QMediaMetaData &metaData,
const QImageEncoderSettings &settings)
{
QImageWriter imageWriter;
imageWriter.setFileName(fileName);
QString format = writerFormat(settings.format());
imageWriter.setFormat(format.toUtf8());
int quality = writerQuality(format, settings.quality());
if (quality > -1)
imageWriter.setQuality(quality);
for (auto key : metaData.keys())
imageWriter.setText(QMediaMetaData::metaDataKeyToString(key),
metaData.stringValue(key));
imageWriter.write(image);
QMetaObject::invokeMethod(this, [this, captureId, fileName] {
Q_EMIT imageSaved(captureId, fileName);
}, Qt::QueuedConnection);
}
QString QWindowsImageCapture::writerFormat(QImageCapture::FileFormat reqFormat)
{
QString format;
switch (reqFormat) {
case QImageCapture::FileFormat::JPEG:
format = u"jpg"_s;
break;
case QImageCapture::FileFormat::PNG:
format = u"png"_s;
break;
case QImageCapture::FileFormat::WebP:
format = u"webp"_s;
break;
case QImageCapture::FileFormat::Tiff:
format = u"tiff"_s;
break;
default:
format = u"jpg"_s;
}
auto supported = QImageWriter::supportedImageFormats();
for (const auto &f : supported)
if (format.compare(QString::fromUtf8(f), Qt::CaseInsensitive) == 0)
return format;
return u"jpg"_s;
}
int QWindowsImageCapture::writerQuality(const QString &writerFormat,
QImageCapture::Quality quality)
{
if (writerFormat.compare(u"jpg", Qt::CaseInsensitive) == 0 ||
writerFormat.compare(u"jpeg", Qt::CaseInsensitive) == 0) {
switch (quality) {
case QImageCapture::Quality::VeryLowQuality:
return 10;
case QImageCapture::Quality::LowQuality:
return 30;
case QImageCapture::Quality::NormalQuality:
return 75;
case QImageCapture::Quality::HighQuality:
return 90;
case QImageCapture::Quality::VeryHighQuality:
return 98;
default:
return 75;
}
}
return -1;
}
QT_END_NAMESPACE
#include "moc_qwindowsimagecapture_p.cpp"