waylandsink : fix buffer ref count with SHM mode
[platform/upstream/gstreamer.git] / ext / wayland / gstwaylandsink.c
1 /* GStreamer Wayland video sink
2  *
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.
7  *
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.
12  *
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.
17  *
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.
22  */
23
24 /**
25  * SECTION:element-waylandsink
26  *
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.
31  *
32  * <refsect2>
33  * <title>Example pipelines</title>
34  * |[
35  * gst-launch -v videotestsrc ! waylandsink
36  * ]| test the video rendering in wayland
37  * </refsect2>
38  */
39
40 #ifdef HAVE_CONFIG_H
41 #include <config.h>
42 #endif
43
44 #include "gstwaylandsink.h"
45 #ifdef GST_WLSINK_ENHANCEMENT
46 #include <mm_types.h>
47 #include "tizen-wlvideoformat.h"
48 #endif
49 #include "wlvideoformat.h"
50 #include "wlbuffer.h"
51 #include "wlshmallocator.h"
52
53 #include <gst/wayland/wayland.h>
54 #include <gst/video/videooverlay.h>
55
56
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60
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())
65
66 static GType
67 gst_waylandsink_rotate_angle_get_type (void)
68 {
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"},
75     {4, NULL, NULL},
76   };
77
78   if (!waylandsink_rotate_angle_type) {
79     waylandsink_rotate_angle_type =
80         g_enum_register_static ("GstWaylandSinkRotateAngleType",
81         rotate_angle_type);
82   }
83
84   return waylandsink_rotate_angle_type;
85 }
86
87
88 static GType
89 gst_waylandsink_display_geometry_method_get_type (void)
90 {
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"},
98     {5, NULL, NULL},
99   };
100
101   if (!waylandsink_display_geometry_method_type) {
102     waylandsink_display_geometry_method_type =
103         g_enum_register_static ("GstWaylandSinkDisplayGeometryMethodType",
104         display_geometry_method_type);
105   }
106   return waylandsink_display_geometry_method_type;
107 }
108
109 static GType
110 gst_waylandsink_flip_get_type (void)
111 {
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},
119   };
120
121   if (!waylandsink_flip_type) {
122     waylandsink_flip_type =
123         g_enum_register_static ("GstWaylandSinkFlipType", flip_type);
124   }
125
126   return waylandsink_flip_type;
127 }
128
129 #endif
130
131 /* signals */
132 enum
133 {
134   SIGNAL_0,
135   LAST_SIGNAL
136 };
137
138 /* Properties */
139 enum
140 {
141   PROP_0,
142   PROP_DISPLAY,
143 #ifdef GST_WLSINK_ENHANCEMENT
144   PROP_USE_GAPLESS,
145   PROP_KEEP_CAMERA_PREVIEW,
146   PROP_USE_TBM,
147   PROP_ROTATE_ANGLE,
148   PROP_DISPLAY_GEOMETRY_METHOD,
149   PROP_ORIENTATION,
150   PROP_FLIP,
151   PROP_VISIBLE
152 #endif
153 };
154 int dump__cnt = 0;
155
156 GST_DEBUG_CATEGORY (gstwayland_debug);
157 #define GST_CAT_DEFAULT gstwayland_debug
158
159 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
160     GST_PAD_SINK,
161     GST_PAD_ALWAYS,
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
166             "SN12, ST12, "
167 #endif
168             "YUV9, YVU9, Y41B, I420, YV12, Y42B, v308 }"))
169     );
170
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);
176
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);
181
182 static GstCaps *gst_wayland_sink_get_caps (GstBaseSink * bsink,
183     GstCaps * filter);
184 static gboolean gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
185 static gboolean gst_wayland_sink_preroll (GstBaseSink * bsink,
186     GstBuffer * buffer);
187 static gboolean
188 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query);
189 static gboolean gst_wayland_sink_render (GstBaseSink * bsink,
190     GstBuffer * buffer);
191
192 /* VideoOverlay interface */
193 static void gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface *
194     iface);
195 static void gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay,
196     guintptr handle);
197 static void
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);
203
204 /* WaylandVideo interface */
205 static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface *
206     iface);
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);
213 #endif
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));
220
221 static void
222 gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
223 {
224   GObjectClass *gobject_class;
225   GstElementClass *gstelement_class;
226   GstBaseSinkClass *gstbasesink_class;
227   FUNCTION;
228
229   gobject_class = (GObjectClass *) klass;
230   gstelement_class = (GstElementClass *) klass;
231   gstbasesink_class = (GstBaseSinkClass *) klass;
232
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);
236
237   gst_element_class_add_pad_template (gstelement_class,
238       gst_static_pad_template_get (&sink_template));
239
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>");
245
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);
250
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);
259 #endif
260
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));
271
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));
277
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));
283
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));
289
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));
296
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));
303
304   g_object_class_install_property (gobject_class, PROP_FLIP,
305       g_param_spec_enum ("flip", "Display flip",
306           "Flip for display",
307           GST_TYPE_WAYLANDSINK_FLIP, DEF_DISPLAY_FLIP,
308           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
309
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));
314 #endif
315 }
316
317 #ifdef DUMP_BUFFER
318 int
319 __write_rawdata (const char *file, const void *data, unsigned int size)
320 {
321   FILE *fp;
322
323   fp = fopen (file, "wb");
324   if (fp == NULL)
325     return -1;
326
327   fwrite ((char *) data, sizeof (char), size, fp);
328   fclose (fp);
329
330   return 0;
331 }
332 #endif
333 static void
334 gst_wayland_sink_init (GstWaylandSink * sink)
335 {
336   FUNCTION;
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);
349 #endif
350   g_mutex_init (&sink->display_lock);
351   g_mutex_init (&sink->render_lock);
352 }
353
354 #ifdef GST_WLSINK_ENHANCEMENT
355 static void
356 gst_wayland_sink_stop_video (GstWaylandSink * sink)
357 {
358   FUNCTION;
359   g_return_if_fail (sink != NULL);
360   gst_wl_window_render (sink->window, NULL, NULL);
361 }
362
363 static int
364 gst_wayland_sink_check_use_gapless (GstWaylandSink * sink)
365 {
366   g_return_val_if_fail (sink != NULL, FALSE);
367   g_return_val_if_fail (sink->display != NULL, FALSE);
368
369   if (sink->use_gapless && sink->got_eos_event && sink->USE_TBM
370       && sink->display->is_native_format)
371     return TRUE;
372
373   return FALSE;
374 }
375
376 static int
377 gst_wayland_sink_need_to_make_flush_buffer (GstWaylandSink * sink)
378 {
379   g_return_val_if_fail (sink != NULL, FALSE);
380   g_return_val_if_fail (sink->display != NULL, FALSE);
381
382   if ((gst_wayland_sink_check_use_gapless (sink))
383       || sink->keep_camera_preview || sink->display->flush_request) {
384     sink->display->flush_request = TRUE;
385     return TRUE;
386   }
387   return FALSE;
388 }
389
390 static void
391 gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink)
392 {
393   GstWlBuffer *wlbuffer;
394   FUNCTION;
395   g_return_if_fail (sink != NULL);
396   g_return_if_fail (sink->last_buffer != NULL);
397   g_return_if_fail (sink->display != NULL);
398   wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
399   g_return_if_fail (wlbuffer != NULL);
400   wlbuffer->used_by_compositor = FALSE;
401
402   GST_LOG ("gstbuffer(%p) ref count(%d)", sink->last_buffer,
403       GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer));
404
405   if (!sink->display->is_native_format) {
406     /* use SHM , use TBM with normal video format*/
407     render_last_buffer (sink);
408     if (!sink->visible)
409       gst_buffer_unref (wlbuffer->gstbuffer);
410     GST_LOG ("gstbuffer(%p) ref count(%d)", sink->last_buffer,
411         GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer));
412     return;
413   }
414   if (sink->visible) {
415     /*need to render last buffer, reuse current GstWlBuffer */
416     render_last_buffer (sink);
417     /* ref count is incresed in gst_wl_buffer_attach() of render_last_buffer(),
418        to call gst_wl_buffer_finalize(), we need to decrease buffer ref count.
419        wayland can not release buffer if we attach same buffer,
420        if we use no visible, we need to attach null buffer and wayland can release buffer,
421        so we don't need to below if() code. */
422     gst_buffer_unref (wlbuffer->gstbuffer);
423   } else {
424     GST_LOG ("skip rendering");
425   }
426
427   GST_LOG ("gstbuffer(%p) ref count(%d)", sink->last_buffer,
428       GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer));
429
430 }
431
432 #ifdef USE_WL_FLUSH_BUFFER
433 static int
434 gst_wayland_sink_make_flush_buffer (GstWlDisplay * display,
435     MMVideoBuffer * mm_video_buf)
436 {
437   GstWlFlushBuffer *flush_buffer = NULL;
438   tbm_bo bo = NULL;
439   int bo_size = 0;
440   int i;
441   FUNCTION;
442
443   g_return_val_if_fail (display != NULL, FALSE);
444   g_return_val_if_fail (mm_video_buf != NULL, FALSE);
445
446   flush_buffer = (GstWlFlushBuffer *) malloc (sizeof (GstWlFlushBuffer));
447   if (!flush_buffer) {
448     GST_ERROR ("GstWlFlushBuffer alloc faile");
449     return FALSE;
450   }
451   memset (flush_buffer, 0x0, sizeof (GstWlFlushBuffer));
452
453   display->flush_tbm_bufmgr =
454       wayland_tbm_client_get_bufmgr (display->tbm_client);
455   g_return_val_if_fail (display->flush_tbm_bufmgr != NULL, FALSE);
456
457   for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
458     if (mm_video_buf->handle.bo[i] != NULL) {
459       tbm_bo_handle src;
460       tbm_bo_handle dst;
461
462       /* get bo size */
463       bo_size = tbm_bo_size (mm_video_buf->handle.bo[i]);
464       GST_LOG ("tbm bo size: %d", bo_size);
465       /* alloc bo */
466       bo = tbm_bo_alloc (display->flush_tbm_bufmgr, bo_size, TBM_DEVICE_CPU);
467       if (!bo) {
468         GST_ERROR ("alloc tbm bo(size:%d) failed: %s", bo_size,
469             strerror (errno));
470         return FALSE;
471       }
472       GST_INFO ("flush buffer tbm_bo =(%p)", bo);
473       flush_buffer->bo[i] = bo;
474       /* get virtual address */
475       src.ptr = dst.ptr = NULL;
476       /* bo map, we can use tbm_bo_map too. */
477       src = tbm_bo_get_handle (mm_video_buf->handle.bo[i], TBM_DEVICE_CPU);
478       dst = tbm_bo_get_handle (bo, TBM_DEVICE_CPU);
479       if (!src.ptr || !dst.ptr) {
480         GST_ERROR ("get tbm bo handle failed src(%p) dst(%p): %s", src.ptr,
481             dst.ptr, strerror (errno));
482         tbm_bo_unref (mm_video_buf->handle.bo[i]);
483         tbm_bo_unref (bo);
484         return FALSE;
485       }
486       /* copy */
487       memcpy (dst.ptr, src.ptr, bo_size);
488       /* bo unmap */
489       tbm_bo_unmap (mm_video_buf->handle.bo[i]);
490       tbm_bo_unmap (bo);
491     }
492   }
493   display->flush_buffer = flush_buffer;
494   return TRUE;
495 }
496
497 static int
498 gst_wayland_sink_copy_mm_video_buf_info_to_flush (GstWlDisplay * display,
499     MMVideoBuffer * mm_video_buf)
500 {
501   int ret = FALSE;
502   g_return_val_if_fail (display != NULL, FALSE);
503   g_return_val_if_fail (mm_video_buf != NULL, FALSE);
504   FUNCTION;
505
506   ret = gst_wayland_sink_make_flush_buffer (display, mm_video_buf);
507   if (ret) {
508     int i;
509     for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
510       if (display->flush_buffer->bo[i] != NULL) {
511         display->bo[i] = display->flush_buffer->bo[i];
512         GST_LOG ("bo %p", display->bo[i]);
513       } else {
514         display->bo[i] = 0;
515       }
516       display->plane_size[i] = mm_video_buf->size[i];
517       display->stride_width[i] = mm_video_buf->stride_width[i];
518       display->stride_height[i] = mm_video_buf->stride_height[i];
519       display->native_video_size += display->plane_size[i];
520     }
521   }
522   return ret;
523 }
524 #endif
525
526 static void
527 gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display,
528     MMVideoBuffer * mm_video_buf)
529 {
530   int i;
531   g_return_if_fail (display != NULL);
532   g_return_if_fail (mm_video_buf != NULL);
533   FUNCTION;
534
535   for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
536     if (mm_video_buf->handle.bo[i] != NULL) {
537       display->bo[i] = mm_video_buf->handle.bo[i];
538     } else {
539       display->bo[i] = 0;
540     }
541     display->plane_size[i] = mm_video_buf->size[i];
542     display->stride_width[i] = mm_video_buf->stride_width[i];
543     display->stride_height[i] = mm_video_buf->stride_height[i];
544     display->native_video_size += display->plane_size[i];
545   }
546 }
547
548 static int
549 gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink,
550     GstBuffer * buffer)
551 {
552   GstWlDisplay *display;
553   GstMemory *mem;
554   GstMapInfo mem_info = GST_MAP_INFO_INIT;
555   MMVideoBuffer *mm_video_buf = NULL;
556
557   g_return_val_if_fail (sink != NULL, FALSE);
558   g_return_val_if_fail (buffer != NULL, FALSE);
559
560   FUNCTION;
561   display = sink->display;
562   g_return_val_if_fail (sink->display != NULL, FALSE);
563
564   mem = gst_buffer_peek_memory (buffer, 1);
565   gst_memory_map (mem, &mem_info, GST_MAP_READ);
566   mm_video_buf = (MMVideoBuffer *) mem_info.data;
567   gst_memory_unmap (mem, &mem_info);
568
569   if (mm_video_buf == NULL) {
570     GST_WARNING ("mm_video_buf is NULL. Skip rendering");
571     return FALSE;
572   }
573   /* assign mm_video_buf info */
574   if (mm_video_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
575     GST_DEBUG ("TBM bo %p %p %p", mm_video_buf->handle.bo[0],
576         mm_video_buf->handle.bo[1], mm_video_buf->handle.bo[2]);
577     display->native_video_size = 0;
578     display->flush_request = mm_video_buf->flush_request;
579     GST_DEBUG ("flush_request value is %d", display->flush_request);
580 #ifdef USE_WL_FLUSH_BUFFER
581     if (gst_wayland_sink_need_to_make_flush_buffer (sink)) {
582       if (!gst_wayland_sink_copy_mm_video_buf_info_to_flush (display,
583               mm_video_buf)) {
584         GST_ERROR ("cat not copy mm_video_buf info to flush");
585         return FALSE;
586       }
587     } else
588 #endif
589       /* normal routine */
590       gst_wayland_sink_add_mm_video_buf_info (display, mm_video_buf);
591   } else {
592     GST_ERROR ("Buffer type is not TBM");
593     return FALSE;
594   }
595   return TRUE;
596 }
597
598 static void
599 gst_wayland_sink_render_flush_buffer (GstBaseSink * bsink)
600 {
601   GstWaylandSink *sink;
602   GstBuffer *buffer;
603   sink = GST_WAYLAND_SINK (bsink);
604   FUNCTION;
605   g_return_if_fail (sink != NULL);
606   g_return_if_fail (sink->last_buffer != NULL);
607
608   buffer = gst_buffer_copy (sink->last_buffer);
609
610   g_mutex_lock (&sink->render_flush_buffer_lock);
611   g_cond_wait (&sink->render_flush_buffer_cond,
612       &sink->render_flush_buffer_lock);
613
614   gst_wayland_sink_render (bsink, buffer);
615   if (buffer)
616     gst_buffer_unref (buffer);
617   g_mutex_unlock (&sink->render_flush_buffer_lock);
618 }
619
620 static void
621 gst_wayland_sink_gapless_render (GstBaseSink * bsink)
622 {
623   g_return_if_fail (bsink != NULL);
624   FUNCTION;
625   gst_wayland_sink_render_flush_buffer (bsink);
626 }
627
628 static void
629 gst_wayland_sink_keep_camera_preview (GstBaseSink * bsink)
630 {
631   g_return_if_fail (bsink != NULL);
632   FUNCTION;
633   gst_wayland_sink_render_flush_buffer (bsink);
634 }
635
636 #endif
637
638 static void
639 gst_wayland_sink_get_property (GObject * object,
640     guint prop_id, GValue * value, GParamSpec * pspec)
641 {
642   GstWaylandSink *sink = GST_WAYLAND_SINK (object);
643   FUNCTION;
644
645   switch (prop_id) {
646     case PROP_DISPLAY:
647       GST_OBJECT_LOCK (sink);
648       g_value_set_string (value, sink->display_name);
649       GST_OBJECT_UNLOCK (sink);
650       break;
651 #ifdef GST_WLSINK_ENHANCEMENT
652     case PROP_USE_GAPLESS:
653       g_value_set_boolean (value, sink->use_gapless);
654       break;
655     case PROP_KEEP_CAMERA_PREVIEW:
656       g_value_set_boolean (value, sink->keep_camera_preview);
657       break;
658     case PROP_USE_TBM:
659       g_value_set_boolean (value, sink->USE_TBM);
660       break;
661     case PROP_ROTATE_ANGLE:
662       g_value_set_enum (value, sink->rotate_angle);
663       break;
664     case PROP_DISPLAY_GEOMETRY_METHOD:
665       g_value_set_enum (value, sink->display_geometry_method);
666       break;
667     case PROP_ORIENTATION:
668       g_value_set_enum (value, sink->orientation);
669       break;
670     case PROP_FLIP:
671       g_value_set_enum (value, sink->flip);
672       break;
673     case PROP_VISIBLE:
674       g_value_set_boolean (value, sink->visible);
675       break;
676 #endif
677     default:
678       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
679       break;
680   }
681 }
682
683 static void
684 gst_wayland_sink_set_property (GObject * object,
685     guint prop_id, const GValue * value, GParamSpec * pspec)
686 {
687   GstWaylandSink *sink = GST_WAYLAND_SINK (object);
688   FUNCTION;
689   g_mutex_lock (&sink->render_lock);
690
691   switch (prop_id) {
692     case PROP_DISPLAY:
693       GST_OBJECT_LOCK (sink);
694       sink->display_name = g_value_dup_string (value);
695       GST_OBJECT_UNLOCK (sink);
696       break;
697 #ifdef GST_WLSINK_ENHANCEMENT
698     case PROP_USE_GAPLESS:
699       sink->use_gapless = g_value_get_boolean (value);
700       GST_LOG ("use gapless is (%d)", sink->use_gapless);
701       break;
702     case PROP_KEEP_CAMERA_PREVIEW:
703       sink->keep_camera_preview = g_value_get_boolean (value);
704       GST_LOG ("keep_camera_preview (%d)", sink->keep_camera_preview);
705       break;
706     case PROP_USE_TBM:
707       sink->USE_TBM = g_value_get_boolean (value);
708       GST_LOG ("1:USE TBM 0: USE SHM set(%d)", sink->USE_TBM);
709       break;
710     case PROP_ROTATE_ANGLE:
711       if (sink->rotate_angle == g_value_get_enum (value))
712         break;
713       sink->rotate_angle = g_value_get_enum (value);
714       GST_WARNING_OBJECT (sink, "Rotate angle is set (%d)", sink->rotate_angle);
715       sink->video_info_changed = TRUE;
716       if (sink->window) {
717         gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
718       }
719       break;
720     case PROP_DISPLAY_GEOMETRY_METHOD:
721       if (sink->display_geometry_method == g_value_get_enum (value))
722         break;
723       sink->display_geometry_method = g_value_get_enum (value);
724       GST_WARNING_OBJECT (sink, "Display geometry method is set (%d)",
725           sink->display_geometry_method);
726       sink->video_info_changed = TRUE;
727       if (sink->window) {
728         gst_wl_window_set_disp_geo_method (sink->window,
729             sink->display_geometry_method);
730       }
731       break;
732     case PROP_ORIENTATION:
733       if (sink->orientation == g_value_get_enum (value))
734         break;
735       sink->orientation = g_value_get_enum (value);
736       GST_WARNING_OBJECT (sink, "Orientation is set (%d)", sink->orientation);
737       sink->video_info_changed = TRUE;
738       if (sink->window) {
739         gst_wl_window_set_orientation (sink->window, sink->orientation);
740       }
741       break;
742     case PROP_FLIP:
743       if (sink->flip == g_value_get_enum (value))
744         break;
745       sink->flip = g_value_get_enum (value);
746       GST_WARNING_OBJECT (sink, "flip is set (%d)", sink->flip);
747       sink->video_info_changed = TRUE;
748       if (sink->window) {
749         gst_wl_window_set_flip (sink->window, sink->flip);
750       }
751       break;
752     case PROP_VISIBLE:
753       if (sink->visible == g_value_get_boolean (value))
754         break;
755       sink->visible = g_value_get_boolean (value);
756       GST_WARNING_OBJECT (sink, "visible is set (%d)", sink->visible);
757       if (sink->visible && GST_STATE (sink) == GST_STATE_PAUSED) {
758         /* need to attatch last buffer */
759         sink->video_info_changed = TRUE;
760       } else if (!sink->visible && GST_STATE (sink) >= GST_STATE_PAUSED) {
761         /* video stop */
762         if (sink->window) {
763           gst_wayland_sink_stop_video (sink);
764         }
765       }
766       break;
767 #endif
768     default:
769       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
770       break;
771   }
772 #ifdef GST_WLSINK_ENHANCEMENT
773   if (sink->video_info_changed && sink->window) {
774     gst_wl_window_set_video_info_change (sink->window, TRUE);
775     if (GST_STATE (sink) == GST_STATE_PAUSED)
776       gst_wayland_sink_update_last_buffer_geometry (sink);
777   }
778 #endif
779   g_mutex_unlock (&sink->render_lock);
780
781 }
782
783 static void
784 gst_wayland_sink_finalize (GObject * object)
785 {
786   GstWaylandSink *sink = GST_WAYLAND_SINK (object);
787   FUNCTION;
788   GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
789
790   if (sink->last_buffer)
791     gst_buffer_unref (sink->last_buffer);
792   if (sink->display)
793     g_object_unref (sink->display);
794   if (sink->window)
795     g_object_unref (sink->window);
796   if (sink->pool)
797     gst_object_unref (sink->pool);
798
799   if (sink->display_name)
800     g_free (sink->display_name);
801
802   g_mutex_clear (&sink->display_lock);
803   g_mutex_clear (&sink->render_lock);
804 #ifdef GST_WLSINK_ENHANCEMENT
805   g_mutex_clear (&sink->render_flush_buffer_lock);
806   g_cond_clear (&sink->render_flush_buffer_cond);
807 #endif
808
809   G_OBJECT_CLASS (parent_class)->finalize (object);
810 }
811
812 #ifdef GST_WLSINK_ENHANCEMENT
813 static gboolean
814 gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event)
815 {
816   GstWaylandSink *sink;
817   sink = GST_WAYLAND_SINK (bsink);
818
819   switch (GST_EVENT_TYPE (event)) {
820     case GST_EVENT_EOS:
821       GST_LOG ("get EOS event..state is %d", GST_STATE (sink));
822       sink->got_eos_event = TRUE;
823       if (gst_wayland_sink_check_use_gapless (sink)) {
824         gst_wayland_sink_gapless_render (bsink);
825         sink->got_eos_event = FALSE;
826       }
827       sink->got_eos_event = FALSE;
828       break;
829     default:
830       break;
831   }
832   return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
833 }
834 #endif
835
836 /* must be called with the display_lock */
837 static void
838 gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
839     GstContext * context)
840 {
841   struct wl_display *display;
842   GError *error = NULL;
843   FUNCTION;
844
845   display = gst_wayland_display_handle_context_get_handle (context);
846   sink->display = gst_wl_display_new_existing (display, FALSE, &error);
847
848   if (error) {
849     GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
850         ("Could not set display handle"),
851         ("Failed to use the external wayland display: '%s'", error->message));
852     g_error_free (error);
853   }
854 #ifdef GST_WLSINK_ENHANCEMENT
855   sink->display->USE_TBM = sink->USE_TBM;
856 #endif
857 }
858
859 static gboolean
860 gst_wayland_sink_find_display (GstWaylandSink * sink)
861 {
862   GstQuery *query;
863   GstMessage *msg;
864   GstContext *context = NULL;
865   GError *error = NULL;
866   gboolean ret = TRUE;
867   FUNCTION;
868
869   g_mutex_lock (&sink->display_lock);
870
871   if (!sink->display) {
872     /* first query upstream for the needed display handle */
873     query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
874     if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) {
875       gst_query_parse_context (query, &context);
876       gst_wayland_sink_set_display_from_context (sink, context);
877     }
878     gst_query_unref (query);
879
880     if (G_LIKELY (!sink->display)) {
881       /* now ask the application to set the display handle */
882       msg = gst_message_new_need_context (GST_OBJECT_CAST (sink),
883           GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
884
885       g_mutex_unlock (&sink->display_lock);
886       gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
887       /* at this point we expect gst_wayland_sink_set_context
888        * to get called and fill sink->display */
889       g_mutex_lock (&sink->display_lock);
890
891       if (!sink->display) {
892         /* if the application didn't set a display, let's create it ourselves */
893         GST_OBJECT_LOCK (sink);
894         sink->display = gst_wl_display_new (sink->display_name, &error);
895         GST_OBJECT_UNLOCK (sink);
896
897         if (error) {
898           GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
899               ("Could not initialise Wayland output"),
900               ("Failed to create GstWlDisplay: '%s'", error->message));
901           g_error_free (error);
902           ret = FALSE;
903         }
904 #ifdef GST_WLSINK_ENHANCEMENT
905         if (sink->display)
906           sink->display->USE_TBM = sink->USE_TBM;
907 #endif
908       }
909     }
910   }
911
912   g_mutex_unlock (&sink->display_lock);
913
914   return ret;
915 }
916
917 static GstStateChangeReturn
918 gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
919 {
920   GstWaylandSink *sink = GST_WAYLAND_SINK (element);
921   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
922   FUNCTION;
923
924   switch (transition) {
925     case GST_STATE_CHANGE_NULL_TO_READY:
926       if (!gst_wayland_sink_find_display (sink))
927         return GST_STATE_CHANGE_FAILURE;
928       break;
929     default:
930       break;
931   }
932
933   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
934   if (ret == GST_STATE_CHANGE_FAILURE)
935     return ret;
936
937   switch (transition) {
938     case GST_STATE_CHANGE_PAUSED_TO_READY:
939 #ifdef GST_WLSINK_ENHANCEMENT
940       if (sink->keep_camera_preview) {
941         if (sink->window) {
942           if (!gst_wl_window_is_toplevel (sink->window)) {
943             GstBaseSink *bsink = GST_BASE_SINK (element);
944             gst_wayland_sink_keep_camera_preview (bsink);
945             break;
946           }
947         }
948       }
949 #endif
950       gst_buffer_replace (&sink->last_buffer, NULL);
951       if (sink->window) {
952         if (gst_wl_window_is_toplevel (sink->window)) {
953           GST_DEBUG ("internal window");
954           g_clear_object (&sink->window);
955         } else {
956           /* remove buffer from surface, show nothing */
957           GST_DEBUG ("external window");
958           gst_wl_window_render (sink->window, NULL, NULL);
959         }
960       }
961       break;
962     case GST_STATE_CHANGE_READY_TO_NULL:
963       g_mutex_lock (&sink->display_lock);
964       /* If we had a toplevel window, we most likely have our own connection
965        * to the display too, and it is a good idea to disconnect and allow
966        * potentially the application to embed us with GstVideoOverlay
967        * (which requires to re-use the same display connection as the parent
968        * surface). If we didn't have a toplevel window, then the display
969        * connection that we have is definitely shared with the application
970        * and it's better to keep it around (together with the window handle)
971        * to avoid requesting them again from the application if/when we are
972        * restarted (GstVideoOverlay behaves like that in other sinks)
973        */
974       if (sink->display && !sink->window) {     /* -> the window was toplevel */
975         g_clear_object (&sink->display);
976       }
977       g_mutex_unlock (&sink->display_lock);
978       g_clear_object (&sink->pool);
979       break;
980     default:
981       break;
982   }
983
984   return ret;
985 }
986
987 static void
988 gst_wayland_sink_set_context (GstElement * element, GstContext * context)
989 {
990   GstWaylandSink *sink = GST_WAYLAND_SINK (element);
991   FUNCTION;
992
993   if (gst_context_has_context_type (context,
994           GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
995     g_mutex_lock (&sink->display_lock);
996     if (G_LIKELY (!sink->display))
997       gst_wayland_sink_set_display_from_context (sink, context);
998     else {
999       GST_WARNING_OBJECT (element, "changing display handle is not supported");
1000 #ifdef GST_WLSINK_ENHANCEMENT
1001       g_mutex_unlock (&sink->display_lock);
1002       return;
1003 #endif
1004     }
1005     g_mutex_unlock (&sink->display_lock);
1006   }
1007
1008   if (GST_ELEMENT_CLASS (parent_class)->set_context)
1009     GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
1010 }
1011
1012 static GstCaps *
1013 gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
1014 {
1015   GstWaylandSink *sink;
1016   GstCaps *caps;
1017   FUNCTION;
1018
1019   sink = GST_WAYLAND_SINK (bsink);
1020
1021   caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
1022
1023   g_mutex_lock (&sink->display_lock);
1024
1025   if (sink->display) {
1026     GValue list = G_VALUE_INIT;
1027     GValue value = G_VALUE_INIT;
1028     GArray *formats;
1029     gint i;
1030 #ifdef GST_WLSINK_ENHANCEMENT
1031     uint32_t tbm_fmt;
1032 #endif
1033     enum wl_shm_format fmt;
1034
1035     g_value_init (&list, GST_TYPE_LIST);
1036     g_value_init (&value, G_TYPE_STRING);
1037 #ifdef GST_WLSINK_ENHANCEMENT
1038     if (sink->display->USE_TBM)
1039       formats = sink->display->tbm_formats;
1040     else                        /* SHM */
1041 #endif
1042       formats = sink->display->formats;
1043
1044     for (i = 0; i < formats->len; i++) {
1045 #ifdef GST_WLSINK_ENHANCEMENT
1046       if (sink->USE_TBM) {
1047         tbm_fmt = g_array_index (formats, uint32_t, i);
1048         g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
1049         gst_value_list_append_value (&list, &value);
1050         /* TBM doesn't support SN12 and ST12. So we add SN12 and ST12 manually as supported format.
1051          * SN12 is same with NV12, ST12 is same with NV12MT
1052          */
1053         if (tbm_fmt == TBM_FORMAT_NV12) {
1054           g_value_set_string (&value,
1055               gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
1056           gst_value_list_append_value (&list, &value);
1057         } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
1058           g_value_set_string (&value,
1059               gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
1060           gst_value_list_append_value (&list, &value);
1061         }
1062       } else {                  /* USE SHM */
1063         fmt = g_array_index (formats, uint32_t, i);
1064         g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1065         gst_value_list_append_value (&list, &value);
1066       }
1067 #else /* open source */
1068       fmt = g_array_index (formats, uint32_t, i);
1069       g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1070       gst_value_list_append_value (&list, &value);
1071 #endif
1072     }
1073
1074     caps = gst_caps_make_writable (caps);
1075     gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
1076
1077     GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
1078     g_value_unset (&value);
1079     g_value_unset (&list);
1080
1081   }
1082
1083   g_mutex_unlock (&sink->display_lock);
1084
1085   if (filter) {
1086     GstCaps *intersection;
1087
1088     intersection =
1089         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1090     gst_caps_unref (caps);
1091     caps = intersection;
1092   }
1093
1094   return caps;
1095 }
1096
1097 static gboolean
1098 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
1099 {
1100   GstWaylandSink *sink;
1101   GstBufferPool *newpool;
1102   GstVideoInfo info;
1103 #ifdef GST_WLSINK_ENHANCEMENT
1104   uint32_t tbm_format;
1105 #endif
1106   enum wl_shm_format format;
1107
1108   GArray *formats;
1109   gint i;
1110   GstStructure *structure;
1111   GstWlShmAllocator *self = NULL;
1112
1113   FUNCTION;
1114
1115   sink = GST_WAYLAND_SINK (bsink);
1116
1117   GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
1118
1119   /* extract info from caps */
1120   if (!gst_video_info_from_caps (&info, caps))
1121     goto invalid_format;
1122 #ifdef GST_WLSINK_ENHANCEMENT
1123   if (sink->USE_TBM) {
1124     tbm_format =
1125         gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
1126     if ((gint) tbm_format == -1)
1127       goto invalid_format;
1128   } else {
1129     format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1130     if ((gint) format == -1)
1131       goto invalid_format;
1132   }
1133 #else /* open source */
1134   format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1135
1136   if ((gint) format == -1)
1137     goto invalid_format;
1138 #endif
1139
1140   /* verify we support the requested format */
1141 #ifdef GST_WLSINK_ENHANCEMENT
1142   if (sink->display->USE_TBM) {
1143     GST_INFO ("USE TBM FORMAT");
1144     formats = sink->display->tbm_formats;
1145     for (i = 0; i < formats->len; i++) {
1146       if (g_array_index (formats, uint32_t, i) == tbm_format)
1147         break;
1148     }
1149   } else {                      /* USE SHM */
1150     GST_INFO ("USE SHM FORMAT");
1151     formats = sink->display->formats;
1152     for (i = 0; i < formats->len; i++) {
1153       if (g_array_index (formats, uint32_t, i) == format)
1154         break;
1155     }
1156   }
1157 #else /* open source */
1158
1159   formats = sink->display->formats;
1160   for (i = 0; i < formats->len; i++) {
1161     if (g_array_index (formats, uint32_t, i) == format)
1162       break;
1163   }
1164 #endif
1165   if (i >= formats->len)
1166     goto unsupported_format;
1167
1168 #ifdef GST_WLSINK_ENHANCEMENT
1169   if (sink->USE_TBM) {
1170     if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1171         GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1172       sink->display->is_native_format = TRUE;
1173
1174       /* store the video info */
1175       sink->video_info = info;
1176       sink->video_info_changed = TRUE;
1177     } else {
1178       sink->display->is_native_format = FALSE;
1179       self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1180       self->display = sink->display;
1181       /* create a new pool for the new configuration */
1182       newpool = gst_video_buffer_pool_new ();
1183       if (!newpool)
1184         goto pool_failed;
1185
1186       structure = gst_buffer_pool_get_config (newpool);
1187       gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1188       gst_buffer_pool_config_set_allocator (structure,
1189           gst_wl_shm_allocator_get (), NULL);
1190       if (!gst_buffer_pool_set_config (newpool, structure))
1191         goto config_failed;
1192
1193       /* store the video info */
1194       sink->video_info = info;
1195       sink->video_info_changed = TRUE;
1196
1197       gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1198       gst_object_unref (newpool);
1199     }
1200   } else {                      /* USE SHM */
1201
1202     self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1203     self->display = sink->display;
1204
1205     /* create a new pool for the new configuration */
1206     newpool = gst_video_buffer_pool_new ();
1207     if (!newpool)
1208       goto pool_failed;
1209
1210     structure = gst_buffer_pool_get_config (newpool);
1211     gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1212     gst_buffer_pool_config_set_allocator (structure,
1213         gst_wl_shm_allocator_get (), NULL);
1214     if (!gst_buffer_pool_set_config (newpool, structure))
1215       goto config_failed;
1216
1217     /* store the video info */
1218     sink->video_info = info;
1219     sink->video_info_changed = TRUE;
1220
1221     gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1222     gst_object_unref (newpool);
1223   }
1224 #else /*open source */
1225   /* create a new pool for the new configuration */
1226   newpool = gst_video_buffer_pool_new ();
1227   if (!newpool)
1228     goto pool_failed;
1229
1230   structure = gst_buffer_pool_get_config (newpool);
1231   gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1232   gst_buffer_pool_config_set_allocator (structure,
1233       gst_wl_shm_allocator_get (), NULL);
1234   if (!gst_buffer_pool_set_config (newpool, structure))
1235     goto config_failed;
1236
1237   /* store the video info */
1238   sink->video_info = info;
1239   sink->video_info_changed = TRUE;
1240
1241   gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1242   gst_object_unref (newpool);
1243 #endif
1244
1245   return TRUE;
1246
1247 invalid_format:
1248   {
1249     GST_DEBUG_OBJECT (sink,
1250         "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1251     return FALSE;
1252   }
1253 unsupported_format:
1254   {
1255 #ifdef GST_WLSINK_ENHANCEMENT
1256     if (sink->USE_TBM)
1257       GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1258           gst_wl_tbm_format_to_string (tbm_format));
1259     else                        /*USE SHM */
1260       GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1261           gst_wl_shm_format_to_string (format));
1262 #else /*open source */
1263     GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1264         gst_wl_shm_format_to_string (format));
1265 #endif
1266     return FALSE;
1267   }
1268 pool_failed:
1269   {
1270     GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1271     return FALSE;
1272   }
1273 config_failed:
1274   {
1275     GST_DEBUG_OBJECT (bsink, "failed setting config");
1276     gst_object_unref (newpool);
1277     return FALSE;
1278   }
1279 }
1280
1281 static gboolean
1282 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1283 {
1284   GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1285   GstStructure *config;
1286   guint size, min_bufs, max_bufs;
1287 #ifdef GST_WLSINK_ENHANCEMENT
1288   gboolean need_pool;
1289   GstCaps *caps;
1290   FUNCTION;
1291
1292   if (sink->USE_TBM) {
1293     if (sink->display->is_native_format == TRUE)
1294       return TRUE;
1295
1296     gst_query_parse_allocation (query, &caps, &need_pool);
1297
1298     if (caps == NULL) {
1299       GST_DEBUG_OBJECT (bsink, "no caps specified");
1300       return FALSE;
1301     }
1302   }
1303 #endif
1304   config = gst_buffer_pool_get_config (sink->pool);
1305   gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1306
1307   /* we do have a pool for sure (created in set_caps),
1308    * so let's propose it anyway, but also propose the allocator on its own */
1309   gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1310   gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1311
1312   gst_structure_free (config);
1313
1314   return TRUE;
1315 }
1316
1317 static GstFlowReturn
1318 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1319 {
1320   FUNCTION;
1321   GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1322   return gst_wayland_sink_render (bsink, buffer);
1323 }
1324
1325 static void
1326 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1327 {
1328   GstWaylandSink *sink = data;
1329   FUNCTION;
1330
1331   GST_LOG ("frame_redraw_cb");
1332
1333   g_atomic_int_set (&sink->redraw_pending, FALSE);
1334   wl_callback_destroy (callback);
1335 #ifdef GST_WLSINK_ENHANCEMENT
1336   if (gst_wayland_sink_check_use_gapless (sink) || sink->keep_camera_preview) {
1337     g_mutex_lock (&sink->render_flush_buffer_lock);
1338     g_cond_signal (&sink->render_flush_buffer_cond);
1339     g_mutex_unlock (&sink->render_flush_buffer_lock);
1340   }
1341 #endif
1342 }
1343
1344 static const struct wl_callback_listener frame_callback_listener = {
1345   frame_redraw_callback
1346 };
1347
1348 #ifdef GST_WLSINK_ENHANCEMENT
1349 static void
1350 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1351 {
1352   FUNCTION;
1353   g_return_if_fail (sink != NULL);
1354   g_return_if_fail (sink->window != NULL);
1355
1356   gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1357   gst_wl_window_set_disp_geo_method (sink->window,
1358       sink->display_geometry_method);
1359   gst_wl_window_set_orientation (sink->window, sink->orientation);
1360   gst_wl_window_set_flip (sink->window, sink->flip);
1361 }
1362 #endif
1363 /* must be called with the render lock */
1364 static void
1365 render_last_buffer (GstWaylandSink * sink)
1366 {
1367   GstWlBuffer *wlbuffer;
1368   const GstVideoInfo *info = NULL;
1369   struct wl_surface *surface;
1370   struct wl_callback *callback;
1371   FUNCTION;
1372 #ifdef GST_WLSINK_ENHANCEMENT
1373   g_return_if_fail (sink->last_buffer != NULL);
1374   g_return_if_fail (sink->window != NULL);
1375 #endif
1376
1377   wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1378   surface = gst_wl_window_get_wl_surface (sink->window);
1379
1380   g_atomic_int_set (&sink->redraw_pending, TRUE);
1381   callback = wl_surface_frame (surface);
1382   /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1383   wl_callback_add_listener (callback, &frame_callback_listener, sink);
1384
1385   if (G_UNLIKELY (sink->video_info_changed)) {
1386 #ifdef GST_WLSINK_ENHANCEMENT
1387     gst_wl_window_set_video_info_change (sink->window, TRUE);
1388 #endif
1389     info = &sink->video_info;
1390     sink->video_info_changed = FALSE;
1391   }
1392   gst_wl_window_render (sink->window, wlbuffer, info);
1393 }
1394
1395 static GstFlowReturn
1396 gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
1397 {
1398   GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1399   GstBuffer *to_render;
1400   GstWlBuffer *wlbuffer;
1401   GstFlowReturn ret = GST_FLOW_OK;
1402   FUNCTION;
1403
1404   g_mutex_lock (&sink->render_lock);
1405
1406   GST_LOG_OBJECT (sink, "render gstbuffer %p, ref_count(%d)", buffer,
1407       GST_OBJECT_REFCOUNT_VALUE (buffer));
1408
1409   if (G_UNLIKELY (!sink->window)) {
1410     /* ask for window handle. Unlock render_lock while doing that because
1411      * set_window_handle & friends will lock it in this context */
1412     g_mutex_unlock (&sink->render_lock);
1413     gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
1414     g_mutex_lock (&sink->render_lock);
1415
1416     if (!sink->window) {
1417       /* if we were not provided a window, create one ourselves */
1418       sink->window =
1419           gst_wl_window_new_toplevel (sink->display, &sink->video_info);
1420     }
1421 #ifdef GST_WLSINK_ENHANCEMENT
1422     gst_wayland_sink_update_window_geometry (sink);
1423 #endif
1424   }
1425   /* drop buffers until we get a frame callback */
1426   if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1427     goto done;
1428   /* make sure that the application has called set_render_rectangle() */
1429   if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1430     goto no_window_size;
1431
1432 #ifdef GST_WLSINK_ENHANCEMENT
1433
1434   wlbuffer = gst_buffer_get_wl_buffer (buffer);
1435   if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)
1436       && !(gst_wayland_sink_check_use_gapless (sink))
1437       && !sink->keep_camera_preview) {
1438     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
1439     GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1440     to_render = buffer;
1441 #ifdef DUMP_BUFFER
1442     GstMemory *mem;
1443     GstMapInfo mem_info = GST_MAP_INFO_INIT;
1444     int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1445     mem = gst_buffer_peek_memory (to_render, 0);
1446     gst_memory_map (mem, &mem_info, GST_MAP_READ);
1447     void *data;
1448     data = mem_info.data;
1449     int ret;
1450     char file_name[128];
1451
1452     sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1453         dump__cnt++);
1454     ret = __write_rawdata (file_name, data, size);
1455     if (ret) {
1456       GST_ERROR ("_write_rawdata() failed");
1457     }
1458     GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1459     gst_memory_unmap (mem, &mem_info);
1460 #endif
1461   } else {
1462     GstMemory *mem;
1463     struct wl_buffer *wbuf = NULL;
1464
1465     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
1466     mem = gst_buffer_peek_memory (buffer, 0);
1467     if (gst_is_wl_shm_memory (mem)) {
1468       FUNCTION;
1469       wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1470           &sink->video_info);
1471       if (wbuf) {
1472         gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add  gstbuffer, wlbuffer, display and etc
1473         to_render = buffer;
1474       }
1475     } else {                    //buffer is not from our pool and have not wl_buffer
1476       GstMapInfo src;
1477       /* we don't know how to create a wl_buffer directly from the provided
1478        * memory, so we have to copy the data to a memory that we know how
1479        * to handle... */
1480
1481       GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1482       GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1483           buffer);
1484
1485       if (sink->USE_TBM && sink->display->is_native_format) {
1486         /* in case of SN12 or ST12 */
1487         if (!gst_wayland_sink_get_mm_video_buf_info (sink, buffer))
1488           return GST_FLOW_ERROR;
1489
1490         wlbuffer = gst_buffer_get_wl_buffer (buffer);
1491         /* last_buffer from gaplasee have wlbuffer */
1492         if (G_UNLIKELY (!wlbuffer)
1493             || (gst_wayland_sink_check_use_gapless (sink))
1494             || sink->keep_camera_preview) {
1495           wbuf =
1496               gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1497               &sink->video_info);
1498           if (G_UNLIKELY (!wbuf))
1499             goto no_wl_buffer;
1500           gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1501         }
1502       } else if (sink->USE_TBM && !sink->display->is_native_format) {
1503
1504         /* sink->pool always exists (created in set_caps), but it may not
1505          * be active if upstream is not using it */
1506         if (!gst_buffer_pool_is_active (sink->pool)
1507             && !gst_buffer_pool_set_active (sink->pool, TRUE))
1508           goto activate_failed;
1509
1510         ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1511         if (ret != GST_FLOW_OK)
1512           goto no_buffer;
1513
1514         //GstMemory *mem;
1515         //mem = gst_buffer_peek_memory (to_render, 0);
1516         //if (gst_is_wl_shm_memory (mem)) {
1517         GST_INFO ("to_render buffer is our buffer");
1518         //}
1519         /* the first time we acquire a buffer,
1520          * we need to attach a wl_buffer on it */
1521         wlbuffer = gst_buffer_get_wl_buffer (buffer);
1522         if (G_UNLIKELY (!wlbuffer)) {
1523           mem = gst_buffer_peek_memory (to_render, 0);
1524           wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1525               &sink->video_info);
1526           if (G_UNLIKELY (!wbuf))
1527             goto no_wl_buffer;
1528
1529           wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1530         }
1531
1532         gst_buffer_map (buffer, &src, GST_MAP_READ);
1533         gst_buffer_fill (to_render, 0, src.data, src.size);
1534         gst_buffer_unmap (buffer, &src);
1535       } else {                  /* USE SHM */
1536         /* sink->pool always exists (created in set_caps), but it may not
1537          * be active if upstream is not using it */
1538         if (!gst_buffer_pool_is_active (sink->pool) &&
1539             !gst_buffer_pool_set_active (sink->pool, TRUE))
1540           goto activate_failed;
1541         ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1542         if (ret != GST_FLOW_OK)
1543           goto no_buffer;
1544         /* the first time we acquire a buffer,
1545          * we need to attach a wl_buffer on it */
1546         wlbuffer = gst_buffer_get_wl_buffer (buffer);
1547         if (G_UNLIKELY (!wlbuffer)) {
1548           mem = gst_buffer_peek_memory (to_render, 0);
1549           wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1550               &sink->video_info);
1551           if (G_UNLIKELY (!wbuf))
1552             goto no_wl_buffer;
1553
1554           gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1555
1556         }
1557
1558         gst_buffer_map (buffer, &src, GST_MAP_READ);
1559         gst_buffer_fill (to_render, 0, src.data, src.size);
1560         gst_buffer_unmap (buffer, &src);
1561       }
1562     }
1563   }
1564
1565   if (sink->USE_TBM && sink->display->is_native_format) {
1566     if ((G_UNLIKELY (buffer == sink->last_buffer)
1567             && !(gst_wayland_sink_check_use_gapless (sink)))
1568         || (G_UNLIKELY (buffer == sink->last_buffer)
1569             && !sink->keep_camera_preview)) {
1570       GST_LOG_OBJECT (sink, "Buffer already being rendered");
1571       goto done;
1572     }
1573     gst_buffer_replace (&sink->last_buffer, buffer);
1574
1575     if (sink->visible) {
1576       render_last_buffer (sink);
1577     } else {
1578       GST_LOG ("skip rendering");
1579     }
1580
1581     goto done;
1582
1583   } else {                      /* USE SHM or normal format */
1584     /* drop double rendering */
1585     if (G_UNLIKELY (buffer == sink->last_buffer)) {
1586       GST_LOG_OBJECT (sink, "Buffer already being rendered");
1587       goto done;
1588     }
1589     gst_buffer_replace (&sink->last_buffer, to_render);
1590
1591     if (sink->visible)
1592       render_last_buffer (sink);
1593
1594     if (buffer != to_render)
1595       gst_buffer_unref (to_render);
1596
1597     goto done;
1598   }
1599
1600 #else /* open source */
1601
1602   wlbuffer = gst_buffer_get_wl_buffer (buffer);
1603
1604   if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1605     GST_LOG_OBJECT (sink,
1606         "buffer %p has a wl_buffer from our display, " "writing directly",
1607         buffer);
1608     GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1609     to_render = buffer;
1610
1611   } else {
1612     GstMemory *mem;
1613     struct wl_buffer *wbuf = NULL;
1614
1615     GST_LOG_OBJECT (sink,
1616         "buffer %p does not have a wl_buffer from our " "display, creating it",
1617         buffer);
1618     mem = gst_buffer_peek_memory (buffer, 0);
1619     if (gst_is_wl_shm_memory (mem)) {
1620       FUNCTION;
1621       wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1622           &sink->video_info);
1623     }
1624     if (wbuf) {
1625       gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1626       to_render = buffer;
1627
1628     } else {
1629       GstMapInfo src;
1630       /* we don't know how to create a wl_buffer directly from the provided
1631        * memory, so we have to copy the data to a memory that we know how
1632        * to handle... */
1633
1634       GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1635       GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1636           buffer);
1637       /* sink->pool always exists (created in set_caps), but it may not
1638        * be active if upstream is not using it */
1639       if (!gst_buffer_pool_is_active (sink->pool) &&
1640           !gst_buffer_pool_set_active (sink->pool, TRUE))
1641         goto activate_failed;
1642
1643       ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1644       if (ret != GST_FLOW_OK)
1645         goto no_buffer;
1646
1647       /* the first time we acquire a buffer,
1648        * we need to attach a wl_buffer on it */
1649       wlbuffer = gst_buffer_get_wl_buffer (buffer);
1650       if (G_UNLIKELY (!wlbuffer)) {
1651         mem = gst_buffer_peek_memory (to_render, 0);
1652         wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1653             &sink->video_info);
1654         if (G_UNLIKELY (!wbuf))
1655           goto no_wl_buffer;
1656
1657         gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1658       }
1659
1660       gst_buffer_map (buffer, &src, GST_MAP_READ);
1661       gst_buffer_fill (to_render, 0, src.data, src.size);
1662       gst_buffer_unmap (buffer, &src);
1663     }
1664   }
1665   /* drop double rendering */
1666   if (G_UNLIKELY (buffer == sink->last_buffer)) {
1667     GST_LOG_OBJECT (sink, "Buffer already being rendered");
1668     goto done;
1669   }
1670
1671   gst_buffer_replace (&sink->last_buffer, to_render);
1672   render_last_buffer (sink);
1673
1674   if (buffer != to_render)
1675     gst_buffer_unref (to_render);
1676
1677   goto done;
1678
1679 #endif /* GST_WLSINK_ENHANCEMENT */
1680
1681 no_window_size:
1682   {
1683     GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1684         ("Window has no size set"),
1685         ("Make sure you set the size after calling set_window_handle"));
1686     ret = GST_FLOW_ERROR;
1687     goto done;
1688   }
1689 no_buffer:
1690   {
1691     GST_WARNING_OBJECT (sink, "could not create buffer");
1692     goto done;
1693   }
1694 no_wl_buffer:
1695   {
1696     GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1697     ret = GST_FLOW_ERROR;
1698     goto done;
1699   }
1700 activate_failed:
1701   {
1702     GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1703     ret = GST_FLOW_ERROR;
1704     goto done;
1705   }
1706 done:
1707   {
1708     g_mutex_unlock (&sink->render_lock);
1709     return ret;
1710   }
1711 }
1712
1713 static void
1714 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1715 {
1716   iface->set_window_handle = gst_wayland_sink_set_window_handle;
1717   iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1718   iface->expose = gst_wayland_sink_expose;
1719 #ifdef GST_WLSINK_ENHANCEMENT   /* use  unique_id */
1720   iface->set_wl_window_wl_surface_id =
1721       gst_wayland_sink_set_wl_window_wl_surface_id;
1722 #endif
1723 }
1724
1725 #ifdef GST_WLSINK_ENHANCEMENT   /* use  unique_id */
1726 static void
1727 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1728     guintptr wl_surface_id)
1729 {
1730   GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1731   FUNCTION;
1732   g_return_if_fail (sink != NULL);
1733
1734   if (sink->window != NULL) {
1735     GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1736     return;
1737   }
1738   g_mutex_lock (&sink->render_lock);
1739   g_clear_object (&sink->window);
1740
1741   GST_INFO ("wl_surface_id %d %x", (int) wl_surface_id,
1742       (guintptr) wl_surface_id);
1743
1744   if (wl_surface_id) {
1745     if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1746       /* we cannot use our own display with an external window handle */
1747       if (G_UNLIKELY (sink->display->own_display)) {
1748         sink->display->wl_surface_id = (int) wl_surface_id;
1749         sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1750       }
1751     } else {
1752       GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1753           "ignoring window handle");
1754     }
1755   }
1756   gst_wayland_sink_update_window_geometry (sink);
1757   g_mutex_unlock (&sink->render_lock);
1758
1759 }
1760 #endif
1761
1762 static void
1763 gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
1764 {
1765   GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1766   struct wl_surface *surface = (struct wl_surface *) handle;
1767   FUNCTION;
1768
1769   g_return_if_fail (sink != NULL);
1770
1771 #ifdef GST_WLSINK_ENHANCEMENT   /* use  unique_id */
1772   if (sink->window != NULL) {
1773     GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1774     return;
1775   }
1776 #endif
1777   g_mutex_lock (&sink->render_lock);
1778
1779   GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
1780       (void *) handle);
1781
1782   g_clear_object (&sink->window);
1783
1784   if (handle) {
1785     if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1786       /* we cannot use our own display with an external window handle */
1787       if (G_UNLIKELY (sink->display->own_display)) {
1788         GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
1789             ("Application did not provide a wayland display handle"),
1790             ("Now waylandsink use internal display handle "
1791                 "which is created ourselves. Consider providing a "
1792                 "display handle from your application with GstContext"));
1793         sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1794       } else {
1795         sink->window = gst_wl_window_new_in_surface (sink->display, surface);
1796       }
1797     } else {
1798       GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1799           "ignoring window handle");
1800     }
1801   }
1802 #ifdef GST_WLSINK_ENHANCEMENT
1803   gst_wayland_sink_update_window_geometry (sink);
1804 #endif
1805   g_mutex_unlock (&sink->render_lock);
1806
1807 }
1808
1809 static void
1810 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1811     gint x, gint y, gint w, gint h)
1812 {
1813   GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1814   FUNCTION;
1815
1816   g_return_if_fail (sink != NULL);
1817
1818   g_mutex_lock (&sink->render_lock);
1819   if (!sink->window) {
1820     g_mutex_unlock (&sink->render_lock);
1821     GST_WARNING_OBJECT (sink,
1822         "set_render_rectangle called without window, ignoring");
1823     return;
1824   }
1825
1826   GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1827       x, y, w, h);
1828   gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1829
1830   g_mutex_unlock (&sink->render_lock);
1831 }
1832
1833 static void
1834 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1835 {
1836   GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1837   FUNCTION;
1838
1839   g_return_if_fail (sink != NULL);
1840
1841   GST_DEBUG_OBJECT (sink, "expose");
1842
1843   g_mutex_lock (&sink->render_lock);
1844   if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1845     GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1846     render_last_buffer (sink);
1847   }
1848   g_mutex_unlock (&sink->render_lock);
1849 }
1850
1851 static void
1852 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1853 {
1854   iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1855   iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1856 }
1857
1858 static void
1859 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1860 {
1861   GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1862   FUNCTION;
1863   g_return_if_fail (sink != NULL);
1864
1865   g_mutex_lock (&sink->render_lock);
1866   if (!sink->window || !sink->window->area_subsurface) {
1867     g_mutex_unlock (&sink->render_lock);
1868     GST_INFO_OBJECT (sink,
1869         "begin_geometry_change called without window, ignoring");
1870     return;
1871   }
1872
1873   wl_subsurface_set_sync (sink->window->area_subsurface);
1874   g_mutex_unlock (&sink->render_lock);
1875 }
1876
1877 static void
1878 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1879 {
1880   GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1881   FUNCTION;
1882   g_return_if_fail (sink != NULL);
1883
1884   g_mutex_lock (&sink->render_lock);
1885   if (!sink->window || !sink->window->area_subsurface) {
1886     g_mutex_unlock (&sink->render_lock);
1887     GST_INFO_OBJECT (sink,
1888         "end_geometry_change called without window, ignoring");
1889     return;
1890   }
1891
1892   wl_subsurface_set_desync (sink->window->area_subsurface);
1893   g_mutex_unlock (&sink->render_lock);
1894 }
1895
1896 static gboolean
1897 plugin_init (GstPlugin * plugin)
1898 {
1899   GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1900       " wayland video sink");
1901
1902   gst_wl_shm_allocator_register ();
1903
1904   return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1905       GST_TYPE_WAYLAND_SINK);
1906 }
1907
1908 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1909     GST_VERSION_MINOR,
1910     waylandsink,
1911     "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
1912     GST_PACKAGE_ORIGIN)