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 g_return_if_fail (wlbuffer != NULL);
402 wlbuffer->used_by_compositor = FALSE;
403 /*need to render last buffer, reuse current GstWlBuffer */
404 render_last_buffer (sink);
405 /* ref count is incresed in gst_wl_buffer_attach() of render_last_buffer(),
406 to call gst_wl_buffer_finalize(), we need to decrease buffer ref count.
407 wayland can not release buffer if we attach same buffer,
408 if we use no visible, we need to attach null buffer and wayland can release buffer,
409 so we don't need to below if() code. */
411 gst_buffer_unref (wlbuffer->gstbuffer);
414 #ifdef USE_WL_FLUSH_BUFFER
416 gst_wayland_sink_make_flush_buffer (GstWlDisplay * display,
417 MMVideoBuffer * mm_video_buf)
419 GstWlFlushBuffer *flush_buffer = NULL;
425 g_return_val_if_fail (display != NULL, FALSE);
426 g_return_val_if_fail (mm_video_buf != NULL, FALSE);
428 flush_buffer = (GstWlFlushBuffer *) malloc (sizeof (GstWlFlushBuffer));
430 GST_ERROR ("GstWlFlushBuffer alloc faile");
433 memset (flush_buffer, 0x0, sizeof (GstWlFlushBuffer));
435 display->flush_tbm_bufmgr =
436 wayland_tbm_client_get_bufmgr (display->tbm_client);
437 g_return_val_if_fail (display->flush_tbm_bufmgr != NULL, FALSE);
439 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
440 if (mm_video_buf->handle.bo[i] != NULL) {
445 bo_size = tbm_bo_size (mm_video_buf->handle.bo[i]);
446 GST_LOG ("tbm bo size: %d", bo_size);
448 bo = tbm_bo_alloc (display->flush_tbm_bufmgr, bo_size, TBM_DEVICE_CPU);
450 GST_ERROR ("alloc tbm bo(size:%d) failed: %s", bo_size,
454 GST_INFO ("flush buffer tbm_bo =(%p)", bo);
455 flush_buffer->bo[i] = bo;
456 /* get virtual address */
457 src.ptr = dst.ptr = NULL;
458 /* bo map, we can use tbm_bo_map too. */
459 src = tbm_bo_get_handle (mm_video_buf->handle.bo[i], TBM_DEVICE_CPU);
460 dst = tbm_bo_get_handle (bo, TBM_DEVICE_CPU);
461 if (!src.ptr || !dst.ptr) {
462 GST_ERROR ("get tbm bo handle failed src(%p) dst(%p): %s", src.ptr,
463 dst.ptr, strerror (errno));
464 tbm_bo_unref (mm_video_buf->handle.bo[i]);
469 memcpy (dst.ptr, src.ptr, bo_size);
471 tbm_bo_unmap (mm_video_buf->handle.bo[i]);
475 display->flush_buffer = flush_buffer;
480 gst_wayland_sink_copy_mm_video_buf_info_to_flush (GstWlDisplay * display,
481 MMVideoBuffer * mm_video_buf)
484 g_return_val_if_fail (display != NULL, FALSE);
485 g_return_val_if_fail (mm_video_buf != NULL, FALSE);
488 ret = gst_wayland_sink_make_flush_buffer (display, mm_video_buf);
491 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
492 if (display->flush_buffer->bo[i] != NULL) {
493 display->bo[i] = display->flush_buffer->bo[i];
494 GST_LOG ("bo %p", display->bo[i]);
498 display->plane_size[i] = mm_video_buf->size[i];
499 display->stride_width[i] = mm_video_buf->stride_width[i];
500 display->stride_height[i] = mm_video_buf->stride_height[i];
501 display->native_video_size += display->plane_size[i];
509 gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display,
510 MMVideoBuffer * mm_video_buf)
513 g_return_if_fail (display != NULL);
514 g_return_if_fail (mm_video_buf != NULL);
517 for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
518 if (mm_video_buf->handle.bo[i] != NULL) {
519 display->bo[i] = mm_video_buf->handle.bo[i];
523 display->plane_size[i] = mm_video_buf->size[i];
524 display->stride_width[i] = mm_video_buf->stride_width[i];
525 display->stride_height[i] = mm_video_buf->stride_height[i];
526 display->native_video_size += display->plane_size[i];
531 gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink,
534 GstWlDisplay *display;
536 GstMapInfo mem_info = GST_MAP_INFO_INIT;
537 MMVideoBuffer *mm_video_buf = NULL;
539 g_return_val_if_fail (sink != NULL, FALSE);
540 g_return_val_if_fail (buffer != NULL, FALSE);
543 display = sink->display;
544 g_return_val_if_fail (sink->display != NULL, FALSE);
546 mem = gst_buffer_peek_memory (buffer, 1);
547 gst_memory_map (mem, &mem_info, GST_MAP_READ);
548 mm_video_buf = (MMVideoBuffer *) mem_info.data;
549 gst_memory_unmap (mem, &mem_info);
551 if (mm_video_buf == NULL) {
552 GST_WARNING ("mm_video_buf is NULL. Skip rendering");
555 /* assign mm_video_buf info */
556 if (mm_video_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
557 GST_DEBUG ("TBM bo %p %p %p", mm_video_buf->handle.bo[0],
558 mm_video_buf->handle.bo[1], mm_video_buf->handle.bo[2]);
559 display->native_video_size = 0;
560 display->flush_request = mm_video_buf->flush_request;
561 GST_DEBUG ("flush_request value is %d", display->flush_request);
562 #ifdef USE_WL_FLUSH_BUFFER
563 if (gst_wayland_sink_need_to_make_flush_buffer (sink)) {
564 if (!gst_wayland_sink_copy_mm_video_buf_info_to_flush (display,
566 GST_ERROR ("cat not copy mm_video_buf info to flush");
572 gst_wayland_sink_add_mm_video_buf_info (display, mm_video_buf);
574 GST_ERROR ("Buffer type is not TBM");
581 gst_wayland_sink_render_flush_buffer (GstBaseSink * bsink)
583 GstWaylandSink *sink;
585 sink = GST_WAYLAND_SINK (bsink);
587 g_return_if_fail (sink != NULL);
588 g_return_if_fail (sink->last_buffer != NULL);
590 buffer = gst_buffer_copy (sink->last_buffer);
592 g_mutex_lock (&sink->render_flush_buffer_lock);
593 g_cond_wait (&sink->render_flush_buffer_cond,
594 &sink->render_flush_buffer_lock);
596 gst_wayland_sink_render (bsink, buffer);
598 gst_buffer_unref (buffer);
599 g_mutex_unlock (&sink->render_flush_buffer_lock);
603 gst_wayland_sink_gapless_render (GstBaseSink * bsink)
605 g_return_if_fail (bsink != NULL);
607 gst_wayland_sink_render_flush_buffer (bsink);
611 gst_wayland_sink_keep_camera_preview (GstBaseSink * bsink)
613 g_return_if_fail (bsink != NULL);
615 gst_wayland_sink_render_flush_buffer (bsink);
621 gst_wayland_sink_get_property (GObject * object,
622 guint prop_id, GValue * value, GParamSpec * pspec)
624 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
629 GST_OBJECT_LOCK (sink);
630 g_value_set_string (value, sink->display_name);
631 GST_OBJECT_UNLOCK (sink);
633 #ifdef GST_WLSINK_ENHANCEMENT
634 case PROP_USE_GAPLESS:
635 g_value_set_boolean (value, sink->use_gapless);
637 case PROP_KEEP_CAMERA_PREVIEW:
638 g_value_set_boolean (value, sink->keep_camera_preview);
641 g_value_set_boolean (value, sink->USE_TBM);
643 case PROP_ROTATE_ANGLE:
644 g_value_set_enum (value, sink->rotate_angle);
646 case PROP_DISPLAY_GEOMETRY_METHOD:
647 g_value_set_enum (value, sink->display_geometry_method);
649 case PROP_ORIENTATION:
650 g_value_set_enum (value, sink->orientation);
653 g_value_set_enum (value, sink->flip);
656 g_value_set_boolean (value, sink->visible);
660 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
666 gst_wayland_sink_set_property (GObject * object,
667 guint prop_id, const GValue * value, GParamSpec * pspec)
669 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
671 g_mutex_lock (&sink->render_lock);
675 GST_OBJECT_LOCK (sink);
676 sink->display_name = g_value_dup_string (value);
677 GST_OBJECT_UNLOCK (sink);
679 #ifdef GST_WLSINK_ENHANCEMENT
680 case PROP_USE_GAPLESS:
681 sink->use_gapless = g_value_get_boolean (value);
682 GST_LOG ("use gapless is (%d)", sink->use_gapless);
684 case PROP_KEEP_CAMERA_PREVIEW:
685 sink->keep_camera_preview = g_value_get_boolean (value);
686 GST_LOG ("keep_camera_preview (%d)", sink->keep_camera_preview);
689 sink->USE_TBM = g_value_get_boolean (value);
690 GST_LOG ("1:USE TBM 0: USE SHM set(%d)", sink->USE_TBM);
692 case PROP_ROTATE_ANGLE:
693 if (sink->rotate_angle == g_value_get_enum (value))
695 sink->rotate_angle = g_value_get_enum (value);
696 GST_WARNING_OBJECT (sink, "Rotate angle is set (%d)", sink->rotate_angle);
697 sink->video_info_changed = TRUE;
699 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
702 case PROP_DISPLAY_GEOMETRY_METHOD:
703 if (sink->display_geometry_method == g_value_get_enum (value))
705 sink->display_geometry_method = g_value_get_enum (value);
706 GST_WARNING_OBJECT (sink, "Display geometry method is set (%d)",
707 sink->display_geometry_method);
708 sink->video_info_changed = TRUE;
710 gst_wl_window_set_disp_geo_method (sink->window,
711 sink->display_geometry_method);
714 case PROP_ORIENTATION:
715 if (sink->orientation == g_value_get_enum (value))
717 sink->orientation = g_value_get_enum (value);
718 GST_WARNING_OBJECT (sink, "Orientation is set (%d)", sink->orientation);
719 sink->video_info_changed = TRUE;
721 gst_wl_window_set_orientation (sink->window, sink->orientation);
725 if (sink->flip == g_value_get_enum (value))
727 sink->flip = g_value_get_enum (value);
728 GST_WARNING_OBJECT (sink, "flip is set (%d)", sink->flip);
729 sink->video_info_changed = TRUE;
731 gst_wl_window_set_flip (sink->window, sink->flip);
735 if (sink->visible == g_value_get_boolean (value))
737 sink->visible = g_value_get_boolean (value);
738 GST_WARNING_OBJECT (sink, "visible is set (%d)", sink->visible);
739 if (sink->visible && GST_STATE (sink) == GST_STATE_PAUSED) {
740 /* need to attatch last buffer */
741 sink->video_info_changed = TRUE;
742 } else if (!sink->visible && GST_STATE (sink) >= GST_STATE_PAUSED) {
745 gst_wayland_sink_stop_video (sink);
751 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
754 if (sink->video_info_changed && sink->window
755 && GST_STATE (sink) == GST_STATE_PAUSED) {
756 gst_wayland_sink_update_last_buffer_geometry (sink);
758 g_mutex_unlock (&sink->render_lock);
763 gst_wayland_sink_finalize (GObject * object)
765 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
767 GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
769 if (sink->last_buffer)
770 gst_buffer_unref (sink->last_buffer);
772 g_object_unref (sink->display);
774 g_object_unref (sink->window);
776 gst_object_unref (sink->pool);
778 if (sink->display_name)
779 g_free (sink->display_name);
781 g_mutex_clear (&sink->display_lock);
782 g_mutex_clear (&sink->render_lock);
783 #ifdef GST_WLSINK_ENHANCEMENT
784 g_mutex_clear (&sink->render_flush_buffer_lock);
785 g_cond_clear (&sink->render_flush_buffer_cond);
788 G_OBJECT_CLASS (parent_class)->finalize (object);
791 #ifdef GST_WLSINK_ENHANCEMENT
793 gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event)
795 GstWaylandSink *sink;
796 sink = GST_WAYLAND_SINK (bsink);
798 switch (GST_EVENT_TYPE (event)) {
800 GST_LOG ("get EOS event..state is %d", GST_STATE (sink));
801 sink->got_eos_event = TRUE;
802 if (gst_wayland_sink_check_use_gapless (sink)) {
803 gst_wayland_sink_gapless_render (bsink);
804 sink->got_eos_event = FALSE;
806 sink->got_eos_event = FALSE;
811 return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
815 /* must be called with the display_lock */
817 gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
818 GstContext * context)
820 struct wl_display *display;
821 GError *error = NULL;
824 display = gst_wayland_display_handle_context_get_handle (context);
825 sink->display = gst_wl_display_new_existing (display, FALSE, &error);
828 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
829 ("Could not set display handle"),
830 ("Failed to use the external wayland display: '%s'", error->message));
831 g_error_free (error);
833 #ifdef GST_WLSINK_ENHANCEMENT
834 sink->display->USE_TBM = sink->USE_TBM;
839 gst_wayland_sink_find_display (GstWaylandSink * sink)
843 GstContext *context = NULL;
844 GError *error = NULL;
848 g_mutex_lock (&sink->display_lock);
850 if (!sink->display) {
851 /* first query upstream for the needed display handle */
852 query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
853 if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) {
854 gst_query_parse_context (query, &context);
855 gst_wayland_sink_set_display_from_context (sink, context);
857 gst_query_unref (query);
859 if (G_LIKELY (!sink->display)) {
860 /* now ask the application to set the display handle */
861 msg = gst_message_new_need_context (GST_OBJECT_CAST (sink),
862 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
864 g_mutex_unlock (&sink->display_lock);
865 gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
866 /* at this point we expect gst_wayland_sink_set_context
867 * to get called and fill sink->display */
868 g_mutex_lock (&sink->display_lock);
870 if (!sink->display) {
871 /* if the application didn't set a display, let's create it ourselves */
872 GST_OBJECT_LOCK (sink);
873 sink->display = gst_wl_display_new (sink->display_name, &error);
874 GST_OBJECT_UNLOCK (sink);
877 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
878 ("Could not initialise Wayland output"),
879 ("Failed to create GstWlDisplay: '%s'", error->message));
880 g_error_free (error);
883 #ifdef GST_WLSINK_ENHANCEMENT
885 sink->display->USE_TBM = sink->USE_TBM;
891 g_mutex_unlock (&sink->display_lock);
896 static GstStateChangeReturn
897 gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
899 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
900 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
903 switch (transition) {
904 case GST_STATE_CHANGE_NULL_TO_READY:
905 if (!gst_wayland_sink_find_display (sink))
906 return GST_STATE_CHANGE_FAILURE;
912 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
913 if (ret == GST_STATE_CHANGE_FAILURE)
916 switch (transition) {
917 case GST_STATE_CHANGE_PAUSED_TO_READY:
918 #ifdef GST_WLSINK_ENHANCEMENT
919 if (sink->keep_camera_preview) {
921 if (!gst_wl_window_is_toplevel (sink->window)) {
922 GstBaseSink *bsink = GST_BASE_SINK (element);
923 gst_wayland_sink_keep_camera_preview (bsink);
929 gst_buffer_replace (&sink->last_buffer, NULL);
931 if (gst_wl_window_is_toplevel (sink->window)) {
932 GST_DEBUG ("internal window");
933 g_clear_object (&sink->window);
935 /* remove buffer from surface, show nothing */
936 GST_DEBUG ("external window");
937 gst_wl_window_render (sink->window, NULL, NULL);
941 case GST_STATE_CHANGE_READY_TO_NULL:
942 g_mutex_lock (&sink->display_lock);
943 /* If we had a toplevel window, we most likely have our own connection
944 * to the display too, and it is a good idea to disconnect and allow
945 * potentially the application to embed us with GstVideoOverlay
946 * (which requires to re-use the same display connection as the parent
947 * surface). If we didn't have a toplevel window, then the display
948 * connection that we have is definitely shared with the application
949 * and it's better to keep it around (together with the window handle)
950 * to avoid requesting them again from the application if/when we are
951 * restarted (GstVideoOverlay behaves like that in other sinks)
953 if (sink->display && !sink->window) { /* -> the window was toplevel */
954 g_clear_object (&sink->display);
956 g_mutex_unlock (&sink->display_lock);
957 g_clear_object (&sink->pool);
967 gst_wayland_sink_set_context (GstElement * element, GstContext * context)
969 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
972 if (gst_context_has_context_type (context,
973 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
974 g_mutex_lock (&sink->display_lock);
975 if (G_LIKELY (!sink->display))
976 gst_wayland_sink_set_display_from_context (sink, context);
978 GST_WARNING_OBJECT (element, "changing display handle is not supported");
979 #ifdef GST_WLSINK_ENHANCEMENT
980 g_mutex_unlock (&sink->display_lock);
984 g_mutex_unlock (&sink->display_lock);
987 if (GST_ELEMENT_CLASS (parent_class)->set_context)
988 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
992 gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
994 GstWaylandSink *sink;
998 sink = GST_WAYLAND_SINK (bsink);
1000 caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
1002 g_mutex_lock (&sink->display_lock);
1004 if (sink->display) {
1005 GValue list = G_VALUE_INIT;
1006 GValue value = G_VALUE_INIT;
1009 #ifdef GST_WLSINK_ENHANCEMENT
1012 enum wl_shm_format fmt;
1014 g_value_init (&list, GST_TYPE_LIST);
1015 g_value_init (&value, G_TYPE_STRING);
1016 #ifdef GST_WLSINK_ENHANCEMENT
1017 if (sink->display->USE_TBM)
1018 formats = sink->display->tbm_formats;
1021 formats = sink->display->formats;
1023 for (i = 0; i < formats->len; i++) {
1024 #ifdef GST_WLSINK_ENHANCEMENT
1025 if (sink->USE_TBM) {
1026 tbm_fmt = g_array_index (formats, uint32_t, i);
1027 g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
1028 gst_value_list_append_value (&list, &value);
1029 /* TBM doesn't support SN12 and ST12. So we add SN12 and ST12 manually as supported format.
1030 * SN12 is same with NV12, ST12 is same with NV12MT
1032 if (tbm_fmt == TBM_FORMAT_NV12) {
1033 g_value_set_string (&value,
1034 gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
1035 gst_value_list_append_value (&list, &value);
1036 } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
1037 g_value_set_string (&value,
1038 gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
1039 gst_value_list_append_value (&list, &value);
1041 } else { /* USE SHM */
1042 fmt = g_array_index (formats, uint32_t, i);
1043 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1044 gst_value_list_append_value (&list, &value);
1046 #else /* open source */
1047 fmt = g_array_index (formats, uint32_t, i);
1048 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1049 gst_value_list_append_value (&list, &value);
1053 caps = gst_caps_make_writable (caps);
1054 gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
1056 GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
1057 g_value_unset (&value);
1058 g_value_unset (&list);
1062 g_mutex_unlock (&sink->display_lock);
1065 GstCaps *intersection;
1068 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1069 gst_caps_unref (caps);
1070 caps = intersection;
1077 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
1079 GstWaylandSink *sink;
1080 GstBufferPool *newpool;
1082 #ifdef GST_WLSINK_ENHANCEMENT
1083 uint32_t tbm_format;
1085 enum wl_shm_format format;
1089 GstStructure *structure;
1090 GstWlShmAllocator *self = NULL;
1094 sink = GST_WAYLAND_SINK (bsink);
1096 GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
1098 /* extract info from caps */
1099 if (!gst_video_info_from_caps (&info, caps))
1100 goto invalid_format;
1101 #ifdef GST_WLSINK_ENHANCEMENT
1102 if (sink->USE_TBM) {
1104 gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
1105 if ((gint) tbm_format == -1)
1106 goto invalid_format;
1108 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1109 if ((gint) format == -1)
1110 goto invalid_format;
1112 #else /* open source */
1113 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1115 if ((gint) format == -1)
1116 goto invalid_format;
1119 /* verify we support the requested format */
1120 #ifdef GST_WLSINK_ENHANCEMENT
1121 if (sink->display->USE_TBM) {
1122 GST_INFO ("USE TBM FORMAT");
1123 formats = sink->display->tbm_formats;
1124 for (i = 0; i < formats->len; i++) {
1125 if (g_array_index (formats, uint32_t, i) == tbm_format)
1128 } else { /* USE SHM */
1129 GST_INFO ("USE SHM FORMAT");
1130 formats = sink->display->formats;
1131 for (i = 0; i < formats->len; i++) {
1132 if (g_array_index (formats, uint32_t, i) == format)
1136 #else /* open source */
1138 formats = sink->display->formats;
1139 for (i = 0; i < formats->len; i++) {
1140 if (g_array_index (formats, uint32_t, i) == format)
1144 if (i >= formats->len)
1145 goto unsupported_format;
1147 #ifdef GST_WLSINK_ENHANCEMENT
1148 if (sink->USE_TBM) {
1149 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1150 GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1151 sink->display->is_native_format = TRUE;
1153 /* store the video info */
1154 sink->video_info = info;
1155 sink->video_info_changed = TRUE;
1157 sink->display->is_native_format = FALSE;
1158 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1159 self->display = sink->display;
1160 /* create a new pool for the new configuration */
1161 newpool = gst_video_buffer_pool_new ();
1165 structure = gst_buffer_pool_get_config (newpool);
1166 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1167 gst_buffer_pool_config_set_allocator (structure,
1168 gst_wl_shm_allocator_get (), NULL);
1169 if (!gst_buffer_pool_set_config (newpool, structure))
1172 /* store the video info */
1173 sink->video_info = info;
1174 sink->video_info_changed = TRUE;
1176 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1177 gst_object_unref (newpool);
1179 } else { /* USE SHM */
1181 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1182 self->display = sink->display;
1184 /* create a new pool for the new configuration */
1185 newpool = gst_video_buffer_pool_new ();
1189 structure = gst_buffer_pool_get_config (newpool);
1190 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1191 gst_buffer_pool_config_set_allocator (structure,
1192 gst_wl_shm_allocator_get (), NULL);
1193 if (!gst_buffer_pool_set_config (newpool, structure))
1196 /* store the video info */
1197 sink->video_info = info;
1198 sink->video_info_changed = TRUE;
1200 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1201 gst_object_unref (newpool);
1203 #else /*open source */
1204 /* create a new pool for the new configuration */
1205 newpool = gst_video_buffer_pool_new ();
1209 structure = gst_buffer_pool_get_config (newpool);
1210 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1211 gst_buffer_pool_config_set_allocator (structure,
1212 gst_wl_shm_allocator_get (), NULL);
1213 if (!gst_buffer_pool_set_config (newpool, structure))
1216 /* store the video info */
1217 sink->video_info = info;
1218 sink->video_info_changed = TRUE;
1220 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1221 gst_object_unref (newpool);
1228 GST_DEBUG_OBJECT (sink,
1229 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1234 #ifdef GST_WLSINK_ENHANCEMENT
1236 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1237 gst_wl_tbm_format_to_string (tbm_format));
1239 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1240 gst_wl_shm_format_to_string (format));
1241 #else /*open source */
1242 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1243 gst_wl_shm_format_to_string (format));
1249 GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1254 GST_DEBUG_OBJECT (bsink, "failed setting config");
1255 gst_object_unref (newpool);
1261 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1263 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1264 GstStructure *config;
1265 guint size, min_bufs, max_bufs;
1266 #ifdef GST_WLSINK_ENHANCEMENT
1271 if (sink->USE_TBM) {
1272 if (sink->display->is_native_format == TRUE)
1275 gst_query_parse_allocation (query, &caps, &need_pool);
1278 GST_DEBUG_OBJECT (bsink, "no caps specified");
1283 config = gst_buffer_pool_get_config (sink->pool);
1284 gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1286 /* we do have a pool for sure (created in set_caps),
1287 * so let's propose it anyway, but also propose the allocator on its own */
1288 gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1289 gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1291 gst_structure_free (config);
1296 static GstFlowReturn
1297 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1300 GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1301 return gst_wayland_sink_render (bsink, buffer);
1305 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1307 GstWaylandSink *sink = data;
1310 GST_LOG ("frame_redraw_cb");
1312 g_atomic_int_set (&sink->redraw_pending, FALSE);
1313 wl_callback_destroy (callback);
1314 #ifdef GST_WLSINK_ENHANCEMENT
1315 if (gst_wayland_sink_check_use_gapless (sink) || sink->keep_camera_preview) {
1316 g_mutex_lock (&sink->render_flush_buffer_lock);
1317 g_cond_signal (&sink->render_flush_buffer_cond);
1318 g_mutex_unlock (&sink->render_flush_buffer_lock);
1323 static const struct wl_callback_listener frame_callback_listener = {
1324 frame_redraw_callback
1327 #ifdef GST_WLSINK_ENHANCEMENT
1329 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1332 g_return_if_fail (sink != NULL);
1333 g_return_if_fail (sink->window != NULL);
1335 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1336 gst_wl_window_set_disp_geo_method (sink->window,
1337 sink->display_geometry_method);
1338 gst_wl_window_set_orientation (sink->window, sink->orientation);
1339 gst_wl_window_set_flip (sink->window, sink->flip);
1342 /* must be called with the render lock */
1344 render_last_buffer (GstWaylandSink * sink)
1346 GstWlBuffer *wlbuffer;
1347 const GstVideoInfo *info = NULL;
1348 struct wl_surface *surface;
1349 struct wl_callback *callback;
1352 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1353 surface = gst_wl_window_get_wl_surface (sink->window);
1355 g_atomic_int_set (&sink->redraw_pending, TRUE);
1356 callback = wl_surface_frame (surface);
1357 /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1358 wl_callback_add_listener (callback, &frame_callback_listener, sink);
1360 if (G_UNLIKELY (sink->video_info_changed)) {
1361 info = &sink->video_info;
1362 sink->video_info_changed = FALSE;
1364 #ifdef GST_WLSINK_ENHANCEMENT
1365 if (sink->last_buffer)
1366 gst_wl_window_render (sink->window, wlbuffer, info);
1368 if (G_UNLIKELY (info)) {
1369 gst_wl_window_set_video_info (sink->window, info);
1373 gst_wl_window_render (sink->window, wlbuffer, info);
1377 static GstFlowReturn
1378 gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
1380 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1381 GstBuffer *to_render;
1382 GstWlBuffer *wlbuffer;
1383 GstFlowReturn ret = GST_FLOW_OK;
1386 g_mutex_lock (&sink->render_lock);
1388 GST_LOG_OBJECT (sink, "render buffer %p", buffer);
1390 if (G_UNLIKELY (!sink->window)) {
1391 /* ask for window handle. Unlock render_lock while doing that because
1392 * set_window_handle & friends will lock it in this context */
1393 g_mutex_unlock (&sink->render_lock);
1394 gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
1395 g_mutex_lock (&sink->render_lock);
1397 if (!sink->window) {
1398 /* if we were not provided a window, create one ourselves */
1400 gst_wl_window_new_toplevel (sink->display, &sink->video_info);
1403 #ifdef GST_WLSINK_ENHANCEMENT
1404 gst_wayland_sink_update_window_geometry (sink);
1405 sink->video_info_changed = TRUE;
1407 /* drop buffers until we get a frame callback */
1408 if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1410 /* make sure that the application has called set_render_rectangle() */
1411 if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1412 goto no_window_size;
1414 #ifdef GST_WLSINK_ENHANCEMENT
1416 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1417 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)
1418 && !(gst_wayland_sink_check_use_gapless (sink))
1419 && !sink->keep_camera_preview) {
1420 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
1421 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1425 GstMapInfo mem_info = GST_MAP_INFO_INIT;
1426 int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1427 mem = gst_buffer_peek_memory (to_render, 0);
1428 gst_memory_map (mem, &mem_info, GST_MAP_READ);
1430 data = mem_info.data;
1432 char file_name[128];
1434 sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1436 ret = __write_rawdata (file_name, data, size);
1438 GST_ERROR ("_write_rawdata() failed");
1440 GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1441 gst_memory_unmap (mem, &mem_info);
1445 struct wl_buffer *wbuf = NULL;
1447 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
1448 mem = gst_buffer_peek_memory (buffer, 0);
1449 if (gst_is_wl_shm_memory (mem)) {
1451 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1454 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add gstbuffer, wlbuffer, display and etc
1457 } else { //buffer is not from our pool and have not wl_buffer
1459 /* we don't know how to create a wl_buffer directly from the provided
1460 * memory, so we have to copy the data to a memory that we know how
1463 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1464 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1467 if (sink->USE_TBM && sink->display->is_native_format) {
1468 /* in case of SN12 or ST12 */
1469 if (!gst_wayland_sink_get_mm_video_buf_info (sink, buffer))
1470 return GST_FLOW_ERROR;
1472 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1473 /* last_buffer from gaplasee have wlbuffer */
1474 if (G_UNLIKELY (!wlbuffer)
1475 || (gst_wayland_sink_check_use_gapless (sink))
1476 || sink->keep_camera_preview) {
1478 gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1480 if (G_UNLIKELY (!wbuf))
1482 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1484 } else if (sink->USE_TBM && !sink->display->is_native_format) {
1486 /* sink->pool always exists (created in set_caps), but it may not
1487 * be active if upstream is not using it */
1488 if (!gst_buffer_pool_is_active (sink->pool)
1489 && !gst_buffer_pool_set_active (sink->pool, TRUE))
1490 goto activate_failed;
1492 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1493 if (ret != GST_FLOW_OK)
1497 //mem = gst_buffer_peek_memory (to_render, 0);
1498 //if (gst_is_wl_shm_memory (mem)) {
1499 GST_INFO ("to_render buffer is our buffer");
1501 /* the first time we acquire a buffer,
1502 * we need to attach a wl_buffer on it */
1503 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1504 if (G_UNLIKELY (!wlbuffer)) {
1505 mem = gst_buffer_peek_memory (to_render, 0);
1506 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1508 if (G_UNLIKELY (!wbuf))
1511 wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1514 gst_buffer_map (buffer, &src, GST_MAP_READ);
1515 gst_buffer_fill (to_render, 0, src.data, src.size);
1516 gst_buffer_unmap (buffer, &src);
1517 } else { /* USE SHM */
1518 /* sink->pool always exists (created in set_caps), but it may not
1519 * be active if upstream is not using it */
1520 if (!gst_buffer_pool_is_active (sink->pool) &&
1521 !gst_buffer_pool_set_active (sink->pool, TRUE))
1522 goto activate_failed;
1523 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1524 if (ret != GST_FLOW_OK)
1526 /* the first time we acquire a buffer,
1527 * we need to attach a wl_buffer on it */
1528 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1529 if (G_UNLIKELY (!wlbuffer)) {
1530 mem = gst_buffer_peek_memory (to_render, 0);
1531 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1533 if (G_UNLIKELY (!wbuf))
1536 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1540 gst_buffer_map (buffer, &src, GST_MAP_READ);
1541 gst_buffer_fill (to_render, 0, src.data, src.size);
1542 gst_buffer_unmap (buffer, &src);
1547 if (sink->USE_TBM && sink->display->is_native_format) {
1548 if ((G_UNLIKELY (buffer == sink->last_buffer)
1549 && !(gst_wayland_sink_check_use_gapless (sink)))
1550 || (G_UNLIKELY (buffer == sink->last_buffer)
1551 && !sink->keep_camera_preview)) {
1552 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1555 gst_buffer_replace (&sink->last_buffer, buffer);
1558 render_last_buffer (sink);
1562 } else { /* USE SHM or normal format */
1563 /* drop double rendering */
1564 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1565 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1568 gst_buffer_replace (&sink->last_buffer, to_render);
1571 render_last_buffer (sink);
1573 if (buffer != to_render)
1574 gst_buffer_unref (to_render);
1579 #else /* open source */
1581 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1583 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1584 GST_LOG_OBJECT (sink,
1585 "buffer %p has a wl_buffer from our display, " "writing directly",
1587 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1592 struct wl_buffer *wbuf = NULL;
1594 GST_LOG_OBJECT (sink,
1595 "buffer %p does not have a wl_buffer from our " "display, creating it",
1597 mem = gst_buffer_peek_memory (buffer, 0);
1598 if (gst_is_wl_shm_memory (mem)) {
1600 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1604 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1609 /* we don't know how to create a wl_buffer directly from the provided
1610 * memory, so we have to copy the data to a memory that we know how
1613 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1614 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1616 /* sink->pool always exists (created in set_caps), but it may not
1617 * be active if upstream is not using it */
1618 if (!gst_buffer_pool_is_active (sink->pool) &&
1619 !gst_buffer_pool_set_active (sink->pool, TRUE))
1620 goto activate_failed;
1622 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1623 if (ret != GST_FLOW_OK)
1626 /* the first time we acquire a buffer,
1627 * we need to attach a wl_buffer on it */
1628 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1629 if (G_UNLIKELY (!wlbuffer)) {
1630 mem = gst_buffer_peek_memory (to_render, 0);
1631 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1633 if (G_UNLIKELY (!wbuf))
1636 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1639 gst_buffer_map (buffer, &src, GST_MAP_READ);
1640 gst_buffer_fill (to_render, 0, src.data, src.size);
1641 gst_buffer_unmap (buffer, &src);
1644 /* drop double rendering */
1645 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1646 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1650 gst_buffer_replace (&sink->last_buffer, to_render);
1651 render_last_buffer (sink);
1653 if (buffer != to_render)
1654 gst_buffer_unref (to_render);
1658 #endif /* GST_WLSINK_ENHANCEMENT */
1662 GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1663 ("Window has no size set"),
1664 ("Make sure you set the size after calling set_window_handle"));
1665 ret = GST_FLOW_ERROR;
1670 GST_WARNING_OBJECT (sink, "could not create buffer");
1675 GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1676 ret = GST_FLOW_ERROR;
1681 GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1682 ret = GST_FLOW_ERROR;
1687 g_mutex_unlock (&sink->render_lock);
1693 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1695 iface->set_window_handle = gst_wayland_sink_set_window_handle;
1696 iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1697 iface->expose = gst_wayland_sink_expose;
1698 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1699 iface->set_wl_window_wl_surface_id =
1700 gst_wayland_sink_set_wl_window_wl_surface_id;
1704 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1706 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1707 guintptr wl_surface_id)
1709 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1711 g_return_if_fail (sink != NULL);
1713 if (sink->window != NULL) {
1714 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1717 g_mutex_lock (&sink->render_lock);
1718 g_clear_object (&sink->window);
1720 GST_INFO ("wl_surface_id %d %x", (int) wl_surface_id,
1721 (guintptr) wl_surface_id);
1723 if (wl_surface_id) {
1724 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1725 /* we cannot use our own display with an external window handle */
1726 if (G_UNLIKELY (sink->display->own_display)) {
1727 sink->display->wl_surface_id = (int) wl_surface_id;
1728 sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1731 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1732 "ignoring window handle");
1735 gst_wayland_sink_update_window_geometry (sink);
1737 g_mutex_unlock (&sink->render_lock);
1743 gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
1745 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1746 struct wl_surface *surface = (struct wl_surface *) handle;
1749 g_return_if_fail (sink != NULL);
1751 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1752 if (sink->window != NULL) {
1753 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1757 g_mutex_lock (&sink->render_lock);
1759 GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
1762 g_clear_object (&sink->window);
1765 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1766 /* we cannot use our own display with an external window handle */
1767 if (G_UNLIKELY (sink->display->own_display)) {
1768 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
1769 ("Application did not provide a wayland display handle"),
1770 ("Now waylandsink use internal display handle "
1771 "which is created ourselves. Consider providing a "
1772 "display handle from your application with GstContext"));
1773 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1775 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1778 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1779 "ignoring window handle");
1782 g_mutex_unlock (&sink->render_lock);
1787 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1788 gint x, gint y, gint w, gint h)
1790 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1793 g_return_if_fail (sink != NULL);
1795 g_mutex_lock (&sink->render_lock);
1796 if (!sink->window) {
1797 g_mutex_unlock (&sink->render_lock);
1798 GST_WARNING_OBJECT (sink,
1799 "set_render_rectangle called without window, ignoring");
1803 GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1805 gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1807 g_mutex_unlock (&sink->render_lock);
1811 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1813 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1816 g_return_if_fail (sink != NULL);
1818 GST_DEBUG_OBJECT (sink, "expose");
1820 g_mutex_lock (&sink->render_lock);
1821 if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1822 GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1823 render_last_buffer (sink);
1825 g_mutex_unlock (&sink->render_lock);
1829 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1831 iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1832 iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1836 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1838 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1840 g_return_if_fail (sink != NULL);
1842 g_mutex_lock (&sink->render_lock);
1843 if (!sink->window || !sink->window->area_subsurface) {
1844 g_mutex_unlock (&sink->render_lock);
1845 GST_INFO_OBJECT (sink,
1846 "begin_geometry_change called without window, ignoring");
1850 wl_subsurface_set_sync (sink->window->area_subsurface);
1851 g_mutex_unlock (&sink->render_lock);
1855 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1857 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1859 g_return_if_fail (sink != NULL);
1861 g_mutex_lock (&sink->render_lock);
1862 if (!sink->window || !sink->window->area_subsurface) {
1863 g_mutex_unlock (&sink->render_lock);
1864 GST_INFO_OBJECT (sink,
1865 "end_geometry_change called without window, ignoring");
1869 wl_subsurface_set_desync (sink->window->area_subsurface);
1870 g_mutex_unlock (&sink->render_lock);
1874 plugin_init (GstPlugin * plugin)
1876 GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1877 " wayland video sink");
1879 gst_wl_shm_allocator_register ();
1881 return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1882 GST_TYPE_WAYLAND_SINK);
1885 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1888 "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,