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