1 /* GStreamer Wayland video sink
3 * Copyright (C) 2011 Intel Corporation
4 * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
5 * Copyright (C) 2012 Wim Taymans <wim.taymans@gmail.com>
6 * Copyright (C) 2014 Collabora Ltd.
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
18 * You should have received a copy of the GNU Library General Public
19 * License along with this library; if not, write to the Free
20 * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301 USA.
25 * SECTION:element-waylandsink
27 * The waylandsink is creating its own window and render the decoded video frames to that.
28 * Setup the Wayland environment as described in
29 * <ulink url="http://wayland.freedesktop.org/building.html">Wayland</ulink> home page.
30 * The current implementaion is based on weston compositor.
33 * <title>Example pipelines</title>
35 * gst-launch -v videotestsrc ! waylandsink
36 * ]| test the video rendering in wayland
44 #include "gstwaylandsink.h"
45 #ifdef GST_WLSINK_ENHANCEMENT
47 #include "tizen-wlvideoformat.h"
49 #include "wlvideoformat.h"
51 #include "wlshmallocator.h"
53 #include <gst/wayland/wayland.h>
54 #include <gst/video/videooverlay.h>
61 #ifdef GST_WLSINK_ENHANCEMENT
62 #define GST_TYPE_WAYLANDSINK_DISPLAY_GEOMETRY_METHOD (gst_waylandsink_display_geometry_method_get_type())
63 #define GST_TYPE_WAYLANDSINK_ROTATE_ANGLE (gst_waylandsink_rotate_angle_get_type())
64 #define GST_TYPE_WAYLANDSINK_FLIP (gst_waylandsink_flip_get_type())
67 gst_waylandsink_rotate_angle_get_type (void)
69 static GType waylandsink_rotate_angle_type = 0;
70 static const GEnumValue rotate_angle_type[] = {
71 {0, "No rotate", "DEGREE_0"},
72 {1, "Rotate 90 degree", "DEGREE_90"},
73 {2, "Rotate 180 degree", "DEGREE_180"},
74 {3, "Rotate 270 degree", "DEGREE_270"},
78 if (!waylandsink_rotate_angle_type) {
79 waylandsink_rotate_angle_type =
80 g_enum_register_static ("GstWaylandSinkRotateAngleType",
84 return waylandsink_rotate_angle_type;
89 gst_waylandsink_display_geometry_method_get_type (void)
91 static GType waylandsink_display_geometry_method_type = 0;
92 static const GEnumValue display_geometry_method_type[] = {
93 {0, "Letter box", "LETTER_BOX"},
94 {1, "Origin size", "ORIGIN_SIZE"},
95 {2, "Full-screen", "FULL_SCREEN"},
96 {3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
97 {4, "Origin size(if screen size is larger than video size(width/height)) or Letter box(if video size(width/height) is larger than screen size)", "ORIGIN_SIZE_OR_LETTER_BOX"},
101 if (!waylandsink_display_geometry_method_type) {
102 waylandsink_display_geometry_method_type =
103 g_enum_register_static ("GstWaylandSinkDisplayGeometryMethodType",
104 display_geometry_method_type);
106 return waylandsink_display_geometry_method_type;
110 gst_waylandsink_flip_get_type (void)
112 static GType waylandsink_flip_type = 0;
113 static const GEnumValue flip_type[] = {
114 {FLIP_NONE, "Flip NONE", "FLIP_NONE"},
115 {FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
116 {FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
117 {FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
118 {FLIP_NUM, NULL, NULL},
121 if (!waylandsink_flip_type) {
122 waylandsink_flip_type =
123 g_enum_register_static ("GstWaylandSinkFlipType", flip_type);
126 return waylandsink_flip_type;
143 #ifdef GST_WLSINK_ENHANCEMENT
146 PROP_DISPLAY_GEOMETRY_METHOD,
154 GST_DEBUG_CATEGORY (gstwayland_debug);
155 #define GST_CAT_DEFAULT gstwayland_debug
157 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
160 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
161 ("{ BGRx, BGRA, RGBx, xBGR, xRGB, RGBA, ABGR, ARGB, RGB, BGR, "
162 "RGB16, BGR16, YUY2, YVYU, UYVY, AYUV, NV12, NV21, NV16, "
163 #ifdef GST_WLSINK_ENHANCEMENT
166 "YUV9, YVU9, Y41B, I420, YV12, Y42B, v308 }"))
169 static void gst_wayland_sink_get_property (GObject * object,
170 guint prop_id, GValue * value, GParamSpec * pspec);
171 static void gst_wayland_sink_set_property (GObject * object,
172 guint prop_id, const GValue * value, GParamSpec * pspec);
173 static void gst_wayland_sink_finalize (GObject * object);
175 static GstStateChangeReturn gst_wayland_sink_change_state (GstElement * element,
176 GstStateChange transition);
177 static void gst_wayland_sink_set_context (GstElement * element,
178 GstContext * context);
180 static GstCaps *gst_wayland_sink_get_caps (GstBaseSink * bsink,
182 static gboolean gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
183 static gboolean gst_wayland_sink_preroll (GstBaseSink * bsink,
186 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query);
187 static gboolean gst_wayland_sink_render (GstBaseSink * bsink,
190 /* VideoOverlay interface */
191 static void gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface *
193 static void gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay,
196 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
197 guintptr wl_surface_id);
198 static void gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
199 gint x, gint y, gint w, gint h);
200 static void gst_wayland_sink_expose (GstVideoOverlay * overlay);
202 /* WaylandVideo interface */
203 static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface *
205 static void gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video);
206 static void gst_wayland_sink_end_geometry_change (GstWaylandVideo * video);
207 #ifdef GST_WLSINK_ENHANCEMENT
208 static void gst_wayland_sink_update_window_geometry (GstWaylandSink * sink);
209 static void render_last_buffer (GstWaylandSink * sink);
211 #define gst_wayland_sink_parent_class parent_class
212 G_DEFINE_TYPE_WITH_CODE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK,
213 G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
214 gst_wayland_sink_videooverlay_init)
215 G_IMPLEMENT_INTERFACE (GST_TYPE_WAYLAND_VIDEO,
216 gst_wayland_sink_waylandvideo_init));
219 gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
221 GObjectClass *gobject_class;
222 GstElementClass *gstelement_class;
223 GstBaseSinkClass *gstbasesink_class;
226 gobject_class = (GObjectClass *) klass;
227 gstelement_class = (GstElementClass *) klass;
228 gstbasesink_class = (GstBaseSinkClass *) klass;
230 gobject_class->set_property = gst_wayland_sink_set_property;
231 gobject_class->get_property = gst_wayland_sink_get_property;
232 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_wayland_sink_finalize);
234 gst_element_class_add_pad_template (gstelement_class,
235 gst_static_pad_template_get (&sink_template));
237 gst_element_class_set_static_metadata (gstelement_class,
238 "wayland video sink", "Sink/Video",
239 "Output to wayland surface",
240 "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
241 "George Kiagiadakis <george.kiagiadakis@collabora.com>");
243 gstelement_class->change_state =
244 GST_DEBUG_FUNCPTR (gst_wayland_sink_change_state);
245 gstelement_class->set_context =
246 GST_DEBUG_FUNCPTR (gst_wayland_sink_set_context);
248 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_get_caps);
249 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_set_caps);
250 gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_wayland_sink_preroll);
251 gstbasesink_class->propose_allocation =
252 GST_DEBUG_FUNCPTR (gst_wayland_sink_propose_allocation);
253 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_wayland_sink_render);
255 g_object_class_install_property (gobject_class, PROP_DISPLAY,
256 g_param_spec_string ("display", "Wayland Display name", "Wayland "
257 "display name to connect to, if not supplied via the GstContext",
258 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
259 #ifdef GST_WLSINK_ENHANCEMENT
260 g_object_class_install_property (gobject_class, PROP_USE_TBM,
261 g_param_spec_boolean ("use-tbm",
262 "Use Tizen Buffer Memory insted of Shared memory",
263 "When enabled, Memory is alloced by TBM insted of SHM ", TRUE,
264 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
266 g_object_class_install_property (gobject_class, PROP_ROTATE_ANGLE,
267 g_param_spec_enum ("rotate", "Rotate angle",
268 "Rotate angle of display output",
269 GST_TYPE_WAYLANDSINK_ROTATE_ANGLE, DEGREE_0,
270 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
272 g_object_class_install_property (gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
273 g_param_spec_enum ("display-geometry-method", "Display geometry method",
274 "Geometrical method for display",
275 GST_TYPE_WAYLANDSINK_DISPLAY_GEOMETRY_METHOD,
276 DEF_DISPLAY_GEOMETRY_METHOD,
277 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
279 g_object_class_install_property (gobject_class, PROP_ORIENTATION,
280 g_param_spec_enum ("orientation",
281 "Orientation information used for ROI/ZOOM",
282 "Orientation information for display",
283 GST_TYPE_WAYLANDSINK_ROTATE_ANGLE, DEGREE_0,
284 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
286 g_object_class_install_property (gobject_class, PROP_FLIP,
287 g_param_spec_enum ("flip", "Display flip",
289 GST_TYPE_WAYLANDSINK_FLIP, DEF_DISPLAY_FLIP,
290 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
292 g_object_class_install_property (gobject_class, PROP_VISIBLE,
293 g_param_spec_boolean ("visible", "Visible",
294 "Draws screen or blacks out, true means visible, false blacks out",
295 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
301 __write_rawdata (const char *file, const void *data, unsigned int size)
305 fp = fopen (file, "wb");
309 fwrite ((char *) data, sizeof (char), size, fp);
316 gst_wayland_sink_init (GstWaylandSink * sink)
319 #ifdef GST_WLSINK_ENHANCEMENT
320 sink->USE_TBM = TRUE;
321 sink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
322 sink->flip = DEF_DISPLAY_FLIP;
323 sink->rotate_angle = DEGREE_0;
324 sink->orientation = DEGREE_0;
325 sink->visible = TRUE;
327 g_mutex_init (&sink->display_lock);
328 g_mutex_init (&sink->render_lock);
331 #ifdef GST_WLSINK_ENHANCEMENT
333 gst_wayland_sink_stop_video (GstWaylandSink * sink)
336 g_return_if_fail (sink != NULL);
337 gst_wl_window_render (sink->window, NULL, NULL);
341 gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink)
343 GstWlBuffer *wlbuffer;
345 g_return_if_fail (sink != NULL);
346 g_return_if_fail (sink->last_buffer != NULL);
348 GST_DEBUG ("gstbuffer ref count is %d",
349 GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer));
350 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
351 wlbuffer->used_by_compositor = FALSE;
352 /*need to render last buffer, reuse current GstWlBuffer */
353 render_last_buffer (sink);
354 /* ref count is incresed in gst_wl_buffer_attach() of render_last_buffer(),
355 to call gst_wl_buffer_finalize(), we need to decrease buffer ref count.
356 wayland can not release buffer if we attach same buffer,
357 if we use visible but we need to attach null buffer and wayland can release buffer,
358 so we don't need to below code. */
360 gst_buffer_unref (wlbuffer->gstbuffer);
363 #ifdef USE_WL_FLUSH_BUFFER
365 gst_wayland_sink_make_flush_buffer (GstWlDisplay * display,
366 MMVideoBuffer * mm_video_buf)
368 GstWlFlushBuffer *flush_buffer = NULL;
374 g_return_val_if_fail (display != NULL, FALSE);
375 g_return_val_if_fail (mm_video_buf != NULL, FALSE);
377 flush_buffer = (GstWlFlushBuffer *) malloc (sizeof (GstWlFlushBuffer));
379 GST_ERROR ("GstWlFlushBuffer alloc faile");
382 memset (flush_buffer, 0x0, sizeof (GstWlFlushBuffer));
384 display->flush_tbm_bufmgr =
385 wayland_tbm_client_get_bufmgr (display->tbm_client);
386 g_return_if_fail (display->flush_tbm_bufmgr != NULL);
388 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
389 if (mm_video_buf->handle.bo[i] != NULL) {
394 bo_size = tbm_bo_size (mm_video_buf->handle.bo[i]);
395 GST_LOG ("tbm bo size: %d", bo_size);
397 bo = tbm_bo_alloc (display->flush_tbm_bufmgr, bo_size, TBM_DEVICE_CPU);
399 GST_ERROR ("alloc tbm bo(size:%d) failed: %s", bo_size,
403 GST_INFO ("flush buffer tbm_bo =(%p)", bo);
404 flush_buffer->bo[i] = bo;
405 /* get virtual address */
406 src.ptr = dst.ptr = NULL;
407 /* bo map, we can use tbm_bo_map too. */
408 src = tbm_bo_get_handle (mm_video_buf->handle.bo[i], TBM_DEVICE_CPU);
409 dst = tbm_bo_get_handle (bo, TBM_DEVICE_CPU);
410 if (!src.ptr || !dst.ptr) {
411 GST_ERROR ("get tbm bo handle failed src(%p) dst(%p): %s", src.ptr,
412 dst.ptr, strerror (errno));
413 tbm_bo_unref (mm_video_buf->handle.bo[i]);
418 memcpy (dst.ptr, src.ptr, bo_size);
420 tbm_bo_unmap (mm_video_buf->handle.bo[i]);
424 display->flush_buffer = flush_buffer;
429 gst_wayland_sink_copy_mm_video_buf_info_to_flush (GstWlDisplay * display,
430 MMVideoBuffer * mm_video_buf)
433 g_return_val_if_fail (display != NULL, FALSE);
434 g_return_val_if_fail (mm_video_buf != NULL, FALSE);
437 ret = gst_wayland_sink_make_flush_buffer (display, mm_video_buf);
440 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
441 if (display->flush_buffer->bo[i] != NULL) {
442 display->bo[i] = display->flush_buffer->bo[i];
443 GST_LOG ("bo %p", display->bo[i]);
447 display->plane_size[i] = mm_video_buf->size[i];
448 display->stride_width[i] = mm_video_buf->stride_width[i];
449 display->stride_height[i] = mm_video_buf->stride_height[i];
450 display->native_video_size += display->plane_size[i];
458 gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display,
459 MMVideoBuffer * mm_video_buf)
462 g_return_if_fail (display != NULL);
463 g_return_if_fail (mm_video_buf != NULL);
466 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
467 if (mm_video_buf->handle.bo[i] != NULL) {
468 display->bo[i] = mm_video_buf->handle.bo[i];
472 display->plane_size[i] = mm_video_buf->size[i];
473 display->stride_width[i] = mm_video_buf->stride_width[i];
474 display->stride_height[i] = mm_video_buf->stride_height[i];
475 display->native_video_size += display->plane_size[i];
480 gst_wayland_sink_get_mm_video_buf_info (GstWlDisplay * display,
484 GstMapInfo mem_info = GST_MAP_INFO_INIT;
485 MMVideoBuffer *mm_video_buf = NULL;
487 g_return_val_if_fail (display != NULL, FALSE);
488 g_return_val_if_fail (buffer != NULL, FALSE);
492 mem = gst_buffer_peek_memory (buffer, 1);
493 gst_memory_map (mem, &mem_info, GST_MAP_READ);
494 mm_video_buf = (MMVideoBuffer *) mem_info.data;
495 gst_memory_unmap (mem, &mem_info);
497 if (mm_video_buf == NULL) {
498 GST_WARNING ("mm_video_buf is NULL. Skip rendering");
501 /* assign mm_video_buf info */
502 if (mm_video_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
503 GST_DEBUG ("TBM bo %p %p %p", mm_video_buf->handle.bo[0],
504 mm_video_buf->handle.bo[1], mm_video_buf->handle.bo[2]);
505 display->native_video_size = 0;
506 display->flush_request = mm_video_buf->flush_request;
507 GST_DEBUG ("flush_request value is %d", display->flush_request);
508 #ifdef USE_WL_FLUSH_BUFFER
509 if (display->flush_request) {
510 if (!gst_wayland_sink_copy_mm_video_buf_info_to_flush (display,
512 GST_ERROR ("cat not copy mm_video_buf info to flush");
518 gst_wayland_sink_add_mm_video_buf_info (display, mm_video_buf);
520 GST_ERROR ("Buffer type is not TBM");
528 gst_wayland_sink_get_property (GObject * object,
529 guint prop_id, GValue * value, GParamSpec * pspec)
531 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
536 GST_OBJECT_LOCK (sink);
537 g_value_set_string (value, sink->display_name);
538 GST_OBJECT_UNLOCK (sink);
540 #ifdef GST_WLSINK_ENHANCEMENT
542 g_value_set_boolean (value, sink->USE_TBM);
544 case PROP_ROTATE_ANGLE:
545 g_value_set_enum (value, sink->rotate_angle);
547 case PROP_DISPLAY_GEOMETRY_METHOD:
548 g_value_set_enum (value, sink->display_geometry_method);
550 case PROP_ORIENTATION:
551 g_value_set_enum (value, sink->orientation);
554 g_value_set_enum (value, sink->flip);
557 g_value_set_boolean (value, sink->visible);
561 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
567 gst_wayland_sink_set_property (GObject * object,
568 guint prop_id, const GValue * value, GParamSpec * pspec)
570 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
572 g_mutex_lock (&sink->render_lock);
576 GST_OBJECT_LOCK (sink);
577 sink->display_name = g_value_dup_string (value);
578 GST_OBJECT_UNLOCK (sink);
580 #ifdef GST_WLSINK_ENHANCEMENT
582 sink->USE_TBM = g_value_get_boolean (value);
583 GST_LOG ("1:USE TBM 0: USE SHM set(%d)", sink->USE_TBM);
586 case PROP_ROTATE_ANGLE:
587 if (sink->rotate_angle == g_value_get_enum (value))
589 sink->rotate_angle = g_value_get_enum (value);
590 GST_WARNING_OBJECT (sink, "Rotate angle is set (%d)", sink->rotate_angle);
591 sink->video_info_changed = TRUE;
593 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
597 case PROP_DISPLAY_GEOMETRY_METHOD:
598 if (sink->display_geometry_method == g_value_get_enum (value))
600 sink->display_geometry_method = g_value_get_enum (value);
601 GST_WARNING_OBJECT (sink, "Display geometry method is set (%d)",
602 sink->display_geometry_method);
603 sink->video_info_changed = TRUE;
605 gst_wl_window_set_disp_geo_method (sink->window,
606 sink->display_geometry_method);
610 case PROP_ORIENTATION:
611 if (sink->orientation == g_value_get_enum (value))
613 sink->orientation = g_value_get_enum (value);
614 GST_WARNING_OBJECT (sink, "Orientation is set (%d)", sink->orientation);
615 sink->video_info_changed = TRUE;
617 gst_wl_window_set_orientation (sink->window, sink->orientation);
622 if (sink->flip == g_value_get_enum (value))
624 sink->flip = g_value_get_enum (value);
625 GST_WARNING_OBJECT (sink, "flip is set (%d)", sink->flip);
626 sink->video_info_changed = TRUE;
628 gst_wl_window_set_flip (sink->window, sink->flip);
633 if (sink->visible == g_value_get_boolean (value))
635 sink->visible = g_value_get_boolean (value);
636 GST_WARNING_OBJECT (sink, "visible is set (%d)", sink->visible);
637 if (sink->visible && GST_STATE (sink) == GST_STATE_PAUSED) {
638 /* need to attatch last buffer */
639 sink->video_info_changed = TRUE;
640 } else if (!sink->visible && GST_STATE (sink) >= GST_STATE_PAUSED) {
643 gst_wayland_sink_stop_video (sink);
649 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
652 if (sink->video_info_changed && sink->window
653 && GST_STATE (sink) == GST_STATE_PAUSED) {
654 gst_wayland_sink_update_last_buffer_geometry (sink);
656 g_mutex_unlock (&sink->render_lock);
661 gst_wayland_sink_finalize (GObject * object)
663 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
665 GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
667 if (sink->last_buffer)
668 gst_buffer_unref (sink->last_buffer);
670 g_object_unref (sink->display);
672 g_object_unref (sink->window);
674 gst_object_unref (sink->pool);
676 if (sink->display_name)
677 g_free (sink->display_name);
679 g_mutex_clear (&sink->display_lock);
680 g_mutex_clear (&sink->render_lock);
682 G_OBJECT_CLASS (parent_class)->finalize (object);
685 /* must be called with the display_lock */
687 gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
688 GstContext * context)
690 struct wl_display *display;
691 GError *error = NULL;
694 display = gst_wayland_display_handle_context_get_handle (context);
695 sink->display = gst_wl_display_new_existing (display, FALSE, &error);
698 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
699 ("Could not set display handle"),
700 ("Failed to use the external wayland display: '%s'", error->message));
701 g_error_free (error);
703 #ifdef GST_WLSINK_ENHANCEMENT
704 sink->display->USE_TBM = sink->USE_TBM;
709 gst_wayland_sink_find_display (GstWaylandSink * sink)
713 GstContext *context = NULL;
714 GError *error = NULL;
718 g_mutex_lock (&sink->display_lock);
720 if (!sink->display) {
721 /* first query upstream for the needed display handle */
722 query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
723 if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) {
724 gst_query_parse_context (query, &context);
725 gst_wayland_sink_set_display_from_context (sink, context);
727 gst_query_unref (query);
729 if (G_LIKELY (!sink->display)) {
730 /* now ask the application to set the display handle */
731 msg = gst_message_new_need_context (GST_OBJECT_CAST (sink),
732 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
734 g_mutex_unlock (&sink->display_lock);
735 gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
736 /* at this point we expect gst_wayland_sink_set_context
737 * to get called and fill sink->display */
738 g_mutex_lock (&sink->display_lock);
740 if (!sink->display) {
741 /* if the application didn't set a display, let's create it ourselves */
742 GST_OBJECT_LOCK (sink);
743 sink->display = gst_wl_display_new (sink->display_name, &error);
744 GST_OBJECT_UNLOCK (sink);
747 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
748 ("Could not initialise Wayland output"),
749 ("Failed to create GstWlDisplay: '%s'", error->message));
750 g_error_free (error);
753 #ifdef GST_WLSINK_ENHANCEMENT
755 sink->display->USE_TBM = sink->USE_TBM;
761 g_mutex_unlock (&sink->display_lock);
766 static GstStateChangeReturn
767 gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
769 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
770 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
773 switch (transition) {
774 case GST_STATE_CHANGE_NULL_TO_READY:
775 if (!gst_wayland_sink_find_display (sink))
776 return GST_STATE_CHANGE_FAILURE;
782 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
783 if (ret == GST_STATE_CHANGE_FAILURE)
786 switch (transition) {
787 case GST_STATE_CHANGE_PAUSED_TO_READY:
788 gst_buffer_replace (&sink->last_buffer, NULL);
790 if (gst_wl_window_is_toplevel (sink->window)) {
791 g_clear_object (&sink->window);
793 /* remove buffer from surface, show nothing */
794 #ifdef USE_WL_FLUSH_BUFFER
795 sink->display->flush_request = 0;
797 gst_wl_window_render (sink->window, NULL, NULL);
801 case GST_STATE_CHANGE_READY_TO_NULL:
802 g_mutex_lock (&sink->display_lock);
803 /* If we had a toplevel window, we most likely have our own connection
804 * to the display too, and it is a good idea to disconnect and allow
805 * potentially the application to embed us with GstVideoOverlay
806 * (which requires to re-use the same display connection as the parent
807 * surface). If we didn't have a toplevel window, then the display
808 * connection that we have is definitely shared with the application
809 * and it's better to keep it around (together with the window handle)
810 * to avoid requesting them again from the application if/when we are
811 * restarted (GstVideoOverlay behaves like that in other sinks)
813 if (sink->display && !sink->window) { /* -> the window was toplevel */
814 g_clear_object (&sink->display);
816 g_mutex_unlock (&sink->display_lock);
817 g_clear_object (&sink->pool);
827 gst_wayland_sink_set_context (GstElement * element, GstContext * context)
829 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
832 if (gst_context_has_context_type (context,
833 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
834 g_mutex_lock (&sink->display_lock);
835 if (G_LIKELY (!sink->display))
836 gst_wayland_sink_set_display_from_context (sink, context);
838 GST_WARNING_OBJECT (element, "changing display handle is not supported");
839 #ifdef GST_WLSINK_ENHANCEMENT
840 g_mutex_unlock (&sink->display_lock);
844 g_mutex_unlock (&sink->display_lock);
847 if (GST_ELEMENT_CLASS (parent_class)->set_context)
848 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
852 gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
854 GstWaylandSink *sink;
858 sink = GST_WAYLAND_SINK (bsink);
860 caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
862 g_mutex_lock (&sink->display_lock);
865 GValue list = G_VALUE_INIT;
866 GValue value = G_VALUE_INIT;
869 #ifdef GST_WLSINK_ENHANCEMENT
872 enum wl_shm_format fmt;
874 g_value_init (&list, GST_TYPE_LIST);
875 g_value_init (&value, G_TYPE_STRING);
876 #ifdef GST_WLSINK_ENHANCEMENT
877 if (sink->display->USE_TBM)
878 formats = sink->display->tbm_formats;
881 formats = sink->display->formats;
883 for (i = 0; i < formats->len; i++) {
884 #ifdef GST_WLSINK_ENHANCEMENT
886 tbm_fmt = g_array_index (formats, uint32_t, i);
887 g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
888 gst_value_list_append_value (&list, &value);
889 /* TBM doesn't support SN12 and ST12. So we add SN12 and ST12 manually as supported format.
890 * SN12 is same with NV12, ST12 is same with NV12MT
892 if (tbm_fmt == TBM_FORMAT_NV12) {
893 g_value_set_string (&value,
894 gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
895 gst_value_list_append_value (&list, &value);
896 } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
897 g_value_set_string (&value,
898 gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
899 gst_value_list_append_value (&list, &value);
901 } else { /* USE SHM */
902 fmt = g_array_index (formats, uint32_t, i);
903 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
904 gst_value_list_append_value (&list, &value);
906 #else /* open source */
907 fmt = g_array_index (formats, uint32_t, i);
908 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
909 gst_value_list_append_value (&list, &value);
913 caps = gst_caps_make_writable (caps);
914 gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
916 GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
919 g_mutex_unlock (&sink->display_lock);
922 GstCaps *intersection;
925 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
926 gst_caps_unref (caps);
934 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
936 GstWaylandSink *sink;
937 GstBufferPool *newpool;
939 #ifdef GST_WLSINK_ENHANCEMENT
942 enum wl_shm_format format;
946 GstStructure *structure;
947 GstWlShmAllocator *self = NULL;
951 sink = GST_WAYLAND_SINK (bsink);
953 GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
955 /* extract info from caps */
956 if (!gst_video_info_from_caps (&info, caps))
958 #ifdef GST_WLSINK_ENHANCEMENT
959 sink->caps = gst_caps_copy (caps);
962 gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
963 if ((gint) tbm_format == -1)
966 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
967 if ((gint) format == -1)
970 #else /* open source */
971 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
973 if ((gint) format == -1)
977 /* verify we support the requested format */
978 #ifdef GST_WLSINK_ENHANCEMENT
979 if (sink->display->USE_TBM) {
980 GST_INFO ("USE TBM FORMAT");
981 formats = sink->display->tbm_formats;
982 for (i = 0; i < formats->len; i++) {
983 if (g_array_index (formats, uint32_t, i) == tbm_format)
986 } else { /* USE SHM */
987 GST_INFO ("USE SHM FORMAT");
988 formats = sink->display->formats;
989 for (i = 0; i < formats->len; i++) {
990 if (g_array_index (formats, uint32_t, i) == format)
994 #else /* open source */
996 formats = sink->display->formats;
997 for (i = 0; i < formats->len; i++) {
998 if (g_array_index (formats, uint32_t, i) == format)
1002 if (i >= formats->len)
1003 goto unsupported_format;
1005 #ifdef GST_WLSINK_ENHANCEMENT
1006 if (sink->USE_TBM) {
1007 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1008 GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1009 sink->display->is_native_format = TRUE;
1011 /* store the video info */
1012 sink->video_info = info;
1013 sink->video_info_changed = TRUE;
1015 sink->display->is_native_format = FALSE;
1016 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1017 self->display = sink->display;
1018 /* create a new pool for the new configuration */
1019 newpool = gst_video_buffer_pool_new ();
1023 structure = gst_buffer_pool_get_config (newpool);
1024 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1025 gst_buffer_pool_config_set_allocator (structure,
1026 gst_wl_shm_allocator_get (), NULL);
1027 if (!gst_buffer_pool_set_config (newpool, structure))
1030 /* store the video info */
1031 sink->video_info = info;
1032 sink->video_info_changed = TRUE;
1034 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1035 gst_object_unref (newpool);
1037 } else { /* USE SHM */
1039 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1040 self->display = sink->display;
1042 /* create a new pool for the new configuration */
1043 newpool = gst_video_buffer_pool_new ();
1047 structure = gst_buffer_pool_get_config (newpool);
1048 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1049 gst_buffer_pool_config_set_allocator (structure,
1050 gst_wl_shm_allocator_get (), NULL);
1051 if (!gst_buffer_pool_set_config (newpool, structure))
1054 /* store the video info */
1055 sink->video_info = info;
1056 sink->video_info_changed = TRUE;
1058 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1059 gst_object_unref (newpool);
1061 #else /*open source */
1062 /* create a new pool for the new configuration */
1063 newpool = gst_video_buffer_pool_new ();
1067 structure = gst_buffer_pool_get_config (newpool);
1068 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1069 gst_buffer_pool_config_set_allocator (structure,
1070 gst_wl_shm_allocator_get (), NULL);
1071 if (!gst_buffer_pool_set_config (newpool, structure))
1074 /* store the video info */
1075 sink->video_info = info;
1076 sink->video_info_changed = TRUE;
1078 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1079 gst_object_unref (newpool);
1086 GST_DEBUG_OBJECT (sink,
1087 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1092 #ifdef GST_WLSINK_ENHANCEMENT
1094 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1095 gst_wl_tbm_format_to_string (tbm_format));
1097 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1098 gst_wl_shm_format_to_string (format));
1099 #else /*open source */
1100 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1101 gst_wl_shm_format_to_string (format));
1107 GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1112 GST_DEBUG_OBJECT (bsink, "failed setting config");
1113 gst_object_unref (newpool);
1119 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1121 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1122 GstStructure *config;
1123 guint size, min_bufs, max_bufs;
1124 #ifdef GST_WLSINK_ENHANCEMENT
1129 if (sink->USE_TBM) {
1130 if (sink->display->is_native_format == TRUE)
1133 gst_query_parse_allocation (query, &caps, &need_pool);
1136 GST_DEBUG_OBJECT (bsink, "no caps specified");
1141 config = gst_buffer_pool_get_config (sink->pool);
1142 gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1144 /* we do have a pool for sure (created in set_caps),
1145 * so let's propose it anyway, but also propose the allocator on its own */
1146 gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1147 gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1149 gst_structure_free (config);
1154 static GstFlowReturn
1155 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1158 GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1159 return gst_wayland_sink_render (bsink, buffer);
1163 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1165 GstWaylandSink *sink = data;
1168 GST_LOG ("frame_redraw_cb");
1170 g_atomic_int_set (&sink->redraw_pending, FALSE);
1171 wl_callback_destroy (callback);
1174 static const struct wl_callback_listener frame_callback_listener = {
1175 frame_redraw_callback
1178 #ifdef GST_WLSINK_ENHANCEMENT
1180 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1183 g_return_if_fail (sink != NULL);
1184 g_return_if_fail (sink->window != NULL);
1186 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1187 gst_wl_window_set_disp_geo_method (sink->window,
1188 sink->display_geometry_method);
1189 gst_wl_window_set_orientation (sink->window, sink->orientation);
1190 gst_wl_window_set_flip (sink->window, sink->flip);
1193 /* must be called with the render lock */
1195 render_last_buffer (GstWaylandSink * sink)
1197 GstWlBuffer *wlbuffer;
1198 const GstVideoInfo *info = NULL;
1199 struct wl_surface *surface;
1200 struct wl_callback *callback;
1203 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1204 surface = gst_wl_window_get_wl_surface (sink->window);
1206 g_atomic_int_set (&sink->redraw_pending, TRUE);
1207 callback = wl_surface_frame (surface);
1208 /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1209 wl_callback_add_listener (callback, &frame_callback_listener, sink);
1211 if (G_UNLIKELY (sink->video_info_changed)) {
1212 info = &sink->video_info;
1213 sink->video_info_changed = FALSE;
1215 #ifdef GST_WLSINK_ENHANCEMENT
1216 if (sink->last_buffer)
1217 gst_wl_window_render (sink->window, wlbuffer, info);
1219 if (G_UNLIKELY (info)) {
1220 gst_wl_window_set_video_info (sink->window, info);
1224 gst_wl_window_render (sink->window, wlbuffer, info);
1228 static GstFlowReturn
1229 gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
1231 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1232 GstBuffer *to_render;
1233 GstWlBuffer *wlbuffer;
1234 GstFlowReturn ret = GST_FLOW_OK;
1237 g_mutex_lock (&sink->render_lock);
1239 GST_LOG_OBJECT (sink, "render buffer %p", buffer);
1241 if (G_UNLIKELY (!sink->window)) {
1242 /* ask for window handle. Unlock render_lock while doing that because
1243 * set_window_handle & friends will lock it in this context */
1244 g_mutex_unlock (&sink->render_lock);
1245 gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
1246 g_mutex_lock (&sink->render_lock);
1248 if (!sink->window) {
1249 /* if we were not provided a window, create one ourselves */
1251 gst_wl_window_new_toplevel (sink->display, &sink->video_info);
1254 #ifdef GST_WLSINK_ENHANCEMENT
1255 gst_wayland_sink_update_window_geometry (sink);
1256 sink->video_info_changed = TRUE;
1258 /* drop buffers until we get a frame callback */
1259 if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1261 /* make sure that the application has called set_render_rectangle() */
1262 if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1263 goto no_window_size;
1265 #ifdef GST_WLSINK_ENHANCEMENT
1267 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1268 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1269 GST_LOG_OBJECT (sink, "buffer %p has a wl_buffer from our display, " "writing directly", buffer); //buffer is from our pool and have wl_buffer
1270 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1274 GstMapInfo mem_info = GST_MAP_INFO_INIT;
1275 int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1276 mem = gst_buffer_peek_memory (to_render, 0);
1277 gst_memory_map (mem, &mem_info, GST_MAP_READ);
1279 data = mem_info.data;
1281 char file_name[128];
1283 sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1285 ret = __write_rawdata (file_name, data, size);
1287 GST_ERROR ("_write_rawdata() failed");
1289 GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1290 gst_memory_unmap (mem, &mem_info);
1294 struct wl_buffer *wbuf = NULL;
1296 GST_LOG_OBJECT (sink, "buffer %p does not have a wl_buffer from our " "display, creating it", buffer); //buffer is from our pool but have not wl_buffer
1297 mem = gst_buffer_peek_memory (buffer, 0);
1298 if (gst_is_wl_shm_memory (mem)) {
1300 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1303 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add gstbuffer, wlbuffer, display and etc
1306 } else { //buffer is not from our pool and have not wl_buffer
1308 /* we don't know how to create a wl_buffer directly from the provided
1309 * memory, so we have to copy the data to a memory that we know how
1312 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1313 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1316 if (sink->USE_TBM && sink->display->is_native_format) {
1317 /* in case of SN12 or ST12 */
1318 if (!gst_wayland_sink_get_mm_video_buf_info (sink->display, buffer))
1319 return GST_FLOW_ERROR;
1321 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1322 if (G_UNLIKELY (!wlbuffer)) {
1324 gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1326 if (G_UNLIKELY (!wbuf))
1328 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1330 } else if (sink->USE_TBM && !sink->display->is_native_format) {
1332 /* sink->pool always exists (created in set_caps), but it may not
1333 * be active if upstream is not using it */
1334 if (!gst_buffer_pool_is_active (sink->pool)
1335 && !gst_buffer_pool_set_active (sink->pool, TRUE))
1336 goto activate_failed;
1338 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1339 if (ret != GST_FLOW_OK)
1343 //mem = gst_buffer_peek_memory (to_render, 0);
1344 //if (gst_is_wl_shm_memory (mem)) {
1345 GST_INFO ("to_render buffer is our buffer");
1347 /* the first time we acquire a buffer,
1348 * we need to attach a wl_buffer on it */
1349 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1350 if (G_UNLIKELY (!wlbuffer)) {
1351 mem = gst_buffer_peek_memory (to_render, 0);
1352 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1354 if (G_UNLIKELY (!wbuf))
1357 wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1360 gst_buffer_map (buffer, &src, GST_MAP_READ);
1361 gst_buffer_fill (to_render, 0, src.data, src.size);
1362 gst_buffer_unmap (buffer, &src);
1363 } else { /* USE SHM */
1364 /* sink->pool always exists (created in set_caps), but it may not
1365 * be active if upstream is not using it */
1366 if (!gst_buffer_pool_is_active (sink->pool) &&
1367 !gst_buffer_pool_set_active (sink->pool, TRUE))
1368 goto activate_failed;
1369 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1370 if (ret != GST_FLOW_OK)
1372 /* the first time we acquire a buffer,
1373 * we need to attach a wl_buffer on it */
1374 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1375 if (G_UNLIKELY (!wlbuffer)) {
1376 mem = gst_buffer_peek_memory (to_render, 0);
1377 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1379 if (G_UNLIKELY (!wbuf))
1382 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1386 gst_buffer_map (buffer, &src, GST_MAP_READ);
1387 gst_buffer_fill (to_render, 0, src.data, src.size);
1388 gst_buffer_unmap (buffer, &src);
1393 if (sink->USE_TBM && sink->display->is_native_format) {
1394 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1395 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1398 gst_buffer_replace (&sink->last_buffer, buffer);
1401 render_last_buffer (sink);
1405 } else { /* USE SHM or normal format */
1406 /* drop double rendering */
1407 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1408 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1411 gst_buffer_replace (&sink->last_buffer, to_render);
1414 render_last_buffer (sink);
1416 if (buffer != to_render)
1417 gst_buffer_unref (to_render);
1422 #else /* open source */
1424 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1426 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1427 GST_LOG_OBJECT (sink,
1428 "buffer %p has a wl_buffer from our display, " "writing directly",
1430 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1435 struct wl_buffer *wbuf = NULL;
1437 GST_LOG_OBJECT (sink,
1438 "buffer %p does not have a wl_buffer from our " "display, creating it",
1440 mem = gst_buffer_peek_memory (buffer, 0);
1441 if (gst_is_wl_shm_memory (mem)) {
1443 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1447 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1452 /* we don't know how to create a wl_buffer directly from the provided
1453 * memory, so we have to copy the data to a memory that we know how
1456 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1457 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1459 /* sink->pool always exists (created in set_caps), but it may not
1460 * be active if upstream is not using it */
1461 if (!gst_buffer_pool_is_active (sink->pool) &&
1462 !gst_buffer_pool_set_active (sink->pool, TRUE))
1463 goto activate_failed;
1465 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1466 if (ret != GST_FLOW_OK)
1469 /* the first time we acquire a buffer,
1470 * we need to attach a wl_buffer on it */
1471 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1472 if (G_UNLIKELY (!wlbuffer)) {
1473 mem = gst_buffer_peek_memory (to_render, 0);
1474 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1476 if (G_UNLIKELY (!wbuf))
1479 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1482 gst_buffer_map (buffer, &src, GST_MAP_READ);
1483 gst_buffer_fill (to_render, 0, src.data, src.size);
1484 gst_buffer_unmap (buffer, &src);
1487 /* drop double rendering */
1488 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1489 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1493 gst_buffer_replace (&sink->last_buffer, to_render);
1494 render_last_buffer (sink);
1496 if (buffer != to_render)
1497 gst_buffer_unref (to_render);
1501 #endif /* GST_WLSINK_ENHANCEMENT */
1505 GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1506 ("Window has no size set"),
1507 ("Make sure you set the size after calling set_window_handle"));
1508 ret = GST_FLOW_ERROR;
1513 GST_WARNING_OBJECT (sink, "could not create buffer");
1518 GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1519 ret = GST_FLOW_ERROR;
1524 GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1525 ret = GST_FLOW_ERROR;
1530 g_mutex_unlock (&sink->render_lock);
1536 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1538 iface->set_window_handle = gst_wayland_sink_set_window_handle;
1539 iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1540 iface->expose = gst_wayland_sink_expose;
1541 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1542 iface->set_wl_window_wl_surface_id =
1543 gst_wayland_sink_set_wl_window_wl_surface_id;
1547 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1549 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1550 guintptr wl_surface_id)
1552 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1554 g_return_if_fail (sink != NULL);
1556 if (sink->window != NULL) {
1557 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1560 g_mutex_lock (&sink->render_lock);
1561 g_clear_object (&sink->window);
1563 GST_INFO ("wl_surface_id %d %x", (int) wl_surface_id,
1564 (guintptr) wl_surface_id);
1566 if (wl_surface_id) {
1567 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1568 /* we cannot use our own display with an external window handle */
1569 if (G_UNLIKELY (sink->display->own_display)) {
1570 sink->display->wl_surface_id = (int) wl_surface_id;
1571 sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1574 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1575 "ignoring window handle");
1578 gst_wayland_sink_update_window_geometry (sink);
1580 g_mutex_unlock (&sink->render_lock);
1586 gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
1588 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1589 struct wl_surface *surface = (struct wl_surface *) handle;
1592 g_return_if_fail (sink != NULL);
1594 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1595 if (sink->window != NULL) {
1596 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1600 g_mutex_lock (&sink->render_lock);
1602 GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
1605 g_clear_object (&sink->window);
1608 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1609 /* we cannot use our own display with an external window handle */
1610 if (G_UNLIKELY (sink->display->own_display)) {
1611 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
1612 ("Application did not provide a wayland display handle"),
1613 ("Now waylandsink use internal display handle "
1614 "which is created ourselves. Consider providing a "
1615 "display handle from your application with GstContext"));
1616 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1618 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1621 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1622 "ignoring window handle");
1625 g_mutex_unlock (&sink->render_lock);
1630 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1631 gint x, gint y, gint w, gint h)
1633 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1636 g_return_if_fail (sink != NULL);
1638 g_mutex_lock (&sink->render_lock);
1639 if (!sink->window) {
1640 g_mutex_unlock (&sink->render_lock);
1641 GST_WARNING_OBJECT (sink,
1642 "set_render_rectangle called without window, ignoring");
1646 GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1648 gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1650 g_mutex_unlock (&sink->render_lock);
1654 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1656 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1659 g_return_if_fail (sink != NULL);
1661 GST_DEBUG_OBJECT (sink, "expose");
1663 g_mutex_lock (&sink->render_lock);
1664 if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1665 GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1666 render_last_buffer (sink);
1668 g_mutex_unlock (&sink->render_lock);
1672 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1674 iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1675 iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1679 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1681 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1683 g_return_if_fail (sink != NULL);
1685 g_mutex_lock (&sink->render_lock);
1686 if (!sink->window || !sink->window->area_subsurface) {
1687 g_mutex_unlock (&sink->render_lock);
1688 GST_INFO_OBJECT (sink,
1689 "begin_geometry_change called without window, ignoring");
1693 wl_subsurface_set_sync (sink->window->area_subsurface);
1694 g_mutex_unlock (&sink->render_lock);
1698 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1700 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1702 g_return_if_fail (sink != NULL);
1704 g_mutex_lock (&sink->render_lock);
1705 if (!sink->window || !sink->window->area_subsurface) {
1706 g_mutex_unlock (&sink->render_lock);
1707 GST_INFO_OBJECT (sink,
1708 "end_geometry_change called without window, ignoring");
1712 wl_subsurface_set_desync (sink->window->area_subsurface);
1713 g_mutex_unlock (&sink->render_lock);
1717 plugin_init (GstPlugin * plugin)
1719 GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1720 " wayland video sink");
1722 gst_wl_shm_allocator_register ();
1724 return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1725 GST_TYPE_WAYLAND_SINK);
1728 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1731 "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,