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