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
752 sink->display->USE_TBM = sink->USE_TBM;
758 g_mutex_unlock (&sink->display_lock);
763 static GstStateChangeReturn
764 gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
766 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
767 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
770 switch (transition) {
771 case GST_STATE_CHANGE_NULL_TO_READY:
772 if (!gst_wayland_sink_find_display (sink))
773 return GST_STATE_CHANGE_FAILURE;
779 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
780 if (ret == GST_STATE_CHANGE_FAILURE)
783 switch (transition) {
784 case GST_STATE_CHANGE_PAUSED_TO_READY:
785 gst_buffer_replace (&sink->last_buffer, NULL);
787 if (gst_wl_window_is_toplevel (sink->window)) {
788 g_clear_object (&sink->window);
790 /* remove buffer from surface, show nothing */
791 #ifdef USE_WL_FLUSH_BUFFER
792 sink->display->flush_request = 0;
794 gst_wl_window_render (sink->window, NULL, NULL);
798 case GST_STATE_CHANGE_READY_TO_NULL:
799 g_mutex_lock (&sink->display_lock);
800 /* If we had a toplevel window, we most likely have our own connection
801 * to the display too, and it is a good idea to disconnect and allow
802 * potentially the application to embed us with GstVideoOverlay
803 * (which requires to re-use the same display connection as the parent
804 * surface). If we didn't have a toplevel window, then the display
805 * connection that we have is definitely shared with the application
806 * and it's better to keep it around (together with the window handle)
807 * to avoid requesting them again from the application if/when we are
808 * restarted (GstVideoOverlay behaves like that in other sinks)
810 if (sink->display && !sink->window) { /* -> the window was toplevel */
811 g_clear_object (&sink->display);
813 g_mutex_unlock (&sink->display_lock);
814 g_clear_object (&sink->pool);
824 gst_wayland_sink_set_context (GstElement * element, GstContext * context)
826 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
829 if (gst_context_has_context_type (context,
830 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
831 g_mutex_lock (&sink->display_lock);
832 if (G_LIKELY (!sink->display))
833 gst_wayland_sink_set_display_from_context (sink, context);
835 GST_WARNING_OBJECT (element, "changing display handle is not supported");
836 #ifdef GST_WLSINK_ENHANCEMENT
837 g_mutex_unlock (&sink->display_lock);
841 g_mutex_unlock (&sink->display_lock);
844 if (GST_ELEMENT_CLASS (parent_class)->set_context)
845 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
849 gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
851 GstWaylandSink *sink;
855 sink = GST_WAYLAND_SINK (bsink);
857 caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
859 g_mutex_lock (&sink->display_lock);
862 GValue list = G_VALUE_INIT;
863 GValue value = G_VALUE_INIT;
866 #ifdef GST_WLSINK_ENHANCEMENT
869 enum wl_shm_format fmt;
871 g_value_init (&list, GST_TYPE_LIST);
872 g_value_init (&value, G_TYPE_STRING);
873 #ifdef GST_WLSINK_ENHANCEMENT
874 if (sink->display->USE_TBM)
875 formats = sink->display->tbm_formats;
878 formats = sink->display->formats;
880 for (i = 0; i < formats->len; i++) {
881 #ifdef GST_WLSINK_ENHANCEMENT
883 tbm_fmt = g_array_index (formats, uint32_t, i);
884 g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
885 gst_value_list_append_value (&list, &value);
886 /* TBM doesn't support SN12 and ST12. So we add SN12 and ST12 manually as supported format.
887 * SN12 is same with NV12, ST12 is same with NV12MT
889 if (tbm_fmt == TBM_FORMAT_NV12) {
890 g_value_set_string (&value,
891 gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
892 gst_value_list_append_value (&list, &value);
893 } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
894 g_value_set_string (&value,
895 gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
896 gst_value_list_append_value (&list, &value);
898 } else { /* USE SHM */
899 fmt = g_array_index (formats, uint32_t, i);
900 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
901 gst_value_list_append_value (&list, &value);
903 #else /* open source */
904 fmt = g_array_index (formats, uint32_t, i);
905 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
906 gst_value_list_append_value (&list, &value);
910 caps = gst_caps_make_writable (caps);
911 gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
913 GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
916 g_mutex_unlock (&sink->display_lock);
919 GstCaps *intersection;
922 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
923 gst_caps_unref (caps);
931 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
933 GstWaylandSink *sink;
934 GstBufferPool *newpool;
936 #ifdef GST_WLSINK_ENHANCEMENT
939 enum wl_shm_format format;
943 GstStructure *structure;
944 GstWlShmAllocator *self = NULL;
948 sink = GST_WAYLAND_SINK (bsink);
950 GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
952 /* extract info from caps */
953 if (!gst_video_info_from_caps (&info, caps))
955 #ifdef GST_WLSINK_ENHANCEMENT
956 sink->caps = gst_caps_copy (caps);
959 gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
960 if ((gint) tbm_format == -1)
963 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
964 if ((gint) format == -1)
967 #else /* open source */
968 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
970 if ((gint) format == -1)
974 /* verify we support the requested format */
975 #ifdef GST_WLSINK_ENHANCEMENT
976 if (sink->display->USE_TBM) {
977 GST_INFO ("USE TBM FORMAT");
978 formats = sink->display->tbm_formats;
979 for (i = 0; i < formats->len; i++) {
980 if (g_array_index (formats, uint32_t, i) == tbm_format)
983 } else { /* USE SHM */
984 GST_INFO ("USE SHM FORMAT");
985 formats = sink->display->formats;
986 for (i = 0; i < formats->len; i++) {
987 if (g_array_index (formats, uint32_t, i) == format)
991 #else /* open source */
993 formats = sink->display->formats;
994 for (i = 0; i < formats->len; i++) {
995 if (g_array_index (formats, uint32_t, i) == format)
999 if (i >= formats->len)
1000 goto unsupported_format;
1002 #ifdef GST_WLSINK_ENHANCEMENT
1003 if (sink->USE_TBM) {
1004 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1005 GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1006 sink->display->is_native_format = TRUE;
1008 /* store the video info */
1009 sink->video_info = info;
1010 sink->video_info_changed = TRUE;
1012 sink->display->is_native_format = FALSE;
1013 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1014 self->display = sink->display;
1015 /* create a new pool for the new configuration */
1016 newpool = gst_video_buffer_pool_new ();
1020 structure = gst_buffer_pool_get_config (newpool);
1021 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1022 gst_buffer_pool_config_set_allocator (structure,
1023 gst_wl_shm_allocator_get (), NULL);
1024 if (!gst_buffer_pool_set_config (newpool, structure))
1027 /* store the video info */
1028 sink->video_info = info;
1029 sink->video_info_changed = TRUE;
1031 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1032 gst_object_unref (newpool);
1034 } else { /* USE SHM */
1036 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1037 self->display = sink->display;
1039 /* create a new pool for the new configuration */
1040 newpool = gst_video_buffer_pool_new ();
1044 structure = gst_buffer_pool_get_config (newpool);
1045 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1046 gst_buffer_pool_config_set_allocator (structure,
1047 gst_wl_shm_allocator_get (), NULL);
1048 if (!gst_buffer_pool_set_config (newpool, structure))
1051 /* store the video info */
1052 sink->video_info = info;
1053 sink->video_info_changed = TRUE;
1055 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1056 gst_object_unref (newpool);
1058 #else /*open source */
1059 /* create a new pool for the new configuration */
1060 newpool = gst_video_buffer_pool_new ();
1064 structure = gst_buffer_pool_get_config (newpool);
1065 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1066 gst_buffer_pool_config_set_allocator (structure,
1067 gst_wl_shm_allocator_get (), NULL);
1068 if (!gst_buffer_pool_set_config (newpool, structure))
1071 /* store the video info */
1072 sink->video_info = info;
1073 sink->video_info_changed = TRUE;
1075 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1076 gst_object_unref (newpool);
1083 GST_DEBUG_OBJECT (sink,
1084 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1089 #ifdef GST_WLSINK_ENHANCEMENT
1091 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1092 gst_wl_tbm_format_to_string (tbm_format));
1094 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1095 gst_wl_shm_format_to_string (format));
1096 #else /*open source */
1097 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1098 gst_wl_shm_format_to_string (format));
1104 GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1109 GST_DEBUG_OBJECT (bsink, "failed setting config");
1110 gst_object_unref (newpool);
1116 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1118 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1119 GstStructure *config;
1120 guint size, min_bufs, max_bufs;
1121 #ifdef GST_WLSINK_ENHANCEMENT
1126 if (sink->USE_TBM) {
1127 if (sink->display->is_native_format == TRUE)
1130 gst_query_parse_allocation (query, &caps, &need_pool);
1133 GST_DEBUG_OBJECT (bsink, "no caps specified");
1138 config = gst_buffer_pool_get_config (sink->pool);
1139 gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1141 /* we do have a pool for sure (created in set_caps),
1142 * so let's propose it anyway, but also propose the allocator on its own */
1143 gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1144 gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1146 gst_structure_free (config);
1151 static GstFlowReturn
1152 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1155 GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1156 return gst_wayland_sink_render (bsink, buffer);
1160 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1162 GstWaylandSink *sink = data;
1165 GST_LOG ("frame_redraw_cb");
1167 g_atomic_int_set (&sink->redraw_pending, FALSE);
1168 wl_callback_destroy (callback);
1171 static const struct wl_callback_listener frame_callback_listener = {
1172 frame_redraw_callback
1175 #ifdef GST_WLSINK_ENHANCEMENT
1177 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1180 g_return_if_fail (sink != NULL);
1181 g_return_if_fail (sink->window != NULL);
1183 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1184 gst_wl_window_set_disp_geo_method (sink->window,
1185 sink->display_geometry_method);
1186 gst_wl_window_set_orientation (sink->window, sink->orientation);
1187 gst_wl_window_set_flip (sink->window, sink->flip);
1190 /* must be called with the render lock */
1192 render_last_buffer (GstWaylandSink * sink)
1194 GstWlBuffer *wlbuffer;
1195 const GstVideoInfo *info = NULL;
1196 struct wl_surface *surface;
1197 struct wl_callback *callback;
1200 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1201 surface = gst_wl_window_get_wl_surface (sink->window);
1203 g_atomic_int_set (&sink->redraw_pending, TRUE);
1204 callback = wl_surface_frame (surface);
1205 /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1206 wl_callback_add_listener (callback, &frame_callback_listener, sink);
1208 if (G_UNLIKELY (sink->video_info_changed)) {
1209 info = &sink->video_info;
1210 sink->video_info_changed = FALSE;
1212 #ifdef GST_WLSINK_ENHANCEMENT
1213 if (sink->last_buffer)
1214 gst_wl_window_render (sink->window, wlbuffer, info);
1216 if (G_UNLIKELY (info)) {
1217 gst_wl_window_set_video_info (sink->window, info);
1221 gst_wl_window_render (sink->window, wlbuffer, info);
1225 static GstFlowReturn
1226 gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
1228 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1229 GstBuffer *to_render;
1230 GstWlBuffer *wlbuffer;
1231 GstFlowReturn ret = GST_FLOW_OK;
1234 g_mutex_lock (&sink->render_lock);
1236 GST_LOG_OBJECT (sink, "render buffer %p", buffer);
1238 if (G_UNLIKELY (!sink->window)) {
1239 /* ask for window handle. Unlock render_lock while doing that because
1240 * set_window_handle & friends will lock it in this context */
1241 g_mutex_unlock (&sink->render_lock);
1242 gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
1243 g_mutex_lock (&sink->render_lock);
1245 if (!sink->window) {
1246 /* if we were not provided a window, create one ourselves */
1248 gst_wl_window_new_toplevel (sink->display, &sink->video_info);
1251 #ifdef GST_WLSINK_ENHANCEMENT
1252 gst_wayland_sink_update_window_geometry (sink);
1253 sink->video_info_changed = TRUE;
1255 /* drop buffers until we get a frame callback */
1256 if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1258 /* make sure that the application has called set_render_rectangle() */
1259 if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1260 goto no_window_size;
1262 #ifdef GST_WLSINK_ENHANCEMENT
1264 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1265 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1266 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
1267 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1271 GstMapInfo mem_info = GST_MAP_INFO_INIT;
1272 int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1273 mem = gst_buffer_peek_memory (to_render, 0);
1274 gst_memory_map (mem, &mem_info, GST_MAP_READ);
1276 data = mem_info.data;
1278 char file_name[128];
1280 sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1282 ret = __write_rawdata (file_name, data, size);
1284 GST_ERROR ("_write_rawdata() failed");
1286 GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1287 gst_memory_unmap (mem, &mem_info);
1291 struct wl_buffer *wbuf = NULL;
1293 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
1294 mem = gst_buffer_peek_memory (buffer, 0);
1295 if (gst_is_wl_shm_memory (mem)) {
1297 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1300 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add gstbuffer, wlbuffer, display and etc
1303 } else { //buffer is not from our pool and have not wl_buffer
1305 /* we don't know how to create a wl_buffer directly from the provided
1306 * memory, so we have to copy the data to a memory that we know how
1309 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1310 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1313 if (sink->USE_TBM && sink->display->is_native_format) {
1314 /* in case of SN12 or ST12 */
1315 if (!gst_wayland_sink_get_mm_video_buf_info (sink->display, buffer))
1316 return GST_FLOW_ERROR;
1318 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1319 if (G_UNLIKELY (!wlbuffer)) {
1321 gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1323 if (G_UNLIKELY (!wbuf))
1325 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1327 } else if (sink->USE_TBM && !sink->display->is_native_format) {
1329 /* sink->pool always exists (created in set_caps), but it may not
1330 * be active if upstream is not using it */
1331 if (!gst_buffer_pool_is_active (sink->pool)
1332 && !gst_buffer_pool_set_active (sink->pool, TRUE))
1333 goto activate_failed;
1335 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1336 if (ret != GST_FLOW_OK)
1340 //mem = gst_buffer_peek_memory (to_render, 0);
1341 //if (gst_is_wl_shm_memory (mem)) {
1342 GST_INFO ("to_render buffer is our buffer");
1344 /* the first time we acquire a buffer,
1345 * we need to attach a wl_buffer on it */
1346 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1347 if (G_UNLIKELY (!wlbuffer)) {
1348 mem = gst_buffer_peek_memory (to_render, 0);
1349 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1351 if (G_UNLIKELY (!wbuf))
1354 wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1357 gst_buffer_map (buffer, &src, GST_MAP_READ);
1358 gst_buffer_fill (to_render, 0, src.data, src.size);
1359 gst_buffer_unmap (buffer, &src);
1360 } else { /* USE SHM */
1361 /* sink->pool always exists (created in set_caps), but it may not
1362 * be active if upstream is not using it */
1363 if (!gst_buffer_pool_is_active (sink->pool) &&
1364 !gst_buffer_pool_set_active (sink->pool, TRUE))
1365 goto activate_failed;
1366 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1367 if (ret != GST_FLOW_OK)
1369 /* the first time we acquire a buffer,
1370 * we need to attach a wl_buffer on it */
1371 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1372 if (G_UNLIKELY (!wlbuffer)) {
1373 mem = gst_buffer_peek_memory (to_render, 0);
1374 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1376 if (G_UNLIKELY (!wbuf))
1379 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1383 gst_buffer_map (buffer, &src, GST_MAP_READ);
1384 gst_buffer_fill (to_render, 0, src.data, src.size);
1385 gst_buffer_unmap (buffer, &src);
1390 if (sink->USE_TBM && sink->display->is_native_format) {
1391 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1392 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1395 gst_buffer_replace (&sink->last_buffer, buffer);
1398 render_last_buffer (sink);
1402 } else { /* USE SHM or normal format */
1403 /* drop double rendering */
1404 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1405 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1408 gst_buffer_replace (&sink->last_buffer, to_render);
1411 render_last_buffer (sink);
1413 if (buffer != to_render)
1414 gst_buffer_unref (to_render);
1419 #else /* open source */
1421 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1423 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1424 GST_LOG_OBJECT (sink,
1425 "buffer %p has a wl_buffer from our display, " "writing directly",
1427 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1432 struct wl_buffer *wbuf = NULL;
1434 GST_LOG_OBJECT (sink,
1435 "buffer %p does not have a wl_buffer from our " "display, creating it",
1437 mem = gst_buffer_peek_memory (buffer, 0);
1438 if (gst_is_wl_shm_memory (mem)) {
1440 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1444 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1449 /* we don't know how to create a wl_buffer directly from the provided
1450 * memory, so we have to copy the data to a memory that we know how
1453 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1454 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1456 /* sink->pool always exists (created in set_caps), but it may not
1457 * be active if upstream is not using it */
1458 if (!gst_buffer_pool_is_active (sink->pool) &&
1459 !gst_buffer_pool_set_active (sink->pool, TRUE))
1460 goto activate_failed;
1462 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1463 if (ret != GST_FLOW_OK)
1466 /* the first time we acquire a buffer,
1467 * we need to attach a wl_buffer on it */
1468 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1469 if (G_UNLIKELY (!wlbuffer)) {
1470 mem = gst_buffer_peek_memory (to_render, 0);
1471 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1473 if (G_UNLIKELY (!wbuf))
1476 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1479 gst_buffer_map (buffer, &src, GST_MAP_READ);
1480 gst_buffer_fill (to_render, 0, src.data, src.size);
1481 gst_buffer_unmap (buffer, &src);
1484 /* drop double rendering */
1485 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1486 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1490 gst_buffer_replace (&sink->last_buffer, to_render);
1491 render_last_buffer (sink);
1493 if (buffer != to_render)
1494 gst_buffer_unref (to_render);
1498 #endif /* GST_WLSINK_ENHANCEMENT */
1502 GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1503 ("Window has no size set"),
1504 ("Make sure you set the size after calling set_window_handle"));
1505 ret = GST_FLOW_ERROR;
1510 GST_WARNING_OBJECT (sink, "could not create buffer");
1515 GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1516 ret = GST_FLOW_ERROR;
1521 GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1522 ret = GST_FLOW_ERROR;
1527 g_mutex_unlock (&sink->render_lock);
1533 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1535 iface->set_window_handle = gst_wayland_sink_set_window_handle;
1536 iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1537 iface->expose = gst_wayland_sink_expose;
1538 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1539 iface->set_wl_window_wl_surface_id =
1540 gst_wayland_sink_set_wl_window_wl_surface_id;
1544 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1546 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1547 guintptr wl_surface_id)
1549 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1551 g_return_if_fail (sink != NULL);
1553 if (sink->window != NULL) {
1554 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1557 g_mutex_lock (&sink->render_lock);
1558 g_clear_object (&sink->window);
1560 GST_INFO ("wl_surface_id %d %x", (int) wl_surface_id,
1561 (guintptr) wl_surface_id);
1563 if (wl_surface_id) {
1564 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1565 /* we cannot use our own display with an external window handle */
1566 if (G_UNLIKELY (sink->display->own_display)) {
1567 sink->display->wl_surface_id = (int) wl_surface_id;
1568 sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1571 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1572 "ignoring window handle");
1575 gst_wayland_sink_update_window_geometry (sink);
1577 g_mutex_unlock (&sink->render_lock);
1583 gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
1585 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1586 struct wl_surface *surface = (struct wl_surface *) handle;
1589 g_return_if_fail (sink != NULL);
1591 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1592 if (sink->window != NULL) {
1593 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1597 g_mutex_lock (&sink->render_lock);
1599 GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
1602 g_clear_object (&sink->window);
1605 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1606 /* we cannot use our own display with an external window handle */
1607 if (G_UNLIKELY (sink->display->own_display)) {
1608 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
1609 ("Application did not provide a wayland display handle"),
1610 ("Now waylandsink use internal display handle "
1611 "which is created ourselves. Consider providing a "
1612 "display handle from your application with GstContext"));
1613 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1615 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1618 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1619 "ignoring window handle");
1622 g_mutex_unlock (&sink->render_lock);
1627 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1628 gint x, gint y, gint w, gint h)
1630 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1633 g_return_if_fail (sink != NULL);
1635 g_mutex_lock (&sink->render_lock);
1636 if (!sink->window) {
1637 g_mutex_unlock (&sink->render_lock);
1638 GST_WARNING_OBJECT (sink,
1639 "set_render_rectangle called without window, ignoring");
1643 GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1645 gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1647 g_mutex_unlock (&sink->render_lock);
1651 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1653 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1656 g_return_if_fail (sink != NULL);
1658 GST_DEBUG_OBJECT (sink, "expose");
1660 g_mutex_lock (&sink->render_lock);
1661 if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1662 GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1663 render_last_buffer (sink);
1665 g_mutex_unlock (&sink->render_lock);
1669 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1671 iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1672 iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1676 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1678 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1680 g_return_if_fail (sink != NULL);
1682 g_mutex_lock (&sink->render_lock);
1683 if (!sink->window || !sink->window->area_subsurface) {
1684 g_mutex_unlock (&sink->render_lock);
1685 GST_INFO_OBJECT (sink,
1686 "begin_geometry_change called without window, ignoring");
1690 wl_subsurface_set_sync (sink->window->area_subsurface);
1691 g_mutex_unlock (&sink->render_lock);
1695 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1697 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1699 g_return_if_fail (sink != NULL);
1701 g_mutex_lock (&sink->render_lock);
1702 if (!sink->window || !sink->window->area_subsurface) {
1703 g_mutex_unlock (&sink->render_lock);
1704 GST_INFO_OBJECT (sink,
1705 "end_geometry_change called without window, ignoring");
1709 wl_subsurface_set_desync (sink->window->area_subsurface);
1710 g_mutex_unlock (&sink->render_lock);
1714 plugin_init (GstPlugin * plugin)
1716 GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1717 " wayland video sink");
1719 gst_wl_shm_allocator_register ();
1721 return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1722 GST_TYPE_WAYLAND_SINK);
1725 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1728 "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,