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
qffmpegimagecapture.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
5#include <private/qplatformmediaformatinfo_p.h>
6#include <private/qplatformcamera_p.h>
7#include <private/qplatformimagecapture_p.h>
8#include <qvideoframeformat.h>
9#include <private/qmediastoragelocation_p.h>
10#include <qimagewriter.h>
11
12#include <QtCore/QDebug>
13#include <QtCore/QDir>
14#include <qstandardpaths.h>
15
16#include <qloggingcategory.h>
17
19
20// Probably, might be increased. To be investigated and tested on Android implementation
21static constexpr int MaxPendingImagesCount = 1;
22
23static Q_LOGGING_CATEGORY(qLcImageCapture, "qt.multimedia.imageCapture")
24
26 : QPlatformImageCapture(parent)
27{
28 qRegisterMetaType<QVideoFrame>();
29}
30
34
36{
37 return m_isReadyForCapture;
38}
39
41{
42 const char *fmt = "jpg";
43 switch (format) {
46 fmt = "jpg";
47 break;
49 fmt = "png";
50 break;
52 fmt = "webp";
53 break;
55 fmt = "tiff";
56 break;
57 }
58 return fmt;
59}
60
66
71
73{
74 qCDebug(qLcImageCapture) << "do capture";
75 if (!m_session) {
76 //emit error in the next event loop,
77 //so application can associate it with returned request id.
79 Q_ARG(int, -1),
82
83 qCDebug(qLcImageCapture) << "error 1";
84 return -1;
85 }
86 if (!m_videoSource) {
87 //emit error in the next event loop,
88 //so application can associate it with returned request id.
90 Q_ARG(int, -1),
92 Q_ARG(QString,tr("No camera available.")));
93
94 qCDebug(qLcImageCapture) << "error 2";
95 return -1;
96 }
97 if (m_pendingImages.size() >= MaxPendingImagesCount) {
98 //emit error in the next event loop,
99 //so application can associate it with returned request id.
101 Q_ARG(int, -1),
104
105 qCDebug(qLcImageCapture) << "error 3";
106 return -1;
107 }
108
109 m_lastId++;
110
111 m_pendingImages.enqueue({ m_lastId, fileName, QMediaMetaData{} });
113
114 return m_lastId;
115}
116
118{
119 auto *captureSession = static_cast<QFFmpegMediaCaptureSession *>(session);
120 if (m_session == captureSession)
121 return;
122
123 if (m_session) {
124 m_session->disconnect(this);
125 m_lastId = 0;
126 m_pendingImages.clear();
127 }
128
129 m_session = captureSession;
130
131 if (m_session)
134
136}
137
139{
140 const bool ready = m_session && m_pendingImages.size() < MaxPendingImagesCount && m_videoSource
141 && m_videoSource->isActive();
142
143 qCDebug(qLcImageCapture) << "updateReadyForCapture" << ready;
144
145 if (std::exchange(m_isReadyForCapture, ready) != ready)
147}
148
150{
151 if (m_pendingImages.empty())
152 return;
153
154 auto pending = m_pendingImages.dequeue();
155
156 qCDebug(qLcImageCapture) << "Taking image" << pending.id;
157
159 // ### Add metadata from the AVFrame
162 QImage image = frame.toImage();
163 if (m_settings.resolution().isValid() && m_settings.resolution() != image.size())
164 image = image.scaled(m_settings.resolution());
165
167 if (!pending.filename.isEmpty()) {
168 const char *fmt = nullptr;
169 switch (m_settings.format()) {
172 fmt = "jpeg";
173 break;
175 fmt = "png";
176 break;
178 fmt = "webp";
179 break;
181 fmt = "tiff";
182 break;
183 }
184 int quality = -1;
185 switch (m_settings.quality()) {
187 quality = 25;
188 break;
190 quality = 50;
191 break;
193 break;
195 quality = 75;
196 break;
198 quality = 99;
199 break;
200 }
201
202 QImageWriter writer(pending.filename, fmt);
203 writer.setQuality(quality);
204
205 if (writer.write(image)) {
206 emit imageSaved(pending.id, pending.filename);
207 } else {
209 if (writer.error() == QImageWriter::UnsupportedFormatError)
211 emit error(pending.id, err, writer.errorString());
212 }
213 }
214
216}
217
223
225{
226 return m_videoSource;
227}
228
230{
231 if (m_videoSource)
232 m_videoSource->disconnect(this);
233
234 m_videoSource = m_session ? m_session->primaryActiveVideoSource() : nullptr;
235
236 // TODO: optimize, setup the connection only when the capture is ready
237 if (m_videoSource)
239
241}
242
244{
245 return m_settings;
246}
247
249{
250 auto s = settings;
251 const auto supportedFormats = QPlatformMediaIntegration::instance()->formatInfo()->imageFormats;
252 if (supportedFormats.isEmpty()) {
253 emit error(-1, QImageCapture::FormatError, "No image formats supported, can't capture.");
254 return;
255 }
256 if (s.format() == QImageCapture::UnspecifiedFormat) {
257 auto f = QImageCapture::JPEG;
258 if (!supportedFormats.contains(f))
259 f = supportedFormats.first();
260 s.setFormat(f);
261 } else if (!supportedFormats.contains(settings.format())) {
262 emit error(-1, QImageCapture::FormatError, "Image format not supported.");
263 return;
264 }
265
266 m_settings = settings;
267}
268
270
271#include "moc_qffmpegimagecapture_p.cpp"
void setImageSettings(const QImageEncoderSettings &settings) override
void newVideoFrame(const QVideoFrame &frame)
virtual int doCapture(const QString &fileName)
QPlatformVideoSource * videoSource() const
QImageEncoderSettings imageSettings() const override
void setCaptureSession(QPlatformMediaCaptureSession *session)
int capture(const QString &fileName) override
virtual void setupVideoSourceConnections()
bool isReadyForCapture() const override
QPlatformVideoSource * primaryActiveVideoSource()
\inmodule QtMultimedia
Error
\value NoError No Errors.
FileFormat
Choose one of the following image formats:
QImageCapture::Quality quality() const
QImageCapture::FileFormat format() const
The QImageWriter class provides a format independent interface for writing images to files or other d...
\inmodule QtGui
Definition qimage.h:37
qsizetype size() const noexcept
Definition qlist.h:397
bool empty() const noexcept
Definition qlist.h:685
void clear()
Definition qlist.h:434
\inmodule QtMultimedia
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 imageAvailable(int requestId, const QVideoFrame &buffer)
static QString msgImageCaptureNotSet()
void imageMetadataAvailable(int id, const QMediaMetaData &)
void imageExposed(int requestId)
void readyForCaptureChanged(bool ready)
static QPlatformMediaIntegration * instance()
virtual bool isActive() const =0
void newVideoFrame(const QVideoFrame &)
void enqueue(const T &t)
Adds value t to the tail of the queue.
Definition qqueue.h:18
T dequeue()
Removes the head item in the queue and returns it.
Definition qqueue.h:19
Format format() const
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
Definition qsize.h:127
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
The QVideoFrame class represents a frame of video data.
Definition qvideoframe.h:27
Q_MULTIMEDIA_EXPORT QString generateFileName(const QString &requestedName, QStandardPaths::StandardLocation type, const QString &extension)
Combined button and popup list for selecting options.
@ QueuedConnection
Definition image.cpp:4
DBusConnection const char DBusError * error
DBusConnection const char DBusError DBusBusType DBusError return DBusConnection DBusHandleMessageFunction void DBusFreeFunction return DBusConnection return DBusConnection return const char DBusError return DBusConnection DBusMessage dbus_uint32_t return DBusConnection dbus_bool_t DBusConnection DBusAddWatchFunction DBusRemoveWatchFunction DBusWatchToggledFunction void DBusFreeFunction return DBusConnection DBusDispatchStatusFunction void DBusFreeFunction DBusTimeout return DBusTimeout return DBusWatch return DBusWatch unsigned int return DBusError const DBusError return const DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessage return DBusMessageIter int const void return DBusMessageIter DBusMessageIter return DBusMessageIter void DBusMessageIter void int return DBusMessage DBusMessageIter return DBusMessageIter return DBusMessageIter DBusMessageIter const char const char const char const char return DBusMessage return DBusMessage const char return DBusMessage dbus_bool_t return DBusMessage dbus_uint32_t return DBusMessage return DBusPendingCall * pending
static QT_BEGIN_NAMESPACE constexpr int MaxPendingImagesCount
static const char * extensionForFormat(QImageCapture::FileFormat format)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
#define Q_ARG(Type, data)
Definition qobjectdefs.h:63
GLfloat GLfloat f
GLint GLsizei GLsizei GLenum format
GLdouble s
[6]
Definition qopenglext.h:235
GLsizei const GLchar *const * path
QLatin1StringView QLatin1String
Definition qstringfwd.h:31
#define tr(X)
#define emit
QVideoFrameFormat::PixelFormat fmt
QSettings settings("MySoft", "Star Runner")
[0]
QFrame frame
[0]
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0=QGenericArgument(nullptr), QGenericArgument val1=QGenericArgument(), QGenericArgument val2=QGenericArgument(), QGenericArgument val3=QGenericArgument(), QGenericArgument val4=QGenericArgument(), QGenericArgument val5=QGenericArgument(), QGenericArgument val6=QGenericArgument(), QGenericArgument val7=QGenericArgument(), QGenericArgument val8=QGenericArgument(), QGenericArgument val9=QGenericArgument())
\threadsafe This is an overloaded member function, provided for convenience. It differs from the abov...