diff options
27 files changed, 262 insertions, 112 deletions
diff --git a/src/multimedia/camera/qcameraimagecapture.cpp b/src/multimedia/camera/qcameraimagecapture.cpp index 384d43fbf..31b5d002c 100644 --- a/src/multimedia/camera/qcameraimagecapture.cpp +++ b/src/multimedia/camera/qcameraimagecapture.cpp @@ -41,6 +41,7 @@ #include <qmediaencodersettings.h> #include <qmediametadata.h> #include <private/qplatformmediacapture_p.h> +#include <private/qplatformmediaintegration_p.h> #include <qmediacapturesession.h> #include "private/qobject_p.h" @@ -115,6 +116,7 @@ QCameraImageCapture::QCameraImageCapture(QObject *parent) { Q_D(QCameraImageCapture); d->q_ptr = this; + d->control = QPlatformMediaIntegration::instance()->createImageCapture(this); } void QCameraImageCapture::setCaptureSession(QMediaCaptureSession *session) @@ -122,15 +124,13 @@ void QCameraImageCapture::setCaptureSession(QMediaCaptureSession *session) Q_D(QCameraImageCapture); d->captureSession = session; - if (!session) { - d->control = nullptr; - return; - } + QPlatformMediaCaptureSession *platformSession = session ? session->platformSession() : nullptr; - d->control = session->platformSession()->imageCapture(); - - if (!d->control) + if (platformSession && d->control) { + platformSession->setImageCapture(d->control); + } else { return; + } connect(d->control, SIGNAL(imageExposed(int)), this, SIGNAL(imageExposed(int))); @@ -155,7 +155,7 @@ void QCameraImageCapture::setCaptureSession(QMediaCaptureSession *session) QCameraImageCapture::~QCameraImageCapture() { if (d_ptr->captureSession) { - //d_ptr->captureSession->platformSession()->releaseImageCapture(d_ptr->control); + d_ptr->captureSession->platformSession()->setImageCapture(nullptr); d_ptr->captureSession->setImageCapture(nullptr); } delete d_ptr; @@ -258,9 +258,13 @@ void QCameraImageCapture::addMetaData(const QMediaMetaData &metaData) bool QCameraImageCapture::isReadyForCapture() const { - if (d_func()->control) - return d_func()->control->isReadyForCapture(); - return false; + Q_D(const QCameraImageCapture); + if (!d->control || !d->captureSession || !d->control->isReadyForCapture()) + return false; + auto *camera = d->captureSession->camera(); + if (!camera || !camera->isActive()) + return false; + return true; } /*! @@ -297,15 +301,17 @@ int QCameraImageCapture::captureToFile(const QString &file) d->unsetError(); - if (d->control) - return d->control->capture(file); - - d->error = NotSupportedFeatureError; - d->errorString = tr("Device does not support images capture."); + if (!d->control) { + d->_q_error(-1, NotSupportedFeatureError, tr("Camera is not ready.")); + return -1; + } - d->_q_error(-1, d->error, d->errorString); + if (!isReadyForCapture()) { + d->_q_error(-1, NotReadyError, tr("Could not capture in stopped state")); + return -1; + } - return -1; + return d->control->capture(file); } /*! diff --git a/src/multimedia/platform/darwin/camera/avfcameraimagecapture.mm b/src/multimedia/platform/darwin/camera/avfcameraimagecapture.mm index 9d04fb3f4..684678471 100644 --- a/src/multimedia/platform/darwin/camera/avfcameraimagecapture.mm +++ b/src/multimedia/platform/darwin/camera/avfcameraimagecapture.mm @@ -42,6 +42,8 @@ #include "avfcameraservice_p.h" #include "avfcamerautility_p.h" #include "avfcamera_p.h" +#include "avfcamerasession_p.h" +#include "avfcamerarenderer_p.h" #include <private/qmemoryvideobuffer_p.h> #include <QtCore/qurl.h> @@ -50,18 +52,16 @@ #include <QtConcurrent/qtconcurrentrun.h> #include <QtGui/qimagereader.h> +#import <AVFoundation/AVFoundation.h> + QT_USE_NAMESPACE -AVFCameraImageCapture::AVFCameraImageCapture(AVFCameraService *service, QObject *parent) +AVFCameraImageCapture::AVFCameraImageCapture(QCameraImageCapture *parent) : QPlatformCameraImageCapture(parent) - , m_service(service) - , m_session(service->session()) - , m_cameraControl(service->avfCameraControl()) , m_ready(false) , m_lastCaptureId(0) , m_videoConnection(nil) { - Q_UNUSED(service); m_stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: @@ -69,13 +69,6 @@ AVFCameraImageCapture::AVFCameraImageCapture(AVFCameraService *service, QObject [m_stillImageOutput setOutputSettings:outputSettings]; [outputSettings release]; - connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateReadyStatus())); - - connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection())); - - connect(m_session, &AVFCameraSession::newViewfinderFrame, - this, &AVFCameraImageCapture::onNewViewfinderFrame, - Qt::DirectConnection); } AVFCameraImageCapture::~AVFCameraImageCapture() @@ -84,7 +77,7 @@ AVFCameraImageCapture::~AVFCameraImageCapture() bool AVFCameraImageCapture::isReadyForCapture() const { - return m_videoConnection && m_cameraControl->status() == QCamera::ActiveStatus; + return m_cameraControl && m_videoConnection && m_cameraControl->status() == QCamera::ActiveStatus; } void AVFCameraImageCapture::updateReadyStatus() @@ -98,7 +91,13 @@ void AVFCameraImageCapture::updateReadyStatus() int AVFCameraImageCapture::doCapture(const QString &actualFileName) { - + if (!m_session) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(int, m_lastCaptureId), + Q_ARG(int, QCameraImageCapture::ResourceError), + Q_ARG(QString, tr("Image capture not set to capture session"))); + return m_lastCaptureId; + } if (!isReadyForCapture()) { QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(int, m_lastCaptureId), @@ -115,6 +114,8 @@ int AVFCameraImageCapture::doCapture(const QString &actualFileName) m_captureRequests.enqueue(request); m_requestsMutex.unlock(); + QString fileName(actualFileName); + [m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { @@ -159,12 +160,12 @@ int AVFCameraImageCapture::doCapture(const QString &actualFileName) Q_ARG(int, request.captureId), Q_ARG(QVideoFrame, frame)); } else { - QFile f(actualFileName); + QFile f(fileName); if (f.open(QFile::WriteOnly)) { if (f.write(jpgData) != -1) { QMetaObject::invokeMethod(this, "imageSaved", Qt::QueuedConnection, Q_ARG(int, request.captureId), - Q_ARG(QString, actualFileName)); + Q_ARG(QString, fileName)); } else { QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(int, request.captureId), @@ -172,7 +173,7 @@ int AVFCameraImageCapture::doCapture(const QString &actualFileName) Q_ARG(QString, f.errorString())); } } else { - QString errorMessage = tr("Could not open destination file:\n%1").arg(actualFileName); + QString errorMessage = tr("Could not open destination file:\n%1").arg(fileName); QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, Q_ARG(int, request.captureId), Q_ARG(int, QCameraImageCapture::ResourceError), @@ -226,6 +227,15 @@ void AVFCameraImageCapture::onNewViewfinderFrame(const QVideoFrame &frame) 0 /* rotation */); } +void AVFCameraImageCapture::onCameraChanged() +{ + Q_ASSERT(m_service); + if (m_service->camera()) { + m_cameraControl = static_cast<AVFCamera *>(m_service->camera()); + connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), this, SLOT(updateReadyStatus())); + } +} + void AVFCameraImageCapture::makeCapturePreview(CaptureRequest request, const QVideoFrame &frame, int rotation) @@ -240,7 +250,7 @@ void AVFCameraImageCapture::makeCapturePreview(CaptureRequest request, void AVFCameraImageCapture::updateCaptureConnection() { - if (m_session->videoCaptureDevice()) { + if (m_session && m_session->videoCaptureDevice()) { qDebugCamera() << Q_FUNC_INFO; AVCaptureSession *captureSession = m_session->captureSession(); @@ -361,9 +371,44 @@ bool AVFCameraImageCapture::applySettings() return activeFormatChanged; } +void AVFCameraImageCapture::setCaptureSession(QPlatformMediaCaptureSession *session) +{ + AVFCameraService *captureSession = static_cast<AVFCameraService *>(session); + if (m_service == captureSession) + return; + + m_service = captureSession; + if (!m_service) { + disconnect(m_session, nullptr, this, nullptr); + disconnect(m_session->videoOutput(), nullptr, this, nullptr); + disconnect(m_cameraControl, nullptr, this, nullptr); + m_session = nullptr; + m_cameraControl = nullptr; + m_videoConnection = nil; + return; + } + + m_session = m_service->session(); + Q_ASSERT(m_session); + m_cameraControl = static_cast<AVFCamera *>(m_service->camera()); + + connect(m_service, &AVFCameraService::cameraChanged, this, &AVFCameraImageCapture::onCameraChanged); + connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection())); + connect(m_session->videoOutput(), &AVFCameraRenderer::newViewfinderFrame, + this, &AVFCameraImageCapture::onNewViewfinderFrame, + Qt::DirectConnection); + + if (m_session->isActive()) + updateCaptureConnection(); + if (m_cameraControl) { + updateReadyStatus(); + connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), this, SLOT(updateReadyStatus())); + } +} + bool AVFCameraImageCapture::videoCaptureDeviceIsValid() const { - if (!m_service->session() || !m_service->session()->videoCaptureDevice()) + if (!m_service || !m_service->session() || !m_service->session()->videoCaptureDevice()) return false; AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); diff --git a/src/multimedia/platform/darwin/camera/avfcameraimagecapture_p.h b/src/multimedia/platform/darwin/camera/avfcameraimagecapture_p.h index 5731d13cb..9fceda4f1 100644 --- a/src/multimedia/platform/darwin/camera/avfcameraimagecapture_p.h +++ b/src/multimedia/platform/darwin/camera/avfcameraimagecapture_p.h @@ -51,17 +51,24 @@ // We mean it. // -#import <AVFoundation/AVFoundation.h> +// #import <AVFoundation/AVFoundation.h> #include <QtCore/qqueue.h> #include <QtCore/qsemaphore.h> #include <QtCore/qsharedpointer.h> #include <private/qplatformcameraimagecapture_p.h> -#include "avfcamerasession_p.h" #include "avfstoragelocation_p.h" QT_BEGIN_NAMESPACE +class AVFCameraService; +class AVFCameraSession; +class AVFCamera; + +Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureStillImageOutput); +Q_FORWARD_DECLARE_OBJC_CLASS(AVCaptureConnection); + + class AVFCameraImageCapture : public QPlatformCameraImageCapture { Q_OBJECT @@ -71,7 +78,7 @@ public: QSharedPointer<QSemaphore> previewReady; }; - AVFCameraImageCapture(AVFCameraService *service, QObject *parent = nullptr); + AVFCameraImageCapture(QCameraImageCapture *parent = nullptr); ~AVFCameraImageCapture(); bool isReadyForCapture() const override; @@ -86,10 +93,13 @@ public: void setImageSettings(const QImageEncoderSettings &settings) override; bool applySettings(); + void setCaptureSession(QPlatformMediaCaptureSession *session) override; + private Q_SLOTS: void updateCaptureConnection(); void updateReadyStatus(); void onNewViewfinderFrame(const QVideoFrame &frame); + void onCameraChanged(); private: void makeCapturePreview(CaptureRequest request, const QVideoFrame &frame, int rotation); diff --git a/src/multimedia/platform/darwin/camera/avfcamerarenderer.mm b/src/multimedia/platform/darwin/camera/avfcamerarenderer.mm index a3b4cc95a..a5be5e030 100644 --- a/src/multimedia/platform/darwin/camera/avfcamerarenderer.mm +++ b/src/multimedia/platform/darwin/camera/avfcamerarenderer.mm @@ -183,6 +183,7 @@ void AVFCameraRenderer::updateCaptureConnection() //can be called from non main thread void AVFCameraRenderer::syncHandleViewfinderFrame(const QVideoFrame &frame) { + Q_EMIT newViewfinderFrame(frame); QMutexLocker lock(&m_vfMutex); if (m_rendersToWindow) return; diff --git a/src/multimedia/platform/darwin/camera/avfcamerarenderer_p.h b/src/multimedia/platform/darwin/camera/avfcamerarenderer_p.h index 9460c41dd..16ff9a6c7 100644 --- a/src/multimedia/platform/darwin/camera/avfcamerarenderer_p.h +++ b/src/multimedia/platform/darwin/camera/avfcamerarenderer_p.h @@ -99,6 +99,9 @@ public: QRhi *rhi() const { return m_rhi; } +Q_SIGNALS: + void newViewfinderFrame(const QVideoFrame &frame); + private Q_SLOTS: void handleViewfinderFrame(); void updateCaptureConnection(); diff --git a/src/multimedia/platform/darwin/camera/avfcameraservice.mm b/src/multimedia/platform/darwin/camera/avfcameraservice.mm index 62df42d56..b23c2bc94 100644 --- a/src/multimedia/platform/darwin/camera/avfcameraservice.mm +++ b/src/multimedia/platform/darwin/camera/avfcameraservice.mm @@ -67,12 +67,6 @@ AVFCameraService::~AVFCameraService() #ifdef Q_OS_IOS delete m_recorderControl; #endif - - //delete controls before session, - //so they have a chance to do deinitialization - if (m_imageCaptureControl) - delete m_imageCaptureControl; - //delete m_recorderControl; if (m_session) delete m_session; } @@ -84,7 +78,7 @@ QPlatformCamera *AVFCameraService::camera() void AVFCameraService::setCamera(QPlatformCamera *camera) { - AVFCamera *control = static_cast<AVFCamera*>(camera); + AVFCamera *control = static_cast<AVFCamera *>(camera); if (m_cameraControl == control) return; @@ -94,6 +88,7 @@ void AVFCameraService::setCamera(QPlatformCamera *camera) m_cameraControl = control; if (m_cameraControl) m_cameraControl->setCaptureSession(this); + emit cameraChanged(); } QPlatformCameraImageCapture *AVFCameraService::imageCapture() @@ -101,6 +96,20 @@ QPlatformCameraImageCapture *AVFCameraService::imageCapture() return m_imageCaptureControl; } +void AVFCameraService::setImageCapture(QPlatformCameraImageCapture *imageCapture) +{ + AVFCameraImageCapture *control = static_cast<AVFCameraImageCapture *>(imageCapture); + if (m_imageCaptureControl == control) + return; + + if (m_imageCaptureControl) + m_imageCaptureControl->setCaptureSession(nullptr); + + m_imageCaptureControl = control; + if (m_imageCaptureControl) + m_imageCaptureControl->setCaptureSession(this); +} + QPlatformMediaEncoder *AVFCameraService::mediaEncoder() { return m_recorderControl; @@ -164,8 +173,4 @@ void AVFCameraService::setVideoPreview(QVideoSink *sink) m_session->setVideoSink(sink); } -void AVFCameraService::cameraChanged() -{ -} - #include "moc_avfcameraservice_p.cpp" diff --git a/src/multimedia/platform/darwin/camera/avfcameraservice_p.h b/src/multimedia/platform/darwin/camera/avfcameraservice_p.h index ff1cca4ae..eb987e23d 100644 --- a/src/multimedia/platform/darwin/camera/avfcameraservice_p.h +++ b/src/multimedia/platform/darwin/camera/avfcameraservice_p.h @@ -74,9 +74,10 @@ public: ~AVFCameraService(); QPlatformCamera *camera() override; - void setCamera(QPlatformCamera *) override; + void setCamera(QPlatformCamera *camera) override; QPlatformCameraImageCapture *imageCapture() override; + void setImageCapture(QPlatformCameraImageCapture *imageCapture) override; QPlatformMediaEncoder *mediaEncoder() override; @@ -94,8 +95,6 @@ public: AVFMediaEncoder *recorderControl() const { return m_recorderControl; } AVFCameraImageCapture *avfImageCaptureControl() const { return m_imageCaptureControl; } - void cameraChanged(); - private: bool m_muted = false; qreal m_volume = 1.0; diff --git a/src/multimedia/platform/darwin/camera/avfcamerasession_p.h b/src/multimedia/platform/darwin/camera/avfcamerasession_p.h index b5361309a..128a20c5a 100644 --- a/src/multimedia/platform/darwin/camera/avfcamerasession_p.h +++ b/src/multimedia/platform/darwin/camera/avfcamerasession_p.h @@ -101,7 +101,6 @@ public Q_SLOTS: Q_SIGNALS: void readyToConfigureConnections(); void activeChanged(bool); - void newViewfinderFrame(const QVideoFrame &frame); void error(int error, const QString &errorString); private: diff --git a/src/multimedia/platform/darwin/qdarwinintegration.cpp b/src/multimedia/platform/darwin/qdarwinintegration.cpp index caf2dc8fc..fa7244949 100644 --- a/src/multimedia/platform/darwin/qdarwinintegration.cpp +++ b/src/multimedia/platform/darwin/qdarwinintegration.cpp @@ -42,6 +42,7 @@ #include <private/avfmediaplayer_p.h> #include <private/avfcameraservice_p.h> #include <private/avfcamera_p.h> +#include <private/avfcameraimagecapture_p.h> #include <private/qdarwinformatsinfo_p.h> #include <private/avfvideosink_p.h> @@ -92,9 +93,9 @@ QPlatformMediaEncoder *QDarwinIntegration::createEncoder(QMediaEncoder*) return nullptr; } -QPlatformImageCapture *QDarwinIntegration::createImageCapture(QCameraImageCapture*) +QPlatformCameraImageCapture *QDarwinIntegration::createImageCapture(QCameraImageCapture *imageCapture) { - return nullptr; + return new AVFCameraImageCapture(imageCapture); } QPlatformVideoSink *QDarwinIntegration::createVideoSink(QVideoSink *sink) diff --git a/src/multimedia/platform/darwin/qdarwinintegration_p.h b/src/multimedia/platform/darwin/qdarwinintegration_p.h index 7dd1b5584..cf7691624 100644 --- a/src/multimedia/platform/darwin/qdarwinintegration_p.h +++ b/src/multimedia/platform/darwin/qdarwinintegration_p.h @@ -70,7 +70,7 @@ public: QPlatformMediaPlayer *createPlayer(QMediaPlayer *player) override; QPlatformCamera *createCamera(QCamera *camera) override; QPlatformMediaEncoder *createEncoder(QMediaEncoder *) override; - QPlatformImageCapture *createImageCapture(QCameraImageCapture *) override; + QPlatformCameraImageCapture *createImageCapture(QCameraImageCapture *) override; QPlatformVideoSink *createVideoSink(QVideoSink *) override; diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercameraimagecapture.cpp b/src/multimedia/platform/gstreamer/mediacapture/qgstreamercameraimagecapture.cpp index 1704ac4a9..cfb66c8b6 100644 --- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercameraimagecapture.cpp +++ b/src/multimedia/platform/gstreamer/mediacapture/qgstreamercameraimagecapture.cpp @@ -53,11 +53,9 @@ QT_BEGIN_NAMESPACE Q_LOGGING_CATEGORY(qLcImageCapture, "qt.multimedia.imageCapture") -QGstreamerCameraImageCapture::QGstreamerCameraImageCapture(QGstreamerMediaCapture *session, const QGstPipeline &pipeline) - : QPlatformCameraImageCapture(session), - QGstreamerBufferProbe(ProbeBuffers), - m_session(session), - gstPipeline(pipeline) +QGstreamerCameraImageCapture::QGstreamerCameraImageCapture(QCameraImageCapture *parent) + : QPlatformCameraImageCapture(parent), + QGstreamerBufferProbe(ProbeBuffers) { bin = QGstBin("imageCaptureBin"); @@ -76,25 +74,22 @@ QGstreamerCameraImageCapture::QGstreamerCameraImageCapture(QGstreamerMediaCaptur queue.link(videoConvert, encoder, sink); bin.addGhostPad(queue, "sink"); bin.lockState(true); - gstPipeline.add(bin); addProbeToPad(queue.staticPad("src").pad(), false); sink.set("signal-handoffs", true); g_signal_connect(sink.object(), "handoff", G_CALLBACK(&QGstreamerCameraImageCapture::saveImageFilter), this); - - connect(m_session->camera(), &QPlatformCamera::activeChanged, this, &QGstreamerCameraImageCapture::cameraActiveChanged); - cameraActive = m_session->camera()->isActive(); } QGstreamerCameraImageCapture::~QGstreamerCameraImageCapture() { - m_session->releaseVideoPad(videoSrcPad); + if (m_session) + m_session->releaseVideoPad(videoSrcPad); } bool QGstreamerCameraImageCapture::isReadyForCapture() const { - return !passImage && cameraActive; + return m_session && !passImage && cameraActive; } @@ -153,6 +148,16 @@ int QGstreamerCameraImageCapture::captureToBuffer() int QGstreamerCameraImageCapture::doCapture(const QString &fileName) { + if (!m_session) { + //emit error in the next event loop, + //so application can associate it with returned request id. + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(int, m_lastId), + Q_ARG(int, QCameraImageCapture::ResourceError), + Q_ARG(QString,tr("Image capture not set to a session."))); + + return -1; + } if (!m_session->camera()) { //emit error in the next event loop, //so application can associate it with returned request id. @@ -225,6 +230,29 @@ bool QGstreamerCameraImageCapture::probeBuffer(GstBuffer *buffer) return true; } +void QGstreamerCameraImageCapture::setCaptureSession(QPlatformMediaCaptureSession *session) +{ + QGstreamerMediaCapture *captureSession = static_cast<QGstreamerMediaCapture *>(session); + if (m_session == captureSession) + return; + + if (m_session) { + disconnect(m_session, nullptr, this, nullptr); + m_lastId = 0; + pendingImages.clear(); + passImage = false; + cameraActive = false; + bin.setStateSync(GST_STATE_NULL); + } + + m_session = captureSession; + if (!m_session) + return; + + connect(m_session, &QPlatformMediaCaptureSession::cameraChanged, this, &QGstreamerCameraImageCapture::onCameraChanged); + onCameraChanged(); +} + void QGstreamerCameraImageCapture::cameraActiveChanged(bool active) { qCDebug(qLcImageCapture) << "cameraActiveChanged" << cameraActive << active; @@ -235,6 +263,15 @@ void QGstreamerCameraImageCapture::cameraActiveChanged(bool active) emit readyForCaptureChanged(isReadyForCapture()); } +void QGstreamerCameraImageCapture::onCameraChanged() +{ + if (m_session->camera()) { + cameraActiveChanged(m_session->camera()->isActive()); + connect(m_session->camera(), &QPlatformCamera::activeChanged, this, &QGstreamerCameraImageCapture::cameraActiveChanged); + } + +} + gboolean QGstreamerCameraImageCapture::saveImageFilter(GstElement *element, GstBuffer *buffer, GstPad *pad, @@ -281,7 +318,8 @@ void QGstreamerCameraImageCapture::unlink() return; if (passImage) return; - + if (gstPipeline.isNull()) + return; gstPipeline.setStateSync(GST_STATE_PAUSED); videoSrcPad.unlinkPeer(); m_session->releaseVideoPad(videoSrcPad); @@ -293,11 +331,10 @@ void QGstreamerCameraImageCapture::unlink() void QGstreamerCameraImageCapture::link() { - Q_ASSERT(m_session->camera()); - - if (!bin.staticPad("sink").peer().isNull()) + if (!(m_session && m_session->camera())) + return; + if (!bin.staticPad("sink").peer().isNull() || gstPipeline.isNull()) return; - gstPipeline.setStateSync(GST_STATE_PAUSED); videoSrcPad = m_session->getVideoPad(); videoSrcPad.link(bin.staticPad("sink")); diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercameraimagecapture_p.h b/src/multimedia/platform/gstreamer/mediacapture/qgstreamercameraimagecapture_p.h index e046eae99..067920518 100644 --- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamercameraimagecapture_p.h +++ b/src/multimedia/platform/gstreamer/mediacapture/qgstreamercameraimagecapture_p.h @@ -68,7 +68,7 @@ class QGstreamerCameraImageCapture : public QPlatformCameraImageCapture, private { Q_OBJECT public: - QGstreamerCameraImageCapture(QGstreamerMediaCapture *session, const QGstPipeline &pipeline); + QGstreamerCameraImageCapture(QCameraImageCapture *parent/*, const QGstPipeline &pipeline*/); virtual ~QGstreamerCameraImageCapture(); bool isReadyForCapture() const override; @@ -80,8 +80,14 @@ public: bool probeBuffer(GstBuffer *buffer) override; + void setCaptureSession(QPlatformMediaCaptureSession *session); + + QGstElement gstElement() const { return bin.element(); } + void setPipeline(const QGstPipeline &pipeline) { gstPipeline = pipeline; } + public Q_SLOTS: void cameraActiveChanged(bool active); + void onCameraChanged(); private: int doCapture(const QString &fileName); diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture.cpp b/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture.cpp index 770b720a5..6ea518705 100644 --- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture.cpp +++ b/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture.cpp @@ -88,7 +88,6 @@ QGstreamerMediaCapture::QGstreamerMediaCapture(QMediaRecorder::CaptureMode) QGstreamerMediaCapture::~QGstreamerMediaCapture() { gstPipeline.setStateSync(GST_STATE_NULL); - delete m_imageCapture; delete m_mediaEncoder; } @@ -130,7 +129,7 @@ void QGstreamerMediaCapture::setCamera(QPlatformCamera *camera) } gstPipeline.setStateSync(GST_STATE_PLAYING); - cameraChanged(); + emit cameraChanged(); dumpGraph(QLatin1String("camera")); } @@ -141,7 +140,29 @@ QPlatformCameraImageCapture *QGstreamerMediaCapture::imageCapture() void QGstreamerMediaCapture::setImageCapture(QPlatformCameraImageCapture *imageCapture) { - Q_UNUSED(imageCapture); + QGstreamerCameraImageCapture *control = static_cast<QGstreamerCameraImageCapture *>(imageCapture); + if (m_imageCapture == control) + return; + + gstPipeline.setStateSync(GST_STATE_PAUSED); + + if (m_imageCapture) { + m_imageCapture->setCaptureSession(nullptr); + if (m_imageCapture->gstElement().state() != GST_STATE_NULL) + m_imageCapture->gstElement().setStateSync(GST_STATE_NULL); + gstPipeline.remove(m_imageCapture->gstElement()); + } + + m_imageCapture = control; + if (m_imageCapture) { + m_imageCapture->setCaptureSession(this); + m_imageCapture->setPipeline(gstPipeline); + gstPipeline.add(m_imageCapture->gstElement()); + // m_imageCapture->gstElement().lockState(false); + // m_imageCapture->gstElement().setState(gstPipeline.state()); + } + gstPipeline.setStateSync(GST_STATE_PLAYING); + emit imageCaptureChanged(); } void QGstreamerMediaCapture::setMediaEncoder(QPlatformMediaEncoder *encoder) @@ -200,9 +221,9 @@ bool QGstreamerMediaCapture::setAudioPreview(const QAudioDeviceInfo &info) return true; } -void QGstreamerMediaCapture::cameraChanged() -{ -} +// void QGstreamerMediaCapture::cameraChanged() +// { +// } void QGstreamerMediaCapture::dumpGraph(const QString &fileName) { diff --git a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture_p.h b/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture_p.h index 5aae7867f..cd097a890 100644 --- a/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture_p.h +++ b/src/multimedia/platform/gstreamer/mediacapture/qgstreamermediacapture_p.h @@ -94,7 +94,7 @@ public: QAudioDeviceInfo audioPreview() const override; bool setAudioPreview(const QAudioDeviceInfo &info) override; - void cameraChanged(); + // void cameraChanged(); void dumpGraph(const QString &fileName); diff --git a/src/multimedia/platform/gstreamer/qgstreamerintegration.cpp b/src/multimedia/platform/gstreamer/qgstreamerintegration.cpp index ea75a060d..c4ad5211f 100644 --- a/src/multimedia/platform/gstreamer/qgstreamerintegration.cpp +++ b/src/multimedia/platform/gstreamer/qgstreamerintegration.cpp @@ -101,9 +101,9 @@ QPlatformMediaEncoder *QGstreamerIntegration::createEncoder(QMediaEncoder*) return nullptr; } -QPlatformImageCapture *QGstreamerIntegration::createImageCapture(QCameraImageCapture*) +QPlatformCameraImageCapture *QGstreamerIntegration::createImageCapture(QCameraImageCapture *imageCapture) { - return nullptr; + return new QGstreamerCameraImageCapture(imageCapture); } QPlatformVideoSink *QGstreamerIntegration::createVideoSink(QVideoSink *sink) diff --git a/src/multimedia/platform/gstreamer/qgstreamerintegration_p.h b/src/multimedia/platform/gstreamer/qgstreamerintegration_p.h index c00dcc4f0..38fc93f43 100644 --- a/src/multimedia/platform/gstreamer/qgstreamerintegration_p.h +++ b/src/multimedia/platform/gstreamer/qgstreamerintegration_p.h @@ -74,7 +74,7 @@ public: QPlatformMediaPlayer *createPlayer(QMediaPlayer *player) override; QPlatformCamera *createCamera(QCamera *) override; QPlatformMediaEncoder *createEncoder(QMediaEncoder *) override; - QPlatformImageCapture *createImageCapture(QCameraImageCapture *) override; + QPlatformCameraImageCapture *createImageCapture(QCameraImageCapture *) override; QPlatformVideoSink *createVideoSink(QVideoSink *sink) override; diff --git a/src/multimedia/platform/qplatformcameraimagecapture.cpp b/src/multimedia/platform/qplatformcameraimagecapture.cpp index bed04b035..907fa3354 100644 --- a/src/multimedia/platform/qplatformcameraimagecapture.cpp +++ b/src/multimedia/platform/qplatformcameraimagecapture.cpp @@ -57,8 +57,9 @@ QT_BEGIN_NAMESPACE /*! Constructs a new image capture control object with the given \a parent */ -QPlatformCameraImageCapture::QPlatformCameraImageCapture(QObject *parent) - :QObject(parent) +QPlatformCameraImageCapture::QPlatformCameraImageCapture(QCameraImageCapture *parent) + : QObject(parent), + m_imageCapture(parent) { } diff --git a/src/multimedia/platform/qplatformcameraimagecapture_p.h b/src/multimedia/platform/qplatformcameraimagecapture_p.h index f6e4e08f2..8971deb63 100644 --- a/src/multimedia/platform/qplatformcameraimagecapture_p.h +++ b/src/multimedia/platform/qplatformcameraimagecapture_p.h @@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE class QImage; +class QPlatformMediaCaptureSession; class Q_MULTIMEDIA_EXPORT QPlatformCameraImageCapture : public QObject { @@ -71,6 +72,9 @@ public: virtual void setImageSettings(const QImageEncoderSettings &settings) = 0; virtual void setMetaData(const QMediaMetaData &) {} + + QCameraImageCapture *imageCapture() { return m_imageCapture; } + Q_SIGNALS: void readyForCaptureChanged(bool ready); @@ -83,7 +87,9 @@ Q_SIGNALS: void error(int id, int error, const QString &errorString); protected: - explicit QPlatformCameraImageCapture(QObject *parent = nullptr); + explicit QPlatformCameraImageCapture(QCameraImageCapture *parent = nullptr); +private: + QCameraImageCapture *m_imageCapture = nullptr; }; QT_END_NAMESPACE diff --git a/src/multimedia/platform/qplatformmediacapture_p.h b/src/multimedia/platform/qplatformmediacapture_p.h index c2c211171..087d5e1cb 100644 --- a/src/multimedia/platform/qplatformmediacapture_p.h +++ b/src/multimedia/platform/qplatformmediacapture_p.h @@ -92,6 +92,9 @@ public: Q_SIGNALS: void mutedChanged(bool muted); void volumeChanged(qreal volume); + void cameraChanged(); + void imageCaptureChanged(); + void encoderChanged(); }; diff --git a/src/multimedia/platform/qplatformmediaintegration_p.h b/src/multimedia/platform/qplatformmediaintegration_p.h index 4fd8aec3f..dd26c2b71 100644 --- a/src/multimedia/platform/qplatformmediaintegration_p.h +++ b/src/multimedia/platform/qplatformmediaintegration_p.h @@ -66,7 +66,7 @@ class QPlatformMediaPlayer; class QPlatformAudioDecoder; class QPlatformCamera; class QPlatformMediaEncoder; -class QPlatformImageCapture; +class QPlatformCameraImageCapture; class QPlatformMediaFormatInfo; class QObject; class QPlatformVideoSink; @@ -90,7 +90,7 @@ public: virtual QPlatformMediaPlayer *createPlayer(QMediaPlayer *) { return nullptr; } virtual QPlatformCamera *createCamera(QCamera *) { return nullptr; } virtual QPlatformMediaEncoder *createEncoder(QMediaEncoder *) { return nullptr; } - virtual QPlatformImageCapture *createImageCapture(QCameraImageCapture *) { return nullptr; } + virtual QPlatformCameraImageCapture *createImageCapture(QCameraImageCapture *) { return nullptr; } virtual QPlatformVideoSink *createVideoSink(QVideoSink *) { return nullptr; } }; diff --git a/src/multimediaquick/qtmultimediaquicktypes_p.h b/src/multimediaquick/qtmultimediaquicktypes_p.h index 2539ef86a..8bbbe29eb 100644 --- a/src/multimediaquick/qtmultimediaquicktypes_p.h +++ b/src/multimediaquick/qtmultimediaquicktypes_p.h @@ -53,7 +53,7 @@ #include <QtQml/qqml.h> #include <QtMultimedia/QtMultimedia> -#include <qtmultimediaquickglobal_p.h> +#include <private/qtmultimediaquickglobal_p.h> QT_BEGIN_NAMESPACE diff --git a/tests/auto/unit/mockbackend/qmockimagecapture.cpp b/tests/auto/unit/mockbackend/qmockimagecapture.cpp index 3cab8ce49..23e9fad60 100644 --- a/tests/auto/unit/mockbackend/qmockimagecapture.cpp +++ b/tests/auto/unit/mockbackend/qmockimagecapture.cpp @@ -29,16 +29,17 @@ #include <qmockimagecapture.h> #include <qmockcamera.h> #include <qmockmediacapturesession.h> +#include <qcameraimagecapture.h> +#include <qcamera.h> -QMockImageCapture::QMockImageCapture(QMockMediaCaptureSession *captureSession) - : QPlatformCameraImageCapture(captureSession), - m_captureSession(captureSession) +QMockImageCapture::QMockImageCapture(QCameraImageCapture *parent) + : QPlatformCameraImageCapture(parent) { } bool QMockImageCapture::isReadyForCapture() const { - return m_ready && m_captureSession->camera() && m_captureSession->camera()->isActive(); + return m_ready; } int QMockImageCapture::capture(const QString &fileName) diff --git a/tests/auto/unit/mockbackend/qmockimagecapture.h b/tests/auto/unit/mockbackend/qmockimagecapture.h index 3107e25fc..7b7a2a5e1 100644 --- a/tests/auto/unit/mockbackend/qmockimagecapture.h +++ b/tests/auto/unit/mockbackend/qmockimagecapture.h @@ -42,25 +42,24 @@ class QMockImageCapture : public QPlatformCameraImageCapture { Q_OBJECT public: - QMockImageCapture(QMockMediaCaptureSession *captureSession); + QMockImageCapture(QCameraImageCapture *parent); ~QMockImageCapture() { } - bool isReadyForCapture() const; + bool isReadyForCapture() const override; - int capture(const QString &fileName); - int captureToBuffer() { return -1; } + int capture(const QString &fileName) override; + int captureToBuffer() override { return -1; } - QImageEncoderSettings imageSettings() const { return m_settings; } - void setImageSettings(const QImageEncoderSettings &settings) { m_settings = settings; } + QImageEncoderSettings imageSettings() const override { return m_settings; } + void setImageSettings(const QImageEncoderSettings &settings) override { m_settings = settings; } private Q_SLOTS: void captured(); private: - QMockMediaCaptureSession *m_captureSession = nullptr; QString m_fileName; int m_captureRequest = 0; bool m_ready = true; diff --git a/tests/auto/unit/mockbackend/qmockintegration.cpp b/tests/auto/unit/mockbackend/qmockintegration.cpp index 383ddc5d3..585cad8ff 100644 --- a/tests/auto/unit/mockbackend/qmockintegration.cpp +++ b/tests/auto/unit/mockbackend/qmockintegration.cpp @@ -44,6 +44,7 @@ #include "qmockcamera.h" #include "qmockmediacapturesession.h" #include "qmockvideosink.h" +#include "qmockimagecapture.h" QT_BEGIN_NAMESPACE @@ -92,6 +93,11 @@ QPlatformCamera *QMockIntegration::createCamera(QCamera *parent) return m_lastCamera; } +QPlatformCameraImageCapture *QMockIntegration::createImageCapture(QCameraImageCapture *capture) +{ + return new QMockImageCapture(capture); +} + QPlatformMediaCaptureSession *QMockIntegration::createCaptureSession(QMediaRecorder::CaptureMode mode) { Q_UNUSED(mode); diff --git a/tests/auto/unit/mockbackend/qmockintegration_p.h b/tests/auto/unit/mockbackend/qmockintegration_p.h index 3d599d129..af86bf5a8 100644 --- a/tests/auto/unit/mockbackend/qmockintegration_p.h +++ b/tests/auto/unit/mockbackend/qmockintegration_p.h @@ -74,7 +74,7 @@ public: QPlatformMediaPlayer *createPlayer(QMediaPlayer *) override; QPlatformCamera *createCamera(QCamera *) override; QPlatformMediaEncoder *createEncoder(QMediaEncoder *) override { return nullptr; } - QPlatformImageCapture *createImageCapture(QCameraImageCapture *) override { return nullptr; } + QPlatformCameraImageCapture *createImageCapture(QCameraImageCapture *) override; QPlatformMediaCaptureSession *createCaptureSession(QMediaRecorder::CaptureMode mode) override; QPlatformVideoSink *createVideoSink(QVideoSink *) override; diff --git a/tests/auto/unit/mockbackend/qmockmediacapturesession.h b/tests/auto/unit/mockbackend/qmockmediacapturesession.h index 1fb33046c..048698288 100644 --- a/tests/auto/unit/mockbackend/qmockmediacapturesession.h +++ b/tests/auto/unit/mockbackend/qmockmediacapturesession.h @@ -43,7 +43,6 @@ public: : hasControls(true) { mockControl = new QMockMediaEncoder(this); - mockCaptureControl = new QMockImageCapture(this); } ~QMockMediaCaptureSession() { @@ -60,7 +59,11 @@ public: mockCameraControl = control; } - QPlatformCameraImageCapture *imageCapture() override { return hasControls ? mockCaptureControl : nullptr; } + void setImageCapture(QPlatformCameraImageCapture *imageCapture) override + { + mockImageCapture = imageCapture; + } + QPlatformCameraImageCapture *imageCapture() override { return hasControls ? mockImageCapture : nullptr; } QPlatformMediaEncoder *mediaEncoder() override { return hasControls ? mockControl : nullptr; } void setVideoPreview(QVideoSink *) override {} @@ -98,7 +101,7 @@ public: } QMockCamera *mockCameraControl = nullptr; - QMockImageCapture *mockCaptureControl = nullptr; + QPlatformCameraImageCapture *mockImageCapture = nullptr; QMockMediaEncoder *mockControl = nullptr; QAudioDeviceInfo m_audioInput; diff --git a/tests/auto/unit/multimedia/qcameraimagecapture/tst_qcameraimagecapture.cpp b/tests/auto/unit/multimedia/qcameraimagecapture/tst_qcameraimagecapture.cpp index 533ec5208..b4a05bbde 100644 --- a/tests/auto/unit/multimedia/qcameraimagecapture/tst_qcameraimagecapture.cpp +++ b/tests/auto/unit/multimedia/qcameraimagecapture/tst_qcameraimagecapture.cpp @@ -55,7 +55,7 @@ public slots: private slots: void constructor(); - void noBackend(); + void isAvailable(); void deleteMediaSource(); void isReadyForCapture(); void capture(); @@ -100,14 +100,11 @@ void tst_QCameraImageCapture::constructor() QVERIFY(imageCapture.isAvailable() == true); } -void tst_QCameraImageCapture::noBackend() +void tst_QCameraImageCapture::isAvailable() { { QMediaCaptureSession session; - QCamera camera; - mockIntegration->lastCaptureService()->hasControls = false; QCameraImageCapture imageCapture; - session.setCamera(&camera); session.setImageCapture(&imageCapture); QVERIFY(!imageCapture.isAvailable()); @@ -154,6 +151,7 @@ void tst_QCameraImageCapture::isReadyForCapture() QVERIFY(imageCapture.isAvailable() == true); QVERIFY(imageCapture.isReadyForCapture() == false); camera.start(); + QVERIFY(imageCapture.isReadyForCapture() == true); imageCapture.captureToFile(); QTRY_VERIFY(imageCapture.isReadyForCapture()); camera.stop(); @@ -209,7 +207,7 @@ void tst_QCameraImageCapture::errors() QVERIFY(imageCapture.isAvailable() == true); imageCapture.captureToFile(QString::fromLatin1("/dev/null")); - QVERIFY(imageCapture.error() == QCameraImageCapture::NotReadyError); + QCOMPARE(imageCapture.error(), QCameraImageCapture::NotReadyError); QVERIFY(!imageCapture.errorString().isEmpty()); } |