• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * GStreamer
3  * Copyright (C) 2015 Matthew Waters <matthew@centricular.com>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20 
21 #ifdef HAVE_CONFIG_H
22 #include "config.h"
23 #endif
24 
25 #include <stdio.h>
26 
27 #include <gst/video/video.h>
28 #include "qtitem.h"
29 #include "gstqsgtexture.h"
30 #include "gstqtglutility.h"
31 
32 #include <QtCore/QMutexLocker>
33 #include <QtCore/QPointer>
34 #include <QtGui/QGuiApplication>
35 #include <QtQuick/QQuickWindow>
36 #include <QtQuick/QSGSimpleTextureNode>
37 
38 /**
39  * SECTION:QtGLVideoItem
40  * @short_description: a Qt5 QtQuick item that renders GStreamer video #GstBuffers
41  *
42  * #QtGLVideoItem is an #QQuickItem that renders GStreamer video buffers.
43  */
44 
45 #define GST_CAT_DEFAULT qt_item_debug
46 GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
47 
48 #define DEFAULT_FORCE_ASPECT_RATIO  TRUE
49 #define DEFAULT_PAR_N               0
50 #define DEFAULT_PAR_D               1
51 
52 enum
53 {
54   PROP_0,
55   PROP_FORCE_ASPECT_RATIO,
56   PROP_PIXEL_ASPECT_RATIO,
57 };
58 
59 struct _QtGLVideoItemPrivate
60 {
61   GMutex lock;
62 
63   /* properties */
64   gboolean force_aspect_ratio;
65   gint par_n, par_d;
66 
67   GWeakRef sink;
68 
69   gint display_width;
70   gint display_height;
71 
72   GstBuffer *buffer;
73   GstCaps *new_caps;
74   GstCaps *caps;
75   GstVideoInfo new_v_info;
76   GstVideoInfo v_info;
77 
78   gboolean initted;
79   GstGLDisplay *display;
80   QOpenGLContext *qt_context;
81   GstGLContext *other_context;
82   GstGLContext *context;
83 
84   /* buffers with textures that were bound by QML */
85   GQueue bound_buffers;
86   /* buffers that were previously bound but in the meantime a new one was
87    * bound so this one is most likely not used anymore
88    * FIXME: Ideally we would use fences for this but there seems to be no
89    * way to reliably "try wait" on a fence */
90   GQueue potentially_unbound_buffers;
91 };
92 
QtGLVideoItem()93 QtGLVideoItem::QtGLVideoItem()
94 {
95   static gsize _debug;
96 
97   if (g_once_init_enter (&_debug)) {
98     GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "qtglwidget", 0, "Qt GL Widget");
99     g_once_init_leave (&_debug, 1);
100   }
101 
102   this->setFlag (QQuickItem::ItemHasContents, true);
103 
104   this->priv = g_new0 (QtGLVideoItemPrivate, 1);
105 
106   this->priv->force_aspect_ratio = DEFAULT_FORCE_ASPECT_RATIO;
107   this->priv->par_n = DEFAULT_PAR_N;
108   this->priv->par_d = DEFAULT_PAR_D;
109 
110   this->priv->initted = FALSE;
111 
112   g_mutex_init (&this->priv->lock);
113 
114   g_weak_ref_init (&priv->sink, NULL);
115 
116   this->priv->display = gst_qt_get_gl_display(TRUE);
117 
118   connect(this, SIGNAL(windowChanged(QQuickWindow*)), this,
119           SLOT(handleWindowChanged(QQuickWindow*)));
120 
121   this->proxy = QSharedPointer<QtGLVideoItemInterface>(new QtGLVideoItemInterface(this));
122 
123   setFlag(ItemHasContents, true);
124   setAcceptedMouseButtons(Qt::AllButtons);
125   setAcceptHoverEvents(true);
126 
127   GST_DEBUG ("%p init Qt Video Item", this);
128 }
129 
~QtGLVideoItem()130 QtGLVideoItem::~QtGLVideoItem()
131 {
132   GstBuffer *tmp_buffer;
133 
134   /* Before destroying the priv info, make sure
135    * no qmlglsink's will call in again, and that
136    * any ongoing calls are done by invalidating the proxy
137    * pointer */
138   GST_INFO ("%p Destroying QtGLVideoItem and invalidating the proxy %p", this, proxy.data());
139   proxy->invalidateRef();
140   proxy.clear();
141 
142   g_mutex_clear (&this->priv->lock);
143   if (this->priv->context)
144     gst_object_unref(this->priv->context);
145   if (this->priv->other_context)
146     gst_object_unref(this->priv->other_context);
147   if (this->priv->display)
148     gst_object_unref(this->priv->display);
149 
150   while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->potentially_unbound_buffers))) {
151     GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer);
152     gst_buffer_unref (tmp_buffer);
153   }
154   while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->bound_buffers))) {
155     GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer);
156     gst_buffer_unref (tmp_buffer);
157   }
158 
159   gst_buffer_replace (&this->priv->buffer, NULL);
160 
161   gst_caps_replace (&this->priv->caps, NULL);
162   gst_caps_replace (&this->priv->new_caps, NULL);
163 
164   g_weak_ref_clear (&this->priv->sink);
165 
166   g_free (this->priv);
167   this->priv = NULL;
168 }
169 
170 void
setDAR(gint num,gint den)171 QtGLVideoItem::setDAR(gint num, gint den)
172 {
173   this->priv->par_n = num;
174   this->priv->par_d = den;
175 }
176 
177 void
getDAR(gint * num,gint * den)178 QtGLVideoItem::getDAR(gint * num, gint * den)
179 {
180   if (num)
181     *num = this->priv->par_n;
182   if (den)
183     *den = this->priv->par_d;
184 }
185 
186 void
setForceAspectRatio(bool force_aspect_ratio)187 QtGLVideoItem::setForceAspectRatio(bool force_aspect_ratio)
188 {
189   this->priv->force_aspect_ratio = !!force_aspect_ratio;
190 
191   emit forceAspectRatioChanged(force_aspect_ratio);
192 }
193 
194 bool
getForceAspectRatio()195 QtGLVideoItem::getForceAspectRatio()
196 {
197   return this->priv->force_aspect_ratio;
198 }
199 
200 bool
itemInitialized()201 QtGLVideoItem::itemInitialized()
202 {
203   return this->priv->initted;
204 }
205 
206 static gboolean
_calculate_par(QtGLVideoItem * widget,GstVideoInfo * info)207 _calculate_par (QtGLVideoItem * widget, GstVideoInfo * info)
208 {
209   gboolean ok;
210   gint width, height;
211   gint par_n, par_d;
212   gint display_par_n, display_par_d;
213   guint display_ratio_num, display_ratio_den;
214 
215   width = GST_VIDEO_INFO_WIDTH (info);
216   height = GST_VIDEO_INFO_HEIGHT (info);
217 
218   par_n = GST_VIDEO_INFO_PAR_N (info);
219   par_d = GST_VIDEO_INFO_PAR_D (info);
220 
221   if (!par_n)
222     par_n = 1;
223 
224   /* get display's PAR */
225   if (widget->priv->par_n != 0 && widget->priv->par_d != 0) {
226     display_par_n = widget->priv->par_n;
227     display_par_d = widget->priv->par_d;
228   } else {
229     display_par_n = 1;
230     display_par_d = 1;
231   }
232 
233   ok = gst_video_calculate_display_ratio (&display_ratio_num,
234       &display_ratio_den, width, height, par_n, par_d, display_par_n,
235       display_par_d);
236 
237   if (!ok)
238     return FALSE;
239 
240   widget->setImplicitWidth (width);
241   widget->setImplicitHeight (height);
242 
243   GST_LOG ("%p PAR: %u/%u DAR:%u/%u", widget, par_n, par_d, display_par_n,
244       display_par_d);
245 
246   if (height % display_ratio_den == 0) {
247     GST_DEBUG ("%p keeping video height", widget);
248     widget->priv->display_width = (guint)
249         gst_util_uint64_scale_int (height, display_ratio_num,
250         display_ratio_den);
251     widget->priv->display_height = height;
252   } else if (width % display_ratio_num == 0) {
253     GST_DEBUG ("%p keeping video width", widget);
254     widget->priv->display_width = width;
255     widget->priv->display_height = (guint)
256         gst_util_uint64_scale_int (width, display_ratio_den, display_ratio_num);
257   } else {
258     GST_DEBUG ("%p approximating while keeping video height", widget);
259     widget->priv->display_width = (guint)
260         gst_util_uint64_scale_int (height, display_ratio_num,
261         display_ratio_den);
262     widget->priv->display_height = height;
263   }
264   GST_DEBUG ("%p scaling to %dx%d", widget, widget->priv->display_width,
265       widget->priv->display_height);
266 
267   return TRUE;
268 }
269 
270 QSGNode *
updatePaintNode(QSGNode * oldNode,UpdatePaintNodeData * updatePaintNodeData)271 QtGLVideoItem::updatePaintNode(QSGNode * oldNode,
272     UpdatePaintNodeData * updatePaintNodeData)
273 {
274   GstBuffer *old_buffer;
275   gboolean was_bound = FALSE;
276 
277   if (!this->priv->initted)
278     return oldNode;
279 
280   QSGSimpleTextureNode *texNode = static_cast<QSGSimpleTextureNode *> (oldNode);
281   GstVideoRectangle src, dst, result;
282   GstQSGTexture *tex;
283 
284   g_mutex_lock (&this->priv->lock);
285 
286   GST_TRACE ("%p updatePaintNode", this);
287 
288   if (!this->priv->caps) {
289     GST_LOG ("%p no caps yet", this);
290     g_mutex_unlock (&this->priv->lock);
291     return NULL;
292   }
293 
294   if (gst_gl_context_get_current() == NULL)
295     gst_gl_context_activate (this->priv->other_context, TRUE);
296 
297   if (!texNode) {
298     texNode = new QSGSimpleTextureNode ();
299     texNode->setOwnsTexture (true);
300     texNode->setTexture (new GstQSGTexture ());
301   }
302 
303   tex = static_cast<GstQSGTexture *> (texNode->texture());
304 
305   if ((old_buffer = tex->getBuffer(&was_bound))) {
306     if (old_buffer == this->priv->buffer) {
307       /* same buffer */
308       gst_buffer_unref (old_buffer);
309     } else if (!was_bound) {
310       GST_TRACE ("old buffer %p was not bound yet, unreffing", old_buffer);
311       gst_buffer_unref (old_buffer);
312     } else {
313       GstBuffer *tmp_buffer;
314 
315       GST_TRACE ("old buffer %p was bound, queueing up for later", old_buffer);
316       /* Unref all buffers that were previously not bound anymore. At least
317        * one more buffer was bound in the meantime so this one is most likely
318        * not in use anymore. */
319       while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->potentially_unbound_buffers))) {
320         GST_TRACE ("old buffer %p should be unbound now, unreffing", tmp_buffer);
321         gst_buffer_unref (tmp_buffer);
322       }
323 
324       /* Move previous bound buffers to the next queue. We now know that
325        * another buffer was bound in the meantime and will free them on
326        * the next iteration above. */
327       while ((tmp_buffer = (GstBuffer*) g_queue_pop_head (&this->priv->bound_buffers))) {
328         GST_TRACE ("old buffer %p is potentially unbound now", tmp_buffer);
329         g_queue_push_tail (&this->priv->potentially_unbound_buffers, tmp_buffer);
330       }
331       g_queue_push_tail (&this->priv->bound_buffers, old_buffer);
332     }
333     old_buffer = NULL;
334   }
335 
336   tex->setCaps (this->priv->caps);
337   tex->setBuffer (this->priv->buffer);
338   texNode->markDirty(QSGNode::DirtyMaterial);
339 
340   if (this->priv->force_aspect_ratio) {
341     src.w = this->priv->display_width;
342     src.h = this->priv->display_height;
343 
344     dst.x = boundingRect().x();
345     dst.y = boundingRect().y();
346     dst.w = boundingRect().width();
347     dst.h = boundingRect().height();
348 
349     gst_video_sink_center_rect (src, dst, &result, TRUE);
350   } else {
351     result.x = boundingRect().x();
352     result.y = boundingRect().y();
353     result.w = boundingRect().width();
354     result.h = boundingRect().height();
355   }
356 
357   texNode->setRect (QRectF (result.x, result.y, result.w, result.h));
358 
359   g_mutex_unlock (&this->priv->lock);
360 
361   return texNode;
362 }
363 
364 /* This method has to be invoked with the the priv->lock taken */
365 void
fitStreamToAllocatedSize(GstVideoRectangle * result)366 QtGLVideoItem::fitStreamToAllocatedSize(GstVideoRectangle * result)
367 {
368   if (this->priv->force_aspect_ratio) {
369     GstVideoRectangle src, dst;
370 
371     src.x = 0;
372     src.y = 0;
373     src.w = this->priv->display_width;
374     src.h = this->priv->display_height;
375 
376     dst.x = 0;
377     dst.y = 0;
378     dst.w = width();
379     dst.h = height();
380 
381     gst_video_sink_center_rect (src, dst, result, TRUE);
382   } else {
383     result->x = 0;
384     result->y = 0;
385     result->w = width();
386     result->h = height();
387   }
388 }
389 
390 /* This method has to be invoked with the the priv->lock taken */
391 QPointF
mapPointToStreamSize(QPointF pos)392 QtGLVideoItem::mapPointToStreamSize(QPointF pos)
393 {
394   gdouble stream_width, stream_height;
395   GstVideoRectangle result;
396   double stream_x, stream_y;
397   double x, y;
398 
399   fitStreamToAllocatedSize(&result);
400 
401   stream_width = (gdouble) GST_VIDEO_INFO_WIDTH (&this->priv->v_info);
402   stream_height = (gdouble) GST_VIDEO_INFO_HEIGHT (&this->priv->v_info);
403   x = pos.x();
404   y = pos.y();
405 
406   /* from display coordinates to stream coordinates */
407   if (result.w > 0)
408     stream_x = (x - result.x) / result.w * stream_width;
409   else
410     stream_x = 0.;
411 
412   /* clip to stream size */
413   stream_x = CLAMP(stream_x, 0., stream_width);
414 
415   /* same for y-axis */
416   if (result.h > 0)
417     stream_y = (y - result.y) / result.h * stream_height;
418   else
419     stream_y = 0.;
420 
421   stream_y = CLAMP(stream_y, 0., stream_height);
422   GST_TRACE ("transform %fx%f into %fx%f", x, y, stream_x, stream_y);
423 
424   return QPointF(stream_x, stream_y);
425 }
426 
427 void
wheelEvent(QWheelEvent * event)428 QtGLVideoItem::wheelEvent(QWheelEvent * event)
429 {
430   g_mutex_lock (&this->priv->lock);
431   QPoint delta = event->angleDelta();
432   GstElement *element = GST_ELEMENT_CAST (g_weak_ref_get (&this->priv->sink));
433 
434   if (element != NULL) {
435 #if (QT_VERSION >= QT_VERSION_CHECK (5, 14, 0))
436     auto position = event->position();
437 #else
438     auto position = *event;
439 #endif
440     gst_navigation_send_mouse_scroll_event (GST_NAVIGATION (element),
441                                             position.x(), position.y(), delta.x(), delta.y());
442     g_object_unref (element);
443   }
444   g_mutex_unlock (&this->priv->lock);
445 }
446 
447 void
hoverEnterEvent(QHoverEvent *)448 QtGLVideoItem::hoverEnterEvent(QHoverEvent *)
449 {
450   mouseHovering = true;
451 }
452 
453 void
hoverLeaveEvent(QHoverEvent *)454 QtGLVideoItem::hoverLeaveEvent(QHoverEvent *)
455 {
456   mouseHovering = false;
457 }
458 
459 void
hoverMoveEvent(QHoverEvent * event)460 QtGLVideoItem::hoverMoveEvent(QHoverEvent * event)
461 {
462   if (!mouseHovering)
463     return;
464 
465   quint32 button = !!mousePressedButton;
466 
467   g_mutex_lock (&this->priv->lock);
468 
469   /* can't do anything when we don't have input format */
470   if (!this->priv->caps) {
471     g_mutex_unlock (&this->priv->lock);
472     return;
473   }
474 
475   if (event->pos() != event->oldPos()) {
476     QPointF pos = mapPointToStreamSize(event->pos());
477     GstElement *element = GST_ELEMENT_CAST (g_weak_ref_get (&this->priv->sink));
478 
479     if (element != NULL) {
480       gst_navigation_send_mouse_event (GST_NAVIGATION (element), "mouse-move",
481                                        button, pos.x(), pos.y());
482       g_object_unref (element);
483     }
484   }
485   g_mutex_unlock (&this->priv->lock);
486 }
487 
488 void
sendMouseEvent(QMouseEvent * event,const gchar * type)489 QtGLVideoItem::sendMouseEvent(QMouseEvent * event, const gchar * type)
490 {
491   quint32 button = 0;
492 
493   switch (event->button()) {
494   case Qt::LeftButton:
495     button = 1;
496     break;
497   case Qt::RightButton:
498     button = 2;
499     break;
500   default:
501     break;
502   }
503 
504   mousePressedButton = button;
505 
506   g_mutex_lock (&this->priv->lock);
507 
508   /* can't do anything when we don't have input format */
509   if (!this->priv->caps) {
510     g_mutex_unlock (&this->priv->lock);
511     return;
512   }
513 
514   QPointF pos = mapPointToStreamSize(event->pos());
515   gchar* event_type = g_strconcat ("mouse-button-", type, NULL);
516   GstElement *element = GST_ELEMENT_CAST (g_weak_ref_get (&this->priv->sink));
517 
518   if (element != NULL) {
519     gst_navigation_send_mouse_event (GST_NAVIGATION (element), event_type,
520                                      button, pos.x(), pos.y());
521     g_object_unref (element);
522   }
523 
524   g_free (event_type);
525   g_mutex_unlock (&this->priv->lock);
526 }
527 
528 void
mousePressEvent(QMouseEvent * event)529 QtGLVideoItem::mousePressEvent(QMouseEvent * event)
530 {
531   forceActiveFocus();
532   sendMouseEvent(event, "press");
533 }
534 
535 void
mouseReleaseEvent(QMouseEvent * event)536 QtGLVideoItem::mouseReleaseEvent(QMouseEvent * event)
537 {
538   sendMouseEvent(event, "release");
539 }
540 
541 void
setSink(GstElement * sink)542 QtGLVideoItemInterface::setSink (GstElement * sink)
543 {
544   QMutexLocker locker(&lock);
545   if (qt_item == NULL)
546     return;
547 
548   g_mutex_lock (&qt_item->priv->lock);
549   g_weak_ref_set (&qt_item->priv->sink, sink);
550   g_mutex_unlock (&qt_item->priv->lock);
551 }
552 
553 void
setBuffer(GstBuffer * buffer)554 QtGLVideoItemInterface::setBuffer (GstBuffer * buffer)
555 {
556   QMutexLocker locker(&lock);
557 
558   if (qt_item == NULL) {
559     GST_WARNING ("%p actual item is NULL. setBuffer call ignored", this);
560     return;
561   }
562 
563   if (!qt_item->priv->caps && !qt_item->priv->new_caps) {
564     GST_WARNING ("%p Got buffer on unnegotiated QtGLVideoItem. Dropping", this);
565     return;
566   }
567 
568   g_mutex_lock (&qt_item->priv->lock);
569 
570   if (qt_item->priv->new_caps) {
571     GST_DEBUG ("%p caps change from %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT,
572         this, qt_item->priv->caps, qt_item->priv->new_caps);
573     gst_caps_take (&qt_item->priv->caps, qt_item->priv->new_caps);
574     qt_item->priv->new_caps = NULL;
575     qt_item->priv->v_info = qt_item->priv->new_v_info;
576 
577     if (!_calculate_par (qt_item, &qt_item->priv->v_info)) {
578       g_mutex_unlock (&qt_item->priv->lock);
579       return;
580     }
581   }
582 
583   gst_buffer_replace (&qt_item->priv->buffer, buffer);
584 
585   QMetaObject::invokeMethod(qt_item, "update", Qt::QueuedConnection);
586 
587   g_mutex_unlock (&qt_item->priv->lock);
588 }
589 
590 void
onSceneGraphInitialized()591 QtGLVideoItem::onSceneGraphInitialized ()
592 {
593   if (this->window() == NULL)
594     return;
595 
596   GST_DEBUG ("%p scene graph initialization with Qt GL context %p", this,
597       this->window()->openglContext ());
598 
599   if (this->priv->qt_context == this->window()->openglContext ())
600     return;
601 
602   this->priv->qt_context = this->window()->openglContext ();
603   if (this->priv->qt_context == NULL) {
604     g_assert_not_reached ();
605     return;
606   }
607 
608   this->priv->initted = gst_qt_get_gl_wrapcontext (this->priv->display,
609       &this->priv->other_context, &this->priv->context);
610 
611   GST_DEBUG ("%p created wrapped GL context %" GST_PTR_FORMAT, this,
612       this->priv->other_context);
613 
614   emit itemInitializedChanged();
615 }
616 
617 void
onSceneGraphInvalidated()618 QtGLVideoItem::onSceneGraphInvalidated ()
619 {
620   GST_FIXME ("%p scene graph invalidated", this);
621 }
622 
623 /**
624  * Retrieve and populate the GL context information from the current
625  * OpenGL context.
626  */
627 gboolean
initWinSys()628 QtGLVideoItemInterface::initWinSys ()
629 {
630   QMutexLocker locker(&lock);
631 
632   GError *error = NULL;
633 
634   if (qt_item == NULL)
635     return FALSE;
636 
637   g_mutex_lock (&qt_item->priv->lock);
638 
639   if (qt_item->priv->display && qt_item->priv->qt_context
640       && qt_item->priv->other_context && qt_item->priv->context) {
641     /* already have the necessary state */
642     g_mutex_unlock (&qt_item->priv->lock);
643     return TRUE;
644   }
645 
646   if (!GST_IS_GL_DISPLAY (qt_item->priv->display)) {
647     GST_ERROR ("%p failed to retrieve display connection %" GST_PTR_FORMAT,
648         qt_item, qt_item->priv->display);
649     g_mutex_unlock (&qt_item->priv->lock);
650     return FALSE;
651   }
652 
653   if (!GST_IS_GL_CONTEXT (qt_item->priv->other_context)) {
654     GST_ERROR ("%p failed to retrieve wrapped context %" GST_PTR_FORMAT, qt_item,
655         qt_item->priv->other_context);
656     g_mutex_unlock (&qt_item->priv->lock);
657     return FALSE;
658   }
659 
660   qt_item->priv->context = gst_gl_context_new (qt_item->priv->display);
661 
662   if (!qt_item->priv->context) {
663     g_mutex_unlock (&qt_item->priv->lock);
664     return FALSE;
665   }
666 
667   if (!gst_gl_context_create (qt_item->priv->context, qt_item->priv->other_context,
668         &error)) {
669     GST_ERROR ("%s", error->message);
670     g_mutex_unlock (&qt_item->priv->lock);
671     return FALSE;
672   }
673 
674   g_mutex_unlock (&qt_item->priv->lock);
675   return TRUE;
676 }
677 
678 void
handleWindowChanged(QQuickWindow * win)679 QtGLVideoItem::handleWindowChanged (QQuickWindow * win)
680 {
681   if (win) {
682     if (win->isSceneGraphInitialized ())
683       win->scheduleRenderJob (new RenderJob (std::
684               bind (&QtGLVideoItem::onSceneGraphInitialized, this)),
685           QQuickWindow::BeforeSynchronizingStage);
686     else
687       connect (win, SIGNAL (sceneGraphInitialized ()), this,
688           SLOT (onSceneGraphInitialized ()), Qt::DirectConnection);
689 
690     connect (win, SIGNAL (sceneGraphInvalidated ()), this,
691         SLOT (onSceneGraphInvalidated ()), Qt::DirectConnection);
692   } else {
693     this->priv->qt_context = NULL;
694     this->priv->initted = FALSE;
695   }
696 }
697 
698 gboolean
setCaps(GstCaps * caps)699 QtGLVideoItemInterface::setCaps (GstCaps * caps)
700 {
701   QMutexLocker locker(&lock);
702   GstVideoInfo v_info;
703 
704   g_return_val_if_fail (GST_IS_CAPS (caps), FALSE);
705   g_return_val_if_fail (gst_caps_is_fixed (caps), FALSE);
706 
707   if (qt_item == NULL)
708     return FALSE;
709 
710   if (qt_item->priv->caps && gst_caps_is_equal_fixed (qt_item->priv->caps, caps))
711     return TRUE;
712 
713   if (!gst_video_info_from_caps (&v_info, caps))
714     return FALSE;
715 
716   g_mutex_lock (&qt_item->priv->lock);
717 
718   GST_DEBUG ("%p set caps %" GST_PTR_FORMAT, qt_item, caps);
719 
720   gst_caps_replace (&qt_item->priv->new_caps, caps);
721 
722   qt_item->priv->new_v_info = v_info;
723 
724   g_mutex_unlock (&qt_item->priv->lock);
725 
726   return TRUE;
727 }
728 
729 GstGLContext *
getQtContext()730 QtGLVideoItemInterface::getQtContext ()
731 {
732   QMutexLocker locker(&lock);
733 
734   if (!qt_item || !qt_item->priv->other_context)
735     return NULL;
736 
737   return (GstGLContext *) gst_object_ref (qt_item->priv->other_context);
738 }
739 
740 GstGLContext *
getContext()741 QtGLVideoItemInterface::getContext ()
742 {
743   QMutexLocker locker(&lock);
744 
745   if (!qt_item || !qt_item->priv->context)
746     return NULL;
747 
748   return (GstGLContext *) gst_object_ref (qt_item->priv->context);
749 }
750 
751 GstGLDisplay *
getDisplay()752 QtGLVideoItemInterface::getDisplay()
753 {
754   QMutexLocker locker(&lock);
755 
756   if (!qt_item || !qt_item->priv->display)
757     return NULL;
758 
759   return (GstGLDisplay *) gst_object_ref (qt_item->priv->display);
760 }
761 
762 void
setDAR(gint num,gint den)763 QtGLVideoItemInterface::setDAR(gint num, gint den)
764 {
765   QMutexLocker locker(&lock);
766   if (!qt_item)
767     return;
768   qt_item->setDAR(num, den);
769 }
770 
771 void
getDAR(gint * num,gint * den)772 QtGLVideoItemInterface::getDAR(gint * num, gint * den)
773 {
774   QMutexLocker locker(&lock);
775   if (!qt_item)
776     return;
777   qt_item->getDAR (num, den);
778 }
779 
780 void
setForceAspectRatio(bool force_aspect_ratio)781 QtGLVideoItemInterface::setForceAspectRatio(bool force_aspect_ratio)
782 {
783   QMutexLocker locker(&lock);
784   if (!qt_item)
785     return;
786   qt_item->setForceAspectRatio(force_aspect_ratio);
787 }
788 
789 bool
getForceAspectRatio()790 QtGLVideoItemInterface::getForceAspectRatio()
791 {
792   QMutexLocker locker(&lock);
793   if (!qt_item)
794     return FALSE;
795   return qt_item->getForceAspectRatio();
796 }
797 
798 void
invalidateRef()799 QtGLVideoItemInterface::invalidateRef()
800 {
801   QMutexLocker locker(&lock);
802   qt_item = NULL;
803 }
804 
805