GStreamer 1.0: fix some problems with QGstVideoRendererSink.
- Correctly free resources on deletion.
- Correctly stop the sink. We were stopping only when null caps
were passed to set_caps() but that doesn't seem to always happen.
Implement GstBaseSink.stop() which is always and consistently
called by GStreamer.
- Remove pre-roll support (as done previously for 0.10, see
commit 3b20608f).
Change-Id: I4c5808938f244f4f8a35e121a3a4a862588b752d
Reviewed-by: Christian Stromme <christian.stromme@theqtcompany.com>
This commit is contained in:
@@ -114,10 +114,9 @@ QVideoSurfaceGstDelegate::QVideoSurfaceGstDelegate(QAbstractVideoSurface *surfac
|
|||||||
, m_activeRenderer(0)
|
, m_activeRenderer(0)
|
||||||
, m_surfaceCaps(0)
|
, m_surfaceCaps(0)
|
||||||
, m_startCaps(0)
|
, m_startCaps(0)
|
||||||
, m_lastBuffer(0)
|
, m_renderBuffer(0)
|
||||||
, m_notified(false)
|
, m_notified(false)
|
||||||
, m_stop(false)
|
, m_stop(false)
|
||||||
, m_render(false)
|
|
||||||
, m_flush(false)
|
, m_flush(false)
|
||||||
{
|
{
|
||||||
foreach (QObject *instance, rendererLoader()->instances(QGstVideoRendererPluginKey)) {
|
foreach (QObject *instance, rendererLoader()->instances(QGstVideoRendererPluginKey)) {
|
||||||
@@ -137,6 +136,8 @@ QVideoSurfaceGstDelegate::~QVideoSurfaceGstDelegate()
|
|||||||
|
|
||||||
if (m_surfaceCaps)
|
if (m_surfaceCaps)
|
||||||
gst_caps_unref(m_surfaceCaps);
|
gst_caps_unref(m_surfaceCaps);
|
||||||
|
if (m_startCaps)
|
||||||
|
gst_caps_unref(m_startCaps);
|
||||||
}
|
}
|
||||||
|
|
||||||
GstCaps *QVideoSurfaceGstDelegate::caps()
|
GstCaps *QVideoSurfaceGstDelegate::caps()
|
||||||
@@ -157,13 +158,6 @@ bool QVideoSurfaceGstDelegate::start(GstCaps *caps)
|
|||||||
m_stop = true;
|
m_stop = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_render = false;
|
|
||||||
|
|
||||||
if (m_lastBuffer) {
|
|
||||||
gst_buffer_unref(m_lastBuffer);
|
|
||||||
m_lastBuffer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_startCaps)
|
if (m_startCaps)
|
||||||
gst_caps_unref(m_startCaps);
|
gst_caps_unref(m_startCaps);
|
||||||
m_startCaps = caps;
|
m_startCaps = caps;
|
||||||
@@ -204,11 +198,6 @@ void QVideoSurfaceGstDelegate::stop()
|
|||||||
m_startCaps = 0;
|
m_startCaps = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_lastBuffer) {
|
|
||||||
gst_buffer_unref(m_lastBuffer);
|
|
||||||
m_lastBuffer = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
waitForAsyncEvent(&locker, &m_setupCondition, 500);
|
waitForAsyncEvent(&locker, &m_setupCondition, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,68 +214,19 @@ bool QVideoSurfaceGstDelegate::proposeAllocation(GstQuery *query)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void QVideoSurfaceGstDelegate::flush()
|
GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer)
|
||||||
{
|
{
|
||||||
QMutexLocker locker(&m_mutex);
|
QMutexLocker locker(&m_mutex);
|
||||||
|
|
||||||
m_flush = true;
|
m_renderBuffer = buffer;
|
||||||
m_render = false;
|
|
||||||
|
|
||||||
if (m_lastBuffer) {
|
GstFlowReturn flowReturn = waitForAsyncEvent(&locker, &m_renderCondition, 300)
|
||||||
gst_buffer_unref(m_lastBuffer);
|
? m_renderReturn
|
||||||
m_lastBuffer = 0;
|
: GST_FLOW_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
notify();
|
m_renderBuffer = 0;
|
||||||
}
|
|
||||||
|
|
||||||
GstFlowReturn QVideoSurfaceGstDelegate::render(GstBuffer *buffer, bool show)
|
return flowReturn;
|
||||||
{
|
|
||||||
QMutexLocker locker(&m_mutex);
|
|
||||||
|
|
||||||
if (m_lastBuffer)
|
|
||||||
gst_buffer_unref(m_lastBuffer);
|
|
||||||
m_lastBuffer = buffer;
|
|
||||||
gst_buffer_ref(m_lastBuffer);
|
|
||||||
|
|
||||||
if (show) {
|
|
||||||
m_render = true;
|
|
||||||
|
|
||||||
return waitForAsyncEvent(&locker, &m_renderCondition, 300)
|
|
||||||
? m_renderReturn
|
|
||||||
: GST_FLOW_ERROR;
|
|
||||||
} else {
|
|
||||||
return GST_FLOW_OK;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void QVideoSurfaceGstDelegate::handleShowPrerollChange(GObject *object, GParamSpec *, gpointer d)
|
|
||||||
{
|
|
||||||
QVideoSurfaceGstDelegate * const delegate = static_cast<QVideoSurfaceGstDelegate *>(d);
|
|
||||||
|
|
||||||
gboolean showPreroll = true; // "show-preroll-frame" property is true by default
|
|
||||||
g_object_get(object, "show-preroll-frame", &showPreroll, NULL);
|
|
||||||
|
|
||||||
GstState state = GST_STATE_NULL;
|
|
||||||
GstState pendingState = GST_STATE_NULL;
|
|
||||||
gst_element_get_state(GST_ELEMENT(object), &state, &pendingState, 0);
|
|
||||||
|
|
||||||
const bool paused
|
|
||||||
= (pendingState == GST_STATE_VOID_PENDING && state == GST_STATE_PAUSED)
|
|
||||||
|| pendingState == GST_STATE_PAUSED;
|
|
||||||
|
|
||||||
if (paused) {
|
|
||||||
QMutexLocker locker(&delegate->m_mutex);
|
|
||||||
|
|
||||||
if (!showPreroll && delegate->m_lastBuffer) {
|
|
||||||
delegate->m_render = false;
|
|
||||||
delegate->m_flush = true;
|
|
||||||
delegate->notify();
|
|
||||||
} else if (delegate->m_lastBuffer) {
|
|
||||||
delegate->m_render = true;
|
|
||||||
delegate->notify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool QVideoSurfaceGstDelegate::event(QEvent *event)
|
bool QVideoSurfaceGstDelegate::event(QEvent *event)
|
||||||
@@ -350,11 +290,9 @@ bool QVideoSurfaceGstDelegate::handleEvent(QMutexLocker *locker)
|
|||||||
}
|
}
|
||||||
|
|
||||||
gst_caps_unref(startCaps);
|
gst_caps_unref(startCaps);
|
||||||
} else if (m_render) {
|
} else if (m_renderBuffer) {
|
||||||
m_render = false;
|
if (m_activeRenderer && m_surface) {
|
||||||
|
GstBuffer *buffer = m_renderBuffer;
|
||||||
if (m_activeRenderer && m_surface && m_lastBuffer) {
|
|
||||||
GstBuffer *buffer = m_lastBuffer;
|
|
||||||
gst_buffer_ref(buffer);
|
gst_buffer_ref(buffer);
|
||||||
|
|
||||||
locker->unlock();
|
locker->unlock();
|
||||||
@@ -442,12 +380,6 @@ QGstVideoRendererSink *QGstVideoRendererSink::createSink(QAbstractVideoSurface *
|
|||||||
|
|
||||||
sink->delegate = new QVideoSurfaceGstDelegate(surface);
|
sink->delegate = new QVideoSurfaceGstDelegate(surface);
|
||||||
|
|
||||||
g_signal_connect(
|
|
||||||
G_OBJECT(sink),
|
|
||||||
"notify::show-preroll-frame",
|
|
||||||
G_CALLBACK(QVideoSurfaceGstDelegate::handleShowPrerollChange),
|
|
||||||
sink->delegate);
|
|
||||||
|
|
||||||
return sink;
|
return sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,7 +419,7 @@ void QGstVideoRendererSink::class_init(gpointer g_class, gpointer class_data)
|
|||||||
base_sink_class->get_caps = QGstVideoRendererSink::get_caps;
|
base_sink_class->get_caps = QGstVideoRendererSink::get_caps;
|
||||||
base_sink_class->set_caps = QGstVideoRendererSink::set_caps;
|
base_sink_class->set_caps = QGstVideoRendererSink::set_caps;
|
||||||
base_sink_class->propose_allocation = QGstVideoRendererSink::propose_allocation;
|
base_sink_class->propose_allocation = QGstVideoRendererSink::propose_allocation;
|
||||||
base_sink_class->preroll = QGstVideoRendererSink::preroll;
|
base_sink_class->stop = QGstVideoRendererSink::stop;
|
||||||
base_sink_class->render = QGstVideoRendererSink::render;
|
base_sink_class->render = QGstVideoRendererSink::render;
|
||||||
|
|
||||||
GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class);
|
GstElementClass *element_class = reinterpret_cast<GstElementClass *>(g_class);
|
||||||
@@ -578,20 +510,17 @@ gboolean QGstVideoRendererSink::propose_allocation(GstBaseSink *base, GstQuery *
|
|||||||
return sink->delegate->proposeAllocation(query);
|
return sink->delegate->proposeAllocation(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
GstFlowReturn QGstVideoRendererSink::preroll(GstBaseSink *base, GstBuffer *buffer)
|
gboolean QGstVideoRendererSink::stop(GstBaseSink *base)
|
||||||
{
|
{
|
||||||
VO_SINK(base);
|
VO_SINK(base);
|
||||||
|
sink->delegate->stop();
|
||||||
gboolean showPreroll = true; // "show-preroll-frame" property is true by default
|
return TRUE;
|
||||||
g_object_get(G_OBJECT(base), "show-preroll-frame", &showPreroll, NULL);
|
|
||||||
|
|
||||||
return sink->delegate->render(buffer, showPreroll); // display frame
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GstFlowReturn QGstVideoRendererSink::render(GstBaseSink *base, GstBuffer *buffer)
|
GstFlowReturn QGstVideoRendererSink::render(GstBaseSink *base, GstBuffer *buffer)
|
||||||
{
|
{
|
||||||
VO_SINK(base);
|
VO_SINK(base);
|
||||||
return sink->delegate->render(buffer, true);
|
return sink->delegate->render(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|||||||
@@ -98,14 +98,10 @@ public:
|
|||||||
void stop();
|
void stop();
|
||||||
bool proposeAllocation(GstQuery *query);
|
bool proposeAllocation(GstQuery *query);
|
||||||
|
|
||||||
void flush();
|
GstFlowReturn render(GstBuffer *buffer);
|
||||||
|
|
||||||
GstFlowReturn render(GstBuffer *buffer, bool show);
|
|
||||||
|
|
||||||
bool event(QEvent *event);
|
bool event(QEvent *event);
|
||||||
|
|
||||||
static void handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
bool handleEvent(QMutexLocker *locker);
|
bool handleEvent(QMutexLocker *locker);
|
||||||
void updateSupportedFormats();
|
void updateSupportedFormats();
|
||||||
@@ -126,11 +122,10 @@ private:
|
|||||||
|
|
||||||
GstCaps *m_surfaceCaps;
|
GstCaps *m_surfaceCaps;
|
||||||
GstCaps *m_startCaps;
|
GstCaps *m_startCaps;
|
||||||
GstBuffer *m_lastBuffer;
|
GstBuffer *m_renderBuffer;
|
||||||
|
|
||||||
bool m_notified;
|
bool m_notified;
|
||||||
bool m_stop;
|
bool m_stop;
|
||||||
bool m_render;
|
|
||||||
bool m_flush;
|
bool m_flush;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -156,7 +151,8 @@ private:
|
|||||||
|
|
||||||
static gboolean propose_allocation(GstBaseSink *sink, GstQuery *query);
|
static gboolean propose_allocation(GstBaseSink *sink, GstQuery *query);
|
||||||
|
|
||||||
static GstFlowReturn preroll(GstBaseSink *sink, GstBuffer *buffer);
|
static gboolean stop(GstBaseSink *sink);
|
||||||
|
|
||||||
static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer);
|
static GstFlowReturn render(GstBaseSink *sink, GstBuffer *buffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
Reference in New Issue
Block a user