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 #ifdef GST_WLSINK_ENHANCEMENT
755 if (sink->video_info_changed && sink->window) {
756 gst_wl_window_set_video_info_change (sink->window, TRUE);
757 if (GST_STATE (sink) == GST_STATE_PAUSED)
758 gst_wayland_sink_update_last_buffer_geometry (sink);
761 g_mutex_unlock (&sink->render_lock);
766 gst_wayland_sink_finalize (GObject * object)
768 GstWaylandSink *sink = GST_WAYLAND_SINK (object);
770 GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
772 if (sink->last_buffer)
773 gst_buffer_unref (sink->last_buffer);
775 g_object_unref (sink->display);
777 g_object_unref (sink->window);
779 gst_object_unref (sink->pool);
781 if (sink->display_name)
782 g_free (sink->display_name);
784 g_mutex_clear (&sink->display_lock);
785 g_mutex_clear (&sink->render_lock);
786 #ifdef GST_WLSINK_ENHANCEMENT
787 g_mutex_clear (&sink->render_flush_buffer_lock);
788 g_cond_clear (&sink->render_flush_buffer_cond);
791 G_OBJECT_CLASS (parent_class)->finalize (object);
794 #ifdef GST_WLSINK_ENHANCEMENT
796 gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event)
798 GstWaylandSink *sink;
799 sink = GST_WAYLAND_SINK (bsink);
801 switch (GST_EVENT_TYPE (event)) {
803 GST_LOG ("get EOS event..state is %d", GST_STATE (sink));
804 sink->got_eos_event = TRUE;
805 if (gst_wayland_sink_check_use_gapless (sink)) {
806 gst_wayland_sink_gapless_render (bsink);
807 sink->got_eos_event = FALSE;
809 sink->got_eos_event = FALSE;
814 return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
818 /* must be called with the display_lock */
820 gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
821 GstContext * context)
823 struct wl_display *display;
824 GError *error = NULL;
827 display = gst_wayland_display_handle_context_get_handle (context);
828 sink->display = gst_wl_display_new_existing (display, FALSE, &error);
831 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
832 ("Could not set display handle"),
833 ("Failed to use the external wayland display: '%s'", error->message));
834 g_error_free (error);
836 #ifdef GST_WLSINK_ENHANCEMENT
837 sink->display->USE_TBM = sink->USE_TBM;
842 gst_wayland_sink_find_display (GstWaylandSink * sink)
846 GstContext *context = NULL;
847 GError *error = NULL;
851 g_mutex_lock (&sink->display_lock);
853 if (!sink->display) {
854 /* first query upstream for the needed display handle */
855 query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
856 if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) {
857 gst_query_parse_context (query, &context);
858 gst_wayland_sink_set_display_from_context (sink, context);
860 gst_query_unref (query);
862 if (G_LIKELY (!sink->display)) {
863 /* now ask the application to set the display handle */
864 msg = gst_message_new_need_context (GST_OBJECT_CAST (sink),
865 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
867 g_mutex_unlock (&sink->display_lock);
868 gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
869 /* at this point we expect gst_wayland_sink_set_context
870 * to get called and fill sink->display */
871 g_mutex_lock (&sink->display_lock);
873 if (!sink->display) {
874 /* if the application didn't set a display, let's create it ourselves */
875 GST_OBJECT_LOCK (sink);
876 sink->display = gst_wl_display_new (sink->display_name, &error);
877 GST_OBJECT_UNLOCK (sink);
880 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
881 ("Could not initialise Wayland output"),
882 ("Failed to create GstWlDisplay: '%s'", error->message));
883 g_error_free (error);
886 #ifdef GST_WLSINK_ENHANCEMENT
888 sink->display->USE_TBM = sink->USE_TBM;
894 g_mutex_unlock (&sink->display_lock);
899 static GstStateChangeReturn
900 gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
902 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
903 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
906 switch (transition) {
907 case GST_STATE_CHANGE_NULL_TO_READY:
908 if (!gst_wayland_sink_find_display (sink))
909 return GST_STATE_CHANGE_FAILURE;
915 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
916 if (ret == GST_STATE_CHANGE_FAILURE)
919 switch (transition) {
920 case GST_STATE_CHANGE_PAUSED_TO_READY:
921 #ifdef GST_WLSINK_ENHANCEMENT
922 if (sink->keep_camera_preview) {
924 if (!gst_wl_window_is_toplevel (sink->window)) {
925 GstBaseSink *bsink = GST_BASE_SINK (element);
926 gst_wayland_sink_keep_camera_preview (bsink);
932 gst_buffer_replace (&sink->last_buffer, NULL);
934 if (gst_wl_window_is_toplevel (sink->window)) {
935 GST_DEBUG ("internal window");
936 g_clear_object (&sink->window);
938 /* remove buffer from surface, show nothing */
939 GST_DEBUG ("external window");
940 gst_wl_window_render (sink->window, NULL, NULL);
944 case GST_STATE_CHANGE_READY_TO_NULL:
945 g_mutex_lock (&sink->display_lock);
946 /* If we had a toplevel window, we most likely have our own connection
947 * to the display too, and it is a good idea to disconnect and allow
948 * potentially the application to embed us with GstVideoOverlay
949 * (which requires to re-use the same display connection as the parent
950 * surface). If we didn't have a toplevel window, then the display
951 * connection that we have is definitely shared with the application
952 * and it's better to keep it around (together with the window handle)
953 * to avoid requesting them again from the application if/when we are
954 * restarted (GstVideoOverlay behaves like that in other sinks)
956 if (sink->display && !sink->window) { /* -> the window was toplevel */
957 g_clear_object (&sink->display);
959 g_mutex_unlock (&sink->display_lock);
960 g_clear_object (&sink->pool);
970 gst_wayland_sink_set_context (GstElement * element, GstContext * context)
972 GstWaylandSink *sink = GST_WAYLAND_SINK (element);
975 if (gst_context_has_context_type (context,
976 GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
977 g_mutex_lock (&sink->display_lock);
978 if (G_LIKELY (!sink->display))
979 gst_wayland_sink_set_display_from_context (sink, context);
981 GST_WARNING_OBJECT (element, "changing display handle is not supported");
982 #ifdef GST_WLSINK_ENHANCEMENT
983 g_mutex_unlock (&sink->display_lock);
987 g_mutex_unlock (&sink->display_lock);
990 if (GST_ELEMENT_CLASS (parent_class)->set_context)
991 GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
995 gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
997 GstWaylandSink *sink;
1001 sink = GST_WAYLAND_SINK (bsink);
1003 caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
1005 g_mutex_lock (&sink->display_lock);
1007 if (sink->display) {
1008 GValue list = G_VALUE_INIT;
1009 GValue value = G_VALUE_INIT;
1012 #ifdef GST_WLSINK_ENHANCEMENT
1015 enum wl_shm_format fmt;
1017 g_value_init (&list, GST_TYPE_LIST);
1018 g_value_init (&value, G_TYPE_STRING);
1019 #ifdef GST_WLSINK_ENHANCEMENT
1020 if (sink->display->USE_TBM)
1021 formats = sink->display->tbm_formats;
1024 formats = sink->display->formats;
1026 for (i = 0; i < formats->len; i++) {
1027 #ifdef GST_WLSINK_ENHANCEMENT
1028 if (sink->USE_TBM) {
1029 tbm_fmt = g_array_index (formats, uint32_t, i);
1030 g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
1031 gst_value_list_append_value (&list, &value);
1032 /* TBM doesn't support SN12 and ST12. So we add SN12 and ST12 manually as supported format.
1033 * SN12 is same with NV12, ST12 is same with NV12MT
1035 if (tbm_fmt == TBM_FORMAT_NV12) {
1036 g_value_set_string (&value,
1037 gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
1038 gst_value_list_append_value (&list, &value);
1039 } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
1040 g_value_set_string (&value,
1041 gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
1042 gst_value_list_append_value (&list, &value);
1044 } else { /* USE SHM */
1045 fmt = g_array_index (formats, uint32_t, i);
1046 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1047 gst_value_list_append_value (&list, &value);
1049 #else /* open source */
1050 fmt = g_array_index (formats, uint32_t, i);
1051 g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1052 gst_value_list_append_value (&list, &value);
1056 caps = gst_caps_make_writable (caps);
1057 gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
1059 GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
1060 g_value_unset (&value);
1061 g_value_unset (&list);
1065 g_mutex_unlock (&sink->display_lock);
1068 GstCaps *intersection;
1071 gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1072 gst_caps_unref (caps);
1073 caps = intersection;
1080 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
1082 GstWaylandSink *sink;
1083 GstBufferPool *newpool;
1085 #ifdef GST_WLSINK_ENHANCEMENT
1086 uint32_t tbm_format;
1088 enum wl_shm_format format;
1092 GstStructure *structure;
1093 GstWlShmAllocator *self = NULL;
1097 sink = GST_WAYLAND_SINK (bsink);
1099 GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
1101 /* extract info from caps */
1102 if (!gst_video_info_from_caps (&info, caps))
1103 goto invalid_format;
1104 #ifdef GST_WLSINK_ENHANCEMENT
1105 if (sink->USE_TBM) {
1107 gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
1108 if ((gint) tbm_format == -1)
1109 goto invalid_format;
1111 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1112 if ((gint) format == -1)
1113 goto invalid_format;
1115 #else /* open source */
1116 format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1118 if ((gint) format == -1)
1119 goto invalid_format;
1122 /* verify we support the requested format */
1123 #ifdef GST_WLSINK_ENHANCEMENT
1124 if (sink->display->USE_TBM) {
1125 GST_INFO ("USE TBM FORMAT");
1126 formats = sink->display->tbm_formats;
1127 for (i = 0; i < formats->len; i++) {
1128 if (g_array_index (formats, uint32_t, i) == tbm_format)
1131 } else { /* USE SHM */
1132 GST_INFO ("USE SHM FORMAT");
1133 formats = sink->display->formats;
1134 for (i = 0; i < formats->len; i++) {
1135 if (g_array_index (formats, uint32_t, i) == format)
1139 #else /* open source */
1141 formats = sink->display->formats;
1142 for (i = 0; i < formats->len; i++) {
1143 if (g_array_index (formats, uint32_t, i) == format)
1147 if (i >= formats->len)
1148 goto unsupported_format;
1150 #ifdef GST_WLSINK_ENHANCEMENT
1151 if (sink->USE_TBM) {
1152 if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1153 GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1154 sink->display->is_native_format = TRUE;
1156 /* store the video info */
1157 sink->video_info = info;
1158 sink->video_info_changed = TRUE;
1160 sink->display->is_native_format = FALSE;
1161 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1162 self->display = sink->display;
1163 /* create a new pool for the new configuration */
1164 newpool = gst_video_buffer_pool_new ();
1168 structure = gst_buffer_pool_get_config (newpool);
1169 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1170 gst_buffer_pool_config_set_allocator (structure,
1171 gst_wl_shm_allocator_get (), NULL);
1172 if (!gst_buffer_pool_set_config (newpool, structure))
1175 /* store the video info */
1176 sink->video_info = info;
1177 sink->video_info_changed = TRUE;
1179 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1180 gst_object_unref (newpool);
1182 } else { /* USE SHM */
1184 self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1185 self->display = sink->display;
1187 /* create a new pool for the new configuration */
1188 newpool = gst_video_buffer_pool_new ();
1192 structure = gst_buffer_pool_get_config (newpool);
1193 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1194 gst_buffer_pool_config_set_allocator (structure,
1195 gst_wl_shm_allocator_get (), NULL);
1196 if (!gst_buffer_pool_set_config (newpool, structure))
1199 /* store the video info */
1200 sink->video_info = info;
1201 sink->video_info_changed = TRUE;
1203 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1204 gst_object_unref (newpool);
1206 #else /*open source */
1207 /* create a new pool for the new configuration */
1208 newpool = gst_video_buffer_pool_new ();
1212 structure = gst_buffer_pool_get_config (newpool);
1213 gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1214 gst_buffer_pool_config_set_allocator (structure,
1215 gst_wl_shm_allocator_get (), NULL);
1216 if (!gst_buffer_pool_set_config (newpool, structure))
1219 /* store the video info */
1220 sink->video_info = info;
1221 sink->video_info_changed = TRUE;
1223 gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1224 gst_object_unref (newpool);
1231 GST_DEBUG_OBJECT (sink,
1232 "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1237 #ifdef GST_WLSINK_ENHANCEMENT
1239 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1240 gst_wl_tbm_format_to_string (tbm_format));
1242 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1243 gst_wl_shm_format_to_string (format));
1244 #else /*open source */
1245 GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1246 gst_wl_shm_format_to_string (format));
1252 GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1257 GST_DEBUG_OBJECT (bsink, "failed setting config");
1258 gst_object_unref (newpool);
1264 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1266 GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1267 GstStructure *config;
1268 guint size, min_bufs, max_bufs;
1269 #ifdef GST_WLSINK_ENHANCEMENT
1274 if (sink->USE_TBM) {
1275 if (sink->display->is_native_format == TRUE)
1278 gst_query_parse_allocation (query, &caps, &need_pool);
1281 GST_DEBUG_OBJECT (bsink, "no caps specified");
1286 config = gst_buffer_pool_get_config (sink->pool);
1287 gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1289 /* we do have a pool for sure (created in set_caps),
1290 * so let's propose it anyway, but also propose the allocator on its own */
1291 gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1292 gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1294 gst_structure_free (config);
1299 static GstFlowReturn
1300 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1303 GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1304 return gst_wayland_sink_render (bsink, buffer);
1308 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1310 GstWaylandSink *sink = data;
1313 GST_LOG ("frame_redraw_cb");
1315 g_atomic_int_set (&sink->redraw_pending, FALSE);
1316 wl_callback_destroy (callback);
1317 #ifdef GST_WLSINK_ENHANCEMENT
1318 if (gst_wayland_sink_check_use_gapless (sink) || sink->keep_camera_preview) {
1319 g_mutex_lock (&sink->render_flush_buffer_lock);
1320 g_cond_signal (&sink->render_flush_buffer_cond);
1321 g_mutex_unlock (&sink->render_flush_buffer_lock);
1326 static const struct wl_callback_listener frame_callback_listener = {
1327 frame_redraw_callback
1330 #ifdef GST_WLSINK_ENHANCEMENT
1332 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1335 g_return_if_fail (sink != NULL);
1336 g_return_if_fail (sink->window != NULL);
1338 gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1339 gst_wl_window_set_disp_geo_method (sink->window,
1340 sink->display_geometry_method);
1341 gst_wl_window_set_orientation (sink->window, sink->orientation);
1342 gst_wl_window_set_flip (sink->window, sink->flip);
1345 /* must be called with the render lock */
1347 render_last_buffer (GstWaylandSink * sink)
1349 GstWlBuffer *wlbuffer;
1350 const GstVideoInfo *info = NULL;
1351 struct wl_surface *surface;
1352 struct wl_callback *callback;
1354 #ifdef GST_WLSINK_ENHANCEMENT
1355 g_return_if_fail (sink->last_buffer != NULL);
1356 g_return_if_fail (sink->window != NULL);
1359 wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1360 surface = gst_wl_window_get_wl_surface (sink->window);
1362 g_atomic_int_set (&sink->redraw_pending, TRUE);
1363 callback = wl_surface_frame (surface);
1364 /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1365 wl_callback_add_listener (callback, &frame_callback_listener, sink);
1367 if (G_UNLIKELY (sink->video_info_changed)) {
1368 #ifdef GST_WLSINK_ENHANCEMENT
1369 gst_wl_window_set_video_info_change (sink->window, TRUE);
1371 info = &sink->video_info;
1372 sink->video_info_changed = FALSE;
1374 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);
1402 #ifdef GST_WLSINK_ENHANCEMENT
1403 gst_wayland_sink_update_window_geometry (sink);
1406 /* drop buffers until we get a frame callback */
1407 if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1409 /* make sure that the application has called set_render_rectangle() */
1410 if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1411 goto no_window_size;
1413 #ifdef GST_WLSINK_ENHANCEMENT
1415 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1416 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)
1417 && !(gst_wayland_sink_check_use_gapless (sink))
1418 && !sink->keep_camera_preview) {
1419 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
1420 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1424 GstMapInfo mem_info = GST_MAP_INFO_INIT;
1425 int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1426 mem = gst_buffer_peek_memory (to_render, 0);
1427 gst_memory_map (mem, &mem_info, GST_MAP_READ);
1429 data = mem_info.data;
1431 char file_name[128];
1433 sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1435 ret = __write_rawdata (file_name, data, size);
1437 GST_ERROR ("_write_rawdata() failed");
1439 GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1440 gst_memory_unmap (mem, &mem_info);
1444 struct wl_buffer *wbuf = NULL;
1446 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
1447 mem = gst_buffer_peek_memory (buffer, 0);
1448 if (gst_is_wl_shm_memory (mem)) {
1450 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1453 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add gstbuffer, wlbuffer, display and etc
1456 } else { //buffer is not from our pool and have not wl_buffer
1458 /* we don't know how to create a wl_buffer directly from the provided
1459 * memory, so we have to copy the data to a memory that we know how
1462 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1463 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1466 if (sink->USE_TBM && sink->display->is_native_format) {
1467 /* in case of SN12 or ST12 */
1468 if (!gst_wayland_sink_get_mm_video_buf_info (sink, buffer))
1469 return GST_FLOW_ERROR;
1471 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1472 /* last_buffer from gaplasee have wlbuffer */
1473 if (G_UNLIKELY (!wlbuffer)
1474 || (gst_wayland_sink_check_use_gapless (sink))
1475 || sink->keep_camera_preview) {
1477 gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1479 if (G_UNLIKELY (!wbuf))
1481 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1483 } else if (sink->USE_TBM && !sink->display->is_native_format) {
1485 /* sink->pool always exists (created in set_caps), but it may not
1486 * be active if upstream is not using it */
1487 if (!gst_buffer_pool_is_active (sink->pool)
1488 && !gst_buffer_pool_set_active (sink->pool, TRUE))
1489 goto activate_failed;
1491 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1492 if (ret != GST_FLOW_OK)
1496 //mem = gst_buffer_peek_memory (to_render, 0);
1497 //if (gst_is_wl_shm_memory (mem)) {
1498 GST_INFO ("to_render buffer is our buffer");
1500 /* the first time we acquire a buffer,
1501 * we need to attach a wl_buffer on it */
1502 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1503 if (G_UNLIKELY (!wlbuffer)) {
1504 mem = gst_buffer_peek_memory (to_render, 0);
1505 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1507 if (G_UNLIKELY (!wbuf))
1510 wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1513 gst_buffer_map (buffer, &src, GST_MAP_READ);
1514 gst_buffer_fill (to_render, 0, src.data, src.size);
1515 gst_buffer_unmap (buffer, &src);
1516 } else { /* USE SHM */
1517 /* sink->pool always exists (created in set_caps), but it may not
1518 * be active if upstream is not using it */
1519 if (!gst_buffer_pool_is_active (sink->pool) &&
1520 !gst_buffer_pool_set_active (sink->pool, TRUE))
1521 goto activate_failed;
1522 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1523 if (ret != GST_FLOW_OK)
1525 /* the first time we acquire a buffer,
1526 * we need to attach a wl_buffer on it */
1527 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1528 if (G_UNLIKELY (!wlbuffer)) {
1529 mem = gst_buffer_peek_memory (to_render, 0);
1530 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1532 if (G_UNLIKELY (!wbuf))
1535 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1539 gst_buffer_map (buffer, &src, GST_MAP_READ);
1540 gst_buffer_fill (to_render, 0, src.data, src.size);
1541 gst_buffer_unmap (buffer, &src);
1546 if (sink->USE_TBM && sink->display->is_native_format) {
1547 if ((G_UNLIKELY (buffer == sink->last_buffer)
1548 && !(gst_wayland_sink_check_use_gapless (sink)))
1549 || (G_UNLIKELY (buffer == sink->last_buffer)
1550 && !sink->keep_camera_preview)) {
1551 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1554 gst_buffer_replace (&sink->last_buffer, buffer);
1557 render_last_buffer (sink);
1561 } else { /* USE SHM or normal format */
1562 /* drop double rendering */
1563 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1564 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1567 gst_buffer_replace (&sink->last_buffer, to_render);
1570 render_last_buffer (sink);
1572 if (buffer != to_render)
1573 gst_buffer_unref (to_render);
1578 #else /* open source */
1580 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1582 if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1583 GST_LOG_OBJECT (sink,
1584 "buffer %p has a wl_buffer from our display, " "writing directly",
1586 GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1591 struct wl_buffer *wbuf = NULL;
1593 GST_LOG_OBJECT (sink,
1594 "buffer %p does not have a wl_buffer from our " "display, creating it",
1596 mem = gst_buffer_peek_memory (buffer, 0);
1597 if (gst_is_wl_shm_memory (mem)) {
1599 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1603 gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1608 /* we don't know how to create a wl_buffer directly from the provided
1609 * memory, so we have to copy the data to a memory that we know how
1612 GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1613 GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1615 /* sink->pool always exists (created in set_caps), but it may not
1616 * be active if upstream is not using it */
1617 if (!gst_buffer_pool_is_active (sink->pool) &&
1618 !gst_buffer_pool_set_active (sink->pool, TRUE))
1619 goto activate_failed;
1621 ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1622 if (ret != GST_FLOW_OK)
1625 /* the first time we acquire a buffer,
1626 * we need to attach a wl_buffer on it */
1627 wlbuffer = gst_buffer_get_wl_buffer (buffer);
1628 if (G_UNLIKELY (!wlbuffer)) {
1629 mem = gst_buffer_peek_memory (to_render, 0);
1630 wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1632 if (G_UNLIKELY (!wbuf))
1635 gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1638 gst_buffer_map (buffer, &src, GST_MAP_READ);
1639 gst_buffer_fill (to_render, 0, src.data, src.size);
1640 gst_buffer_unmap (buffer, &src);
1643 /* drop double rendering */
1644 if (G_UNLIKELY (buffer == sink->last_buffer)) {
1645 GST_LOG_OBJECT (sink, "Buffer already being rendered");
1649 gst_buffer_replace (&sink->last_buffer, to_render);
1650 render_last_buffer (sink);
1652 if (buffer != to_render)
1653 gst_buffer_unref (to_render);
1657 #endif /* GST_WLSINK_ENHANCEMENT */
1661 GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1662 ("Window has no size set"),
1663 ("Make sure you set the size after calling set_window_handle"));
1664 ret = GST_FLOW_ERROR;
1669 GST_WARNING_OBJECT (sink, "could not create buffer");
1674 GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1675 ret = GST_FLOW_ERROR;
1680 GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1681 ret = GST_FLOW_ERROR;
1686 g_mutex_unlock (&sink->render_lock);
1692 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1694 iface->set_window_handle = gst_wayland_sink_set_window_handle;
1695 iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1696 iface->expose = gst_wayland_sink_expose;
1697 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1698 iface->set_wl_window_wl_surface_id =
1699 gst_wayland_sink_set_wl_window_wl_surface_id;
1703 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1705 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1706 guintptr wl_surface_id)
1708 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1710 g_return_if_fail (sink != NULL);
1712 if (sink->window != NULL) {
1713 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1716 g_mutex_lock (&sink->render_lock);
1717 g_clear_object (&sink->window);
1719 GST_INFO ("wl_surface_id %d %x", (int) wl_surface_id,
1720 (guintptr) wl_surface_id);
1722 if (wl_surface_id) {
1723 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1724 /* we cannot use our own display with an external window handle */
1725 if (G_UNLIKELY (sink->display->own_display)) {
1726 sink->display->wl_surface_id = (int) wl_surface_id;
1727 sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1730 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1731 "ignoring window handle");
1734 gst_wayland_sink_update_window_geometry (sink);
1735 g_mutex_unlock (&sink->render_lock);
1741 gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
1743 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1744 struct wl_surface *surface = (struct wl_surface *) handle;
1747 g_return_if_fail (sink != NULL);
1749 #ifdef GST_WLSINK_ENHANCEMENT /* use unique_id */
1750 if (sink->window != NULL) {
1751 GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1755 g_mutex_lock (&sink->render_lock);
1757 GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
1760 g_clear_object (&sink->window);
1763 if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1764 /* we cannot use our own display with an external window handle */
1765 if (G_UNLIKELY (sink->display->own_display)) {
1766 GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
1767 ("Application did not provide a wayland display handle"),
1768 ("Now waylandsink use internal display handle "
1769 "which is created ourselves. Consider providing a "
1770 "display handle from your application with GstContext"));
1771 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1773 sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1776 GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1777 "ignoring window handle");
1780 #ifdef GST_WLSINK_ENHANCEMENT
1781 gst_wayland_sink_update_window_geometry (sink);
1783 g_mutex_unlock (&sink->render_lock);
1788 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1789 gint x, gint y, gint w, gint h)
1791 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1794 g_return_if_fail (sink != NULL);
1796 g_mutex_lock (&sink->render_lock);
1797 if (!sink->window) {
1798 g_mutex_unlock (&sink->render_lock);
1799 GST_WARNING_OBJECT (sink,
1800 "set_render_rectangle called without window, ignoring");
1804 GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1806 gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1808 g_mutex_unlock (&sink->render_lock);
1812 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1814 GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1817 g_return_if_fail (sink != NULL);
1819 GST_DEBUG_OBJECT (sink, "expose");
1821 g_mutex_lock (&sink->render_lock);
1822 if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1823 GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1824 render_last_buffer (sink);
1826 g_mutex_unlock (&sink->render_lock);
1830 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1832 iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1833 iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1837 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1839 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1841 g_return_if_fail (sink != NULL);
1843 g_mutex_lock (&sink->render_lock);
1844 if (!sink->window || !sink->window->area_subsurface) {
1845 g_mutex_unlock (&sink->render_lock);
1846 GST_INFO_OBJECT (sink,
1847 "begin_geometry_change called without window, ignoring");
1851 wl_subsurface_set_sync (sink->window->area_subsurface);
1852 g_mutex_unlock (&sink->render_lock);
1856 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1858 GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1860 g_return_if_fail (sink != NULL);
1862 g_mutex_lock (&sink->render_lock);
1863 if (!sink->window || !sink->window->area_subsurface) {
1864 g_mutex_unlock (&sink->render_lock);
1865 GST_INFO_OBJECT (sink,
1866 "end_geometry_change called without window, ignoring");
1870 wl_subsurface_set_desync (sink->window->area_subsurface);
1871 g_mutex_unlock (&sink->render_lock);
1875 plugin_init (GstPlugin * plugin)
1877 GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1878 " wayland video sink");
1880 gst_wl_shm_allocator_register ();
1882 return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1883 GST_TYPE_WAYLAND_SINK);
1886 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1889 "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,