diff --git a/src/plugins/gstreamer/camerabin/camerabincontrol.cpp b/src/plugins/gstreamer/camerabin/camerabincontrol.cpp index a1cd377f..8eb90134 100644 --- a/src/plugins/gstreamer/camerabin/camerabincontrol.cpp +++ b/src/plugins/gstreamer/camerabin/camerabincontrol.cpp @@ -49,30 +49,10 @@ QT_BEGIN_NAMESPACE CameraBinControl::CameraBinControl(CameraBinSession *session) :QCameraControl(session), - m_session(session), - m_state(QCamera::UnloadedState), - m_reloadPending(false) + m_session(session) { connect(m_session, SIGNAL(statusChanged(QCamera::Status)), this, SIGNAL(statusChanged(QCamera::Status))); - - connect(m_session, SIGNAL(viewfinderChanged()), - SLOT(reloadLater())); - connect(m_session, SIGNAL(readyChanged(bool)), - SLOT(reloadLater())); - connect(m_session, SIGNAL(error(int,QString)), - SLOT(handleCameraError(int,QString))); - - m_resourcePolicy = new CamerabinResourcePolicy(this); - connect(m_resourcePolicy, SIGNAL(resourcesGranted()), - SLOT(handleResourcesGranted())); - connect(m_resourcePolicy, SIGNAL(resourcesDenied()), - SLOT(handleResourcesLost())); - connect(m_resourcePolicy, SIGNAL(resourcesLost()), - SLOT(handleResourcesLost())); - - connect(m_session, SIGNAL(busyChanged(bool)), - SLOT(handleBusyChanged(bool))); } CameraBinControl::~CameraBinControl() @@ -86,17 +66,7 @@ QCamera::CaptureModes CameraBinControl::captureMode() const void CameraBinControl::setCaptureMode(QCamera::CaptureModes mode) { - if (m_session->captureMode() != mode) { - m_session->setCaptureMode(mode); - - if (m_state == QCamera::ActiveState) { - m_resourcePolicy->setResourceSet( - captureMode() == QCamera::CaptureStillImage ? - CamerabinResourcePolicy::ImageCaptureResources : - CamerabinResourcePolicy::VideoCaptureResources); - } - emit captureModeChanged(mode); - } + m_session->setCaptureMode(mode); } bool CameraBinControl::isCaptureModeSupported(QCamera::CaptureModes mode) const @@ -109,59 +79,12 @@ void CameraBinControl::setState(QCamera::State state) #ifdef CAMEABIN_DEBUG qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", state); #endif - if (m_state != state) { - m_state = state; - - //special case for stopping the camera while it's busy, - //it should be delayed until the camera is idle - if ((state == QCamera::LoadedState || state == QCamera::UnloadedState) && - m_session->status() == QCamera::ActiveStatus && - m_session->isBusy()) { -#ifdef CAMEABIN_DEBUG - qDebug() << Q_FUNC_INFO << "Camera is busy, QCamera::stop() is delayed"; -#endif - emit stateChanged(m_state); - return; - } - - CamerabinResourcePolicy::ResourceSet resourceSet = CamerabinResourcePolicy::NoResources; - switch (state) { - case QCamera::UnloadedState: - resourceSet = CamerabinResourcePolicy::NoResources; - break; - case QCamera::LoadedState: - resourceSet = CamerabinResourcePolicy::LoadedResources; - break; - case QCamera::ActiveState: - resourceSet = captureMode() == QCamera::CaptureStillImage ? - CamerabinResourcePolicy::ImageCaptureResources : - CamerabinResourcePolicy::VideoCaptureResources; - break; - } - - m_resourcePolicy->setResourceSet(resourceSet); - - if (m_resourcePolicy->isResourcesGranted()) { - //postpone changing to Active if the session is nor ready yet - if (state == QCamera::ActiveState) { - if (m_session->isReady()) { - m_session->setState(state); - } else { -#ifdef CAMEABIN_DEBUG - qDebug() << "Camera session is not ready yet, postpone activating"; -#endif - } - } else - m_session->setState(state); - } - - emit stateChanged(m_state); - } + m_session->setState(state); } QCamera::State CameraBinControl::state() const { - return m_state; + return m_session->requestedState(); } QCamera::Status CameraBinControl::status() const @@ -169,81 +92,6 @@ QCamera::Status CameraBinControl::status() const return m_session->status(); } -void CameraBinControl::reloadLater() -{ -#ifdef CAMEABIN_DEBUG - qDebug() << "CameraBinControl: reload pipeline requested" << ENUM_NAME(QCamera, "State", m_state); -#endif - if (!m_reloadPending && m_state == QCamera::ActiveState) { - m_reloadPending = true; - - if (!m_session->isBusy()) { - m_session->setState(QCamera::LoadedState); - QMetaObject::invokeMethod(this, "delayedReload", Qt::QueuedConnection); - } - } -} - -void CameraBinControl::handleResourcesLost() -{ -#ifdef CAMEABIN_DEBUG - qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", m_state); -#endif - m_session->setState(QCamera::UnloadedState); -} - -void CameraBinControl::handleResourcesGranted() -{ -#ifdef CAMEABIN_DEBUG - qDebug() << Q_FUNC_INFO << ENUM_NAME(QCamera, "State", m_state); -#endif - - //camera will be started soon by delayedReload() - if (m_reloadPending && m_state == QCamera::ActiveState) - return; - - if (m_state == QCamera::ActiveState && m_session->isReady()) - m_session->setState(QCamera::ActiveState); - else if (m_state == QCamera::LoadedState) - m_session->setState(QCamera::LoadedState); -} - -void CameraBinControl::handleBusyChanged(bool busy) -{ - if (!busy && m_session->status() == QCamera::ActiveStatus) { - if (m_state == QCamera::LoadedState) { - //handle delayed stop() because of busy camera - m_resourcePolicy->setResourceSet(CamerabinResourcePolicy::LoadedResources); - m_session->setState(QCamera::LoadedState); - } else if (m_state == QCamera::ActiveState && m_reloadPending) { - //handle delayed reload because of busy camera - m_session->setState(QCamera::LoadedState); - QMetaObject::invokeMethod(this, "delayedReload", Qt::QueuedConnection); - } - } -} - -void CameraBinControl::handleCameraError(int errorCode, const QString &errorString) -{ - emit error(errorCode, errorString); - setState(QCamera::UnloadedState); -} - -void CameraBinControl::delayedReload() -{ -#ifdef CAMEABIN_DEBUG - qDebug() << "CameraBinControl: reload pipeline"; -#endif - if (m_reloadPending) { - m_reloadPending = false; - if (m_state == QCamera::ActiveState && - m_session->isReady() && - m_resourcePolicy->isResourcesGranted()) { - m_session->setState(QCamera::ActiveState); - } - } -} - bool CameraBinControl::canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const { Q_UNUSED(status); diff --git a/src/plugins/gstreamer/camerabin/camerabincontrol.h b/src/plugins/gstreamer/camerabin/camerabincontrol.h index 6a6b47d5..7d3ce24e 100644 --- a/src/plugins/gstreamer/camerabin/camerabincontrol.h +++ b/src/plugins/gstreamer/camerabin/camerabincontrol.h @@ -65,29 +65,13 @@ public: bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const; bool viewfinderColorSpaceConversion() const; - CamerabinResourcePolicy *resourcePolicy() { return m_resourcePolicy; } - public slots: - void reloadLater(); void setViewfinderColorSpaceConversion(bool enabled); -private slots: - void delayedReload(); - - void handleResourcesGranted(); - void handleResourcesLost(); - - void handleBusyChanged(bool); - void handleCameraError(int error, const QString &errorString); - private: void updateSupportedResolutions(const QString &device); CameraBinSession *m_session; - QCamera::State m_state; - CamerabinResourcePolicy *m_resourcePolicy; - - bool m_reloadPending; }; QT_END_NAMESPACE diff --git a/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp b/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp index ccc5d299..348cda98 100644 --- a/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinimagecapture.cpp @@ -64,7 +64,7 @@ CameraBinImageCapture::CameraBinImageCapture(CameraBinSession *session) connect(m_session, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateState())); connect(m_session, SIGNAL(imageExposed(int)), this, SIGNAL(imageExposed(int))); connect(m_session, SIGNAL(imageCaptured(int,QImage)), this, SIGNAL(imageCaptured(int,QImage))); - connect(m_session->cameraControl()->resourcePolicy(), SIGNAL(canCaptureChanged()), this, SLOT(updateState())); + connect(m_session->resourcePolicy(), SIGNAL(canCaptureChanged()), this, SLOT(updateState())); connect(m_session, SIGNAL(handleReadyForCaptureChanged(bool)), this, SLOT(updateState())); m_session->bus()->installMessageFilter(this); @@ -102,7 +102,7 @@ void CameraBinImageCapture::cancelCapture() void CameraBinImageCapture::updateState() { bool ready = m_session->status() == QCamera::ActiveStatus - && m_session->cameraControl()->resourcePolicy()->canCapture() + && m_session->resourcePolicy()->canCapture() && m_session->isReadyForCapture(); if (m_ready != ready) { #ifdef DEBUG_CAPTURE diff --git a/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp b/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp index ad0596a6..944953b0 100644 --- a/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinrecorder.cpp @@ -54,7 +54,7 @@ CameraBinRecorder::CameraBinRecorder(CameraBinSession *session) connect(m_session, SIGNAL(durationChanged(qint64)), SIGNAL(durationChanged(qint64))); connect(m_session, SIGNAL(mutedChanged(bool)), this, SIGNAL(mutedChanged(bool))); - connect(m_session->cameraControl()->resourcePolicy(), SIGNAL(canCaptureChanged()), + connect(m_session->resourcePolicy(), SIGNAL(canCaptureChanged()), this, SLOT(updateStatus())); } @@ -93,7 +93,7 @@ void CameraBinRecorder::updateStatus() if (sessionStatus == QCamera::ActiveStatus && m_session->captureMode().testFlag(QCamera::CaptureVideo)) { - if (!m_session->cameraControl()->resourcePolicy()->canCapture()) { + if (!m_session->resourcePolicy()->canCapture()) { m_status = QMediaRecorder::UnavailableStatus; m_state = QMediaRecorder::StoppedState; m_session->stopVideoRecording(); @@ -109,7 +109,7 @@ void CameraBinRecorder::updateStatus() m_state = QMediaRecorder::StoppedState; m_session->stopVideoRecording(); } - m_status = m_session->pendingState() == QCamera::ActiveState + m_status = m_session->requestedState() == QCamera::ActiveState && m_session->captureMode().testFlag(QCamera::CaptureVideo) ? QMediaRecorder::LoadingStatus : QMediaRecorder::UnloadedStatus; @@ -221,7 +221,7 @@ void CameraBinRecorder::setState(QMediaRecorder::State state) if (m_session->status() != QCamera::ActiveStatus) { emit error(QMediaRecorder::ResourceError, tr("Service has not been started")); - } else if (!m_session->cameraControl()->resourcePolicy()->canCapture()) { + } else if (!m_session->resourcePolicy()->canCapture()) { emit error(QMediaRecorder::ResourceError, tr("Recording permissions are not available")); } else { m_session->recordVideo(); diff --git a/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.h b/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.h index c8e0a2a2..c9703661 100644 --- a/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.h +++ b/src/plugins/gstreamer/camerabin/camerabinresourcepolicy.h @@ -53,7 +53,7 @@ public: VideoCaptureResources }; - CamerabinResourcePolicy(QObject *parent); + CamerabinResourcePolicy(QObject *parent = nullptr); ~CamerabinResourcePolicy(); ResourceSet resourceSet() const; diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.cpp b/src/plugins/gstreamer/camerabin/camerabinsession.cpp index b1a0b76c..5d17e5a7 100644 --- a/src/plugins/gstreamer/camerabin/camerabinsession.cpp +++ b/src/plugins/gstreamer/camerabin/camerabinsession.cpp @@ -113,11 +113,15 @@ CameraBinSession::CameraBinSession(GstElementFactory *sourceFactory, QObject *pa :QObject(parent), m_recordingActive(false), m_status(QCamera::UnloadedStatus), - m_pendingState(QCamera::UnloadedState), + m_requestedState(QCamera::UnloadedState), + m_transientState(QCamera::UnloadedState), + m_acceptedState(QCamera::UnloadedState), m_muted(false), - m_busy(false), m_readyForCapture(false), m_captureMode(QCamera::CaptureStillImage), + m_appliedCaptureMode(QCamera::CaptureStillImage), + m_busy(false), + m_reportedReadyForCapture(false), m_audioInputFactory(0), m_videoInputFactory(0), m_viewfinder(0), @@ -187,6 +191,10 @@ CameraBinSession::CameraBinSession(GstElementFactory *sourceFactory, QObject *pa g_object_set(G_OBJECT(m_camerabin), PREVIEW_CAPS_PROPERTY, previewCaps, NULL); gst_caps_unref(previewCaps); + + connect(&m_resourcePolicy, &CamerabinResourcePolicy::resourcesGranted, this, &CameraBinSession::applyState); + connect(&m_resourcePolicy, &CamerabinResourcePolicy::resourcesDenied, this, &CameraBinSession::resourcesLost); + connect(&m_resourcePolicy, &CamerabinResourcePolicy::resourcesLost, this, &CameraBinSession::resourcesLost); } CameraBinSession::~CameraBinSession() @@ -270,7 +278,7 @@ bool CameraBinSession::setupCameraBin() #endif m_viewfinderHasChanged = false; if (!m_viewfinderElement) { - if (m_pendingState == QCamera::ActiveState) + if (m_requestedState == QCamera::ActiveState) qWarning() << "Starting camera without viewfinder available"; m_viewfinderElement = gst_element_factory_make("fakesink", NULL); } @@ -561,22 +569,25 @@ void CameraBinSession::captureImage(int requestId, const QString &fileName) g_signal_emit_by_name(G_OBJECT(m_camerabin), CAPTURE_START, NULL); m_imageFileName = actualFileName; + + updateCaptureStatus(); +} + +void CameraBinSession::updateCaptureStatus() +{ + if (m_reportedReadyForCapture != m_readyForCapture) { + m_readyForCapture = m_reportedReadyForCapture; + emit handleReadyForCaptureChanged(m_readyForCapture); + } } void CameraBinSession::setCaptureMode(QCamera::CaptureModes mode) { - m_captureMode = mode; - - switch (m_captureMode) { - case QCamera::CaptureStillImage: - g_object_set(m_camerabin, MODE_PROPERTY, CAMERABIN_IMAGE_MODE, NULL); - break; - case QCamera::CaptureVideo: - g_object_set(m_camerabin, MODE_PROPERTY, CAMERABIN_VIDEO_MODE, NULL); - break; + if (m_captureMode != mode) { + m_captureMode = mode; + emit m_cameraControl->captureModeChanged(m_captureMode); } - m_recorderControl->updateStatus(); } QUrl CameraBinSession::outputLocation() const @@ -631,32 +642,29 @@ void CameraBinSession::setViewfinder(QObject *viewfinder) viewfinder = 0; if (m_viewfinder != viewfinder) { - bool oldReady = isReady(); - if (m_viewfinder) { disconnect(m_viewfinder, SIGNAL(sinkChanged()), this, SLOT(handleViewfinderChange())); disconnect(m_viewfinder, SIGNAL(readyChanged(bool)), - this, SIGNAL(readyChanged(bool))); + this, SLOT(applyState())); m_busHelper->removeMessageFilter(m_viewfinder); } m_viewfinder = viewfinder; m_viewfinderHasChanged = true; + m_transientState = QCamera::UnloadedState; if (m_viewfinder) { connect(m_viewfinder, SIGNAL(sinkChanged()), this, SLOT(handleViewfinderChange())); connect(m_viewfinder, SIGNAL(readyChanged(bool)), - this, SIGNAL(readyChanged(bool))); + this, SLOT(applyState())); m_busHelper->installMessageFilter(m_viewfinder); } - emit viewfinderChanged(); - if (oldReady != isReady()) - emit readyChanged(isReady()); + applyState(); } } @@ -687,7 +695,9 @@ void CameraBinSession::handleViewfinderChange() //the viewfinder will be reloaded //shortly when the pipeline is started m_viewfinderHasChanged = true; - emit viewfinderChanged(); + m_transientState = QCamera::UnloadedState; + + applyState(); } void CameraBinSession::setStatus(QCamera::Status status) @@ -697,8 +707,6 @@ void CameraBinSession::setStatus(QCamera::Status status) m_status = status; emit statusChanged(m_status); - - setStateHelper(m_pendingState); } QCamera::Status CameraBinSession::status() const @@ -706,60 +714,122 @@ QCamera::Status CameraBinSession::status() const return m_status; } -QCamera::State CameraBinSession::pendingState() const +QCamera::State CameraBinSession::requestedState() const { - return m_pendingState; + return m_requestedState; } void CameraBinSession::setState(QCamera::State newState) { - if (newState == m_pendingState) + if (newState == m_requestedState) return; - m_pendingState = newState; - emit pendingStateChanged(m_pendingState); + if (newState < m_transientState) { + m_transientState = newState; + } + + m_requestedState = newState; + emit pendingStateChanged(m_requestedState); + m_cameraControl->stateChanged(m_requestedState); #if CAMERABIN_DEBUG qDebug() << Q_FUNC_INFO << newState; #endif - setStateHelper(newState); + applyState(); } -void CameraBinSession::setStateHelper(QCamera::State state) +void CameraBinSession::applyState() { - switch (state) { + CamerabinResourcePolicy::ResourceSet resourceSet = CamerabinResourcePolicy::NoResources; + switch (m_requestedState) { case QCamera::UnloadedState: - unload(); + resourceSet = CamerabinResourcePolicy::NoResources; break; case QCamera::LoadedState: - if (m_status == QCamera::ActiveStatus) - stop(); - else if (m_status == QCamera::UnloadedStatus) - load(); + resourceSet = CamerabinResourcePolicy::LoadedResources; break; case QCamera::ActiveState: - // If the viewfinder changed while in the loaded state, we need to reload the pipeline - if (m_status == QCamera::LoadedStatus && !m_viewfinderHasChanged) - start(); - else if (m_status == QCamera::UnloadedStatus || m_viewfinderHasChanged) - load(); + resourceSet = m_captureMode == QCamera::CaptureStillImage + ? CamerabinResourcePolicy::ImageCaptureResources + : CamerabinResourcePolicy::VideoCaptureResources; + break; } + + if (m_resourcePolicy.resourceSet() != resourceSet) { + m_resourcePolicy.setResourceSet(resourceSet); + } + + if (!m_resourcePolicy.isResourcesGranted()) { + m_transientState = QCamera::UnloadedState; + } + + if (m_transientState < m_acceptedState) { + // Ensure that if something tried to unload or stop the pipeline that it happens and + // settings changes are applied. + switch (m_transientState) { + case QCamera::UnloadedState: + unload(); + break; + case QCamera::LoadedState: + stop(); + break; + case QCamera::ActiveState: + // Unreachable + break; + } + } + + if (m_requestedState > m_acceptedState + && !m_busy + && isReady() + && m_resourcePolicy.isResourcesGranted()) { + m_transientState = m_requestedState; + + switch (m_requestedState) { + case QCamera::UnloadedState: + // Unreachable. + break; + case QCamera::LoadedState: + load(); + break; + case QCamera::ActiveState: + if (m_status == QCamera::UnloadedStatus) { + load(); + } else if (m_status == QCamera::LoadedStatus) { + start(); + } + } + } +} + +void CameraBinSession::resourcesLost() +{ + m_transientState = QCamera::UnloadedState; + + applyState(); } void CameraBinSession::setError(int err, const QString &errorString) { - m_pendingState = QCamera::UnloadedState; - emit error(err, errorString); - setStatus(QCamera::UnloadedStatus); + m_requestedState = QCamera::UnloadedState; + m_transientState = QCamera::UnloadedState; + + emit m_cameraControl->error(err, errorString); + + applyState(); + + emit m_cameraControl->stateChanged(m_requestedState); } void CameraBinSession::load() { - if (m_status != QCamera::UnloadedStatus && !m_viewfinderHasChanged) + if (m_status != QCamera::UnloadedStatus) return; - setStatus(QCamera::LoadingStatus); + m_acceptedState = QCamera::LoadedState; + + m_status = QCamera::LoadingStatus; if (!setupCameraBin()) { setError(QCamera::CameraError, QStringLiteral("No camera source available")); @@ -780,23 +850,34 @@ void CameraBinSession::load() setupCaptureResolution(); gst_element_set_state(m_camerabin, GST_STATE_READY); + + emit statusChanged(m_status); } void CameraBinSession::unload() { - if (m_status == QCamera::UnloadedStatus || m_status == QCamera::UnloadingStatus) + if (m_status == QCamera::UnloadedStatus) return; - // We save the recording state in case something reacted to setStatus() and - // stopped recording. - bool wasRecording = m_recordingActive; - - setStatus(QCamera::UnloadingStatus); + bool changed = m_status != QCamera::UnloadingStatus; + m_status = QCamera::UnloadingStatus; if (m_recordingActive) stopVideoRecording(); - else if (!wasRecording) - handleBusyChanged(false); + + if (!m_busy) { + m_acceptedState = QCamera::UnloadedState; + + if (m_viewfinderInterface) + m_viewfinderInterface->stopRenderer(); + + gst_element_set_state(m_camerabin, GST_STATE_NULL); + + m_status = QCamera::UnloadedStatus; + emit statusChanged(m_status); + } else if (changed) { + emit statusChanged(m_status); + } } void CameraBinSession::start() @@ -804,7 +885,20 @@ void CameraBinSession::start() if (m_status != QCamera::LoadedStatus) return; - setStatus(QCamera::StartingStatus); + m_acceptedState = QCamera::ActiveState; + + m_status = QCamera::StartingStatus; + + m_appliedCaptureMode = m_captureMode; + + switch (m_captureMode) { + case QCamera::CaptureStillImage: + g_object_set(m_camerabin, MODE_PROPERTY, CAMERABIN_IMAGE_MODE, NULL); + break; + case QCamera::CaptureVideo: + g_object_set(m_camerabin, MODE_PROPERTY, CAMERABIN_VIDEO_MODE, NULL); + break; + } m_recorderControl->applySettings(); @@ -822,22 +916,30 @@ void CameraBinSession::start() setupCaptureResolution(); gst_element_set_state(m_camerabin, GST_STATE_PLAYING); + + emit statusChanged(m_status); } void CameraBinSession::stop() { - if (m_status != QCamera::ActiveStatus) + if (m_status != QCamera::ActiveStatus && m_status != QCamera::StartingStatus) return; - setStatus(QCamera::StoppingStatus); + m_status = QCamera::StoppingStatus; if (m_recordingActive) stopVideoRecording(); - if (m_viewfinderInterface) - m_viewfinderInterface->stopRenderer(); + if (!m_busy) { + m_acceptedState = QCamera::LoadedState; - gst_element_set_state(m_camerabin, GST_STATE_READY); + if (m_viewfinderInterface) + m_viewfinderInterface->stopRenderer(); + + gst_element_set_state(m_camerabin, GST_STATE_READY); + } + + emit statusChanged(m_status); } bool CameraBinSession::isBusy() const @@ -859,11 +961,8 @@ void CameraBinSession::updateBusyStatus(GObject *o, GParamSpec *p, gpointer d) g_object_get(o, "idle", &idle, NULL); bool busy = !idle; - if (session->m_busy != busy) { - session->m_busy = busy; - QMetaObject::invokeMethod(session, "handleBusyChanged", - Qt::QueuedConnection, - Q_ARG(bool, busy)); + if (session->m_busy.fetchAndStoreRelaxed(busy) != busy) { + QMetaObject::invokeMethod(session, "applyState", Qt::QueuedConnection); } } @@ -875,10 +974,9 @@ void CameraBinSession::updateReadyForCapture(GObject *o, GParamSpec *p, gpointer CameraBinSession *session = reinterpret_cast(d); gboolean ready = false; g_object_get(o, "ready-for-capture", &ready, NULL); - if (session->m_readyForCapture != ready) { - session->m_readyForCapture = ready; - QMetaObject::invokeMethod(session, "handleReadyForCaptureChanged", - Qt::QueuedConnection, Q_ARG(bool, ready)); + + if (session->m_reportedReadyForCapture.fetchAndStoreRelaxed(ready) != ready) { + QMetaObject::invokeMethod(session, "updateCaptureStatus", Qt::QueuedConnection); } } @@ -1091,6 +1189,9 @@ bool CameraBinSession::processBusMessage(const QGstreamerMessage &message) default: break; } + + // Update any chained state changes. + applyState(); } break; default: @@ -1125,6 +1226,10 @@ QString CameraBinSession::currentContainerFormat() const void CameraBinSession::recordVideo() { + if (!m_reportedReadyForCapture || m_appliedCaptureMode != QCamera::CaptureVideo || m_busy) { + return; + } + QString format = currentContainerFormat(); if (format.isEmpty()) format = m_mediaContainerControl->actualContainerFormat(); @@ -1535,28 +1640,4 @@ void CameraBinSession::elementRemoved(GstBin *, GstElement *element, CameraBinSe session->m_muxer = 0; } -void CameraBinSession::handleBusyChanged(bool busy) -{ - // don't do anything if we are not unloading. - // It could be that the camera is starting again while it is being unloaded - if (m_status != QCamera::UnloadingStatus) { - if (m_busy != busy) - emit busyChanged(m_busy = busy); - return; - } - - // Now we can really stop - if (m_viewfinderInterface) - m_viewfinderInterface->stopRenderer(); - - gst_element_set_state(m_camerabin, GST_STATE_NULL); - - if (m_busy != busy) - emit busyChanged(m_busy = busy); - - m_supportedViewfinderSettings.clear(); - - setStatus(QCamera::UnloadedStatus); -} - QT_END_NAMESPACE diff --git a/src/plugins/gstreamer/camerabin/camerabinsession.h b/src/plugins/gstreamer/camerabin/camerabinsession.h index 3493bd01..5f6a6524 100644 --- a/src/plugins/gstreamer/camerabin/camerabinsession.h +++ b/src/plugins/gstreamer/camerabin/camerabinsession.h @@ -49,6 +49,8 @@ #include #include "qcamera.h" +#include "camerabinresourcepolicy.h" + QT_BEGIN_NAMESPACE class QGstreamerMessage; @@ -118,6 +120,7 @@ public: CameraBinLocks *cameraLocksControl(); #endif + CamerabinResourcePolicy *resourcePolicy() { return &m_resourcePolicy; } CameraBinZoom *cameraZoomControl() const { return m_cameraZoomControl; } CameraBinImageProcessing *imageProcessingControl() const { return m_imageProcessingControl; } CameraBinCaptureDestination *captureDestinationControl() const { return m_captureDestinationControl; } @@ -143,7 +146,7 @@ public: void captureImage(int requestId, const QString &fileName); QCamera::Status status() const; - QCamera::State pendingState() const; + QCamera::State requestedState() const; bool isBusy() const; bool isReadyForCapture() const; @@ -182,7 +185,8 @@ public slots: private slots: void handleViewfinderChange(); void setupCaptureResolution(); - void handleBusyChanged(bool busy); + void updateCaptureStatus(); + void applyState(); private: void load(); @@ -191,7 +195,7 @@ private: void stop(); void setStatus(QCamera::Status status); - void setStateHelper(QCamera::State state); + void resourcesLost(); void setError(int error, const QString &errorString); bool setupCameraBin(); @@ -211,16 +215,21 @@ private: bool m_recordingActive; QString m_captureDevice; QCamera::Status m_status; - QCamera::State m_pendingState; + QCamera::State m_requestedState; // The desired state, transitioning to this may be blocked resource policy or outstanding actions. + QCamera::State m_transientState; // A state that must be passed through. If the pipeline is busy and can't be unloaded immediately it should still go through unloaded when it can to apply settings changes. + QCamera::State m_acceptedState; // The current state or the state the pipeline is actively transitioning to. QString m_inputDevice; bool m_muted; - bool m_busy; bool m_readyForCapture; QMediaStorageLocation m_mediaStorageLocation; QCamera::CaptureModes m_captureMode; + QCamera::CaptureModes m_appliedCaptureMode; QMap m_metaData; + QAtomicInteger m_busy; + QAtomicInteger m_reportedReadyForCapture; + QGstreamerElementFactory *m_audioInputFactory; QGstreamerElementFactory *m_videoInputFactory; QObject *m_viewfinder; @@ -229,6 +238,7 @@ private: QCameraViewfinderSettings m_viewfinderSettings; QCameraViewfinderSettings m_actualViewfinderSettings; + CamerabinResourcePolicy m_resourcePolicy; CameraBinControl *m_cameraControl; CameraBinAudioEncoder *m_audioEncodeControl; CameraBinVideoEncoder *m_videoEncodeControl;