6#include <QtMultimedia/qvideoframeformat.h>
7#include <QtMultimedia/private/qmediastoragelocation_p.h>
8#include <QtMultimedia/private/qplatformcamera_p.h>
9#include <QtMultimedia/private/qplatformimagecapture_p.h>
10#include <QtMultimedia/private/qvideoframe_p.h>
11#include <QtCore/qdebug.h>
12#include <QtCore/qdir.h>
13#include <QtCore/qstandardpaths.h>
14#include <QtCore/qcoreapplication.h>
15#include <QtCore/qloggingcategory.h>
33 bool m_appUnderDestruction =
false;
39 if (m_appUnderDestruction || !
qApp)
42 using namespace std::chrono;
45 m_instance->setMaxThreadCount(1);
46 static constexpr auto expiryTimeout = minutes(5);
47 m_instance->setExpiryTimeout(round<milliseconds>(expiryTimeout).
count());
55 m_appUnderDestruction =
true;
59 m_appUnderDestruction =
false;
64 template <
typename Functor>
70 return QFuture<void>{};
83 "queue",
"capsfilter",
"videoconvert",
"jpegenc",
"jifmux",
"fakesink");
90QGstreamerImageCapture::QGstreamerImageCapture(
QImageCapture *parent)
97 QGstElement::createFromFactory(
"queue",
"imageCaptureQueue"),
100 QGstElement::createFromFactory(
"capsfilter",
"filter"),
103 QGstElement::createFromFactory(
"videoconvert",
"imageCaptureConvert"),
106 QGstElement::createFromFactory(
"jpegenc",
"jpegEncoder"),
109 QGstElement::createFromFactory(
"jifmux",
"jpegMuxer"),
112 QGstElement::createFromFactory(
"fakesink",
"imageCaptureSink"),
116 queue.
set(
"leaky", 2 );
117 queue.
set(
"silent",
true);
118 queue.
set(
"max-size-buffers",
uint(1));
119 queue.
set(
"max-size-bytes",
uint(0));
124 sink.set(
"async",
false);
132 sink.set(
"signal-handoffs",
true);
133 m_handoffConnection =
sink.connect(
"handoff", G_CALLBACK(&saveImageFilter),
this);
141 auto pendingFutures = [&] {
143 return std::move(m_pendingFutures);
146 for (QFuture<void> &pendingImage : pendingFutures)
147 pendingImage.waitForFinished();
153 return m_session && !passImage && cameraActive;
161 return doCapture(
path);
171 qCDebug(qLcImageCaptureGst) <<
"do capture";
176 invokeDeferred([
this] {
181 qCDebug(qLcImageCaptureGst) <<
"error 1";
184 if (!m_session->
camera()) {
185 invokeDeferred([
this] {
189 qCDebug(qLcImageCaptureGst) <<
"error 2";
193 invokeDeferred([
this] {
198 qCDebug(qLcImageCaptureGst) <<
"error 3";
212void QGstreamerImageCapture::setResolution(
const QSize &resolution)
215 if (padCaps.isNull()) {
216 qDebug() <<
"Camera not ready";
223 gst_caps_set_simple(caps.
caps(),
"width", G_TYPE_INT, resolution.
width(),
"height", G_TYPE_INT,
224 resolution.
height(),
nullptr);
229#if __cplusplus >= 202002L
230# define EQ_THIS_CAPTURE =, this
232# define EQ_THIS_CAPTURE =
241 qCDebug(qLcImageCaptureGst) <<
"probe buffer";
251 invokeDeferred([
this, ready] {
256 auto memoryFormat = caps.memoryFormat();
258 GstVideoInfo previewInfo;
260 auto optionalFormatAndVideoInfo = caps.formatAndVideoInfo();
261 if (optionalFormatAndVideoInfo)
262 std::tie(
fmt, previewInfo) = std::move(*optionalFormatAndVideoInfo);
264 int futureId = futureIDAllocator += 1;
271 m_pendingFutures.
remove(futureId);
275 qDebug() <<
"QGstreamerImageCapture::probeBuffer: no session";
280 auto gstBuffer = std::make_unique<QGstVideoBuffer>(std::move(bufferHandle), previewInfo,
286 qDebug() <<
"received a null image";
292 pendingImages.
head().metaData = std::move(imageMetaData);
293 PendingImage pendingImage = pendingImages.
head();
295 invokeDeferred([
this, pendingImage = std::move(pendingImage),
frame = std::move(
frame),
296 img = std::move(
img)]()
mutable {
298 qCDebug(qLcImageCaptureGst) <<
"Image available!";
313#undef EQ_THIS_CAPTURE
319 if (m_session == captureSession)
324 disconnect(m_session,
nullptr,
this,
nullptr);
326 pendingImages.
clear();
328 cameraActive =
false;
331 m_session = captureSession;
356 qCDebug(qLcImageCaptureGst) <<
"cameraActiveChanged" << cameraActive << active;
357 if (cameraActive == active)
359 cameraActive = active;
367 if (m_session->
camera()) {
376gboolean QGstreamerImageCapture::saveImageFilter(
GstElement *, GstBuffer *
buffer, GstPad *,
383void QGstreamerImageCapture::saveBufferToImage(GstBuffer *
buffer)
395 int id = futureIDAllocator++;
405 m_pendingFutures.
remove(
id);
412 qCDebug(qLcImageCaptureGst) <<
" could not open image file for writing";
417 GstBuffer *
buffer = bufferHandle.get();
418 if (gst_buffer_map(
buffer, &
info, GST_MAP_READ)) {
419 f.write(
reinterpret_cast<const char *
>(
info.data),
info.size);
429 m_pendingFutures.
insert(
id, saveImageFuture);
442 setResolution(resolution);
450#include "moc_qgstreamerimagecapture_p.cpp"
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
void aboutToQuit(QPrivateSignal)
This signal is emitted when the application is about to quit the main event loop, e....
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void add)(const Ts &...ts)
void addGhostPad(const QGstElement &child, const char *name)
bool setStateSync(GstState state, std::chrono::nanoseconds timeout=std::chrono::seconds(1))
QGstPad staticPad(const char *name) const
void set(const char *property, const char *str)
QGstCaps currentCaps() const
void addProbeToPad(GstPad *pad, bool downstream=true)
int capture(const QString &fileName) override
bool isReadyForCapture() const override
virtual ~QGstreamerImageCapture()
bool probeBuffer(GstBuffer *buffer) override
QImageEncoderSettings imageSettings() const override
int captureToBuffer() override
static QMaybe< QPlatformImageCapture * > create(QImageCapture *parent)
void setImageSettings(const QImageEncoderSettings &settings) override
void cameraActiveChanged(bool active)
void setMetaData(const QMediaMetaData &m) override
void setCaptureSession(QPlatformMediaCaptureSession *session)
bool isEmpty() const noexcept
iterator insert(const Key &key, const T &value)
size_type remove(const Key &key)
QObject * parent() const
Returns a pointer to the parent object.
static QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *member, Qt::ConnectionType=Qt::AutoConnection)
\threadsafe
void destroyed(QObject *=nullptr)
This signal is emitted immediately before the object obj is destroyed, after any instances of QPointe...
void enqueue(const T &t)
Adds value t to the tail of the queue.
T & head()
Returns a reference to the queue's head item.
T dequeue()
Removes the head item in the queue and returns it.
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
\macro QT_RESTRICTED_CAST_FROM_ASCII
static QVideoFrame createFrame(std::unique_ptr< Buffer > buffer, QVideoFrameFormat format)
The QVideoFrame class represents a frame of video data.
Combined button and popup list for selecting options.
ThreadPoolSingleton s_threadPoolSingleton
QTCONCURRENT_RUN_NODISCARD auto run(QThreadPool *pool, Function &&f, Args &&...args)
DBusConnection const char DBusError * error
static QDBusError::ErrorType get(const char *name)
std::enable_if_t<(std::is_base_of_v< QGstElement, Ts > &&...), void qLinkGstElements)(const Ts &...ts)
std::optional< QString > qGstErrorMessageIfElementsNotAvailable(const Arg &arg, Args... args)
#define Q_LOGGING_CATEGORY(name,...)
#define qCDebug(category,...)
GLenum GLenum GLsizei count
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLsizei const GLchar *const * path
GLsizei GLenum GLboolean sink
QScopeGuard< typename std::decay< F >::type > qScopeGuard(F &&f)
[qScopeGuard]
unsigned long long quint64
QVideoFrameFormat::PixelFormat fmt
QFuture< void > future
[5]
QSettings settings("MySoft", "Star Runner")
[0]
myObject disconnect()
[26]
QThreadPool * get(const QMutexLocker< QMutex > &)
QFuture< void > run(Functor &&f)