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 GST_DEBUG ("gstbuffer ref count is %d",
347 GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer));
348 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
349 wlbuffer->used_by_compositor = FALSE;
350 /*need to render last buffer, reuse current GstWlBuffer */
351 render_last_buffer (sink);
352 /* ref count is incresed in gst_wl_buffer_attach() of render_last_buffer(),
353 to call gst_wl_buffer_finalize(), we need to decrease buffer ref count.
354 wayland can not release buffer if we attach same buffer,
355 if we use visible but we need to attach null buffer and wayland can release buffer,
356 so we don't need to below code. */
358 gst_buffer_unref (wlbuffer->gstbuffer);
361 #ifdef USE_WL_FLUSH_BUFFER
363 gst_wayland_sink_make_flush_buffer (GstWlDisplay * display,
364 MMVideoBuffer * mm_video_buf)
366 GstWlFlushBuffer *flush_buffer = NULL;
372 g_return_val_if_fail (display != NULL, FALSE);
373 g_return_val_if_fail (mm_video_buf != NULL, FALSE);
375 flush_buffer = (GstWlFlushBuffer *) malloc (sizeof (GstWlFlushBuffer));
377 GST_ERROR ("GstWlFlushBuffer alloc faile");
380 memset (flush_buffer, 0x0, sizeof (GstWlFlushBuffer));
382 display->flush_tbm_bufmgr =
383 wayland_tbm_client_get_bufmgr (display->tbm_client);
384 g_return_if_fail (display->flush_tbm_bufmgr != NULL);
386 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
387 if (mm_video_buf->handle.bo[i] != NULL) {
392 bo_size = tbm_bo_size (mm_video_buf->handle.bo[i]);
393 GST_LOG ("tbm bo size: %d", bo_size);
395 bo = tbm_bo_alloc (display->flush_tbm_bufmgr, bo_size, TBM_DEVICE_CPU);
397 GST_ERROR ("alloc tbm bo(size:%d) failed: %s", bo_size,
401 GST_INFO ("flush buffer tbm_bo =(%p)", bo);
402 flush_buffer->bo[i] = bo;
403 /* get virtual address */
404 src.ptr = dst.ptr = NULL;
405 /* bo map, we can use tbm_bo_map too. */
406 src = tbm_bo_get_handle (mm_video_buf->handle.bo[i], TBM_DEVICE_CPU);
407 dst = tbm_bo_get_handle (bo, TBM_DEVICE_CPU);
408 if (!src.ptr || !dst.ptr) {
409 GST_ERROR ("get tbm bo handle failed src(%p) dst(%p): %s", src.ptr,
410 dst.ptr, strerror (errno));
411 tbm_bo_unref (mm_video_buf->handle.bo[i]);
416 memcpy (dst.ptr, src.ptr, bo_size);
418 tbm_bo_unmap (mm_video_buf->handle.bo[i]);
422 display->flush_buffer = flush_buffer;
427 gst_wayland_sink_copy_mm_video_buf_info_to_flush (GstWlDisplay * display,
428 MMVideoBuffer * mm_video_buf)
431 g_return_val_if_fail (display != NULL, FALSE);
432 g_return_val_if_fail (mm_video_buf != NULL, FALSE);
435 ret = gst_wayland_sink_make_flush_buffer (display, mm_video_buf);
438 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
439 if (display->flush_buffer->bo[i] != NULL) {
440 display->bo[i] = display->flush_buffer->bo[i];
441 GST_LOG ("bo %p", display->bo[i]);
445 display->plane_size[i] = mm_video_buf->size[i];
446 display->stride_width[i] = mm_video_buf->stride_width[i];
447 display->stride_height[i] = mm_video_buf->stride_height[i];
448 display->native_video_size += display->plane_size[i];
456 gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display,
457 MMVideoBuffer * mm_video_buf)
460 g_return_if_fail (display != NULL);
461 g_return_if_fail (mm_video_buf != NULL);
464 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
465 if (mm_video_buf->handle.bo[i] != NULL) {
466 display->bo[i] = mm_video_buf->handle.bo[i];
470 display->plane_size[i] = mm_video_buf->size[i];
471 display->stride_width[i] = mm_video_buf->stride_width[i];
472 display->stride_height[i] = mm_video_buf->stride_height[i];
473 display->native_video_size += display->plane_size[i];
478 gst_wayland_sink_get_mm_video_buf_info (GstWlDisplay * display,
482 GstMapInfo mem_info = GST_MAP_INFO_INIT;
483 MMVideoBuffer *mm_video_buf = NULL;
485 g_return_val_if_fail (display != NULL, FALSE);
486 g_return_val_if_fail (buffer != NULL, FALSE);
490 mem = gst_buffer_peek_memory (buffer, 1);
491 gst_memory_map (mem, &mem_info, GST_MAP_READ);
492 mm_video_buf = (MMVideoBuffer *) mem_info.data;
493 gst_memory_unmap (mem, &mem_info);
495 if (mm_video_buf == NULL) {
496 GST_WARNING ("mm_video_buf is NULL. Skip rendering");
499 /* assign mm_video_buf info */
500 if (mm_video_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
501 GST_DEBUG ("TBM bo %p %p %p", mm_video_buf->handle.bo[0],
502 mm_video_buf->handle.bo[1], mm_video_buf->handle.bo[2]);
503 display->native_video_size = 0;
504 display->flush_request = mm_video_buf->flush_request;
505 GST_DEBUG ("flush_request value is %d", display->flush_request);
506 #ifdef USE_WL_FLUSH_BUFFER
507 if (display->flush_request) {
508 if (!gst_wayland_sink_copy_mm_video_buf_info_to_flush (display,
510 GST_ERROR ("cat not copy mm_video_buf info to flush");
516 gst_wayland_sink_add_mm_video_buf_info (display, mm_video_buf);
518 GST_ERROR ("Buffer type is not TBM");
526 gst_wayland_sink_get_property (GObject * object,
527 guint prop_id, GValue * value, GParamSpec * pspec)
529 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
534 GST_OBJECT_LOCK (sink);
535 g_value_set_string (value, sink->display_name);
536 GST_OBJECT_UNLOCK (sink);
538 #ifdef GST_WLSINK_ENHANCEMENT
540 g_value_set_boolean (value, sink->USE_TBM);
542 case PROP_ROTATE_ANGLE:
543 g_value_set_enum (value, sink->rotate_angle);
545 case PROP_DISPLAY_GEOMETRY_METHOD:
546 g_value_set_enum (value, sink->display_geometry_method);
548 case PROP_ORIENTATION:
549 g_value_set_enum (value, sink->orientation);
552 g_value_set_enum (value, sink->flip);
555 g_value_set_boolean (value, sink->visible);
559 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
565 gst_wayland_sink_set_property (GObject * object,
566 guint prop_id, const GValue * value, GParamSpec * pspec)
568 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
570 g_mutex_lock (&sink->render_lock);
574 GST_OBJECT_LOCK (sink);
575 sink->display_name = g_value_dup_string (value);
576 GST_OBJECT_UNLOCK (sink);
578 #ifdef GST_WLSINK_ENHANCEMENT
580 sink->USE_TBM = g_value_get_boolean (value);
581 GST_LOG ("1:USE TBM 0: USE SHM set(%d)", sink->USE_TBM);
584 case PROP_ROTATE_ANGLE:
585 if (sink->rotate_angle == g_value_get_enum (value))
587 sink->rotate_angle = g_value_get_enum (value);
588 GST_WARNING_OBJECT (sink, "Rotate angle is set (%d)", sink->rotate_angle);
589 sink->video_info_changed = TRUE;
591 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
595 case PROP_DISPLAY_GEOMETRY_METHOD:
596 if (sink->display_geometry_method == g_value_get_enum (value))
598 sink->display_geometry_method = g_value_get_enum (value);
599 GST_WARNING_OBJECT (sink, "Display geometry method is set (%d)",
600 sink->display_geometry_method);
601 sink->video_info_changed = TRUE;
603 gst_wl_window_set_disp_geo_method (sink->window,
604 sink->display_geometry_method);
608 case PROP_ORIENTATION:
609 if (sink->orientation == g_value_get_enum (value))
611 sink->orientation = g_value_get_enum (value);
612 GST_WARNING_OBJECT (sink, "Orientation is set (%d)", sink->orientation);
613 sink->video_info_changed = TRUE;
615 gst_wl_window_set_orientation (sink->window, sink->orientation);
620 if (sink->flip == g_value_get_enum (value))
622 sink->flip = g_value_get_enum (value);
623 GST_WARNING_OBJECT (sink, "flip is set (%d)", sink->flip);
624 sink->video_info_changed = TRUE;
626 gst_wl_window_set_flip (sink->window, sink->flip);
631 if (sink->visible == g_value_get_boolean (value))
633 sink->visible = g_value_get_boolean (value);
634 GST_WARNING_OBJECT (sink, "visible is set (%d)", sink->visible);
635 if (sink->visible && GST_STATE (sink) == GST_STATE_PAUSED) {
636 /* need to attatch last buffer */
637 sink->video_info_changed = TRUE;
638 } else if (!sink->visible && GST_STATE (sink) >= GST_STATE_PAUSED) {
641 gst_wayland_sink_stop_video (sink);
647 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
650 if (sink->video_info_changed && sink->window
651 && GST_STATE (sink) == GST_STATE_PAUSED) {
652 gst_wayland_sink_update_last_buffer_geometry (sink);
654 g_mutex_unlock (&sink->render_lock);
659 gst_wayland_sink_finalize (GObject * object)
661 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
663 GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
665 if (sink->last_buffer)
666 gst_buffer_unref (sink->last_buffer);
668 g_object_unref (sink->display);
670 g_object_unref (sink->window);
672 gst_object_unref (sink->pool);
674 if (sink->display_name)
675 g_free (sink->display_name);
677 g_mutex_clear (&sink->display_lock);
678 g_mutex_clear (&sink->render_lock);
680 G_OBJECT_CLASS (parent_class)->finalize (object);
683 /* must be called with the display_lock */
685 gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
686 GstContext * context)
688 struct wl_display *display;
689 GError *error = NULL;
692 display = gst_wayland_display_handle_context_get_handle (context);
693 sink->display = gst_wl_display_new_existing (display, FALSE, &error);
696 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
697 ("Could not set display handle"),
698 ("Failed to use the external wayland display: '%s'", error->message));
699 g_error_free (error);
701 #ifdef GST_WLSINK_ENHANCEMENT
702 sink->display->USE_TBM = sink->USE_TBM;
707 gst_wayland_sink_find_display (GstWaylandSink * sink)
711 GstContext *context = NULL;
712 GError *error = NULL;
716 g_mutex_lock (&sink->display_lock);
718 if (!sink->display) {
719 /* first query upstream for the needed display handle */
720 query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
721 if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) {
722 gst_query_parse_context (query, &context);
723 gst_wayland_sink_set_display_from_context (sink, context);
725 gst_query_unref (query);
727 if (G_LIKELY (!sink->display)) {
728 /* now ask the application to set the display handle */
729 msg = gst_message_new_need_context (GST_OBJECT_CAST (sink),
730 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
732 g_mutex_unlock (&sink->display_lock);
733 gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
734 /* at this point we expect gst_wayland_sink_set_context
735 * to get called and fill sink->display */
736 g_mutex_lock (&sink->display_lock);
738 if (!sink->display) {
739 /* if the application didn't set a display, let's create it ourselves */
740 GST_OBJECT_LOCK (sink);
741 sink->display = gst_wl_display_new (sink->display_name, &error);
742 GST_OBJECT_UNLOCK (sink);
745 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
746 ("Could not initialise Wayland output"),
747 ("Failed to create GstWlDisplay: '%s'", error->message));
748 g_error_free (error);
751 #ifdef GST_WLSINK_ENHANCEMENT
753 sink->display->USE_TBM = sink->USE_TBM;
759 g_mutex_unlock (&sink->display_lock);
764 static GstStateChangeReturn
765 gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
767 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
768 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
771 switch (transition) {
772 case GST_STATE_CHANGE_NULL_TO_READY:
773 if (!gst_wayland_sink_find_display (sink))
774 return GST_STATE_CHANGE_FAILURE;
780 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
781 if (ret == GST_STATE_CHANGE_FAILURE)
784 switch (transition) {
785 case GST_STATE_CHANGE_PAUSED_TO_READY:
786 gst_buffer_replace (&sink->last_buffer, NULL);
788 if (gst_wl_window_is_toplevel (sink->window)) {
789 g_clear_object (&sink->window);
791 /* remove buffer from surface, show nothing */
792 #ifdef USE_WL_FLUSH_BUFFER
793 sink->display->flush_request = 0;
795 gst_wl_window_render (sink->window, NULL, NULL);
799 case GST_STATE_CHANGE_READY_TO_NULL:
800 g_mutex_lock (&sink->display_lock);
801 /* If we had a toplevel window, we most likely have our own connection
802 * to the display too, and it is a good idea to disconnect and allow
803 * potentially the application to embed us with GstVideoOverlay
804 * (which requires to re-use the same display connection as the parent
805 * surface). If we didn't have a toplevel window, then the display
806 * connection that we have is definitely shared with the application
807 * and it's better to keep it around (together with the window handle)
808 * to avoid requesting them again from the application if/when we are
809 * restarted (GstVideoOverlay behaves like that in other sinks)
811 if (sink->display && !sink->window) { /* -> the window was toplevel */
812 g_clear_object (&sink->display);
814 g_mutex_unlock (&sink->display_lock);
815 g_clear_object (&sink->pool);
825 gst_wayland_sink_set_context (GstElement * element, GstContext * context)
827 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
830 if (gst_context_has_context_type (context,
831 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
832 g_mutex_lock (&sink->display_lock);
833 if (G_LIKELY (!sink->display))
834 gst_wayland_sink_set_display_from_context (sink, context);
836 GST_WARNING_OBJECT (element, "changing display handle is not supported");
837 #ifdef GST_WLSINK_ENHANCEMENT
838 g_mutex_unlock (&sink->display_lock);
842 g_mutex_unlock (&sink->display_lock);
845 if (GST_ELEMENT_CLASS (parent_class)->set_context)
846 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
850 gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
852 GstWaylandSink *sink;
856 sink = GST_WAYLAND_SINK (bsink);
858 caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
860 g_mutex_lock (&sink->display_lock);
863 GValue list = G_VALUE_INIT;
864 GValue value = G_VALUE_INIT;
867 #ifdef GST_WLSINK_ENHANCEMENT
870 enum wl_shm_format fmt;
872 g_value_init (&list, GST_TYPE_LIST);
873 g_value_init (&value, G_TYPE_STRING);
874 #ifdef GST_WLSINK_ENHANCEMENT
875 if (sink->display->USE_TBM)
876 formats = sink->display->tbm_formats;
879 formats = sink->display->formats;
881 for (i = 0; i < formats->len; i++) {
882 #ifdef GST_WLSINK_ENHANCEMENT
884 tbm_fmt = g_array_index (formats, uint32_t, i);
885 g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
886 gst_value_list_append_value (&list, &value);
887 /* TBM doesn't support SN12 and ST12. So we add SN12 and ST12 manually as supported format.
888 * SN12 is same with NV12, ST12 is same with NV12MT
890 if (tbm_fmt == TBM_FORMAT_NV12) {
891 g_value_set_string (&value,
892 gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
893 gst_value_list_append_value (&list, &value);
894 } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
895 g_value_set_string (&value,
896 gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
897 gst_value_list_append_value (&list, &value);
899 } else { /* USE SHM */
900 fmt = g_array_index (formats, uint32_t, i);
901 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
902 gst_value_list_append_value (&list, &value);
904 #else /* open source */
905 fmt = g_array_index (formats, uint32_t, i);
906 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
907 gst_value_list_append_value (&list, &value);
911 caps = gst_caps_make_writable (caps);
912 gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
914 GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
917 g_mutex_unlock (&sink->display_lock);
920 GstCaps *intersection;
923 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
924 gst_caps_unref (caps);
932 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
934 GstWaylandSink *sink;
935 GstBufferPool *newpool;
937 #ifdef GST_WLSINK_ENHANCEMENT
940 enum wl_shm_format format;
944 GstStructure *structure;
945 GstWlShmAllocator *self = NULL;
949 sink = GST_WAYLAND_SINK (bsink);
951 GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
953 /* extract info from caps */
954 if (!gst_video_info_from_caps (&info, caps))
956 #ifdef GST_WLSINK_ENHANCEMENT
957 sink->caps = gst_caps_copy (caps);
960 gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
961 if ((gint) tbm_format == -1)
964 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
965 if ((gint) format == -1)
968 #else /* open source */
969 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
971 if ((gint) format == -1)
975 /* verify we support the requested format */
976 #ifdef GST_WLSINK_ENHANCEMENT
977 if (sink->display->USE_TBM) {
978 GST_INFO ("USE TBM FORMAT");
979 formats = sink->display->tbm_formats;
980 for (i = 0; i < formats->len; i++) {
981 if (g_array_index (formats, uint32_t, i) == tbm_format)
984 } else { /* USE SHM */
985 GST_INFO ("USE SHM FORMAT");
986 formats = sink->display->formats;
987 for (i = 0; i < formats->len; i++) {
988 if (g_array_index (formats, uint32_t, i) == format)
992 #else /* open source */
994 formats = sink->display->formats;
995 for (i = 0; i < formats->len; i++) {
996 if (g_array_index (formats, uint32_t, i) == format)
1000 if (i >= formats->len)
1001 goto unsupported_format;
1003 #ifdef GST_WLSINK_ENHANCEMENT
1004 if (sink->USE_TBM) {
1005 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1006 GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1007 sink->display->is_native_format = TRUE;
1009 /* store the video info */
1010 sink->video_info = info;
1011 sink->video_info_changed = TRUE;
1013 sink->display->is_native_format = FALSE;
1014 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1015 self->display = sink->display;
1016 /* create a new pool for the new configuration */
1017 newpool = gst_video_buffer_pool_new ();
1021 structure = gst_buffer_pool_get_config (newpool);
1022 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1023 gst_buffer_pool_config_set_allocator (structure,
1024 gst_wl_shm_allocator_get (), NULL);
1025 if (!gst_buffer_pool_set_config (newpool, structure))
1028 /* store the video info */
1029 sink->video_info = info;
1030 sink->video_info_changed = TRUE;
1032 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1033 gst_object_unref (newpool);
1035 } else { /* USE SHM */
1037 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1038 self->display = sink->display;
1040 /* create a new pool for the new configuration */
1041 newpool = gst_video_buffer_pool_new ();
1045 structure = gst_buffer_pool_get_config (newpool);
1046 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1047 gst_buffer_pool_config_set_allocator (structure,
1048 gst_wl_shm_allocator_get (), NULL);
1049 if (!gst_buffer_pool_set_config (newpool, structure))
1052 /* store the video info */
1053 sink->video_info = info;
1054 sink->video_info_changed = TRUE;
1056 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1057 gst_object_unref (newpool);
1059 #else /*open source */
1060 /* create a new pool for the new configuration */
1061 newpool = gst_video_buffer_pool_new ();
1065 structure = gst_buffer_pool_get_config (newpool);
1066 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1067 gst_buffer_pool_config_set_allocator (structure,
1068 gst_wl_shm_allocator_get (), NULL);
1069 if (!gst_buffer_pool_set_config (newpool, structure))
1072 /* store the video info */
1073 sink->video_info = info;
1074 sink->video_info_changed = TRUE;
1076 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1077 gst_object_unref (newpool);
1084 GST_DEBUG_OBJECT (sink,
1085 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1090 #ifdef GST_WLSINK_ENHANCEMENT
1092 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1093 gst_wl_tbm_format_to_string (tbm_format));
1095 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1096 gst_wl_shm_format_to_string (format));
1097 #else /*open source */
1098 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1099 gst_wl_shm_format_to_string (format));
1105 GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1110 GST_DEBUG_OBJECT (bsink, "failed setting config");
1111 gst_object_unref (newpool);
1117 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1119 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1120 GstStructure *config;
1121 guint size, min_bufs, max_bufs;
1122 #ifdef GST_WLSINK_ENHANCEMENT
1127 if (sink->USE_TBM) {
1128 if (sink->display->is_native_format == TRUE)
1131 gst_query_parse_allocation (query, &caps, &need_pool);
1134 GST_DEBUG_OBJECT (bsink, "no caps specified");
1139 config = gst_buffer_pool_get_config (sink->pool);
1140 gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1142 /* we do have a pool for sure (created in set_caps),
1143 * so let's propose it anyway, but also propose the allocator on its own */
1144 gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1145 gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1147 gst_structure_free (config);
1152 static GstFlowReturn
1153 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1156 GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1157 return gst_wayland_sink_render (bsink, buffer);
1161 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1163 GstWaylandSink *sink = data;
1166 GST_LOG ("frame_redraw_cb");
1168 g_atomic_int_set (&sink->redraw_pending, FALSE);
1169 wl_callback_destroy (callback);
1172 static const struct wl_callback_listener frame_callback_listener = {
1173 frame_redraw_callback
1176 #ifdef GST_WLSINK_ENHANCEMENT
1178 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1181 g_return_if_fail (sink != NULL);
1182 g_return_if_fail (sink->window != NULL);
1184 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1185 gst_wl_window_set_disp_geo_method (sink->window,
1186 sink->display_geometry_method);
1187 gst_wl_window_set_orientation (sink->window, sink->orientation);
1188 gst_wl_window_set_flip (sink->window, sink->flip);
1191 /* must be called with the render lock */
1193 render_last_buffer (GstWaylandSink * sink)
1195 GstWlBuffer *wlbuffer;
1196 const GstVideoInfo *info = NULL;
1197 struct wl_surface *surface;
1198 struct wl_callback *callback;
1201 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1202 surface = gst_wl_window_get_wl_surface (sink->window);
1204 g_atomic_int_set (&sink->redraw_pending, TRUE);
1205 callback = wl_surface_frame (surface);
1206 /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1207 wl_callback_add_listener (callback, &frame_callback_listener, sink);
1209 if (G_UNLIKELY (sink->video_info_changed)) {
1210 info = &sink->video_info;
1211 sink->video_info_changed = FALSE;
1213 #ifdef GST_WLSINK_ENHANCEMENT
1214 if (sink->last_buffer)
1215 gst_wl_window_render (sink->window, wlbuffer, info);
1217 if (G_UNLIKELY (info)) {
1218 gst_wl_window_set_video_info (sink->window, info);
1222 gst_wl_window_render (sink->window, wlbuffer, info);
1226 static GstFlowReturn
1227 gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
1229 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1230 GstBuffer *to_render;
1231 GstWlBuffer *wlbuffer;
1232 GstFlowReturn ret = GST_FLOW_OK;
1235 g_mutex_lock (&sink->render_lock);
1237 GST_LOG_OBJECT (sink, "render buffer %p", buffer);
1239 if (G_UNLIKELY (!sink->window)) {
1240 /* ask for window handle. Unlock render_lock while doing that because
1241 * set_window_handle & friends will lock it in this context */
1242 g_mutex_unlock (&sink->render_lock);
1243 gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
1244 g_mutex_lock (&sink->render_lock);
1246 if (!sink->window) {
1247 /* if we were not provided a window, create one ourselves */
1249 gst_wl_window_new_toplevel (sink->display, &sink->video_info);
1252 #ifdef GST_WLSINK_ENHANCEMENT
1253 gst_wayland_sink_update_window_geometry (sink);
1254 sink->video_info_changed = TRUE;
1256 /* drop buffers until we get a frame callback */
1257 if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1259 /* make sure that the application has called set_render_rectangle() */
1260 if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1261 goto no_window_size;
1263 #ifdef GST_WLSINK_ENHANCEMENT
1265 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1266 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1267 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
1268 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1272 GstMapInfo mem_info = GST_MAP_INFO_INIT;
1273 int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1274 mem = gst_buffer_peek_memory (to_render, 0);
1275 gst_memory_map (mem, &mem_info, GST_MAP_READ);
1277 data = mem_info.data;
1279 char file_name[128];
1281 sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1283 ret = __write_rawdata (file_name, data, size);
1285 GST_ERROR ("_write_rawdata() failed");
1287 GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1288 gst_memory_unmap (mem, &mem_info);
1292 struct wl_buffer *wbuf = NULL;
1294 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
1295 mem = gst_buffer_peek_memory (buffer, 0);
1296 if (gst_is_wl_shm_memory (mem)) {
1298 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1301 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add gstbuffer, wlbuffer, display and etc
1304 } else { //buffer is not from our pool and have not wl_buffer
1306 /* we don't know how to create a wl_buffer directly from the provided
1307 * memory, so we have to copy the data to a memory that we know how
1310 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1311 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1314 if (sink->USE_TBM && sink->display->is_native_format) {
1315 /* in case of SN12 or ST12 */
1316 if (!gst_wayland_sink_get_mm_video_buf_info (sink->display, buffer))
1317 return GST_FLOW_ERROR;
1319 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1320 if (G_UNLIKELY (!wlbuffer)) {
1322 gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1324 if (G_UNLIKELY (!wbuf))
1326 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1328 } else if (sink->USE_TBM && !sink->display->is_native_format) {
1330 /* sink->pool always exists (created in set_caps), but it may not
1331 * be active if upstream is not using it */
1332 if (!gst_buffer_pool_is_active (sink->pool)
1333 && !gst_buffer_pool_set_active (sink->pool, TRUE))
1334 goto activate_failed;
1336 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1337 if (ret != GST_FLOW_OK)
1341 //mem = gst_buffer_peek_memory (to_render, 0);
1342 //if (gst_is_wl_shm_memory (mem)) {
1343 GST_INFO ("to_render buffer is our buffer");
1345 /* the first time we acquire a buffer,
1346 * we need to attach a wl_buffer on it */
1347 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1348 if (G_UNLIKELY (!wlbuffer)) {
1349 mem = gst_buffer_peek_memory (to_render, 0);
1350 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1352 if (G_UNLIKELY (!wbuf))
1355 wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1358 gst_buffer_map (buffer, &src, GST_MAP_READ);
1359 gst_buffer_fill (to_render, 0, src.data, src.size);
1360 gst_buffer_unmap (buffer, &src);
1361 } else { /* USE SHM */
1362 /* sink->pool always exists (created in set_caps), but it may not
1363 * be active if upstream is not using it */
1364 if (!gst_buffer_pool_is_active (sink->pool) &&
1365 !gst_buffer_pool_set_active (sink->pool, TRUE))
1366 goto activate_failed;
1367 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1368 if (ret != GST_FLOW_OK)
1370 /* the first time we acquire a buffer,
1371 * we need to attach a wl_buffer on it */
1372 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1373 if (G_UNLIKELY (!wlbuffer)) {
1374 mem = gst_buffer_peek_memory (to_render, 0);
1375 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1377 if (G_UNLIKELY (!wbuf))
1380 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1384 gst_buffer_map (buffer, &src, GST_MAP_READ);
1385 gst_buffer_fill (to_render, 0, src.data, src.size);
1386 gst_buffer_unmap (buffer, &src);
1391 if (sink->USE_TBM && sink->display->is_native_format) {
1392 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1393 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1396 gst_buffer_replace (&sink->last_buffer, buffer);
1399 render_last_buffer (sink);
1403 } else { /* USE SHM or normal format */
1404 /* drop double rendering */
1405 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1406 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1409 gst_buffer_replace (&sink->last_buffer, to_render);
1412 render_last_buffer (sink);
1414 if (buffer != to_render)
1415 gst_buffer_unref (to_render);
1420 #else /* open source */
1422 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1424 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1425 GST_LOG_OBJECT (sink,
1426 "buffer %p has a wl_buffer from our display, " "writing directly",
1428 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1433 struct wl_buffer *wbuf = NULL;
1435 GST_LOG_OBJECT (sink,
1436 "buffer %p does not have a wl_buffer from our " "display, creating it",
1438 mem = gst_buffer_peek_memory (buffer, 0);
1439 if (gst_is_wl_shm_memory (mem)) {
1441 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1445 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1450 /* we don't know how to create a wl_buffer directly from the provided
1451 * memory, so we have to copy the data to a memory that we know how
1454 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1455 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1457 /* sink->pool always exists (created in set_caps), but it may not
1458 * be active if upstream is not using it */
1459 if (!gst_buffer_pool_is_active (sink->pool) &&
1460 !gst_buffer_pool_set_active (sink->pool, TRUE))
1461 goto activate_failed;
1463 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1464 if (ret != GST_FLOW_OK)
1467 /* the first time we acquire a buffer,
1468 * we need to attach a wl_buffer on it */
1469 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1470 if (G_UNLIKELY (!wlbuffer)) {
1471 mem = gst_buffer_peek_memory (to_render, 0);
1472 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1474 if (G_UNLIKELY (!wbuf))
1477 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1480 gst_buffer_map (buffer, &src, GST_MAP_READ);
1481 gst_buffer_fill (to_render, 0, src.data, src.size);
1482 gst_buffer_unmap (buffer, &src);
1485 /* drop double rendering */
1486 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1487 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1491 gst_buffer_replace (&sink->last_buffer, to_render);
1492 render_last_buffer (sink);
1494 if (buffer != to_render)
1495 gst_buffer_unref (to_render);
1499 #endif /* GST_WLSINK_ENHANCEMENT */
1503 GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1504 ("Window has no size set"),
1505 ("Make sure you set the size after calling set_window_handle"));
1506 ret = GST_FLOW_ERROR;
1511 GST_WARNING_OBJECT (sink, "could not create buffer");
1516 GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1517 ret = GST_FLOW_ERROR;
1522 GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1523 ret = GST_FLOW_ERROR;
1528 g_mutex_unlock (&sink->render_lock);
1534 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1536 iface->set_window_handle = gst_wayland_sink_set_window_handle;
1537 iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1538 iface->expose = gst_wayland_sink_expose;
1539 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1540 iface->set_wl_window_wl_surface_id =
1541 gst_wayland_sink_set_wl_window_wl_surface_id;
1545 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1547 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1548 guintptr wl_surface_id)
1550 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1552 g_return_if_fail (sink != NULL);
1554 if (sink->window != NULL) {
1555 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1558 g_mutex_lock (&sink->render_lock);
1559 g_clear_object (&sink->window);
1561 GST_INFO ("wl_surface_id %d %x", (int) wl_surface_id,
1562 (guintptr) wl_surface_id);
1564 if (wl_surface_id) {
1565 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1566 /* we cannot use our own display with an external window handle */
1567 if (G_UNLIKELY (sink->display->own_display)) {
1568 sink->display->wl_surface_id = (int) wl_surface_id;
1569 sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1572 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1573 "ignoring window handle");
1576 gst_wayland_sink_update_window_geometry (sink);
1578 g_mutex_unlock (&sink->render_lock);
1584 gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
1586 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1587 struct wl_surface *surface = (struct wl_surface *) handle;
1590 g_return_if_fail (sink != NULL);
1592 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1593 if (sink->window != NULL) {
1594 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1598 g_mutex_lock (&sink->render_lock);
1600 GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
1603 g_clear_object (&sink->window);
1606 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1607 /* we cannot use our own display with an external window handle */
1608 if (G_UNLIKELY (sink->display->own_display)) {
1609 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
1610 ("Application did not provide a wayland display handle"),
1611 ("Now waylandsink use internal display handle "
1612 "which is created ourselves. Consider providing a "
1613 "display handle from your application with GstContext"));
1614 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1616 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1619 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1620 "ignoring window handle");
1623 g_mutex_unlock (&sink->render_lock);
1628 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1629 gint x, gint y, gint w, gint h)
1631 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1634 g_return_if_fail (sink != NULL);
1636 g_mutex_lock (&sink->render_lock);
1637 if (!sink->window) {
1638 g_mutex_unlock (&sink->render_lock);
1639 GST_WARNING_OBJECT (sink,
1640 "set_render_rectangle called without window, ignoring");
1644 GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1646 gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1648 g_mutex_unlock (&sink->render_lock);
1652 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1654 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1657 g_return_if_fail (sink != NULL);
1659 GST_DEBUG_OBJECT (sink, "expose");
1661 g_mutex_lock (&sink->render_lock);
1662 if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1663 GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1664 render_last_buffer (sink);
1666 g_mutex_unlock (&sink->render_lock);
1670 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1672 iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1673 iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1677 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1679 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1681 g_return_if_fail (sink != NULL);
1683 g_mutex_lock (&sink->render_lock);
1684 if (!sink->window || !sink->window->area_subsurface) {
1685 g_mutex_unlock (&sink->render_lock);
1686 GST_INFO_OBJECT (sink,
1687 "begin_geometry_change called without window, ignoring");
1691 wl_subsurface_set_sync (sink->window->area_subsurface);
1692 g_mutex_unlock (&sink->render_lock);
1696 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1698 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1700 g_return_if_fail (sink != NULL);
1702 g_mutex_lock (&sink->render_lock);
1703 if (!sink->window || !sink->window->area_subsurface) {
1704 g_mutex_unlock (&sink->render_lock);
1705 GST_INFO_OBJECT (sink,
1706 "end_geometry_change called without window, ignoring");
1710 wl_subsurface_set_desync (sink->window->area_subsurface);
1711 g_mutex_unlock (&sink->render_lock);
1715 plugin_init (GstPlugin * plugin)
1717 GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1718 " wayland video sink");
1720 gst_wl_shm_allocator_register ();
1722 return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1723 GST_TYPE_WAYLAND_SINK);
1726 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1729 "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,