diff options
Diffstat (limited to 'src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp')
-rw-r--r-- | src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp | 546 |
1 files changed, 189 insertions, 357 deletions
diff --git a/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp b/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp index 1a8107889..f9c936ea6 100644 --- a/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp +++ b/src/plugins/multimedia/gstreamer/common/qgstvideorenderersink.cpp @@ -1,64 +1,32 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Jolla Ltd. -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the Qt Toolkit. -** -** $QT_BEGIN_LICENSE:LGPL$ -** Commercial License Usage -** Licensees holding valid commercial Qt licenses may use this file in -** accordance with the commercial license agreement provided with the -** Software or, alternatively, in accordance with the terms contained in -** a written agreement between you and The Qt Company. For licensing terms -** and conditions see https://www.qt.io/terms-conditions. For further -** information use the contact form at https://www.qt.io/contact-us. -** -** GNU Lesser General Public License Usage -** Alternatively, this file may be used under the terms of the GNU Lesser -** General Public License version 3 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL3 included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 3 requirements -** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. -** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 2.0 or (at your option) the GNU General -** Public license version 3 or any later version approved by the KDE Free -** Qt Foundation. The licenses are as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 -** included in the packaging of this file. Please review the following -** information to ensure the GNU General Public License requirements will -** be met: https://www.gnu.org/licenses/gpl-2.0.html and -** https://www.gnu.org/licenses/gpl-3.0.html. -** -** $QT_END_LICENSE$ -** -****************************************************************************/ - -#include <qvideoframe.h> -#include <qvideosink.h> -#include <QDebug> -#include <QMap> -#include <QThread> -#include <QEvent> -#include <QCoreApplication> - -#include <private/qfactoryloader_p.h> -#include "qgstvideobuffer_p.h" -#include "qgstreamervideosink_p.h" +// Copyright (C) 2016 Jolla Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qgstvideorenderersink_p.h" +#include <QtMultimedia/qvideoframe.h> +#include <QtMultimedia/qvideosink.h> +#include <QtCore/private/qfactoryloader_p.h> +#include <QtCore/private/quniquehandle_p.h> +#include <QtCore/qcoreapplication.h> +#include <QtCore/qdebug.h> +#include <QtCore/qdebug.h> +#include <QtCore/qloggingcategory.h> +#include <QtCore/qmap.h> +#include <QtCore/qthread.h> +#include <QtGui/qevent.h> + +#include <common/qgstvideobuffer_p.h> +#include <common/qgstreamervideosink_p.h> +#include <common/qgst_debug_p.h> +#include <common/qgstutils_p.h> + +#include <private/qvideoframe_p.h> + #include <gst/video/video.h> #include <gst/video/gstvideometa.h> -#include <qloggingcategory.h> -#include <qdebug.h> -#include "qgstutils_p.h" -#include <QtGui/private/qrhi_p.h> +#include <rhi/qrhi.h> #if QT_CONFIG(gstreamer_gl) #include <gst/gl/gl.h> #endif // #if QT_CONFIG(gstreamer_gl) @@ -68,29 +36,27 @@ #include <gst/allocators/gstdmabuf.h> #endif -//#define DEBUG_VIDEO_SURFACE_SINK - -Q_LOGGING_CATEGORY(qLcGstVideoRenderer, "qt.multimedia.gstvideorenderer") +static Q_LOGGING_CATEGORY(qLcGstVideoRenderer, "qt.multimedia.gstvideorenderer") QT_BEGIN_NAMESPACE QGstVideoRenderer::QGstVideoRenderer(QGstreamerVideoSink *sink) - : m_sink(sink) + : m_sink(sink), m_surfaceCaps(createSurfaceCaps(sink)) { - createSurfaceCaps(); + QObject::connect( + sink, &QGstreamerVideoSink::aboutToBeDestroyed, this, + [this] { + QMutexLocker locker(&m_sinkMutex); + m_sink = nullptr; + }, + Qt::DirectConnection); } -QGstVideoRenderer::~QGstVideoRenderer() -{ -} +QGstVideoRenderer::~QGstVideoRenderer() = default; -void QGstVideoRenderer::createSurfaceCaps() +QGstCaps QGstVideoRenderer::createSurfaceCaps([[maybe_unused]] QGstreamerVideoSink *sink) { - QRhi *rhi = m_sink->rhi(); - Q_UNUSED(rhi); - - QGstMutableCaps caps; - caps.create(); + QGstCaps caps = QGstCaps::create(); // All the formats that both we and gstreamer support auto formats = QList<QVideoFrameFormat::PixelFormat>() @@ -115,10 +81,11 @@ void QGstVideoRenderer::createSurfaceCaps() << QVideoFrameFormat::Format_Y16 ; #if QT_CONFIG(gstreamer_gl) + QRhi *rhi = sink->rhi(); if (rhi && rhi->backend() == QRhi::OpenGLES2) { caps.addPixelFormats(formats, GST_CAPS_FEATURE_MEMORY_GL_MEMORY); #if QT_CONFIG(linux_dmabuf) - if (m_sink->eglDisplay() && m_sink->eglImageTargetTexture2D()) { + if (sink->eglDisplay() && sink->eglImageTargetTexture2D()) { // We currently do not handle planar DMA buffers, as it's somewhat unclear how to // convert the planar EGLImage into something we can use from OpenGL auto singlePlaneFormats = QList<QVideoFrameFormat::PixelFormat>() @@ -142,105 +109,115 @@ void QGstVideoRenderer::createSurfaceCaps() } #endif caps.addPixelFormats(formats); - - m_surfaceCaps = caps; + return caps; } -QGstMutableCaps QGstVideoRenderer::caps() +const QGstCaps &QGstVideoRenderer::caps() { - QMutexLocker locker(&m_mutex); - return m_surfaceCaps; } -bool QGstVideoRenderer::start(GstCaps *caps) +bool QGstVideoRenderer::start(const QGstCaps& caps) { - qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::start" << QGstCaps(caps).toString(); - QMutexLocker locker(&m_mutex); - - m_frameMirrored = false; - m_frameRotationAngle = QVideoFrame::Rotation0; - - if (m_active) { - m_flush = true; - m_stop = true; - } - - m_startCaps = QGstMutableCaps(caps, QGstMutableCaps::NeedsRef); - - /* - 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. + qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::start" << caps; - The proper solution to this involves controlling gstreamer pipeline from - other thread than video surface. - - Currently start() fails if wait() timed out. - */ - if (!waitForAsyncEvent(&locker, &m_setupCondition, 1000) && !m_startCaps.isNull()) { - qWarning() << "Failed to start video surface due to main thread blocked."; - m_startCaps = {}; + { + m_frameRotationAngle = QtVideo::Rotation::None; + auto optionalFormatAndVideoInfo = caps.formatAndVideoInfo(); + if (optionalFormatAndVideoInfo) { + std::tie(m_format, m_videoInfo) = std::move(*optionalFormatAndVideoInfo); + } else { + m_format = {}; + m_videoInfo = {}; + } + m_memoryFormat = caps.memoryFormat(); } - return m_active; + return true; } void QGstVideoRenderer::stop() { - QMutexLocker locker(&m_mutex); + qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::stop"; - if (!m_active) + QMetaObject::invokeMethod(this, [this] { + m_currentState.buffer = {}; + m_sink->setVideoFrame(QVideoFrame{}); return; - - m_flush = true; - m_stop = true; - - m_startCaps = {}; - - waitForAsyncEvent(&locker, &m_setupCondition, 500); + }); } void QGstVideoRenderer::unlock() { - QMutexLocker locker(&m_mutex); - - m_setupCondition.wakeAll(); - m_renderCondition.wakeAll(); -} - -bool QGstVideoRenderer::proposeAllocation(GstQuery *query) -{ - Q_UNUSED(query); - QMutexLocker locker(&m_mutex); - return m_active; + qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::unlock"; } -void QGstVideoRenderer::flush() +bool QGstVideoRenderer::proposeAllocation(GstQuery *) { - QMutexLocker locker(&m_mutex); - - m_flush = true; - m_renderBuffer = nullptr; - m_renderCondition.wakeAll(); - - notify(); + qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::proposeAllocation"; + return true; } GstFlowReturn QGstVideoRenderer::render(GstBuffer *buffer) { - QMutexLocker locker(&m_mutex); qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::render"; - m_renderReturn = GST_FLOW_OK; - m_renderBuffer = buffer; + GstVideoCropMeta *meta = gst_buffer_get_video_crop_meta(buffer); + if (meta) { + QRect vp(meta->x, meta->y, meta->width, meta->height); + if (m_format.viewport() != vp) { + qCDebug(qLcGstVideoRenderer) + << Q_FUNC_INFO << " Update viewport on Metadata: [" << meta->height << "x" + << meta->width << " | " << meta->x << "x" << meta->y << "]"; + // Update viewport if data is not the same + m_format.setViewport(vp); + } + } + + RenderBufferState state{ + .buffer = QGstBufferHandle{ buffer, QGstBufferHandle::NeedsRef }, + .format = m_format, + .memoryFormat = m_memoryFormat, + .mirrored = m_frameMirrored, + .rotationAngle = m_frameRotationAngle, + }; + + qCDebug(qLcGstVideoRenderer) << " sending video frame"; + + QMetaObject::invokeMethod(this, [this, state = std::move(state)]() mutable { + if (state == m_currentState) { + // same buffer received twice + if (!m_sink || !m_sink->inStoppedState()) + return; + + qCDebug(qLcGstVideoRenderer) << " showing empty video frame"; + m_currentVideoFrame = {}; + m_sink->setVideoFrame(m_currentVideoFrame); + m_currentState = {}; + return; + } - waitForAsyncEvent(&locker, &m_renderCondition, 300); + auto videoBuffer = std::make_unique<QGstVideoBuffer>(state.buffer, m_videoInfo, m_sink, + state.format, state.memoryFormat); + QVideoFrame frame = QVideoFramePrivate::createFrame(std::move(videoBuffer), state.format); + QGstUtils::setFrameTimeStampsFromBuffer(&frame, state.buffer.get()); + frame.setMirrored(state.mirrored); + frame.setRotation(state.rotationAngle); + m_currentVideoFrame = std::move(frame); + m_currentState = std::move(state); + + if (!m_sink) + return; + + if (m_sink->inStoppedState()) { + qCDebug(qLcGstVideoRenderer) << " showing empty video frame"; + m_currentVideoFrame = {}; + } - m_renderBuffer = nullptr; + m_sink->setVideoFrame(m_currentVideoFrame); + }); - return m_renderReturn; + return GST_FLOW_OK; } bool QGstVideoRenderer::query(GstQuery *query) @@ -253,6 +230,10 @@ bool QGstVideoRenderer::query(GstQuery *query) if (strcmp(type, "gst.gl.local_context") != 0) return false; + QMutexLocker locker(&m_sinkMutex); + if (!m_sink) + return false; + auto *gstGlContext = m_sink->gstGlLocalContext(); if (!gstGlContext) return false; @@ -269,15 +250,28 @@ bool QGstVideoRenderer::query(GstQuery *query) void QGstVideoRenderer::gstEvent(GstEvent *event) { - if (GST_EVENT_TYPE(event) != GST_EVENT_TAG) + switch (GST_EVENT_TYPE(event)) { + case GST_EVENT_TAG: + qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::gstEvent: Tag"; + return gstEventHandleTag(event); + case GST_EVENT_EOS: + qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::gstEvent: EOS"; + return gstEventHandleEOS(event); + + default: + qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::gstEvent: unhandled event - " << event; return; + } +} +void QGstVideoRenderer::gstEventHandleTag(GstEvent *event) +{ GstTagList *taglist = nullptr; gst_event_parse_tag(event, &taglist); if (!taglist) return; - gchar *value = nullptr; + QGString value; if (!gst_tag_list_get_string(taglist, GST_TAG_IMAGE_ORIENTATION, &value)) return; @@ -289,157 +283,41 @@ void QGstVideoRenderer::gstEvent(GstEvent *event) bool mirrored = false; int rotationAngle = 0; - if (!strncmp(rotate, value, rotateLen)) { - rotationAngle = atoi(value + rotateLen); - } else if (!strncmp(flipRotate, value, flipRotateLen)) { + if (!strncmp(rotate, value.get(), rotateLen)) { + rotationAngle = atoi(value.get() + rotateLen); + } else if (!strncmp(flipRotate, value.get(), flipRotateLen)) { // To flip by horizontal axis is the same as to mirror by vertical axis // and rotate by 180 degrees. mirrored = true; - rotationAngle = (180 + atoi(value + flipRotateLen)) % 360; + rotationAngle = (180 + atoi(value.get() + flipRotateLen)) % 360; } - QMutexLocker locker(&m_mutex); m_frameMirrored = mirrored; switch (rotationAngle) { - case 0: m_frameRotationAngle = QVideoFrame::Rotation0; break; - case 90: m_frameRotationAngle = QVideoFrame::Rotation90; break; - case 180: m_frameRotationAngle = QVideoFrame::Rotation180; break; - case 270: m_frameRotationAngle = QVideoFrame::Rotation270; break; - default: m_frameRotationAngle = QVideoFrame::Rotation0; - } -} - -bool QGstVideoRenderer::event(QEvent *event) -{ - if (event->type() == QEvent::UpdateRequest) { - QMutexLocker locker(&m_mutex); - - if (m_notified) { - while (handleEvent(&locker)) {} - m_notified = false; - } - return true; - } - - return QObject::event(event); -} - -bool QGstVideoRenderer::handleEvent(QMutexLocker<QMutex> *locker) -{ - if (m_flush) { - m_flush = false; - if (m_active) { - locker->unlock(); - - if (m_sink && !m_flushed) - m_sink->setVideoFrame(QVideoFrame()); - m_flushed = true; - } - } else if (m_stop) { - m_stop = false; - - if (m_active) { - m_active = false; - m_flushed = true; - } - } else if (!m_startCaps.isNull()) { - Q_ASSERT(!m_active); - - auto startCaps = m_startCaps; - m_startCaps = nullptr; - - if (m_sink) { - locker->unlock(); - - m_flushed = true; - m_format = startCaps.formatForCaps(&m_videoInfo); - memoryFormat = startCaps.memoryFormat(); - - locker->relock(); - m_active = m_format.isValid(); - } else if (m_active) { - m_active = false; - m_flushed = true; - } - - } else if (m_renderBuffer) { - GstBuffer *buffer = m_renderBuffer; - m_renderBuffer = nullptr; - m_renderReturn = GST_FLOW_ERROR; - - qCDebug(qLcGstVideoRenderer) << "QGstVideoRenderer::handleEvent(renderBuffer)" << m_active << m_sink; - if (m_active && m_sink) { - gst_buffer_ref(buffer); - - locker->unlock(); - - m_flushed = false; - - auto meta = gst_buffer_get_video_crop_meta (buffer); - if (meta) { - QRect vp(meta->x, meta->y, meta->width, meta->height); - if (m_format.viewport() != vp) { - qCDebug(qLcGstVideoRenderer) << Q_FUNC_INFO << " Update viewport on Metadata: [" << meta->height << "x" << meta->width << " | " << meta->x << "x" << meta->y << "]"; - // Update viewport if data is not the same - m_format.setViewport(vp); - } - } - - if (m_sink->inStoppedState()) { - qCDebug(qLcGstVideoRenderer) << " sending empty video frame"; - m_sink->setVideoFrame(QVideoFrame()); - } else { - QGstVideoBuffer *videoBuffer = new QGstVideoBuffer(buffer, m_videoInfo, m_sink, m_format, memoryFormat); - QVideoFrame frame(videoBuffer, m_format); - QGstUtils::setFrameTimeStamps(&frame, buffer); - frame.setMirrored(m_frameMirrored); - frame.setRotationAngle(m_frameRotationAngle); - - qCDebug(qLcGstVideoRenderer) << " sending video frame"; - m_sink->setVideoFrame(frame); - } - - gst_buffer_unref(buffer); - - locker->relock(); - - m_renderReturn = GST_FLOW_OK; - } - - m_renderCondition.wakeAll(); - } else { - m_setupCondition.wakeAll(); - - return false; - } - return true; -} - -void QGstVideoRenderer::notify() -{ - if (!m_notified) { - m_notified = true; - QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest)); + case 0: + m_frameRotationAngle = QtVideo::Rotation::None; + break; + case 90: + m_frameRotationAngle = QtVideo::Rotation::Clockwise90; + break; + case 180: + m_frameRotationAngle = QtVideo::Rotation::Clockwise180; + break; + case 270: + m_frameRotationAngle = QtVideo::Rotation::Clockwise270; + break; + default: + m_frameRotationAngle = QtVideo::Rotation::None; } } -bool QGstVideoRenderer::waitForAsyncEvent( - QMutexLocker<QMutex> *locker, QWaitCondition *condition, unsigned long time) +void QGstVideoRenderer::gstEventHandleEOS(GstEvent *) { - if (QThread::currentThread() == thread()) { - while (handleEvent(locker)) {} - m_notified = false; - - return true; - } - - notify(); - - return condition->wait(&m_mutex, time); + stop(); } -static GstVideoSinkClass *sink_parent_class; -static thread_local QGstreamerVideoSink *current_sink; +static GstVideoSinkClass *gvrs_sink_parent_class; +static thread_local QGstreamerVideoSink *gvrs_current_sink; #define VO_SINK(s) QGstVideoRendererSink *sink(reinterpret_cast<QGstVideoRendererSink *>(s)) @@ -449,43 +327,32 @@ QGstVideoRendererSink *QGstVideoRendererSink::createSink(QGstreamerVideoSink *si QGstVideoRendererSink *gstSink = reinterpret_cast<QGstVideoRendererSink *>( g_object_new(QGstVideoRendererSink::get_type(), nullptr)); - g_signal_connect(G_OBJECT(gstSink), "notify::show-preroll-frame", G_CALLBACK(handleShowPrerollChange), gstSink); - return gstSink; } void QGstVideoRendererSink::setSink(QGstreamerVideoSink *sink) { - current_sink = sink; - get_type(); + gvrs_current_sink = sink; } GType QGstVideoRendererSink::get_type() { - static GType type = 0; - - if (type == 0) { - static const GTypeInfo info = - { - sizeof(QGstVideoRendererSinkClass), // class_size - base_init, // base_init - nullptr, // base_finalize - class_init, // class_init - nullptr, // class_finalize - nullptr, // class_data - sizeof(QGstVideoRendererSink), // instance_size - 0, // n_preallocs - instance_init, // instance_init - nullptr // value_table - }; - - type = g_type_register_static( - GST_TYPE_VIDEO_SINK, "QGstVideoRendererSink", &info, GTypeFlags(0)); - - // Register the sink type to be used in custom piplines. - // When surface is ready the sink can be used. - gst_element_register(nullptr, "qtvideosink", GST_RANK_PRIMARY, type); - } + static const GTypeInfo info = + { + sizeof(QGstVideoRendererSinkClass), // class_size + base_init, // base_init + nullptr, // base_finalize + class_init, // class_init + nullptr, // class_finalize + nullptr, // class_data + sizeof(QGstVideoRendererSink), // instance_size + 0, // n_preallocs + instance_init, // instance_init + nullptr // value_table + }; + + static const GType type = g_type_register_static(GST_TYPE_VIDEO_SINK, "QGstVideoRendererSink", + &info, GTypeFlags(0)); return type; } @@ -494,7 +361,7 @@ void QGstVideoRendererSink::class_init(gpointer g_class, gpointer class_data) { Q_UNUSED(class_data); - sink_parent_class = reinterpret_cast<GstVideoSinkClass *>(g_type_class_peek_parent(g_class)); + gvrs_sink_parent_class = reinterpret_cast<GstVideoSinkClass *>(g_type_class_peek_parent(g_class)); GstVideoSinkClass *video_sink_class = reinterpret_cast<GstVideoSinkClass *>(g_class); video_sink_class->show_frame = QGstVideoRendererSink::show_frame; @@ -538,11 +405,11 @@ void QGstVideoRendererSink::instance_init(GTypeInstance *instance, gpointer g_cl Q_UNUSED(g_class); VO_SINK(instance); - Q_ASSERT(current_sink); + Q_ASSERT(gvrs_current_sink); - sink->renderer = new QGstVideoRenderer(current_sink); - sink->renderer->moveToThread(current_sink->thread()); - current_sink = nullptr; + sink->renderer = new QGstVideoRenderer(gvrs_current_sink); + sink->renderer->moveToThread(gvrs_current_sink->thread()); + gvrs_current_sink = nullptr; } void QGstVideoRendererSink::finalize(GObject *object) @@ -552,74 +419,39 @@ void QGstVideoRendererSink::finalize(GObject *object) delete sink->renderer; // Chain up - G_OBJECT_CLASS(sink_parent_class)->finalize(object); -} - -void QGstVideoRendererSink::handleShowPrerollChange(GObject *o, GParamSpec *p, gpointer d) -{ - Q_UNUSED(o); - Q_UNUSED(p); - QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(d); - - gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(sink), "show-preroll-frame", &showPrerollFrame, nullptr); - - if (!showPrerollFrame) { - GstState state = GST_STATE_VOID_PENDING; - GstClockTime timeout = 10000000; // 10 ms - gst_element_get_state(GST_ELEMENT(sink), &state, nullptr, timeout); - // show-preroll-frame being set to 'false' while in GST_STATE_PAUSED means - // the QMediaPlayer was stopped from the paused state. - // We need to flush the current frame. - if (state == GST_STATE_PAUSED) - sink->renderer->flush(); - } + G_OBJECT_CLASS(gvrs_sink_parent_class)->finalize(object); } GstStateChangeReturn QGstVideoRendererSink::change_state( GstElement *element, GstStateChange transition) { - QGstVideoRendererSink *sink = reinterpret_cast<QGstVideoRendererSink *>(element); - - gboolean showPrerollFrame = true; // "show-preroll-frame" property is true by default - g_object_get(G_OBJECT(element), "show-preroll-frame", &showPrerollFrame, nullptr); - - // If show-preroll-frame is 'false' when transitioning from GST_STATE_PLAYING to - // GST_STATE_PAUSED, it means the QMediaPlayer was stopped. - // We need to flush the current frame. - if (transition == GST_STATE_CHANGE_PLAYING_TO_PAUSED && !showPrerollFrame) - sink->renderer->flush(); - - return GST_ELEMENT_CLASS(sink_parent_class)->change_state(element, transition); + return GST_ELEMENT_CLASS(gvrs_sink_parent_class)->change_state(element, transition); } GstCaps *QGstVideoRendererSink::get_caps(GstBaseSink *base, GstCaps *filter) { VO_SINK(base); - QGstMutableCaps caps = sink->renderer->caps(); + QGstCaps caps = sink->renderer->caps(); if (filter) - caps = gst_caps_intersect(caps.get(), filter); + caps = QGstCaps(gst_caps_intersect(caps.caps(), filter), QGstCaps::HasRef); - gst_caps_ref(caps.get()); - return caps.get(); + return caps.release(); } -gboolean QGstVideoRendererSink::set_caps(GstBaseSink *base, GstCaps *caps) +gboolean QGstVideoRendererSink::set_caps(GstBaseSink *base, GstCaps *gcaps) { VO_SINK(base); + auto caps = QGstCaps(gcaps, QGstCaps::NeedsRef); - qCDebug(qLcGstVideoRenderer) << "set_caps:" << QGstCaps(caps).toString(); + qCDebug(qLcGstVideoRenderer) << "set_caps:" << caps; - if (!caps) { + if (caps.isNull()) { sink->renderer->stop(); - return TRUE; - } else if (sink->renderer->start(caps)) { - return TRUE; - } else { - return FALSE; } + + return sink->renderer->start(caps); } gboolean QGstVideoRendererSink::propose_allocation(GstBaseSink *base, GstQuery *query) @@ -654,14 +486,14 @@ gboolean QGstVideoRendererSink::query(GstBaseSink *base, GstQuery *query) if (sink->renderer->query(query)) return TRUE; - return GST_BASE_SINK_CLASS(sink_parent_class)->query(base, query); + return GST_BASE_SINK_CLASS(gvrs_sink_parent_class)->query(base, query); } gboolean QGstVideoRendererSink::event(GstBaseSink *base, GstEvent * event) { VO_SINK(base); sink->renderer->gstEvent(event); - return GST_BASE_SINK_CLASS(sink_parent_class)->event(base, event); + return GST_BASE_SINK_CLASS(gvrs_sink_parent_class)->event(base, event); } QT_END_NAMESPACE |