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