[qtmultimedia] don't stop the camera pipeline until it's done recording. Fixes JB#30862

stopping video recording is asynchronous. Aan EOS event gets sent from camera source,
travels across the whole pipeline until it reaches the muxer which then finalizes the
file by writing the mov atom and friends and then pushes the EOS event farther downstream
until it reaches our file writer (multifilesink in our case).

The sink sends an EOS _message_ which is then caught by camerabin and causes it to flip the
idle property from FALSE to TRUE.

Any attempt to stop the pipeline before this property gets flipped will cause corrupted videos.
Probably because the muxer gets shut down before it gets the EOS event so it does not write the
needed header.

When we are unloading camera we stop video recording and immediately switch camera bin to NULL state.
This can lead to corrupted files. A more proper solution would be to postpone this pipeline tear down
until we are idle.
Since an application can attempt to start the pipeline again before it's completely unloaded, I have added
a check to make sure we never tear down the pipeline if we are not in unloaded state. This check is also needed
because we will be notified about the idle property change while we are loading the camera and we should
not unload it when that happens.

This also required removing the pipeline state change to NULL when we are loading camera.
This commit is contained in:
Mohammed Hassan
2015-07-21 20:00:53 +03:00
committed by Martin Jones
parent 770e009cff
commit 6ecbfc3cb1
2 changed files with 32 additions and 15 deletions

View File

@@ -757,8 +757,6 @@ void CameraBinSession::load()
setStatus(QCamera::LoadingStatus);
gst_element_set_state(m_camerabin, GST_STATE_NULL);
if (!setupCameraBin()) {
setError(QCamera::CameraError, QStringLiteral("No camera source available"));
return;
@@ -785,22 +783,16 @@ void CameraBinSession::unload()
if (m_status == QCamera::UnloadedStatus || m_status == QCamera::UnloadingStatus)
return;
// We save the recording state in case something reacted to setStatus() and
// stopped recording.
bool wasRecording = m_recordingActive;
setStatus(QCamera::UnloadingStatus);
if (m_recordingActive)
stopVideoRecording();
if (m_viewfinderInterface)
m_viewfinderInterface->stopRenderer();
gst_element_set_state(m_camerabin, GST_STATE_NULL);
if (m_busy)
emit busyChanged(m_busy = false);
m_supportedViewfinderSettings.clear();
setStatus(QCamera::UnloadedStatus);
else if (!wasRecording)
handleBusyChanged(false);
}
void CameraBinSession::start()
@@ -860,7 +852,7 @@ void CameraBinSession::updateBusyStatus(GObject *o, GParamSpec *p, gpointer d)
if (session->m_busy != busy) {
session->m_busy = busy;
QMetaObject::invokeMethod(session, "busyChanged",
QMetaObject::invokeMethod(session, "handleBusyChanged",
Qt::QueuedConnection,
Q_ARG(bool, busy));
}
@@ -1509,4 +1501,28 @@ 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

@@ -180,6 +180,7 @@ public slots:
private slots:
void handleViewfinderChange();
void setupCaptureResolution();
void handleBusyChanged(bool busy);
private:
void load();