mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-02 04:22:27 +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
|
||||
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_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * param_spec);
|
||||
|
@ -134,7 +135,9 @@ enum
|
|||
#define gst_qt_sink_parent_class parent_class
|
||||
G_DEFINE_TYPE_WITH_CODE (GstQtSink, gst_qt_sink,
|
||||
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_RANK_NONE, GST_TYPE_QT_SINK, qt5_element_init (plugin));
|
||||
|
||||
|
@ -194,6 +197,8 @@ static void
|
|||
gst_qt_sink_init (GstQtSink * qt_sink)
|
||||
{
|
||||
qt_sink->widget = QSharedPointer<QtGLVideoItemInterface>();
|
||||
if (qt_sink->widget)
|
||||
qt_sink->widget->setSink (GST_ELEMENT_CAST (qt_sink));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -205,10 +210,14 @@ gst_qt_sink_set_property (GObject * object, guint prop_id,
|
|||
switch (prop_id) {
|
||||
case PROP_WIDGET: {
|
||||
QtGLVideoItem *qt_item = static_cast<QtGLVideoItem *> (g_value_get_pointer (value));
|
||||
if (qt_item)
|
||||
if (qt_item) {
|
||||
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();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PROP_FORCE_ASPECT_RATIO:
|
||||
|
@ -546,3 +555,33 @@ config_failed:
|
|||
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>
|
||||
|
||||
/**
|
||||
* SECTION:gtkgstglwidget
|
||||
* @short_description: a #GtkGLArea that renders GStreamer video #GstBuffers
|
||||
* @see_also: #GtkGLArea, #GstBuffer
|
||||
* SECTION:QtGLVideoItem
|
||||
* @short_description: a Qt5 QtQuick item that renders GStreamer video #GstBuffers
|
||||
*
|
||||
* #QtGLVideoItem is an #QQuickItem that renders GStreamer video buffers.
|
||||
*/
|
||||
|
@ -66,6 +65,8 @@ struct _QtGLVideoItemPrivate
|
|||
gboolean force_aspect_ratio;
|
||||
gint par_n, par_d;
|
||||
|
||||
GWeakRef sink;
|
||||
|
||||
gint display_width;
|
||||
gint display_height;
|
||||
|
||||
|
@ -129,6 +130,8 @@ QtGLVideoItem::QtGLVideoItem()
|
|||
|
||||
g_mutex_init (&this->priv->lock);
|
||||
|
||||
g_weak_ref_init (&priv->sink, NULL);
|
||||
|
||||
this->priv->display = gst_qt_get_gl_display(TRUE);
|
||||
|
||||
connect(this, SIGNAL(windowChanged(QQuickWindow*)), this,
|
||||
|
@ -136,6 +139,10 @@ QtGLVideoItem::QtGLVideoItem()
|
|||
|
||||
this->proxy = QSharedPointer<QtGLVideoItemInterface>(new QtGLVideoItemInterface(this));
|
||||
|
||||
setFlag(ItemHasContents, true);
|
||||
setAcceptedMouseButtons(Qt::AllButtons);
|
||||
setAcceptHoverEvents(true);
|
||||
|
||||
GST_DEBUG ("%p init Qt Video Item", this);
|
||||
}
|
||||
|
||||
|
@ -171,6 +178,9 @@ QtGLVideoItem::~QtGLVideoItem()
|
|||
gst_buffer_replace (&this->priv->buffer, NULL);
|
||||
|
||||
gst_caps_replace (&this->priv->caps, NULL);
|
||||
|
||||
g_weak_ref_clear (&this->priv->sink);
|
||||
|
||||
g_free (this->priv);
|
||||
this->priv = NULL;
|
||||
}
|
||||
|
@ -305,6 +315,165 @@ QtGLVideoItem::updatePaintNode(QSGNode * oldNode,
|
|||
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
|
||||
_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
|
||||
QtGLVideoItemInterface::setBuffer (GstBuffer * buffer)
|
||||
{
|
||||
|
|
|
@ -42,6 +42,7 @@ public:
|
|||
|
||||
void invalidateRef();
|
||||
|
||||
void setSink (GstElement * sink);
|
||||
void setBuffer (GstBuffer * buffer);
|
||||
gboolean setCaps (GstCaps *caps);
|
||||
gboolean initWinSys ();
|
||||
|
@ -98,6 +99,12 @@ private Q_SLOTS:
|
|||
|
||||
protected:
|
||||
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:
|
||||
|
||||
|
@ -105,8 +112,14 @@ private:
|
|||
void setViewportSize(const QSize &size);
|
||||
void shareContext();
|
||||
|
||||
void fitStreamToAllocatedSize(GstVideoRectangle * result);
|
||||
QPointF mapPointToStreamSize(QPointF);
|
||||
|
||||
void sendMouseEvent(QMouseEvent * event, const gchar * type);
|
||||
QSize m_viewportSize;
|
||||
bool m_openGlContextInitialized;
|
||||
bool m_hovering;
|
||||
uint32_t m_mousePressedButton;
|
||||
|
||||
QSharedPointer<QtGLVideoItemInterface> proxy;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue