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. So we add SN12 manually as supported format.
887 * SN12 is exactly same with NV12.
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);
894 } else { /* USE SHM */
895 fmt = g_array_index (formats, uint32_t, i);
896 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
897 gst_value_list_append_value (&list, &value);
899 #else /* open source */
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);
906 caps = gst_caps_make_writable (caps);
907 gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
909 GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
912 g_mutex_unlock (&sink->display_lock);
915 GstCaps *intersection;
918 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
919 gst_caps_unref (caps);
927 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
929 GstWaylandSink *sink;
930 GstBufferPool *newpool;
932 #ifdef GST_WLSINK_ENHANCEMENT
935 enum wl_shm_format format;
939 GstStructure *structure;
940 GstWlShmAllocator *self = NULL;
944 sink = GST_WAYLAND_SINK (bsink);
946 GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
948 /* extract info from caps */
949 if (!gst_video_info_from_caps (&info, caps))
951 #ifdef GST_WLSINK_ENHANCEMENT
952 sink->caps = gst_caps_copy (caps);
955 gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
956 if ((gint) tbm_format == -1)
959 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
960 if ((gint) format == -1)
963 #else /* open source */
964 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
966 if ((gint) format == -1)
970 /* verify we support the requested format */
971 #ifdef GST_WLSINK_ENHANCEMENT
972 if (sink->display->USE_TBM) {
973 GST_INFO ("USE TBM FORMAT");
974 formats = sink->display->tbm_formats;
975 for (i = 0; i < formats->len; i++) {
976 if (g_array_index (formats, uint32_t, i) == tbm_format)
979 } else { /* USE SHM */
980 GST_INFO ("USE SHM FORMAT");
981 formats = sink->display->formats;
982 for (i = 0; i < formats->len; i++) {
983 if (g_array_index (formats, uint32_t, i) == format)
987 #else /* open source */
989 formats = sink->display->formats;
990 for (i = 0; i < formats->len; i++) {
991 if (g_array_index (formats, uint32_t, i) == format)
995 if (i >= formats->len)
996 goto unsupported_format;
998 #ifdef GST_WLSINK_ENHANCEMENT
1000 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1001 GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1002 sink->display->is_native_format = TRUE;
1004 /* store the video info */
1005 sink->video_info = info;
1006 sink->video_info_changed = TRUE;
1008 sink->display->is_native_format = FALSE;
1009 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1010 self->display = sink->display;
1011 /* create a new pool for the new configuration */
1012 newpool = gst_video_buffer_pool_new ();
1016 structure = gst_buffer_pool_get_config (newpool);
1017 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1018 gst_buffer_pool_config_set_allocator (structure,
1019 gst_wl_shm_allocator_get (), NULL);
1020 if (!gst_buffer_pool_set_config (newpool, structure))
1023 /* store the video info */
1024 sink->video_info = info;
1025 sink->video_info_changed = TRUE;
1027 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1028 gst_object_unref (newpool);
1030 } else { /* USE SHM */
1032 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1033 self->display = sink->display;
1035 /* create a new pool for the new configuration */
1036 newpool = gst_video_buffer_pool_new ();
1040 structure = gst_buffer_pool_get_config (newpool);
1041 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1042 gst_buffer_pool_config_set_allocator (structure,
1043 gst_wl_shm_allocator_get (), NULL);
1044 if (!gst_buffer_pool_set_config (newpool, structure))
1047 /* store the video info */
1048 sink->video_info = info;
1049 sink->video_info_changed = TRUE;
1051 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1052 gst_object_unref (newpool);
1054 #else /*open source */
1055 /* create a new pool for the new configuration */
1056 newpool = gst_video_buffer_pool_new ();
1060 structure = gst_buffer_pool_get_config (newpool);
1061 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1062 gst_buffer_pool_config_set_allocator (structure,
1063 gst_wl_shm_allocator_get (), NULL);
1064 if (!gst_buffer_pool_set_config (newpool, structure))
1067 /* store the video info */
1068 sink->video_info = info;
1069 sink->video_info_changed = TRUE;
1071 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1072 gst_object_unref (newpool);
1079 GST_DEBUG_OBJECT (sink,
1080 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1085 #ifdef GST_WLSINK_ENHANCEMENT
1087 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1088 gst_wl_tbm_format_to_string (tbm_format));
1090 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1091 gst_wl_shm_format_to_string (format));
1092 #else /*open source */
1093 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1094 gst_wl_shm_format_to_string (format));
1100 GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1105 GST_DEBUG_OBJECT (bsink, "failed setting config");
1106 gst_object_unref (newpool);
1112 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1114 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1115 GstStructure *config;
1116 guint size, min_bufs, max_bufs;
1117 #ifdef GST_WLSINK_ENHANCEMENT
1122 if (sink->USE_TBM) {
1123 if (sink->display->is_native_format == TRUE)
1126 gst_query_parse_allocation (query, &caps, &need_pool);
1129 GST_DEBUG_OBJECT (bsink, "no caps specified");
1134 config = gst_buffer_pool_get_config (sink->pool);
1135 gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1137 /* we do have a pool for sure (created in set_caps),
1138 * so let's propose it anyway, but also propose the allocator on its own */
1139 gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1140 gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1142 gst_structure_free (config);
1147 static GstFlowReturn
1148 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1151 GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1152 return gst_wayland_sink_render (bsink, buffer);
1156 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1158 GstWaylandSink *sink = data;
1161 GST_LOG ("frame_redraw_cb");
1163 g_atomic_int_set (&sink->redraw_pending, FALSE);
1164 wl_callback_destroy (callback);
1167 static const struct wl_callback_listener frame_callback_listener = {
1168 frame_redraw_callback
1171 #ifdef GST_WLSINK_ENHANCEMENT
1173 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1176 g_return_if_fail (sink != NULL);
1177 g_return_if_fail (sink->window != NULL);
1179 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1180 gst_wl_window_set_disp_geo_method (sink->window,
1181 sink->display_geometry_method);
1182 gst_wl_window_set_orientation (sink->window, sink->orientation);
1183 gst_wl_window_set_flip (sink->window, sink->flip);
1186 /* must be called with the render lock */
1188 render_last_buffer (GstWaylandSink * sink)
1190 GstWlBuffer *wlbuffer;
1191 const GstVideoInfo *info = NULL;
1192 struct wl_surface *surface;
1193 struct wl_callback *callback;
1196 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1197 surface = gst_wl_window_get_wl_surface (sink->window);
1199 g_atomic_int_set (&sink->redraw_pending, TRUE);
1200 callback = wl_surface_frame (surface);
1201 /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1202 wl_callback_add_listener (callback, &frame_callback_listener, sink);
1204 if (G_UNLIKELY (sink->video_info_changed)) {
1205 info = &sink->video_info;
1206 sink->video_info_changed = FALSE;
1208 #ifdef GST_WLSINK_ENHANCEMENT
1209 if (sink->last_buffer)
1210 gst_wl_window_render (sink->window, wlbuffer, info);
1212 if (G_UNLIKELY (info)) {
1213 gst_wl_window_set_video_info (sink->window, &info);
1217 gst_wl_window_render (sink->window, wlbuffer, info);
1221 static GstFlowReturn
1222 gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
1224 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1225 GstBuffer *to_render;
1226 GstWlBuffer *wlbuffer;
1227 GstFlowReturn ret = GST_FLOW_OK;
1230 g_mutex_lock (&sink->render_lock);
1232 GST_LOG_OBJECT (sink, "render buffer %p", buffer);
1234 if (G_UNLIKELY (!sink->window)) {
1235 /* ask for window handle. Unlock render_lock while doing that because
1236 * set_window_handle & friends will lock it in this context */
1237 g_mutex_unlock (&sink->render_lock);
1238 gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
1239 g_mutex_lock (&sink->render_lock);
1241 if (!sink->window) {
1242 /* if we were not provided a window, create one ourselves */
1244 gst_wl_window_new_toplevel (sink->display, &sink->video_info);
1247 #ifdef GST_WLSINK_ENHANCEMENT
1248 gst_wayland_sink_update_window_geometry (sink);
1249 sink->video_info_changed = TRUE;
1251 /* drop buffers until we get a frame callback */
1252 if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1254 /* make sure that the application has called set_render_rectangle() */
1255 if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1256 goto no_window_size;
1258 #ifdef GST_WLSINK_ENHANCEMENT
1260 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1261 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1262 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
1263 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1267 GstMapInfo mem_info = GST_MAP_INFO_INIT;
1268 int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1269 mem = gst_buffer_peek_memory (to_render, 0);
1270 gst_memory_map (mem, &mem_info, GST_MAP_READ);
1272 data = mem_info.data;
1274 char file_name[128];
1276 sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1278 ret = __write_rawdata (file_name, data, size);
1280 GST_ERROR ("_write_rawdata() failed");
1282 GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1283 gst_memory_unmap (mem, &mem_info);
1287 struct wl_buffer *wbuf = NULL;
1289 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
1290 mem = gst_buffer_peek_memory (buffer, 0);
1291 if (gst_is_wl_shm_memory (mem)) {
1293 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1296 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add gstbuffer, wlbuffer, display and etc
1299 } else { //buffer is not from our pool and have not wl_buffer
1301 /* we don't know how to create a wl_buffer directly from the provided
1302 * memory, so we have to copy the data to a memory that we know how
1305 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1306 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1309 if (sink->USE_TBM && sink->display->is_native_format) {
1310 /* in case of SN12 or ST12 */
1311 if (!gst_wayland_sink_get_mm_video_buf_info (sink->display, buffer))
1312 return GST_FLOW_ERROR;
1314 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1315 if (G_UNLIKELY (!wlbuffer)) {
1317 gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1319 if (G_UNLIKELY (!wbuf))
1321 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1323 } else if (sink->USE_TBM && !sink->display->is_native_format) {
1325 /* sink->pool always exists (created in set_caps), but it may not
1326 * be active if upstream is not using it */
1327 if (!gst_buffer_pool_is_active (sink->pool)
1328 && !gst_buffer_pool_set_active (sink->pool, TRUE))
1329 goto activate_failed;
1331 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1332 if (ret != GST_FLOW_OK)
1336 //mem = gst_buffer_peek_memory (to_render, 0);
1337 //if (gst_is_wl_shm_memory (mem)) {
1338 GST_INFO ("to_render buffer is our buffer");
1340 /* the first time we acquire a buffer,
1341 * we need to attach a wl_buffer on it */
1342 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1343 if (G_UNLIKELY (!wlbuffer)) {
1344 mem = gst_buffer_peek_memory (to_render, 0);
1345 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1347 if (G_UNLIKELY (!wbuf))
1350 wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1353 gst_buffer_map (buffer, &src, GST_MAP_READ);
1354 gst_buffer_fill (to_render, 0, src.data, src.size);
1355 gst_buffer_unmap (buffer, &src);
1356 } else { /* USE SHM */
1357 /* sink->pool always exists (created in set_caps), but it may not
1358 * be active if upstream is not using it */
1359 if (!gst_buffer_pool_is_active (sink->pool) &&
1360 !gst_buffer_pool_set_active (sink->pool, TRUE))
1361 goto activate_failed;
1362 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1363 if (ret != GST_FLOW_OK)
1365 /* the first time we acquire a buffer,
1366 * we need to attach a wl_buffer on it */
1367 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1368 if (G_UNLIKELY (!wlbuffer)) {
1369 mem = gst_buffer_peek_memory (to_render, 0);
1370 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1372 if (G_UNLIKELY (!wbuf))
1375 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1379 gst_buffer_map (buffer, &src, GST_MAP_READ);
1380 gst_buffer_fill (to_render, 0, src.data, src.size);
1381 gst_buffer_unmap (buffer, &src);
1386 if (sink->USE_TBM && sink->display->is_native_format) {
1387 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1388 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1391 gst_buffer_replace (&sink->last_buffer, buffer);
1394 render_last_buffer (sink);
1398 } else { /* USE SHM or normal format */
1399 /* drop double rendering */
1400 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1401 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1404 gst_buffer_replace (&sink->last_buffer, to_render);
1407 render_last_buffer (sink);
1409 if (buffer != to_render)
1410 gst_buffer_unref (to_render);
1415 #else /* open source */
1417 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1419 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1420 GST_LOG_OBJECT (sink,
1421 "buffer %p has a wl_buffer from our display, " "writing directly",
1423 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1428 struct wl_buffer *wbuf = NULL;
1430 GST_LOG_OBJECT (sink,
1431 "buffer %p does not have a wl_buffer from our " "display, creating it",
1433 mem = gst_buffer_peek_memory (buffer, 0);
1434 if (gst_is_wl_shm_memory (mem)) {
1436 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1440 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1445 /* we don't know how to create a wl_buffer directly from the provided
1446 * memory, so we have to copy the data to a memory that we know how
1449 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1450 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1452 /* sink->pool always exists (created in set_caps), but it may not
1453 * be active if upstream is not using it */
1454 if (!gst_buffer_pool_is_active (sink->pool) &&
1455 !gst_buffer_pool_set_active (sink->pool, TRUE))
1456 goto activate_failed;
1458 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1459 if (ret != GST_FLOW_OK)
1462 /* the first time we acquire a buffer,
1463 * we need to attach a wl_buffer on it */
1464 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1465 if (G_UNLIKELY (!wlbuffer)) {
1466 mem = gst_buffer_peek_memory (to_render, 0);
1467 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1469 if (G_UNLIKELY (!wbuf))
1472 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1475 gst_buffer_map (buffer, &src, GST_MAP_READ);
1476 gst_buffer_fill (to_render, 0, src.data, src.size);
1477 gst_buffer_unmap (buffer, &src);
1480 /* drop double rendering */
1481 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1482 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1486 gst_buffer_replace (&sink->last_buffer, to_render);
1487 render_last_buffer (sink);
1489 if (buffer != to_render)
1490 gst_buffer_unref (to_render);
1494 #endif /* GST_WLSINK_ENHANCEMENT */
1498 GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1499 ("Window has no size set"),
1500 ("Make sure you set the size after calling set_window_handle"));
1501 ret = GST_FLOW_ERROR;
1506 GST_WARNING_OBJECT (sink, "could not create buffer");
1511 GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1512 ret = GST_FLOW_ERROR;
1517 GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1518 ret = GST_FLOW_ERROR;
1523 g_mutex_unlock (&sink->render_lock);
1529 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1531 iface->set_window_handle = gst_wayland_sink_set_window_handle;
1532 iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1533 iface->expose = gst_wayland_sink_expose;
1534 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1535 iface->set_wl_window_wl_surface_id =
1536 gst_wayland_sink_set_wl_window_wl_surface_id;
1540 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1542 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1543 guintptr wl_surface_id)
1545 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1547 g_return_if_fail (sink != NULL);
1549 if (sink->window != NULL) {
1550 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1553 g_mutex_lock (&sink->render_lock);
1554 g_clear_object (&sink->window);
1556 GST_INFO ("wl_surface_id %d %p", (int) wl_surface_id,
1557 (guintptr) wl_surface_id);
1559 if (wl_surface_id) {
1560 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1561 /* we cannot use our own display with an external window handle */
1562 if (G_UNLIKELY (sink->display->own_display)) {
1563 sink->display->wl_surface_id = (int) wl_surface_id;
1564 sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1567 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1568 "ignoring window handle");
1571 gst_wayland_sink_update_window_geometry (sink);
1573 g_mutex_unlock (&sink->render_lock);
1579 gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
1581 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1582 struct wl_surface *surface = (struct wl_surface *) handle;
1585 g_return_if_fail (sink != NULL);
1587 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1588 if (sink->window != NULL) {
1589 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1593 g_mutex_lock (&sink->render_lock);
1595 GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
1598 g_clear_object (&sink->window);
1601 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1602 /* we cannot use our own display with an external window handle */
1603 if (G_UNLIKELY (sink->display->own_display)) {
1604 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
1605 ("Application did not provide a wayland display handle"),
1606 ("Now waylandsink use internal display handle "
1607 "which is created ourselves. Consider providing a "
1608 "display handle from your application with GstContext"));
1609 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1611 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1614 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1615 "ignoring window handle");
1618 g_mutex_unlock (&sink->render_lock);
1623 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1624 gint x, gint y, gint w, gint h)
1626 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1629 g_return_if_fail (sink != NULL);
1631 g_mutex_lock (&sink->render_lock);
1632 if (!sink->window) {
1633 g_mutex_unlock (&sink->render_lock);
1634 GST_WARNING_OBJECT (sink,
1635 "set_render_rectangle called without window, ignoring");
1639 GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1641 gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1643 g_mutex_unlock (&sink->render_lock);
1647 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1649 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1652 g_return_if_fail (sink != NULL);
1654 GST_DEBUG_OBJECT (sink, "expose");
1656 g_mutex_lock (&sink->render_lock);
1657 if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1658 GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1659 render_last_buffer (sink);
1661 g_mutex_unlock (&sink->render_lock);
1665 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1667 iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1668 iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1672 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1674 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1676 g_return_if_fail (sink != NULL);
1678 g_mutex_lock (&sink->render_lock);
1679 if (!sink->window || !sink->window->area_subsurface) {
1680 g_mutex_unlock (&sink->render_lock);
1681 GST_INFO_OBJECT (sink,
1682 "begin_geometry_change called without window, ignoring");
1686 wl_subsurface_set_sync (sink->window->area_subsurface);
1687 g_mutex_unlock (&sink->render_lock);
1691 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1693 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1695 g_return_if_fail (sink != NULL);
1697 g_mutex_lock (&sink->render_lock);
1698 if (!sink->window || !sink->window->area_subsurface) {
1699 g_mutex_unlock (&sink->render_lock);
1700 GST_INFO_OBJECT (sink,
1701 "end_geometry_change called without window, ignoring");
1705 wl_subsurface_set_desync (sink->window->area_subsurface);
1706 g_mutex_unlock (&sink->render_lock);
1710 plugin_init (GstPlugin * plugin)
1712 GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1713 " wayland video sink");
1715 gst_wl_shm_allocator_register ();
1717 return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1718 GST_TYPE_WAYLAND_SINK);
1721 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1724 "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,