[camera] Fix crashes and lockups caused by changing the capture mode during an image capture. Contributes to JB#42936

A camera source may reject changing the mode while it is busy leaving
the the camerabin plugin in a state inconsistent with the gstreamer
pipeline which can lead to attempts to record video in the image
capture mode and ultimately a lockup.

Changing any of the source resolutions requires putting the pipeline
into the the READY state to apply the changes. If this happened during
a capture the state change was deferred and the internal plugin state
was restored to active before the capture finished and the state changes
were treated as a no-op and the resolution change wasn't applied leading
to an attempt to record video with an unsupported resolution set for
the image capture mode. So if a change to a lower state is requested
and the plugin is unable to process it immediately still defer the
change but ensure the pipeline is still dropped to the lowest requested
state before being restored to the current requested state so that
any changes made on state transitions are applied.
This commit is contained in:
Andrew den Exter
2018-11-28 22:14:16 -05:00
parent 1428794048
commit 5deb9dda60
7 changed files with 200 additions and 277 deletions

View File

@@ -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);
}
}
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);
}
}
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);

View File

@@ -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

View File

@@ -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

View File

@@ -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();

View File

@@ -53,7 +53,7 @@ public:
VideoCaptureResources
};
CamerabinResourcePolicy(QObject *parent);
CamerabinResourcePolicy(QObject *parent = nullptr);
~CamerabinResourcePolicy();
ResourceSet resourceSet() const;

View File

@@ -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)
{
if (m_captureMode != 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;
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:
resourceSet = CamerabinResourcePolicy::NoResources;
break;
case QCamera::LoadedState:
resourceSet = CamerabinResourcePolicy::LoadedResources;
break;
case QCamera::ActiveState:
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:
if (m_status == QCamera::ActiveStatus)
stop();
else if (m_status == QCamera::UnloadedStatus)
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 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)
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,24 +916,32 @@ 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_busy) {
m_acceptedState = QCamera::LoadedState;
if (m_viewfinderInterface)
m_viewfinderInterface->stopRenderer();
gst_element_set_state(m_camerabin, GST_STATE_READY);
}
emit statusChanged(m_status);
}
bool CameraBinSession::isBusy() const
{
return m_busy;
@@ -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);
}
}
@@ -1087,6 +1185,9 @@ bool CameraBinSession::processBusMessage(const QGstreamerMessage &message)
default:
break;
}
// Update any chained state changes.
applyState();
}
break;
default:
@@ -1121,6 +1222,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();
@@ -1531,28 +1636,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

View File

@@ -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;