Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qqnximagecapture.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Research In Motion
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
4
7#include "qqnxcamera_p.h"
8#include "qfile.h"
9
10#include <private/qmediastoragelocation_p.h>
11
12#include <QtCore/qfileinfo.h>
13#include <QtCore/qfuture.h>
14#include <QtCore/qpromise.h>
15#include <QtCore/qthread.h>
16
17#include <camera/camera_api.h>
18
19using namespace Qt::Literals::StringLiterals;
20
22{
23 switch (format) {
25 return u"jpg"_s;
27 return u"png"_s;
31 break;
32 }
33
34 return {};
35}
36
38{
40
41 if (extension.isEmpty())
42 return {};
43
44 if (fileName.isEmpty()) {
47 }
48
49 if (fileName.endsWith(extension))
51
53 path.append(u".%1"_s.arg(extension));
54
56}
57
59
64
66{
67 return m_camera && m_camera->isActive();
68}
69
71{
72 if (!isReadyForCapture()) {
74 return -1;
75 }
76
77 // default to PNG format if no format has been specified
80 ? QImageCapture::PNG : m_settings.format();
81
82 const QString resolvedFileName = resolveFileName(fileName, format);
83
84 if (resolvedFileName.isEmpty()) {
85 const QString errorMessage = (u"Invalid file format: %1"_s).arg(
87
89 return -1;
90 }
91
92 const int id = m_lastId++;
93
94 auto callback = [this, id, fn=std::move(resolvedFileName)](const QVideoFrame &frame) {
95 saveFrame(id, frame, fn);
96 };
97
98 m_camera->requestVideoFrame(std::move(callback));
99
100 return id;
101}
102
104{
105 if (!isReadyForCapture()) {
107 return -1;
108 }
109
110 const int id = m_lastId++;
111
112 auto callback = [this, id](const QVideoFrame &frame) { decodeFrame(id, frame); };
113
114 m_camera->requestVideoFrame(std::move(callback));
115
116 return id;
117}
118
119QFuture<QImage> QQnxImageCapture::decodeFrame(int id, const QVideoFrame &frame)
120{
121 if (!frame.isValid()) {
122 Q_EMIT error(id, QImageCapture::NotReadyError, u"Invalid frame"_s);
123 return {};
124 }
125
126 QPromise<QImage> promise;
127 QFuture<QImage> future = promise.future();
128
129 // converting a QVideoFrame to QImage is an expensive operation
130 // run it on a background thread to prevent it from stalling the UI
131 auto runner = [frame, promise=std::move(promise)]() mutable {
132 promise.start();
133 promise.addResult(frame.toImage());
134 promise.finish();
135 };
136
137 auto *worker = QThread::create(std::move(runner));
138
139 auto onFinished = [this, worker, id, future]() mutable {
140 worker->deleteLater();
141
142 if (future.isValid()) {
144 } else {
145 qWarning("QQnxImageCapture: failed to capture image to buffer");
146 }
147 };
148
149 connect(worker, &QThread::finished, this, std::move(onFinished));
150
152
153 worker->start();
154
155 return future;
156}
157
158void QQnxImageCapture::saveFrame(int id, const QVideoFrame &frame, const QString &fileName)
159{
160 QFuture<QImage> decodeFuture = decodeFrame(id, frame);
161
162 if (decodeFuture.isCanceled())
163 return;
164
165 QPromise<bool> promise;
166 QFuture<bool> saveFuture = promise.future();
167
168 // writing a QImage to disk is a _very_ expensive operation
169 // run it on a background thread to prevent it from stalling the UI
170 auto runner = [future=std::move(decodeFuture),
171 promise=std::move(promise), fileName]() mutable {
172 promise.start();
173 promise.addResult(future.result().save(fileName));
174 promise.finish();
175 };
176
177 auto *worker = QThread::create(std::move(runner));
178
179 auto onFinished = [this, worker, id, future=std::move(saveFuture), fn=std::move(fileName)]() {
180 worker->deleteLater();
181
182 if (future.isValid() && future.result())
183 Q_EMIT imageSaved(id, fn);
184 else
185 Q_EMIT error(id, QImageCapture::NotSupportedFeatureError, u"Failed to save image"_s);
186 };
187
188 connect(worker, &QThread::finished, this, std::move(onFinished));
189
190 worker->start();
191}
192
194{
195 return m_settings;
196}
197
202
204{
205 if (m_session == captureSession)
206 return;
207
208 if (m_session)
209 m_session->disconnect(this);
210
211 m_session = captureSession;
212
213 if (m_session) {
215 this, &QQnxImageCapture::onCameraChanged);
216 }
217
218 onCameraChanged();
219}
220
221void QQnxImageCapture::onCameraChanged()
222{
223 if (m_camera)
224 m_camera->disconnect(this);
225
226 m_camera = m_session ? static_cast<QQnxPlatformCamera*>(m_session->camera()) : nullptr;
227
228 if (m_camera) {
230 this, &QQnxImageCapture::onCameraChanged);
231 }
232
233 updateReadyForCapture();
234}
235
236void QQnxImageCapture::onCameraActiveChanged(bool active)
237{
238 Q_UNUSED(active);
239
240 updateReadyForCapture();
241}
242
243void QQnxImageCapture::updateReadyForCapture()
244{
245 const bool readyForCapture = isReadyForCapture();
246
247 if (m_lastReadyForCapture == readyForCapture)
248 return;
249
250 m_lastReadyForCapture = readyForCapture;
251
252 Q_EMIT readyForCaptureChanged(m_lastReadyForCapture);
253}
254
256
257#include "moc_qqnximagecapture_p.cpp"
QString canonicalFilePath() const
Returns the file system entry's canonical path, including the entry's name, that is,...
bool isValid() const
Definition qfuture.h:125
T result() const
Definition qfuture.h:309
\inmodule QtMultimedia
static QString fileFormatName(FileFormat c)
Returns the name of the given format, f.
FileFormat
Choose one of the following image formats:
QImageCapture::FileFormat format() const
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
Definition qobject.cpp:2960
static bool disconnect(const QObject *sender, const char *signal, const QObject *receiver, const char *member)
\threadsafe
Definition qobject.cpp:3236
void imageCaptured(int requestId, const QImage &preview)
void imageSaved(int requestId, const QString &fileName)
void imageExposed(int requestId)
void readyForCaptureChanged(bool ready)
void activeChanged(bool)
QQnxImageCapture(QImageCapture *parent)
void setImageSettings(const QImageEncoderSettings &settings) override
QImageEncoderSettings imageSettings() const override
void setCaptureSession(QQnxMediaCaptureSession *session)
int captureToBuffer() override
int capture(const QString &fileName) override
bool isReadyForCapture() const override
QPlatformCamera * camera() override
void requestVideoFrame(VideoFrameCallback cb)
bool isActive() const override
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString & append(QChar c)
Definition qstring.cpp:3252
static QThread * create(Function &&f, Args &&... args)
Definition qthread.h:122
void finished(QPrivateSignal)
The QVideoFrame class represents a frame of video data.
Definition qvideoframe.h:27
void extension()
[6]
Definition dialogs.cpp:230
Q_MULTIMEDIA_EXPORT QString generateFileName(const QString &requestedName, QStandardPaths::StandardLocation type, const QString &extension)
Combined button and popup list for selecting options.
DBusConnection const char DBusError * error
#define qWarning
Definition qlogging.h:166
GLenum GLuint id
[7]
GLint GLsizei GLsizei GLenum format
GLsizei const GLchar *const * path
static QString resolveFileName(const QString &fileName, QImageCapture::FileFormat format)
static QString formatExtension(QImageCapture::FileFormat format)
SSL_CTX int void * arg
#define Q_EMIT
#define Q_UNUSED(x)
static QString errorMessage(QUrlPrivate::ErrorCode errorCode, const QString &errorSource, qsizetype errorPosition)
Definition qurl.cpp:3517
QFuture< void > future
[5]
QSettings settings("MySoft", "Star Runner")
[0]
QObject::connect nullptr
QFrame frame
[0]