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
145 PROP_KEEP_CAMERA_PREVIEW,
148 PROP_DISPLAY_GEOMETRY_METHOD,
156 GST_DEBUG_CATEGORY (gstwayland_debug);
157 #define GST_CAT_DEFAULT gstwayland_debug
159 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
162 GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
163 ("{ BGRx, BGRA, RGBx, xBGR, xRGB, RGBA, ABGR, ARGB, RGB, BGR, "
164 "RGB16, BGR16, YUY2, YVYU, UYVY, AYUV, NV12, NV21, NV16, "
165 #ifdef GST_WLSINK_ENHANCEMENT
168 "YUV9, YVU9, Y41B, I420, YV12, Y42B, v308 }"))
171 static void gst_wayland_sink_get_property (GObject * object,
172 guint prop_id, GValue * value, GParamSpec * pspec);
173 static void gst_wayland_sink_set_property (GObject * object,
174 guint prop_id, const GValue * value, GParamSpec * pspec);
175 static void gst_wayland_sink_finalize (GObject * object);
177 static GstStateChangeReturn gst_wayland_sink_change_state (GstElement * element,
178 GstStateChange transition);
179 static void gst_wayland_sink_set_context (GstElement * element,
180 GstContext * context);
182 static GstCaps *gst_wayland_sink_get_caps (GstBaseSink * bsink,
184 static gboolean gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
185 static gboolean gst_wayland_sink_preroll (GstBaseSink * bsink,
188 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query);
189 static gboolean gst_wayland_sink_render (GstBaseSink * bsink,
192 /* VideoOverlay interface */
193 static void gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface *
195 static void gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay,
198 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
199 guintptr wl_surface_id);
200 static void gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
201 gint x, gint y, gint w, gint h);
202 static void gst_wayland_sink_expose (GstVideoOverlay * overlay);
204 /* WaylandVideo interface */
205 static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface *
207 static void gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video);
208 static void gst_wayland_sink_end_geometry_change (GstWaylandVideo * video);
209 #ifdef GST_WLSINK_ENHANCEMENT
210 static gboolean gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event);
211 static void gst_wayland_sink_update_window_geometry (GstWaylandSink * sink);
212 static void render_last_buffer (GstWaylandSink * sink);
214 #define gst_wayland_sink_parent_class parent_class
215 G_DEFINE_TYPE_WITH_CODE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK,
216 G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
217 gst_wayland_sink_videooverlay_init)
218 G_IMPLEMENT_INTERFACE (GST_TYPE_WAYLAND_VIDEO,
219 gst_wayland_sink_waylandvideo_init));
222 gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
224 GObjectClass *gobject_class;
225 GstElementClass *gstelement_class;
226 GstBaseSinkClass *gstbasesink_class;
229 gobject_class = (GObjectClass *) klass;
230 gstelement_class = (GstElementClass *) klass;
231 gstbasesink_class = (GstBaseSinkClass *) klass;
233 gobject_class->set_property = gst_wayland_sink_set_property;
234 gobject_class->get_property = gst_wayland_sink_get_property;
235 gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_wayland_sink_finalize);
237 gst_element_class_add_pad_template (gstelement_class,
238 gst_static_pad_template_get (&sink_template));
240 gst_element_class_set_static_metadata (gstelement_class,
241 "wayland video sink", "Sink/Video",
242 "Output to wayland surface",
243 "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
244 "George Kiagiadakis <george.kiagiadakis@collabora.com>");
246 gstelement_class->change_state =
247 GST_DEBUG_FUNCPTR (gst_wayland_sink_change_state);
248 gstelement_class->set_context =
249 GST_DEBUG_FUNCPTR (gst_wayland_sink_set_context);
251 gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_get_caps);
252 gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_set_caps);
253 gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_wayland_sink_preroll);
254 gstbasesink_class->propose_allocation =
255 GST_DEBUG_FUNCPTR (gst_wayland_sink_propose_allocation);
256 gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_wayland_sink_render);
257 #ifdef GST_WLSINK_ENHANCEMENT
258 gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_wayland_sink_event);
261 g_object_class_install_property (gobject_class, PROP_DISPLAY,
262 g_param_spec_string ("display", "Wayland Display name", "Wayland "
263 "display name to connect to, if not supplied via the GstContext",
264 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
265 #ifdef GST_WLSINK_ENHANCEMENT
266 g_object_class_install_property (gobject_class, PROP_USE_GAPLESS,
267 g_param_spec_boolean ("use-gapless", "use flush buffer mechanism",
268 "Use gapless playback on GST_STATE_PLAYING state, "
269 "Last tbm buffer is copied and returned to codec immediately when enabled",
270 FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
272 g_object_class_install_property (gobject_class, PROP_KEEP_CAMERA_PREVIEW,
273 g_param_spec_boolean ("keep-camera-preview", "use flush buffer mechanism",
274 "Last tbm buffer is copied and returned to camerasrc immediately "
275 "when state change(PAUSED_TO_READY)", FALSE,
276 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
278 g_object_class_install_property (gobject_class, PROP_USE_TBM,
279 g_param_spec_boolean ("use-tbm", "use tbm buffer",
280 "Use Tizen Buffer Memory insted of Shared memory, "
281 "Memory is alloced by TBM insted of SHM when enabled", TRUE,
282 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
284 g_object_class_install_property (gobject_class, PROP_ROTATE_ANGLE,
285 g_param_spec_enum ("rotate", "Rotate angle",
286 "Rotate angle of display output",
287 GST_TYPE_WAYLANDSINK_ROTATE_ANGLE, DEGREE_0,
288 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
290 g_object_class_install_property (gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
291 g_param_spec_enum ("display-geometry-method", "Display geometry method",
292 "Geometrical method for display",
293 GST_TYPE_WAYLANDSINK_DISPLAY_GEOMETRY_METHOD,
294 DEF_DISPLAY_GEOMETRY_METHOD,
295 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
297 g_object_class_install_property (gobject_class, PROP_ORIENTATION,
298 g_param_spec_enum ("orientation",
299 "Orientation information used for ROI/ZOOM",
300 "Orientation information for display",
301 GST_TYPE_WAYLANDSINK_ROTATE_ANGLE, DEGREE_0,
302 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
304 g_object_class_install_property (gobject_class, PROP_FLIP,
305 g_param_spec_enum ("flip", "Display flip",
307 GST_TYPE_WAYLANDSINK_FLIP, DEF_DISPLAY_FLIP,
308 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
310 g_object_class_install_property (gobject_class, PROP_VISIBLE,
311 g_param_spec_boolean ("visible", "Visible",
312 "Draws screen or blacks out, true means visible, false blacks out",
313 TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
319 __write_rawdata (const char *file, const void *data, unsigned int size)
323 fp = fopen (file, "wb");
327 fwrite ((char *) data, sizeof (char), size, fp);
334 gst_wayland_sink_init (GstWaylandSink * sink)
337 #ifdef GST_WLSINK_ENHANCEMENT
338 sink->use_gapless = FALSE;
339 sink->keep_camera_preview = FALSE;
340 sink->got_eos_event = FALSE;
341 sink->USE_TBM = TRUE;
342 sink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
343 sink->flip = DEF_DISPLAY_FLIP;
344 sink->rotate_angle = DEGREE_0;
345 sink->orientation = DEGREE_0;
346 sink->visible = TRUE;
347 g_mutex_init (&sink->render_flush_buffer_lock);
348 g_cond_init (&sink->render_flush_buffer_cond);
350 g_mutex_init (&sink->display_lock);
351 g_mutex_init (&sink->render_lock);
354 #ifdef GST_WLSINK_ENHANCEMENT
356 gst_wayland_sink_stop_video (GstWaylandSink * sink)
359 g_return_if_fail (sink != NULL);
360 gst_wl_window_render (sink->window, NULL, NULL);
364 gst_wayland_sink_check_use_gapless (GstWaylandSink * sink)
366 g_return_val_if_fail (sink != NULL, FALSE);
367 g_return_val_if_fail (sink->display != NULL, FALSE);
369 if (sink->use_gapless && sink->got_eos_event && sink->USE_TBM
370 && sink->display->is_native_format)
377 gst_wayland_sink_need_to_make_flush_buffer (GstWaylandSink * sink)
379 g_return_val_if_fail (sink != NULL, FALSE);
380 g_return_val_if_fail (sink->display != NULL, FALSE);
382 if ((gst_wayland_sink_check_use_gapless (sink))
383 || sink->keep_camera_preview || sink->display->flush_request) {
384 sink->display->flush_request = TRUE;
391 gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink)
393 GstWlBuffer *wlbuffer;
395 g_return_if_fail (sink != NULL);
396 g_return_if_fail (sink->last_buffer != NULL);
398 GST_DEBUG ("gstbuffer ref count is %d",
399 GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer));
400 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
401 wlbuffer->used_by_compositor = FALSE;
402 /*need to render last buffer, reuse current GstWlBuffer */
403 render_last_buffer (sink);
404 /* ref count is incresed in gst_wl_buffer_attach() of render_last_buffer(),
405 to call gst_wl_buffer_finalize(), we need to decrease buffer ref count.
406 wayland can not release buffer if we attach same buffer,
407 if we use no visible, we need to attach null buffer and wayland can release buffer,
408 so we don't need to below if() code. */
410 gst_buffer_unref (wlbuffer->gstbuffer);
413 #ifdef USE_WL_FLUSH_BUFFER
415 gst_wayland_sink_make_flush_buffer (GstWlDisplay * display,
416 MMVideoBuffer * mm_video_buf)
418 GstWlFlushBuffer *flush_buffer = NULL;
424 g_return_val_if_fail (display != NULL, FALSE);
425 g_return_val_if_fail (mm_video_buf != NULL, FALSE);
427 flush_buffer = (GstWlFlushBuffer *) malloc (sizeof (GstWlFlushBuffer));
429 GST_ERROR ("GstWlFlushBuffer alloc faile");
432 memset (flush_buffer, 0x0, sizeof (GstWlFlushBuffer));
434 display->flush_tbm_bufmgr =
435 wayland_tbm_client_get_bufmgr (display->tbm_client);
436 g_return_val_if_fail (display->flush_tbm_bufmgr != NULL, FALSE);
438 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
439 if (mm_video_buf->handle.bo[i] != NULL) {
444 bo_size = tbm_bo_size (mm_video_buf->handle.bo[i]);
445 GST_LOG ("tbm bo size: %d", bo_size);
447 bo = tbm_bo_alloc (display->flush_tbm_bufmgr, bo_size, TBM_DEVICE_CPU);
449 GST_ERROR ("alloc tbm bo(size:%d) failed: %s", bo_size,
453 GST_INFO ("flush buffer tbm_bo =(%p)", bo);
454 flush_buffer->bo[i] = bo;
455 /* get virtual address */
456 src.ptr = dst.ptr = NULL;
457 /* bo map, we can use tbm_bo_map too. */
458 src = tbm_bo_get_handle (mm_video_buf->handle.bo[i], TBM_DEVICE_CPU);
459 dst = tbm_bo_get_handle (bo, TBM_DEVICE_CPU);
460 if (!src.ptr || !dst.ptr) {
461 GST_ERROR ("get tbm bo handle failed src(%p) dst(%p): %s", src.ptr,
462 dst.ptr, strerror (errno));
463 tbm_bo_unref (mm_video_buf->handle.bo[i]);
468 memcpy (dst.ptr, src.ptr, bo_size);
470 tbm_bo_unmap (mm_video_buf->handle.bo[i]);
474 display->flush_buffer = flush_buffer;
479 gst_wayland_sink_copy_mm_video_buf_info_to_flush (GstWlDisplay * display,
480 MMVideoBuffer * mm_video_buf)
483 g_return_val_if_fail (display != NULL, FALSE);
484 g_return_val_if_fail (mm_video_buf != NULL, FALSE);
487 ret = gst_wayland_sink_make_flush_buffer (display, mm_video_buf);
490 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
491 if (display->flush_buffer->bo[i] != NULL) {
492 display->bo[i] = display->flush_buffer->bo[i];
493 GST_LOG ("bo %p", display->bo[i]);
497 display->plane_size[i] = mm_video_buf->size[i];
498 display->stride_width[i] = mm_video_buf->stride_width[i];
499 display->stride_height[i] = mm_video_buf->stride_height[i];
500 display->native_video_size += display->plane_size[i];
508 gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display,
509 MMVideoBuffer * mm_video_buf)
512 g_return_if_fail (display != NULL);
513 g_return_if_fail (mm_video_buf != NULL);
516 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
517 if (mm_video_buf->handle.bo[i] != NULL) {
518 display->bo[i] = mm_video_buf->handle.bo[i];
522 display->plane_size[i] = mm_video_buf->size[i];
523 display->stride_width[i] = mm_video_buf->stride_width[i];
524 display->stride_height[i] = mm_video_buf->stride_height[i];
525 display->native_video_size += display->plane_size[i];
530 gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink,
533 GstWlDisplay *display;
535 GstMapInfo mem_info = GST_MAP_INFO_INIT;
536 MMVideoBuffer *mm_video_buf = NULL;
538 g_return_val_if_fail (sink != NULL, FALSE);
539 g_return_val_if_fail (buffer != NULL, FALSE);
542 display = sink->display;
543 g_return_val_if_fail (sink->display != NULL, FALSE);
545 mem = gst_buffer_peek_memory (buffer, 1);
546 gst_memory_map (mem, &mem_info, GST_MAP_READ);
547 mm_video_buf = (MMVideoBuffer *) mem_info.data;
548 gst_memory_unmap (mem, &mem_info);
550 if (mm_video_buf == NULL) {
551 GST_WARNING ("mm_video_buf is NULL. Skip rendering");
554 /* assign mm_video_buf info */
555 if (mm_video_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
556 GST_DEBUG ("TBM bo %p %p %p", mm_video_buf->handle.bo[0],
557 mm_video_buf->handle.bo[1], mm_video_buf->handle.bo[2]);
558 display->native_video_size = 0;
559 display->flush_request = mm_video_buf->flush_request;
560 GST_DEBUG ("flush_request value is %d", display->flush_request);
561 #ifdef USE_WL_FLUSH_BUFFER
562 if (gst_wayland_sink_need_to_make_flush_buffer (sink)) {
563 if (!gst_wayland_sink_copy_mm_video_buf_info_to_flush (display,
565 GST_ERROR ("cat not copy mm_video_buf info to flush");
571 gst_wayland_sink_add_mm_video_buf_info (display, mm_video_buf);
573 GST_ERROR ("Buffer type is not TBM");
580 gst_wayland_sink_render_flush_buffer (GstBaseSink * bsink)
582 GstWaylandSink *sink;
584 sink = GST_WAYLAND_SINK (bsink);
586 g_return_if_fail (sink != NULL);
587 g_return_if_fail (sink->last_buffer != NULL);
589 buffer = gst_buffer_copy (sink->last_buffer);
591 g_mutex_lock (&sink->render_flush_buffer_lock);
592 g_cond_wait (&sink->render_flush_buffer_cond,
593 &sink->render_flush_buffer_lock);
595 gst_wayland_sink_render (bsink, buffer);
597 gst_buffer_unref (buffer);
598 g_mutex_unlock (&sink->render_flush_buffer_lock);
602 gst_wayland_sink_gapless_render (GstBaseSink * bsink)
604 g_return_if_fail (bsink != NULL);
606 gst_wayland_sink_render_flush_buffer (bsink);
610 gst_wayland_sink_keep_camera_preview (GstBaseSink * bsink)
612 g_return_if_fail (bsink != NULL);
614 gst_wayland_sink_render_flush_buffer (bsink);
620 gst_wayland_sink_get_property (GObject * object,
621 guint prop_id, GValue * value, GParamSpec * pspec)
623 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
628 GST_OBJECT_LOCK (sink);
629 g_value_set_string (value, sink->display_name);
630 GST_OBJECT_UNLOCK (sink);
632 #ifdef GST_WLSINK_ENHANCEMENT
633 case PROP_USE_GAPLESS:
634 g_value_set_boolean (value, sink->use_gapless);
636 case PROP_KEEP_CAMERA_PREVIEW:
637 g_value_set_boolean (value, sink->keep_camera_preview);
640 g_value_set_boolean (value, sink->USE_TBM);
642 case PROP_ROTATE_ANGLE:
643 g_value_set_enum (value, sink->rotate_angle);
645 case PROP_DISPLAY_GEOMETRY_METHOD:
646 g_value_set_enum (value, sink->display_geometry_method);
648 case PROP_ORIENTATION:
649 g_value_set_enum (value, sink->orientation);
652 g_value_set_enum (value, sink->flip);
655 g_value_set_boolean (value, sink->visible);
659 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
665 gst_wayland_sink_set_property (GObject * object,
666 guint prop_id, const GValue * value, GParamSpec * pspec)
668 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
670 g_mutex_lock (&sink->render_lock);
674 GST_OBJECT_LOCK (sink);
675 sink->display_name = g_value_dup_string (value);
676 GST_OBJECT_UNLOCK (sink);
678 #ifdef GST_WLSINK_ENHANCEMENT
679 case PROP_USE_GAPLESS:
680 sink->use_gapless = g_value_get_boolean (value);
681 GST_LOG ("use gapless is (%d)", sink->use_gapless);
683 case PROP_KEEP_CAMERA_PREVIEW:
684 sink->keep_camera_preview = g_value_get_boolean (value);
685 GST_LOG ("keep_camera_preview (%d)", sink->keep_camera_preview);
688 sink->USE_TBM = g_value_get_boolean (value);
689 GST_LOG ("1:USE TBM 0: USE SHM set(%d)", sink->USE_TBM);
691 case PROP_ROTATE_ANGLE:
692 if (sink->rotate_angle == g_value_get_enum (value))
694 sink->rotate_angle = g_value_get_enum (value);
695 GST_WARNING_OBJECT (sink, "Rotate angle is set (%d)", sink->rotate_angle);
696 sink->video_info_changed = TRUE;
698 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
701 case PROP_DISPLAY_GEOMETRY_METHOD:
702 if (sink->display_geometry_method == g_value_get_enum (value))
704 sink->display_geometry_method = g_value_get_enum (value);
705 GST_WARNING_OBJECT (sink, "Display geometry method is set (%d)",
706 sink->display_geometry_method);
707 sink->video_info_changed = TRUE;
709 gst_wl_window_set_disp_geo_method (sink->window,
710 sink->display_geometry_method);
713 case PROP_ORIENTATION:
714 if (sink->orientation == g_value_get_enum (value))
716 sink->orientation = g_value_get_enum (value);
717 GST_WARNING_OBJECT (sink, "Orientation is set (%d)", sink->orientation);
718 sink->video_info_changed = TRUE;
720 gst_wl_window_set_orientation (sink->window, sink->orientation);
724 if (sink->flip == g_value_get_enum (value))
726 sink->flip = g_value_get_enum (value);
727 GST_WARNING_OBJECT (sink, "flip is set (%d)", sink->flip);
728 sink->video_info_changed = TRUE;
730 gst_wl_window_set_flip (sink->window, sink->flip);
734 if (sink->visible == g_value_get_boolean (value))
736 sink->visible = g_value_get_boolean (value);
737 GST_WARNING_OBJECT (sink, "visible is set (%d)", sink->visible);
738 if (sink->visible && GST_STATE (sink) == GST_STATE_PAUSED) {
739 /* need to attatch last buffer */
740 sink->video_info_changed = TRUE;
741 } else if (!sink->visible && GST_STATE (sink) >= GST_STATE_PAUSED) {
744 gst_wayland_sink_stop_video (sink);
750 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
753 if (sink->video_info_changed && sink->window
754 && GST_STATE (sink) == GST_STATE_PAUSED) {
755 gst_wayland_sink_update_last_buffer_geometry (sink);
757 g_mutex_unlock (&sink->render_lock);
762 gst_wayland_sink_finalize (GObject * object)
764 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
766 GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
768 if (sink->last_buffer)
769 gst_buffer_unref (sink->last_buffer);
771 g_object_unref (sink->display);
773 g_object_unref (sink->window);
775 gst_object_unref (sink->pool);
777 if (sink->display_name)
778 g_free (sink->display_name);
780 g_mutex_clear (&sink->display_lock);
781 g_mutex_clear (&sink->render_lock);
782 #ifdef GST_WLSINK_ENHANCEMENT
783 g_mutex_clear (&sink->render_flush_buffer_lock);
784 g_cond_clear (&sink->render_flush_buffer_cond);
787 G_OBJECT_CLASS (parent_class)->finalize (object);
790 #ifdef GST_WLSINK_ENHANCEMENT
792 gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event)
794 GstWaylandSink *sink;
795 sink = GST_WAYLAND_SINK (bsink);
797 switch (GST_EVENT_TYPE (event)) {
799 GST_LOG ("get EOS event..state is %d", GST_STATE (sink));
800 sink->got_eos_event = TRUE;
801 if (gst_wayland_sink_check_use_gapless (sink)) {
802 gst_wayland_sink_gapless_render (bsink);
803 sink->got_eos_event = FALSE;
805 sink->got_eos_event = FALSE;
810 return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
814 /* must be called with the display_lock */
816 gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
817 GstContext * context)
819 struct wl_display *display;
820 GError *error = NULL;
823 display = gst_wayland_display_handle_context_get_handle (context);
824 sink->display = gst_wl_display_new_existing (display, FALSE, &error);
827 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
828 ("Could not set display handle"),
829 ("Failed to use the external wayland display: '%s'", error->message));
830 g_error_free (error);
832 #ifdef GST_WLSINK_ENHANCEMENT
833 sink->display->USE_TBM = sink->USE_TBM;
838 gst_wayland_sink_find_display (GstWaylandSink * sink)
842 GstContext *context = NULL;
843 GError *error = NULL;
847 g_mutex_lock (&sink->display_lock);
849 if (!sink->display) {
850 /* first query upstream for the needed display handle */
851 query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
852 if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) {
853 gst_query_parse_context (query, &context);
854 gst_wayland_sink_set_display_from_context (sink, context);
856 gst_query_unref (query);
858 if (G_LIKELY (!sink->display)) {
859 /* now ask the application to set the display handle */
860 msg = gst_message_new_need_context (GST_OBJECT_CAST (sink),
861 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
863 g_mutex_unlock (&sink->display_lock);
864 gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
865 /* at this point we expect gst_wayland_sink_set_context
866 * to get called and fill sink->display */
867 g_mutex_lock (&sink->display_lock);
869 if (!sink->display) {
870 /* if the application didn't set a display, let's create it ourselves */
871 GST_OBJECT_LOCK (sink);
872 sink->display = gst_wl_display_new (sink->display_name, &error);
873 GST_OBJECT_UNLOCK (sink);
876 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
877 ("Could not initialise Wayland output"),
878 ("Failed to create GstWlDisplay: '%s'", error->message));
879 g_error_free (error);
882 #ifdef GST_WLSINK_ENHANCEMENT
884 sink->display->USE_TBM = sink->USE_TBM;
890 g_mutex_unlock (&sink->display_lock);
895 static GstStateChangeReturn
896 gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
898 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
899 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
902 switch (transition) {
903 case GST_STATE_CHANGE_NULL_TO_READY:
904 if (!gst_wayland_sink_find_display (sink))
905 return GST_STATE_CHANGE_FAILURE;
911 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
912 if (ret == GST_STATE_CHANGE_FAILURE)
915 switch (transition) {
916 case GST_STATE_CHANGE_PAUSED_TO_READY:
917 #ifdef GST_WLSINK_ENHANCEMENT
918 if (sink->keep_camera_preview) {
920 if (!gst_wl_window_is_toplevel (sink->window)) {
921 GstBaseSink *bsink = GST_BASE_SINK (element);
922 gst_wayland_sink_keep_camera_preview (bsink);
928 gst_buffer_replace (&sink->last_buffer, NULL);
930 if (gst_wl_window_is_toplevel (sink->window)) {
931 GST_DEBUG ("internal window");
932 g_clear_object (&sink->window);
934 /* remove buffer from surface, show nothing */
935 GST_DEBUG ("external window");
936 gst_wl_window_render (sink->window, NULL, NULL);
940 case GST_STATE_CHANGE_READY_TO_NULL:
941 g_mutex_lock (&sink->display_lock);
942 /* If we had a toplevel window, we most likely have our own connection
943 * to the display too, and it is a good idea to disconnect and allow
944 * potentially the application to embed us with GstVideoOverlay
945 * (which requires to re-use the same display connection as the parent
946 * surface). If we didn't have a toplevel window, then the display
947 * connection that we have is definitely shared with the application
948 * and it's better to keep it around (together with the window handle)
949 * to avoid requesting them again from the application if/when we are
950 * restarted (GstVideoOverlay behaves like that in other sinks)
952 if (sink->display && !sink->window) { /* -> the window was toplevel */
953 g_clear_object (&sink->display);
955 g_mutex_unlock (&sink->display_lock);
956 g_clear_object (&sink->pool);
966 gst_wayland_sink_set_context (GstElement * element, GstContext * context)
968 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
971 if (gst_context_has_context_type (context,
972 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
973 g_mutex_lock (&sink->display_lock);
974 if (G_LIKELY (!sink->display))
975 gst_wayland_sink_set_display_from_context (sink, context);
977 GST_WARNING_OBJECT (element, "changing display handle is not supported");
978 #ifdef GST_WLSINK_ENHANCEMENT
979 g_mutex_unlock (&sink->display_lock);
983 g_mutex_unlock (&sink->display_lock);
986 if (GST_ELEMENT_CLASS (parent_class)->set_context)
987 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
991 gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
993 GstWaylandSink *sink;
997 sink = GST_WAYLAND_SINK (bsink);
999 caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
1001 g_mutex_lock (&sink->display_lock);
1003 if (sink->display) {
1004 GValue list = G_VALUE_INIT;
1005 GValue value = G_VALUE_INIT;
1008 #ifdef GST_WLSINK_ENHANCEMENT
1011 enum wl_shm_format fmt;
1013 g_value_init (&list, GST_TYPE_LIST);
1014 g_value_init (&value, G_TYPE_STRING);
1015 #ifdef GST_WLSINK_ENHANCEMENT
1016 if (sink->display->USE_TBM)
1017 formats = sink->display->tbm_formats;
1020 formats = sink->display->formats;
1022 for (i = 0; i < formats->len; i++) {
1023 #ifdef GST_WLSINK_ENHANCEMENT
1024 if (sink->USE_TBM) {
1025 tbm_fmt = g_array_index (formats, uint32_t, i);
1026 g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
1027 gst_value_list_append_value (&list, &value);
1028 /* TBM doesn't support SN12 and ST12. So we add SN12 and ST12 manually as supported format.
1029 * SN12 is same with NV12, ST12 is same with NV12MT
1031 if (tbm_fmt == TBM_FORMAT_NV12) {
1032 g_value_set_string (&value,
1033 gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
1034 gst_value_list_append_value (&list, &value);
1035 } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
1036 g_value_set_string (&value,
1037 gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
1038 gst_value_list_append_value (&list, &value);
1040 } else { /* USE SHM */
1041 fmt = g_array_index (formats, uint32_t, i);
1042 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1043 gst_value_list_append_value (&list, &value);
1045 #else /* open source */
1046 fmt = g_array_index (formats, uint32_t, i);
1047 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1048 gst_value_list_append_value (&list, &value);
1052 caps = gst_caps_make_writable (caps);
1053 gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
1055 GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
1058 g_mutex_unlock (&sink->display_lock);
1061 GstCaps *intersection;
1064 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1065 gst_caps_unref (caps);
1066 caps = intersection;
1073 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
1075 GstWaylandSink *sink;
1076 GstBufferPool *newpool;
1078 #ifdef GST_WLSINK_ENHANCEMENT
1079 uint32_t tbm_format;
1081 enum wl_shm_format format;
1085 GstStructure *structure;
1086 GstWlShmAllocator *self = NULL;
1090 sink = GST_WAYLAND_SINK (bsink);
1092 GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
1094 /* extract info from caps */
1095 if (!gst_video_info_from_caps (&info, caps))
1096 goto invalid_format;
1097 #ifdef GST_WLSINK_ENHANCEMENT
1098 sink->caps = gst_caps_copy (caps);
1099 if (sink->USE_TBM) {
1101 gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
1102 if ((gint) tbm_format == -1)
1103 goto invalid_format;
1105 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1106 if ((gint) format == -1)
1107 goto invalid_format;
1109 #else /* open source */
1110 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1112 if ((gint) format == -1)
1113 goto invalid_format;
1116 /* verify we support the requested format */
1117 #ifdef GST_WLSINK_ENHANCEMENT
1118 if (sink->display->USE_TBM) {
1119 GST_INFO ("USE TBM FORMAT");
1120 formats = sink->display->tbm_formats;
1121 for (i = 0; i < formats->len; i++) {
1122 if (g_array_index (formats, uint32_t, i) == tbm_format)
1125 } else { /* USE SHM */
1126 GST_INFO ("USE SHM FORMAT");
1127 formats = sink->display->formats;
1128 for (i = 0; i < formats->len; i++) {
1129 if (g_array_index (formats, uint32_t, i) == format)
1133 #else /* open source */
1135 formats = sink->display->formats;
1136 for (i = 0; i < formats->len; i++) {
1137 if (g_array_index (formats, uint32_t, i) == format)
1141 if (i >= formats->len)
1142 goto unsupported_format;
1144 #ifdef GST_WLSINK_ENHANCEMENT
1145 if (sink->USE_TBM) {
1146 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1147 GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1148 sink->display->is_native_format = TRUE;
1150 /* store the video info */
1151 sink->video_info = info;
1152 sink->video_info_changed = TRUE;
1154 sink->display->is_native_format = FALSE;
1155 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1156 self->display = sink->display;
1157 /* create a new pool for the new configuration */
1158 newpool = gst_video_buffer_pool_new ();
1162 structure = gst_buffer_pool_get_config (newpool);
1163 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1164 gst_buffer_pool_config_set_allocator (structure,
1165 gst_wl_shm_allocator_get (), NULL);
1166 if (!gst_buffer_pool_set_config (newpool, structure))
1169 /* store the video info */
1170 sink->video_info = info;
1171 sink->video_info_changed = TRUE;
1173 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1174 gst_object_unref (newpool);
1176 } else { /* USE SHM */
1178 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1179 self->display = sink->display;
1181 /* create a new pool for the new configuration */
1182 newpool = gst_video_buffer_pool_new ();
1186 structure = gst_buffer_pool_get_config (newpool);
1187 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1188 gst_buffer_pool_config_set_allocator (structure,
1189 gst_wl_shm_allocator_get (), NULL);
1190 if (!gst_buffer_pool_set_config (newpool, structure))
1193 /* store the video info */
1194 sink->video_info = info;
1195 sink->video_info_changed = TRUE;
1197 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1198 gst_object_unref (newpool);
1200 #else /*open source */
1201 /* create a new pool for the new configuration */
1202 newpool = gst_video_buffer_pool_new ();
1206 structure = gst_buffer_pool_get_config (newpool);
1207 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1208 gst_buffer_pool_config_set_allocator (structure,
1209 gst_wl_shm_allocator_get (), NULL);
1210 if (!gst_buffer_pool_set_config (newpool, structure))
1213 /* store the video info */
1214 sink->video_info = info;
1215 sink->video_info_changed = TRUE;
1217 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1218 gst_object_unref (newpool);
1225 GST_DEBUG_OBJECT (sink,
1226 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1231 #ifdef GST_WLSINK_ENHANCEMENT
1233 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1234 gst_wl_tbm_format_to_string (tbm_format));
1236 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1237 gst_wl_shm_format_to_string (format));
1238 #else /*open source */
1239 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1240 gst_wl_shm_format_to_string (format));
1246 GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1251 GST_DEBUG_OBJECT (bsink, "failed setting config");
1252 gst_object_unref (newpool);
1258 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1260 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1261 GstStructure *config;
1262 guint size, min_bufs, max_bufs;
1263 #ifdef GST_WLSINK_ENHANCEMENT
1268 if (sink->USE_TBM) {
1269 if (sink->display->is_native_format == TRUE)
1272 gst_query_parse_allocation (query, &caps, &need_pool);
1275 GST_DEBUG_OBJECT (bsink, "no caps specified");
1280 config = gst_buffer_pool_get_config (sink->pool);
1281 gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1283 /* we do have a pool for sure (created in set_caps),
1284 * so let's propose it anyway, but also propose the allocator on its own */
1285 gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1286 gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1288 gst_structure_free (config);
1293 static GstFlowReturn
1294 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1297 GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1298 return gst_wayland_sink_render (bsink, buffer);
1302 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1304 GstWaylandSink *sink = data;
1307 GST_LOG ("frame_redraw_cb");
1309 g_atomic_int_set (&sink->redraw_pending, FALSE);
1310 wl_callback_destroy (callback);
1311 #ifdef GST_WLSINK_ENHANCEMENT
1312 if (gst_wayland_sink_check_use_gapless (sink) || sink->keep_camera_preview) {
1313 g_mutex_lock (&sink->render_flush_buffer_lock);
1314 g_cond_signal (&sink->render_flush_buffer_cond);
1315 g_mutex_unlock (&sink->render_flush_buffer_lock);
1320 static const struct wl_callback_listener frame_callback_listener = {
1321 frame_redraw_callback
1324 #ifdef GST_WLSINK_ENHANCEMENT
1326 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1329 g_return_if_fail (sink != NULL);
1330 g_return_if_fail (sink->window != NULL);
1332 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1333 gst_wl_window_set_disp_geo_method (sink->window,
1334 sink->display_geometry_method);
1335 gst_wl_window_set_orientation (sink->window, sink->orientation);
1336 gst_wl_window_set_flip (sink->window, sink->flip);
1339 /* must be called with the render lock */
1341 render_last_buffer (GstWaylandSink * sink)
1343 GstWlBuffer *wlbuffer;
1344 const GstVideoInfo *info = NULL;
1345 struct wl_surface *surface;
1346 struct wl_callback *callback;
1349 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1350 surface = gst_wl_window_get_wl_surface (sink->window);
1352 g_atomic_int_set (&sink->redraw_pending, TRUE);
1353 callback = wl_surface_frame (surface);
1354 /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1355 wl_callback_add_listener (callback, &frame_callback_listener, sink);
1357 if (G_UNLIKELY (sink->video_info_changed)) {
1358 info = &sink->video_info;
1359 sink->video_info_changed = FALSE;
1361 #ifdef GST_WLSINK_ENHANCEMENT
1362 if (sink->last_buffer)
1363 gst_wl_window_render (sink->window, wlbuffer, info);
1365 if (G_UNLIKELY (info)) {
1366 gst_wl_window_set_video_info (sink->window, info);
1370 gst_wl_window_render (sink->window, wlbuffer, info);
1374 static GstFlowReturn
1375 gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
1377 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1378 GstBuffer *to_render;
1379 GstWlBuffer *wlbuffer;
1380 GstFlowReturn ret = GST_FLOW_OK;
1383 g_mutex_lock (&sink->render_lock);
1385 GST_LOG_OBJECT (sink, "render buffer %p", buffer);
1387 if (G_UNLIKELY (!sink->window)) {
1388 /* ask for window handle. Unlock render_lock while doing that because
1389 * set_window_handle & friends will lock it in this context */
1390 g_mutex_unlock (&sink->render_lock);
1391 gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
1392 g_mutex_lock (&sink->render_lock);
1394 if (!sink->window) {
1395 /* if we were not provided a window, create one ourselves */
1397 gst_wl_window_new_toplevel (sink->display, &sink->video_info);
1400 #ifdef GST_WLSINK_ENHANCEMENT
1401 gst_wayland_sink_update_window_geometry (sink);
1402 sink->video_info_changed = TRUE;
1404 /* drop buffers until we get a frame callback */
1405 if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1407 /* make sure that the application has called set_render_rectangle() */
1408 if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1409 goto no_window_size;
1411 #ifdef GST_WLSINK_ENHANCEMENT
1413 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1414 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)
1415 && !(gst_wayland_sink_check_use_gapless (sink))
1416 && !sink->keep_camera_preview) {
1417 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
1418 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1422 GstMapInfo mem_info = GST_MAP_INFO_INIT;
1423 int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1424 mem = gst_buffer_peek_memory (to_render, 0);
1425 gst_memory_map (mem, &mem_info, GST_MAP_READ);
1427 data = mem_info.data;
1429 char file_name[128];
1431 sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1433 ret = __write_rawdata (file_name, data, size);
1435 GST_ERROR ("_write_rawdata() failed");
1437 GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1438 gst_memory_unmap (mem, &mem_info);
1442 struct wl_buffer *wbuf = NULL;
1444 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
1445 mem = gst_buffer_peek_memory (buffer, 0);
1446 if (gst_is_wl_shm_memory (mem)) {
1448 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1451 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add gstbuffer, wlbuffer, display and etc
1454 } else { //buffer is not from our pool and have not wl_buffer
1456 /* we don't know how to create a wl_buffer directly from the provided
1457 * memory, so we have to copy the data to a memory that we know how
1460 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1461 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1464 if (sink->USE_TBM && sink->display->is_native_format) {
1465 /* in case of SN12 or ST12 */
1466 if (!gst_wayland_sink_get_mm_video_buf_info (sink, buffer))
1467 return GST_FLOW_ERROR;
1469 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1470 /* last_buffer from gaplasee have wlbuffer */
1471 if (G_UNLIKELY (!wlbuffer)
1472 || (gst_wayland_sink_check_use_gapless (sink))
1473 || sink->keep_camera_preview) {
1475 gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1477 if (G_UNLIKELY (!wbuf))
1479 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1481 } else if (sink->USE_TBM && !sink->display->is_native_format) {
1483 /* sink->pool always exists (created in set_caps), but it may not
1484 * be active if upstream is not using it */
1485 if (!gst_buffer_pool_is_active (sink->pool)
1486 && !gst_buffer_pool_set_active (sink->pool, TRUE))
1487 goto activate_failed;
1489 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1490 if (ret != GST_FLOW_OK)
1494 //mem = gst_buffer_peek_memory (to_render, 0);
1495 //if (gst_is_wl_shm_memory (mem)) {
1496 GST_INFO ("to_render buffer is our buffer");
1498 /* the first time we acquire a buffer,
1499 * we need to attach a wl_buffer on it */
1500 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1501 if (G_UNLIKELY (!wlbuffer)) {
1502 mem = gst_buffer_peek_memory (to_render, 0);
1503 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1505 if (G_UNLIKELY (!wbuf))
1508 wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1511 gst_buffer_map (buffer, &src, GST_MAP_READ);
1512 gst_buffer_fill (to_render, 0, src.data, src.size);
1513 gst_buffer_unmap (buffer, &src);
1514 } else { /* USE SHM */
1515 /* sink->pool always exists (created in set_caps), but it may not
1516 * be active if upstream is not using it */
1517 if (!gst_buffer_pool_is_active (sink->pool) &&
1518 !gst_buffer_pool_set_active (sink->pool, TRUE))
1519 goto activate_failed;
1520 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1521 if (ret != GST_FLOW_OK)
1523 /* the first time we acquire a buffer,
1524 * we need to attach a wl_buffer on it */
1525 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1526 if (G_UNLIKELY (!wlbuffer)) {
1527 mem = gst_buffer_peek_memory (to_render, 0);
1528 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1530 if (G_UNLIKELY (!wbuf))
1533 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1537 gst_buffer_map (buffer, &src, GST_MAP_READ);
1538 gst_buffer_fill (to_render, 0, src.data, src.size);
1539 gst_buffer_unmap (buffer, &src);
1544 if (sink->USE_TBM && sink->display->is_native_format) {
1545 if ((G_UNLIKELY (buffer == sink->last_buffer)
1546 && !(gst_wayland_sink_check_use_gapless (sink)))
1547 || (G_UNLIKELY (buffer == sink->last_buffer)
1548 && !sink->keep_camera_preview)) {
1549 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1552 gst_buffer_replace (&sink->last_buffer, buffer);
1555 render_last_buffer (sink);
1559 } else { /* USE SHM or normal format */
1560 /* drop double rendering */
1561 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1562 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1565 gst_buffer_replace (&sink->last_buffer, to_render);
1568 render_last_buffer (sink);
1570 if (buffer != to_render)
1571 gst_buffer_unref (to_render);
1576 #else /* open source */
1578 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1580 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1581 GST_LOG_OBJECT (sink,
1582 "buffer %p has a wl_buffer from our display, " "writing directly",
1584 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1589 struct wl_buffer *wbuf = NULL;
1591 GST_LOG_OBJECT (sink,
1592 "buffer %p does not have a wl_buffer from our " "display, creating it",
1594 mem = gst_buffer_peek_memory (buffer, 0);
1595 if (gst_is_wl_shm_memory (mem)) {
1597 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1601 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1606 /* we don't know how to create a wl_buffer directly from the provided
1607 * memory, so we have to copy the data to a memory that we know how
1610 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1611 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1613 /* sink->pool always exists (created in set_caps), but it may not
1614 * be active if upstream is not using it */
1615 if (!gst_buffer_pool_is_active (sink->pool) &&
1616 !gst_buffer_pool_set_active (sink->pool, TRUE))
1617 goto activate_failed;
1619 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1620 if (ret != GST_FLOW_OK)
1623 /* the first time we acquire a buffer,
1624 * we need to attach a wl_buffer on it */
1625 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1626 if (G_UNLIKELY (!wlbuffer)) {
1627 mem = gst_buffer_peek_memory (to_render, 0);
1628 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1630 if (G_UNLIKELY (!wbuf))
1633 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1636 gst_buffer_map (buffer, &src, GST_MAP_READ);
1637 gst_buffer_fill (to_render, 0, src.data, src.size);
1638 gst_buffer_unmap (buffer, &src);
1641 /* drop double rendering */
1642 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1643 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1647 gst_buffer_replace (&sink->last_buffer, to_render);
1648 render_last_buffer (sink);
1650 if (buffer != to_render)
1651 gst_buffer_unref (to_render);
1655 #endif /* GST_WLSINK_ENHANCEMENT */
1659 GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1660 ("Window has no size set"),
1661 ("Make sure you set the size after calling set_window_handle"));
1662 ret = GST_FLOW_ERROR;
1667 GST_WARNING_OBJECT (sink, "could not create buffer");
1672 GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1673 ret = GST_FLOW_ERROR;
1678 GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1679 ret = GST_FLOW_ERROR;
1684 g_mutex_unlock (&sink->render_lock);
1690 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1692 iface->set_window_handle = gst_wayland_sink_set_window_handle;
1693 iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1694 iface->expose = gst_wayland_sink_expose;
1695 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1696 iface->set_wl_window_wl_surface_id =
1697 gst_wayland_sink_set_wl_window_wl_surface_id;
1701 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1703 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1704 guintptr wl_surface_id)
1706 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1708 g_return_if_fail (sink != NULL);
1710 if (sink->window != NULL) {
1711 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1714 g_mutex_lock (&sink->render_lock);
1715 g_clear_object (&sink->window);
1717 GST_INFO ("wl_surface_id %d %x", (int) wl_surface_id,
1718 (guintptr) wl_surface_id);
1720 if (wl_surface_id) {
1721 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1722 /* we cannot use our own display with an external window handle */
1723 if (G_UNLIKELY (sink->display->own_display)) {
1724 sink->display->wl_surface_id = (int) wl_surface_id;
1725 sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1728 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1729 "ignoring window handle");
1732 gst_wayland_sink_update_window_geometry (sink);
1734 g_mutex_unlock (&sink->render_lock);
1740 gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
1742 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1743 struct wl_surface *surface = (struct wl_surface *) handle;
1746 g_return_if_fail (sink != NULL);
1748 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1749 if (sink->window != NULL) {
1750 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1754 g_mutex_lock (&sink->render_lock);
1756 GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
1759 g_clear_object (&sink->window);
1762 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1763 /* we cannot use our own display with an external window handle */
1764 if (G_UNLIKELY (sink->display->own_display)) {
1765 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
1766 ("Application did not provide a wayland display handle"),
1767 ("Now waylandsink use internal display handle "
1768 "which is created ourselves. Consider providing a "
1769 "display handle from your application with GstContext"));
1770 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1772 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1775 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1776 "ignoring window handle");
1779 g_mutex_unlock (&sink->render_lock);
1784 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1785 gint x, gint y, gint w, gint h)
1787 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1790 g_return_if_fail (sink != NULL);
1792 g_mutex_lock (&sink->render_lock);
1793 if (!sink->window) {
1794 g_mutex_unlock (&sink->render_lock);
1795 GST_WARNING_OBJECT (sink,
1796 "set_render_rectangle called without window, ignoring");
1800 GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1802 gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1804 g_mutex_unlock (&sink->render_lock);
1808 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1810 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1813 g_return_if_fail (sink != NULL);
1815 GST_DEBUG_OBJECT (sink, "expose");
1817 g_mutex_lock (&sink->render_lock);
1818 if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1819 GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1820 render_last_buffer (sink);
1822 g_mutex_unlock (&sink->render_lock);
1826 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1828 iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1829 iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1833 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1835 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1837 g_return_if_fail (sink != NULL);
1839 g_mutex_lock (&sink->render_lock);
1840 if (!sink->window || !sink->window->area_subsurface) {
1841 g_mutex_unlock (&sink->render_lock);
1842 GST_INFO_OBJECT (sink,
1843 "begin_geometry_change called without window, ignoring");
1847 wl_subsurface_set_sync (sink->window->area_subsurface);
1848 g_mutex_unlock (&sink->render_lock);
1852 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1854 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1856 g_return_if_fail (sink != NULL);
1858 g_mutex_lock (&sink->render_lock);
1859 if (!sink->window || !sink->window->area_subsurface) {
1860 g_mutex_unlock (&sink->render_lock);
1861 GST_INFO_OBJECT (sink,
1862 "end_geometry_change called without window, ignoring");
1866 wl_subsurface_set_desync (sink->window->area_subsurface);
1867 g_mutex_unlock (&sink->render_lock);
1871 plugin_init (GstPlugin * plugin)
1873 GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1874 " wayland video sink");
1876 gst_wl_shm_allocator_register ();
1878 return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1879 GST_TYPE_WAYLAND_SINK);
1882 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1885 "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,