77#include <QtGui/QGuiApplication>
79#include <gst/gl/gstglfuncs.h>
81#define GST_CAT_DEFAULT gst_debug_qml6_gl_sink
87 const GValue * value, GParamSpec * param_spec);
89 GValue * value, GParamSpec * param_spec);
95static GstStateChangeReturn
99 GstClockTime * start, GstClockTime * end);
107GST_STATIC_PAD_TEMPLATE (
"sink",
110 GST_STATIC_CAPS (
"video/x-raw(" GST_CAPS_FEATURE_MEMORY_GL_MEMORY
"), "
111 "format = (string) { RGB, RGBA }, "
112 "width = " GST_VIDEO_SIZE_RANGE
", "
113 "height = " GST_VIDEO_SIZE_RANGE
", "
114 "framerate = " GST_VIDEO_FPS_RANGE
", "
115 "texture-target = (string) 2D"));
117#define DEFAULT_FORCE_ASPECT_RATIO TRUE
118#define DEFAULT_PAR_N 0
119#define DEFAULT_PAR_D 1
135#define gst_qml6_gl_sink_parent_class parent_class
138 "qtsink", 0,
"Qt Video Sink");
139 G_IMPLEMENT_INTERFACE (GST_TYPE_NAVIGATION,
141G_BEGIN_DECLS gboolean
G_PASTE(gst_element_register_, qml6glsink)(GstPlugin *plugin)
148 return gst_element_register(plugin,
"qml6glsink", GST_RANK_NONE, (gst_qml6_gl_sink_get_type()));
155 GObjectClass *gobject_class;
156 GstElementClass *gstelement_class;
157 GstBaseSinkClass *gstbasesink_class;
158 GstVideoSinkClass *gstvideosink_class;
160 gobject_class = (GObjectClass *) klass;
161 gstelement_class = (GstElementClass *) klass;
162 gstbasesink_class = (GstBaseSinkClass *) klass;
163 gstvideosink_class = (GstVideoSinkClass *) klass;
168 gst_element_class_set_metadata (gstelement_class,
"Qt6 Video Sink",
169 "Sink/Video",
"A video sink that renders to a QQuickItem for Qt6",
170 "Matthew Waters <matthew@centricular.com>");
172 g_object_class_install_property (gobject_class,
PROP_WIDGET,
173 g_param_spec_pointer (
"widget",
"QQuickItem",
174 "The QQuickItem to place in the object hierarchy",
175 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
178 g_param_spec_boolean (
"force-aspect-ratio",
179 "Force aspect ratio",
180 "When enabled, scaling will respect original aspect ratio",
182 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
185 gst_param_spec_fraction (
"pixel-aspect-ratio",
"Pixel Aspect Ratio",
188 (GParamFlags) (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)));
207 qt_sink->widget = QSharedPointer<Qt6GLVideoItemInterface>();
209 qt_sink->widget->setSink (GST_ELEMENT_CAST (qt_sink));
214 const GValue * value, GParamSpec * pspec)
216 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (
object);
222 qt_sink->widget = qt_item->getInterface();
223 if (qt_sink->widget) {
224 qt_sink->widget->setSink (GST_ELEMENT_CAST (qt_sink));
227 qt_sink->widget.clear();
232 g_return_if_fail (qt_sink->widget);
233 qt_sink->widget->setForceAspectRatio (g_value_get_boolean (value));
236 g_return_if_fail (qt_sink->widget);
237 qt_sink->widget->setDAR (gst_value_get_fraction_numerator (value),
238 gst_value_get_fraction_denominator (value));
241 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
249 if (qt_sink->display) {
250 gst_object_unref (qt_sink->display);
251 qt_sink->display = NULL;
254 if (qt_sink->context) {
255 gst_object_unref (qt_sink->context);
256 qt_sink->context = NULL;
259 if (qt_sink->qt_context) {
260 gst_object_unref (qt_sink->qt_context);
261 qt_sink->qt_context = NULL;
268 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (
object);
272 qt_sink->widget.clear();
274 G_OBJECT_CLASS (parent_class)->finalize (
object);
279 GValue * value, GParamSpec * pspec)
281 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (
object);
289 g_value_set_pointer (value, qt_sink->widget->videoItem());
291 g_value_set_pointer (value, NULL);
295 g_value_set_boolean (value, qt_sink->widget->getForceAspectRatio ());
300 if (qt_sink->widget) {
302 qt_sink->widget->getDAR (&num, &den);
303 gst_value_set_fraction (value, num, den);
309 G_OBJECT_WARN_INVALID_PROPERTY_ID (
object, prop_id, pspec);
317 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (bsink);
318 gboolean res = FALSE;
320 switch (GST_QUERY_TYPE (query)) {
321 case GST_QUERY_CONTEXT:
323 if (gst_gl_handle_context_query ((
GstElement *) qt_sink, query,
324 qt_sink->display, qt_sink->context, qt_sink->qt_context))
330 res = GST_BASE_SINK_CLASS (parent_class)->query (bsink, query);
343static GstStateChangeReturn
346 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (element);
347 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
348 QGuiApplication *app;
350 GST_DEBUG (
"changing state: %s => %s",
351 gst_element_state_get_name (GST_STATE_TRANSITION_CURRENT (transition)),
352 gst_element_state_get_name (GST_STATE_TRANSITION_NEXT (transition)));
354 switch (transition) {
355 case GST_STATE_CHANGE_NULL_TO_READY:
356 app =
static_cast<QGuiApplication *
> (QCoreApplication::instance ());
358 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND,
359 (
"%s",
"Failed to connect to Qt"),
360 (
"%s",
"Could not retrieve QGuiApplication instance"));
361 return GST_STATE_CHANGE_FAILURE;
364 if (!qt_sink->widget) {
365 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND,
366 (
"%s",
"Required property \'widget\' not set"),
368 return GST_STATE_CHANGE_FAILURE;
371 if (!qt_sink->widget->initWinSys()) {
372 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND,
373 (
"%s",
"Could not initialize window system"),
375 return GST_STATE_CHANGE_FAILURE;
378 qt_sink->display = qt_sink->widget->getDisplay();
379 qt_sink->context = qt_sink->widget->getContext();
380 qt_sink->qt_context = qt_sink->widget->getQtContext();
382 if (!qt_sink->display || !qt_sink->context || !qt_sink->qt_context) {
383 GST_ELEMENT_ERROR (element, RESOURCE, NOT_FOUND,
384 (
"%s",
"Could not retrieve window system OpenGL configuration"),
386 return GST_STATE_CHANGE_FAILURE;
389 GST_OBJECT_LOCK (qt_sink->display);
390 gst_gl_display_add_context (qt_sink->display, qt_sink->context);
391 GST_OBJECT_UNLOCK (qt_sink->display);
393 gst_gl_element_propagate_display_context (GST_ELEMENT (qt_sink), qt_sink->display);
396 case GST_STATE_CHANGE_READY_TO_PAUSED:
398 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
404 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
405 if (ret == GST_STATE_CHANGE_FAILURE)
408 switch (transition) {
409 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
411 case GST_STATE_CHANGE_PAUSED_TO_READY:
413 qt_sink->widget->setBuffer(NULL);
415 case GST_STATE_CHANGE_READY_TO_NULL:
426 GstClockTime * start, GstClockTime * end)
428 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (bsink);
430 if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
431 *start = GST_BUFFER_TIMESTAMP (buf);
432 if (GST_BUFFER_DURATION_IS_VALID (buf))
433 *end = *start + GST_BUFFER_DURATION (buf);
435 if (GST_VIDEO_INFO_FPS_N (&qt_sink->v_info) > 0) {
437 gst_util_uint64_scale_int (GST_SECOND,
438 GST_VIDEO_INFO_FPS_D (&qt_sink->v_info),
439 GST_VIDEO_INFO_FPS_N (&qt_sink->v_info));
448 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (bsink);
450 GST_DEBUG (
"set caps with %" GST_PTR_FORMAT, caps);
452 if (!gst_video_info_from_caps (&qt_sink->v_info, caps))
455 if (!qt_sink->widget)
458 return qt_sink->widget->setCaps(caps);
464 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (vsink);
466 GST_TRACE (
"rendering buffer:%p", buf);
469 qt_sink->widget->setBuffer(buf);
477 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (bsink);
479 GstStructure *config;
484 if (!qt_sink->display || !qt_sink->context)
487 gst_query_parse_allocation (query, &caps, &need_pool);
493 if ((pool = qt_sink->pool))
494 gst_object_ref (pool);
500 GST_DEBUG_OBJECT (qt_sink,
"check existing pool caps");
501 config = gst_buffer_pool_get_config (pool);
502 gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
504 if (!gst_caps_is_equal (caps, pcaps)) {
505 GST_DEBUG_OBJECT (qt_sink,
"pool has different caps");
507 gst_object_unref (pool);
510 gst_structure_free (config);
514 if (!gst_video_info_from_caps (&info, caps))
521 if (pool == NULL && need_pool) {
523 GST_DEBUG_OBJECT (qt_sink,
"create new pool");
524 pool = gst_gl_buffer_pool_new (qt_sink->context);
526 config = gst_buffer_pool_get_config (pool);
527 gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
528 if (!gst_buffer_pool_set_config (pool, config))
533 gst_query_add_allocation_pool (query, pool, size, 2, 0);
535 gst_object_unref (pool);
538 gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);
540 if (qt_sink->context->gl_vtable->FenceSync)
541 gst_query_add_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, 0);
548 GST_DEBUG_OBJECT (bsink,
"no caps specified");
553 GST_DEBUG_OBJECT (bsink,
"invalid caps specified");
558 GST_DEBUG_OBJECT (bsink,
"failed setting config");
565 GstStructure *structure)
567 GstQml6GLSink *qt_sink = GST_QML6_GL_SINK (navigation);
568 GST_TRACE_OBJECT (qt_sink,
"navigation event %" GST_PTR_FORMAT,
struct _GstElement GstElement
static void gst_qml6_gl_sink_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *param_spec)
GST_DEBUG_CATEGORY(gst_debug_qml6_gl_sink)
static void gst_qml6_gl_sink_class_init(GstQml6GLSinkClass *klass)
static GstStateChangeReturn gst_qml6_gl_sink_change_state(GstElement *element, GstStateChange transition)
static void gst_qml6_gl_sink_navigation_send_event(GstNavigation *navigation, GstStructure *structure)
static void gst_qml6_gl_sink_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *param_spec)
G_DEFINE_TYPE_WITH_CODE(GstQml6GLSink, gst_qml6_gl_sink, GST_TYPE_VIDEO_SINK, GST_DEBUG_CATEGORY_INIT(gst_debug_qml6_gl_sink, "qtsink", 0, "Qt Video Sink");G_IMPLEMENT_INTERFACE(GST_TYPE_NAVIGATION, gst_qml6_gl_sink_navigation_interface_init))
static void gst_qml6_gl_sink_get_times(GstBaseSink *bsink, GstBuffer *buf, GstClockTime *start, GstClockTime *end)
#define DEFAULT_FORCE_ASPECT_RATIO
static gboolean gst_qml6_gl_sink_query(GstBaseSink *bsink, GstQuery *query)
static void _reset(GstQml6GLSink *qt_sink)
static void gst_qml6_gl_sink_navigation_interface_init(GstNavigationInterface *iface)
G_BEGIN_DECLS gboolean G_PASTE(gst_element_register_, qml6glsink)(GstPlugin *plugin)
static void gst_qml6_gl_sink_init(GstQml6GLSink *qt_sink)
static GstStaticPadTemplate gst_qt_sink_template
@ PROP_FORCE_ASPECT_RATIO
@ PROP_PIXEL_ASPECT_RATIO
static gboolean gst_qml6_gl_sink_set_caps(GstBaseSink *bsink, GstCaps *caps)
static gboolean gst_qml6_gl_sink_stop(GstBaseSink *bsink)
static gboolean gst_qml6_gl_sink_propose_allocation(GstBaseSink *bsink, GstQuery *query)
static GstFlowReturn gst_qml6_gl_sink_show_frame(GstVideoSink *bsink, GstBuffer *buf)
static void gst_qml6_gl_sink_finalize(GObject *object)
void qt6_element_init(GstPlugin *plugin)