Merge branch 'jb42936' into 'mer-5.6'
Fix crashes and lockups caused by changing the capture mode during an image capture See merge request mer-core/qtmultimedia!20
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -53,7 +53,7 @@ public:
|
||||
VideoCaptureResources
|
||||
};
|
||||
|
||||
CamerabinResourcePolicy(QObject *parent);
|
||||
CamerabinResourcePolicy(QObject *parent = nullptr);
|
||||
~CamerabinResourcePolicy();
|
||||
|
||||
ResourceSet resourceSet() const;
|
||||
|
||||
@@ -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<CameraBinSession *>(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
|
||||
|
||||
@@ -49,6 +49,8 @@
|
||||
#include <private/qmediastoragelocation_p.h>
|
||||
#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<QByteArray, QVariant> m_metaData;
|
||||
|
||||
QAtomicInteger<bool> m_busy;
|
||||
QAtomicInteger<bool> 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;
|
||||
|
||||
Reference in New Issue
Block a user