Gst backend: Fixed deadlock when pipeline is stopped during prerolling.

Waiting for start() to be invoked in the main thread may block
if gstreamer blocks the main thread until this call is finished.
This situation is rare and usually caused by setState(Null)
while pipeline is being prerolled.

The proper solution to this involves controlling gstreamer pipeline
from other thread than video surface.

Currently start() fails if wait() timed out.

Task-number: QTMOBILITY-1663
Reviewed-by: Michael Goddard
Change-Id: Ib95e589a814e53efb9b4c454ef9f233658ff8c6a
(cherry picked from commit ac9762e2dbc06d696c6c74825ee22ac1fc176d9c)
Reviewed-on: http://codereview.qt.nokia.com/2073
Reviewed-by: Qt Sanity Bot <qt_sanity_bot@ovi.com>
Reviewed-by: Michael Goddard <michael.goddard@nokia.com>
This commit is contained in:
Dmytro Poplavskiy
2011-07-20 10:45:06 +10:00
committed by Qt by Nokia
parent e47fa8b5a5
commit e45902822c
2 changed files with 27 additions and 7 deletions

View File

@@ -66,6 +66,7 @@ QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(
, m_pool(0)
, m_renderReturn(GST_FLOW_ERROR)
, m_bytesPerLine(0)
, m_startCanceled(false)
{
if (m_surface) {
#if defined(Q_WS_X11) && !defined(QT_NO_XVIDEO)
@@ -114,9 +115,25 @@ bool QVideoSurfaceGstDelegate::start(const QVideoSurfaceFormat &format, int byte
if (QThread::currentThread() == thread()) {
m_started = !m_surface.isNull() ? m_surface->start(m_format) : false;
} else {
m_started = false;
m_startCanceled = false;
QMetaObject::invokeMethod(this, "queuedStart", Qt::QueuedConnection);
m_setupCondition.wait(&m_mutex);
/*
Waiting for start() to be invoked in the main thread may block
if gstreamer blocks the main thread until this call is finished.
This situation is rare and usually caused by setState(Null)
while pipeline is being prerolled.
The proper solution to this involves controlling gstreamer pipeline from
other thread than video surface.
Currently start() fails if wait() timed out.
*/
if (!m_setupCondition.wait(&m_mutex, 1000)) {
qWarning() << "Failed to start video surface due to main thread blocked.";
m_startCanceled = true;
}
}
m_format = m_surface->surfaceFormat();
@@ -137,7 +154,9 @@ void QVideoSurfaceGstDelegate::stop()
} else {
QMetaObject::invokeMethod(this, "queuedStop", Qt::QueuedConnection);
m_setupCondition.wait(&m_mutex);
// Waiting for stop() to be invoked in the main thread may block
// if gstreamer blocks the main thread until this call is finished.
m_setupCondition.wait(&m_mutex, 500);
}
m_started = false;
@@ -195,12 +214,12 @@ GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer)
void QVideoSurfaceGstDelegate::queuedStart()
{
if (!m_startCanceled) {
QMutexLocker locker(&m_mutex);
m_started = m_surface->start(m_format);
m_setupCondition.wakeAll();
}
}
void QVideoSurfaceGstDelegate::queuedStop()
{

View File

@@ -109,6 +109,7 @@ private:
GstFlowReturn m_renderReturn;
int m_bytesPerLine;
bool m_started;
bool m_startCanceled;
};
class QVideoSurfaceGstSink