mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-06-05 06:58:56 +00:00
qt: Add navigation events support
Currently handles only mouse events. Part-of: <https://gitlab.freedesktop.org/gstreamer/gst-plugins-good/-/merge_requests/567>
This commit is contained in:
parent
a9bb6d4572
commit
5f1b290fe8
3 changed files with 239 additions and 6 deletions
|
@ -81,6 +81,7 @@
|
||||||
#define GST_CAT_DEFAULT gst_debug_qt_gl_sink
|
#define GST_CAT_DEFAULT gst_debug_qt_gl_sink
|
||||||
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
|
GST_DEBUG_CATEGORY (GST_CAT_DEFAULT);
|
||||||
|
|
||||||
|
static void gst_qt_sink_navigation_interface_init (GstNavigationInterface * iface);
|
||||||
static void gst_qt_sink_finalize (GObject * object);
|
static void gst_qt_sink_finalize (GObject * object);
|
||||||
static void gst_qt_sink_set_property (GObject * object, guint prop_id,
|
static void gst_qt_sink_set_property (GObject * object, guint prop_id,
|
||||||
const GValue * value, GParamSpec * param_spec);
|
const GValue * value, GParamSpec * param_spec);
|
||||||
|
@ -134,7 +135,9 @@ enum
|
||||||
#define gst_qt_sink_parent_class parent_class
|
#define gst_qt_sink_parent_class parent_class
|
||||||
G_DEFINE_TYPE_WITH_CODE (GstQtSink, gst_qt_sink,
|
G_DEFINE_TYPE_WITH_CODE (GstQtSink, gst_qt_sink,
|
||||||
GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
|
GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT,
|
||||||
"qtsink", 0, "Qt Video Sink"));
|
"qtsink", 0, "Qt Video Sink");
|
||||||
|
G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
|
||||||
|
gst_qt_sink_navigation_interface_init));
|
||||||
GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qmlglsink, "qmlglsink",
|
GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (qmlglsink, "qmlglsink",
|
||||||
GST_RANK_NONE, GST_TYPE_QT_SINK, qt5_element_init (plugin));
|
GST_RANK_NONE, GST_TYPE_QT_SINK, qt5_element_init (plugin));
|
||||||
|
|
||||||
|
@ -194,6 +197,8 @@ static void
|
||||||
gst_qt_sink_init (GstQtSink * qt_sink)
|
gst_qt_sink_init (GstQtSink * qt_sink)
|
||||||
{
|
{
|
||||||
qt_sink->widget = QSharedPointer<QtGLVideoItemInterface>();
|
qt_sink->widget = QSharedPointer<QtGLVideoItemInterface>();
|
||||||
|
if (qt_sink->widget)
|
||||||
|
qt_sink->widget->setSink (GST_ELEMENT_CAST (qt_sink));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -205,10 +210,14 @@ gst_qt_sink_set_property (GObject * object, guint prop_id,
|
||||||
switch (prop_id) {
|
switch (prop_id) {
|
||||||
case PROP_WIDGET: {
|
case PROP_WIDGET: {
|
||||||
QtGLVideoItem *qt_item = static_cast<QtGLVideoItem *> (g_value_get_pointer (value));
|
QtGLVideoItem *qt_item = static_cast<QtGLVideoItem *> (g_value_get_pointer (value));
|
||||||
if (qt_item)
|
if (qt_item) {
|
||||||
qt_sink->widget = qt_item->getInterface();
|
qt_sink->widget = qt_item->getInterface();
|
||||||
else
|
if (qt_sink->widget) {
|
||||||
|
qt_sink->widget->setSink (GST_ELEMENT_CAST (qt_sink));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
qt_sink->widget.clear();
|
qt_sink->widget.clear();
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PROP_FORCE_ASPECT_RATIO:
|
case PROP_FORCE_ASPECT_RATIO:
|
||||||
|
@ -546,3 +555,33 @@ config_failed:
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gst_qt_sink_navigation_send_event (GstNavigation * navigation,
|
||||||
|
GstStructure * structure)
|
||||||
|
{
|
||||||
|
GstQtSink *qt_sink = GST_QT_SINK (navigation);
|
||||||
|
GstEvent *event;
|
||||||
|
GstPad *pad;
|
||||||
|
|
||||||
|
event = gst_event_new_navigation (structure);
|
||||||
|
pad = gst_pad_get_peer (GST_VIDEO_SINK_PAD (qt_sink));
|
||||||
|
|
||||||
|
GST_TRACE_OBJECT (qt_sink, "navigation event %" GST_PTR_FORMAT, structure);
|
||||||
|
|
||||||
|
if (GST_IS_PAD (pad) && GST_IS_EVENT (event)) {
|
||||||
|
if (!gst_pad_send_event (pad, gst_event_ref (event))) {
|
||||||
|
/* If upstream didn't handle the event we'll post a message with it
|
||||||
|
* for the application in case it wants to do something with it */
|
||||||
|
gst_element_post_message (GST_ELEMENT_CAST (qt_sink),
|
||||||
|
gst_navigation_message_new_event (GST_OBJECT_CAST (qt_sink), event));
|
||||||
|
}
|
||||||
|
gst_event_unref (event);
|
||||||
|
gst_object_unref (pad);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void gst_qt_sink_navigation_interface_init (GstNavigationInterface * iface)
|
||||||
|
{
|
||||||
|
iface->send_event = gst_qt_sink_navigation_send_event;
|
||||||
|
}
|
||||||
|
|
187
ext/qt/qtitem.cc
187
ext/qt/qtitem.cc
|
@ -37,9 +37,8 @@
|
||||||
#include <QtQuick/QSGSimpleTextureNode>
|
#include <QtQuick/QSGSimpleTextureNode>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* SECTION:gtkgstglwidget
|
* SECTION:QtGLVideoItem
|
||||||
* @short_description: a #GtkGLArea that renders GStreamer video #GstBuffers
|
* @short_description: a Qt5 QtQuick item that renders GStreamer video #GstBuffers
|
||||||
* @see_also: #GtkGLArea, #GstBuffer
|
|
||||||
*
|
*
|
||||||
* #QtGLVideoItem is an #QQuickItem that renders GStreamer video buffers.
|
* #QtGLVideoItem is an #QQuickItem that renders GStreamer video buffers.
|
||||||
*/
|
*/
|
||||||
|
@ -66,6 +65,8 @@ struct _QtGLVideoItemPrivate
|
||||||
gboolean force_aspect_ratio;
|
gboolean force_aspect_ratio;
|
||||||
gint par_n, par_d;
|
gint par_n, par_d;
|
||||||
|
|
||||||
|
GWeakRef sink;
|
||||||
|
|
||||||
gint display_width;
|
gint display_width;
|
||||||
gint display_height;
|
gint display_height;
|
||||||
|
|
||||||
|
@ -129,6 +130,8 @@ QtGLVideoItem::QtGLVideoItem()
|
||||||
|
|
||||||
g_mutex_init (&this->priv->lock);
|
g_mutex_init (&this->priv->lock);
|
||||||
|
|
||||||
|
g_weak_ref_init (&priv->sink, NULL);
|
||||||
|
|
||||||
this->priv->display = gst_qt_get_gl_display(TRUE);
|
this->priv->display = gst_qt_get_gl_display(TRUE);
|
||||||
|
|
||||||
connect(this, SIGNAL(windowChanged(QQuickWindow*)), this,
|
connect(this, SIGNAL(windowChanged(QQuickWindow*)), this,
|
||||||
|
@ -136,6 +139,10 @@ QtGLVideoItem::QtGLVideoItem()
|
||||||
|
|
||||||
this->proxy = QSharedPointer<QtGLVideoItemInterface>(new QtGLVideoItemInterface(this));
|
this->proxy = QSharedPointer<QtGLVideoItemInterface>(new QtGLVideoItemInterface(this));
|
||||||
|
|
||||||
|
setFlag(ItemHasContents, true);
|
||||||
|
setAcceptedMouseButtons(Qt::AllButtons);
|
||||||
|
setAcceptHoverEvents(true);
|
||||||
|
|
||||||
GST_DEBUG ("%p init Qt Video Item", this);
|
GST_DEBUG ("%p init Qt Video Item", this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +178,9 @@ QtGLVideoItem::~QtGLVideoItem()
|
||||||
gst_buffer_replace (&this->priv->buffer, NULL);
|
gst_buffer_replace (&this->priv->buffer, NULL);
|
||||||
|
|
||||||
gst_caps_replace (&this->priv->caps, NULL);
|
gst_caps_replace (&this->priv->caps, NULL);
|
||||||
|
|
||||||
|
g_weak_ref_clear (&this->priv->sink);
|
||||||
|
|
||||||
g_free (this->priv);
|
g_free (this->priv);
|
||||||
this->priv = NULL;
|
this->priv = NULL;
|
||||||
}
|
}
|
||||||
|
@ -305,6 +315,165 @@ QtGLVideoItem::updatePaintNode(QSGNode * oldNode,
|
||||||
return texNode;
|
return texNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* This method has to be invoked with the the priv->lock taken */
|
||||||
|
void
|
||||||
|
QtGLVideoItem::fitStreamToAllocatedSize(GstVideoRectangle * result)
|
||||||
|
{
|
||||||
|
if (this->priv->force_aspect_ratio) {
|
||||||
|
GstVideoRectangle src, dst;
|
||||||
|
|
||||||
|
src.x = 0;
|
||||||
|
src.y = 0;
|
||||||
|
src.w = this->priv->display_width;
|
||||||
|
src.h = this->priv->display_height;
|
||||||
|
|
||||||
|
dst.x = 0;
|
||||||
|
dst.y = 0;
|
||||||
|
dst.w = size().width();
|
||||||
|
dst.h = size().height();
|
||||||
|
|
||||||
|
gst_video_sink_center_rect (src, dst, result, TRUE);
|
||||||
|
} else {
|
||||||
|
result->x = 0;
|
||||||
|
result->y = 0;
|
||||||
|
result->w = size().width();
|
||||||
|
result->h = size().height();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This method has to be invoked with the the priv->lock taken */
|
||||||
|
QPointF
|
||||||
|
QtGLVideoItem::mapPointToStreamSize(QPointF pos)
|
||||||
|
{
|
||||||
|
gdouble stream_width, stream_height;
|
||||||
|
GstVideoRectangle result;
|
||||||
|
double stream_x, stream_y;
|
||||||
|
double x, y;
|
||||||
|
|
||||||
|
fitStreamToAllocatedSize(&result);
|
||||||
|
|
||||||
|
stream_width = (gdouble) GST_VIDEO_INFO_WIDTH (&this->priv->v_info);
|
||||||
|
stream_height = (gdouble) GST_VIDEO_INFO_HEIGHT (&this->priv->v_info);
|
||||||
|
x = pos.x();
|
||||||
|
y = pos.y();
|
||||||
|
|
||||||
|
/* from display coordinates to stream coordinates */
|
||||||
|
if (result.w > 0)
|
||||||
|
stream_x = (x - result.x) / result.w * stream_width;
|
||||||
|
else
|
||||||
|
stream_x = 0.;
|
||||||
|
|
||||||
|
/* clip to stream size */
|
||||||
|
stream_x = CLAMP(stream_x, 0., stream_width);
|
||||||
|
|
||||||
|
/* same for y-axis */
|
||||||
|
if (result.h > 0)
|
||||||
|
stream_y = (y - result.y) / result.h * stream_height;
|
||||||
|
else
|
||||||
|
stream_y = 0.;
|
||||||
|
|
||||||
|
stream_y = CLAMP(stream_y, 0., stream_height);
|
||||||
|
GST_TRACE ("transform %fx%f into %fx%f", x, y, stream_x, stream_y);
|
||||||
|
return QPointF(stream_x, stream_y);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QtGLVideoItem::wheelEvent(QWheelEvent * event)
|
||||||
|
{
|
||||||
|
g_mutex_lock (&this->priv->lock);
|
||||||
|
QPoint delta = event->angleDelta();
|
||||||
|
GstElement *element = GST_ELEMENT_CAST (g_weak_ref_get (&this->priv->sink));
|
||||||
|
|
||||||
|
if (element != NULL) {
|
||||||
|
#if (QT_VERSION >= QT_VERSION_CHECK (5, 14, 0))
|
||||||
|
auto position = event->position();
|
||||||
|
#else
|
||||||
|
auto position = *event;
|
||||||
|
#endif
|
||||||
|
gst_navigation_send_mouse_scroll_event (GST_NAVIGATION (element),
|
||||||
|
position.x(), position.y(), delta.x(), delta.y());
|
||||||
|
g_object_unref (element);
|
||||||
|
}
|
||||||
|
g_mutex_unlock (&this->priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QtGLVideoItem::hoverEnterEvent(QHoverEvent *)
|
||||||
|
{
|
||||||
|
m_hovering = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QtGLVideoItem::hoverLeaveEvent(QHoverEvent *)
|
||||||
|
{
|
||||||
|
m_hovering = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QtGLVideoItem::hoverMoveEvent(QHoverEvent * event)
|
||||||
|
{
|
||||||
|
if (!m_hovering)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int button = !!m_mousePressedButton;
|
||||||
|
g_mutex_lock (&this->priv->lock);
|
||||||
|
if (event->pos() != event->oldPos()) {
|
||||||
|
QPointF pos = mapPointToStreamSize(event->pos());
|
||||||
|
GstElement *element = GST_ELEMENT_CAST (g_weak_ref_get (&this->priv->sink));
|
||||||
|
|
||||||
|
if (element != NULL) {
|
||||||
|
gst_navigation_send_mouse_event (GST_NAVIGATION (element), "mouse-move",
|
||||||
|
button, pos.x(), pos.y());
|
||||||
|
g_object_unref (element);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_mutex_unlock (&this->priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QtGLVideoItem::sendMouseEvent(QMouseEvent * event, const gchar * type)
|
||||||
|
{
|
||||||
|
int button = 0;
|
||||||
|
switch (event->button()) {
|
||||||
|
case Qt::LeftButton:
|
||||||
|
button = 1;
|
||||||
|
break;
|
||||||
|
case Qt::RightButton:
|
||||||
|
button = 2;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
m_mousePressedButton = button;
|
||||||
|
g_mutex_lock (&this->priv->lock);
|
||||||
|
|
||||||
|
QPointF pos = mapPointToStreamSize(event->pos());
|
||||||
|
gchar* event_type = g_strconcat ("mouse-button-", type, NULL);
|
||||||
|
GstElement *element = GST_ELEMENT_CAST (g_weak_ref_get (&this->priv->sink));
|
||||||
|
|
||||||
|
if (element != NULL) {
|
||||||
|
gst_navigation_send_mouse_event (GST_NAVIGATION (element), event_type,
|
||||||
|
button, pos.x(), pos.y());
|
||||||
|
g_object_unref (element);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_free (event_type);
|
||||||
|
g_mutex_unlock (&this->priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QtGLVideoItem::mousePressEvent(QMouseEvent * event)
|
||||||
|
{
|
||||||
|
forceActiveFocus();
|
||||||
|
sendMouseEvent(event, "press");
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QtGLVideoItem::mouseReleaseEvent(QMouseEvent * event)
|
||||||
|
{
|
||||||
|
sendMouseEvent(event, "release");
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_reset (QtGLVideoItem * qt_item)
|
_reset (QtGLVideoItem * qt_item)
|
||||||
{
|
{
|
||||||
|
@ -327,6 +496,18 @@ _reset (QtGLVideoItem * qt_item)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
QtGLVideoItemInterface::setSink (GstElement * sink)
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&lock);
|
||||||
|
if (qt_item == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
g_mutex_lock (&qt_item->priv->lock);
|
||||||
|
g_weak_ref_set (&qt_item->priv->sink, sink);
|
||||||
|
g_mutex_unlock (&qt_item->priv->lock);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
QtGLVideoItemInterface::setBuffer (GstBuffer * buffer)
|
QtGLVideoItemInterface::setBuffer (GstBuffer * buffer)
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,6 +42,7 @@ public:
|
||||||
|
|
||||||
void invalidateRef();
|
void invalidateRef();
|
||||||
|
|
||||||
|
void setSink (GstElement * sink);
|
||||||
void setBuffer (GstBuffer * buffer);
|
void setBuffer (GstBuffer * buffer);
|
||||||
gboolean setCaps (GstCaps *caps);
|
gboolean setCaps (GstCaps *caps);
|
||||||
gboolean initWinSys ();
|
gboolean initWinSys ();
|
||||||
|
@ -98,6 +99,12 @@ private Q_SLOTS:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSGNode * updatePaintNode (QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData);
|
QSGNode * updatePaintNode (QSGNode * oldNode, UpdatePaintNodeData * updatePaintNodeData);
|
||||||
|
void wheelEvent(QWheelEvent *) override;
|
||||||
|
void hoverEnterEvent(QHoverEvent *) override;
|
||||||
|
void hoverLeaveEvent (QHoverEvent *) override;
|
||||||
|
void hoverMoveEvent (QHoverEvent *) override;
|
||||||
|
void mousePressEvent(QMouseEvent*) override;
|
||||||
|
void mouseReleaseEvent(QMouseEvent*) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -105,8 +112,14 @@ private:
|
||||||
void setViewportSize(const QSize &size);
|
void setViewportSize(const QSize &size);
|
||||||
void shareContext();
|
void shareContext();
|
||||||
|
|
||||||
|
void fitStreamToAllocatedSize(GstVideoRectangle * result);
|
||||||
|
QPointF mapPointToStreamSize(QPointF);
|
||||||
|
|
||||||
|
void sendMouseEvent(QMouseEvent * event, const gchar * type);
|
||||||
QSize m_viewportSize;
|
QSize m_viewportSize;
|
||||||
bool m_openGlContextInitialized;
|
bool m_openGlContextInitialized;
|
||||||
|
bool m_hovering;
|
||||||
|
uint32_t m_mousePressedButton;
|
||||||
|
|
||||||
QSharedPointer<QtGLVideoItemInterface> proxy;
|
QSharedPointer<QtGLVideoItemInterface> proxy;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue