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