waylandsink : remove repetitive IPC of Upstream (update video info)
[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 #ifdef GST_WLSINK_ENHANCEMENT
755   if (sink->video_info_changed && sink->window) {
756     gst_wl_window_set_video_info_change (sink->window, TRUE);
757     if (GST_STATE (sink) == GST_STATE_PAUSED)
758       gst_wayland_sink_update_last_buffer_geometry (sink);
759   }
760 #endif
761   g_mutex_unlock (&sink->render_lock);
762
763 }
764
765 static void
766 gst_wayland_sink_finalize (GObject * object)
767 {
768   GstWaylandSink *sink = GST_WAYLAND_SINK (object);
769   FUNCTION;
770   GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
771
772   if (sink->last_buffer)
773     gst_buffer_unref (sink->last_buffer);
774   if (sink->display)
775     g_object_unref (sink->display);
776   if (sink->window)
777     g_object_unref (sink->window);
778   if (sink->pool)
779     gst_object_unref (sink->pool);
780
781   if (sink->display_name)
782     g_free (sink->display_name);
783
784   g_mutex_clear (&sink->display_lock);
785   g_mutex_clear (&sink->render_lock);
786 #ifdef GST_WLSINK_ENHANCEMENT
787   g_mutex_clear (&sink->render_flush_buffer_lock);
788   g_cond_clear (&sink->render_flush_buffer_cond);
789 #endif
790
791   G_OBJECT_CLASS (parent_class)->finalize (object);
792 }
793
794 #ifdef GST_WLSINK_ENHANCEMENT
795 static gboolean
796 gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event)
797 {
798   GstWaylandSink *sink;
799   sink = GST_WAYLAND_SINK (bsink);
800
801   switch (GST_EVENT_TYPE (event)) {
802     case GST_EVENT_EOS:
803       GST_LOG ("get EOS event..state is %d", GST_STATE (sink));
804       sink->got_eos_event = TRUE;
805       if (gst_wayland_sink_check_use_gapless (sink)) {
806         gst_wayland_sink_gapless_render (bsink);
807         sink->got_eos_event = FALSE;
808       }
809       sink->got_eos_event = FALSE;
810       break;
811     default:
812       break;
813   }
814   return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
815 }
816 #endif
817
818 /* must be called with the display_lock */
819 static void
820 gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
821     GstContext * context)
822 {
823   struct wl_display *display;
824   GError *error = NULL;
825   FUNCTION;
826
827   display = gst_wayland_display_handle_context_get_handle (context);
828   sink->display = gst_wl_display_new_existing (display, FALSE, &error);
829
830   if (error) {
831     GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
832         ("Could not set display handle"),
833         ("Failed to use the external wayland display: '%s'", error->message));
834     g_error_free (error);
835   }
836 #ifdef GST_WLSINK_ENHANCEMENT
837   sink->display->USE_TBM = sink->USE_TBM;
838 #endif
839 }
840
841 static gboolean
842 gst_wayland_sink_find_display (GstWaylandSink * sink)
843 {
844   GstQuery *query;
845   GstMessage *msg;
846   GstContext *context = NULL;
847   GError *error = NULL;
848   gboolean ret = TRUE;
849   FUNCTION;
850
851   g_mutex_lock (&sink->display_lock);
852
853   if (!sink->display) {
854     /* first query upstream for the needed display handle */
855     query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
856     if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) {
857       gst_query_parse_context (query, &context);
858       gst_wayland_sink_set_display_from_context (sink, context);
859     }
860     gst_query_unref (query);
861
862     if (G_LIKELY (!sink->display)) {
863       /* now ask the application to set the display handle */
864       msg = gst_message_new_need_context (GST_OBJECT_CAST (sink),
865           GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
866
867       g_mutex_unlock (&sink->display_lock);
868       gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
869       /* at this point we expect gst_wayland_sink_set_context
870        * to get called and fill sink->display */
871       g_mutex_lock (&sink->display_lock);
872
873       if (!sink->display) {
874         /* if the application didn't set a display, let's create it ourselves */
875         GST_OBJECT_LOCK (sink);
876         sink->display = gst_wl_display_new (sink->display_name, &error);
877         GST_OBJECT_UNLOCK (sink);
878
879         if (error) {
880           GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
881               ("Could not initialise Wayland output"),
882               ("Failed to create GstWlDisplay: '%s'", error->message));
883           g_error_free (error);
884           ret = FALSE;
885         }
886 #ifdef GST_WLSINK_ENHANCEMENT
887         if (sink->display)
888           sink->display->USE_TBM = sink->USE_TBM;
889 #endif
890       }
891     }
892   }
893
894   g_mutex_unlock (&sink->display_lock);
895
896   return ret;
897 }
898
899 static GstStateChangeReturn
900 gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
901 {
902   GstWaylandSink *sink = GST_WAYLAND_SINK (element);
903   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
904   FUNCTION;
905
906   switch (transition) {
907     case GST_STATE_CHANGE_NULL_TO_READY:
908       if (!gst_wayland_sink_find_display (sink))
909         return GST_STATE_CHANGE_FAILURE;
910       break;
911     default:
912       break;
913   }
914
915   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
916   if (ret == GST_STATE_CHANGE_FAILURE)
917     return ret;
918
919   switch (transition) {
920     case GST_STATE_CHANGE_PAUSED_TO_READY:
921 #ifdef GST_WLSINK_ENHANCEMENT
922       if (sink->keep_camera_preview) {
923         if (sink->window) {
924           if (!gst_wl_window_is_toplevel (sink->window)) {
925             GstBaseSink *bsink = GST_BASE_SINK (element);
926             gst_wayland_sink_keep_camera_preview (bsink);
927             break;
928           }
929         }
930       }
931 #endif
932       gst_buffer_replace (&sink->last_buffer, NULL);
933       if (sink->window) {
934         if (gst_wl_window_is_toplevel (sink->window)) {
935           GST_DEBUG ("internal window");
936           g_clear_object (&sink->window);
937         } else {
938           /* remove buffer from surface, show nothing */
939           GST_DEBUG ("external window");
940           gst_wl_window_render (sink->window, NULL, NULL);
941         }
942       }
943       break;
944     case GST_STATE_CHANGE_READY_TO_NULL:
945       g_mutex_lock (&sink->display_lock);
946       /* If we had a toplevel window, we most likely have our own connection
947        * to the display too, and it is a good idea to disconnect and allow
948        * potentially the application to embed us with GstVideoOverlay
949        * (which requires to re-use the same display connection as the parent
950        * surface). If we didn't have a toplevel window, then the display
951        * connection that we have is definitely shared with the application
952        * and it's better to keep it around (together with the window handle)
953        * to avoid requesting them again from the application if/when we are
954        * restarted (GstVideoOverlay behaves like that in other sinks)
955        */
956       if (sink->display && !sink->window) {     /* -> the window was toplevel */
957         g_clear_object (&sink->display);
958       }
959       g_mutex_unlock (&sink->display_lock);
960       g_clear_object (&sink->pool);
961       break;
962     default:
963       break;
964   }
965
966   return ret;
967 }
968
969 static void
970 gst_wayland_sink_set_context (GstElement * element, GstContext * context)
971 {
972   GstWaylandSink *sink = GST_WAYLAND_SINK (element);
973   FUNCTION;
974
975   if (gst_context_has_context_type (context,
976           GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
977     g_mutex_lock (&sink->display_lock);
978     if (G_LIKELY (!sink->display))
979       gst_wayland_sink_set_display_from_context (sink, context);
980     else {
981       GST_WARNING_OBJECT (element, "changing display handle is not supported");
982 #ifdef GST_WLSINK_ENHANCEMENT
983       g_mutex_unlock (&sink->display_lock);
984       return;
985 #endif
986     }
987     g_mutex_unlock (&sink->display_lock);
988   }
989
990   if (GST_ELEMENT_CLASS (parent_class)->set_context)
991     GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
992 }
993
994 static GstCaps *
995 gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
996 {
997   GstWaylandSink *sink;
998   GstCaps *caps;
999   FUNCTION;
1000
1001   sink = GST_WAYLAND_SINK (bsink);
1002
1003   caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
1004
1005   g_mutex_lock (&sink->display_lock);
1006
1007   if (sink->display) {
1008     GValue list = G_VALUE_INIT;
1009     GValue value = G_VALUE_INIT;
1010     GArray *formats;
1011     gint i;
1012 #ifdef GST_WLSINK_ENHANCEMENT
1013     uint32_t tbm_fmt;
1014 #endif
1015     enum wl_shm_format fmt;
1016
1017     g_value_init (&list, GST_TYPE_LIST);
1018     g_value_init (&value, G_TYPE_STRING);
1019 #ifdef GST_WLSINK_ENHANCEMENT
1020     if (sink->display->USE_TBM)
1021       formats = sink->display->tbm_formats;
1022     else                        /* SHM */
1023 #endif
1024       formats = sink->display->formats;
1025
1026     for (i = 0; i < formats->len; i++) {
1027 #ifdef GST_WLSINK_ENHANCEMENT
1028       if (sink->USE_TBM) {
1029         tbm_fmt = g_array_index (formats, uint32_t, i);
1030         g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
1031         gst_value_list_append_value (&list, &value);
1032         /* TBM doesn't support SN12 and ST12. So we add SN12 and ST12 manually as supported format.
1033          * SN12 is same with NV12, ST12 is same with NV12MT
1034          */
1035         if (tbm_fmt == TBM_FORMAT_NV12) {
1036           g_value_set_string (&value,
1037               gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
1038           gst_value_list_append_value (&list, &value);
1039         } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
1040           g_value_set_string (&value,
1041               gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
1042           gst_value_list_append_value (&list, &value);
1043         }
1044       } else {                  /* USE SHM */
1045         fmt = g_array_index (formats, uint32_t, i);
1046         g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1047         gst_value_list_append_value (&list, &value);
1048       }
1049 #else /* open source */
1050       fmt = g_array_index (formats, uint32_t, i);
1051       g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
1052       gst_value_list_append_value (&list, &value);
1053 #endif
1054     }
1055
1056     caps = gst_caps_make_writable (caps);
1057     gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
1058
1059     GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
1060     g_value_unset (&value);
1061     g_value_unset (&list);
1062
1063   }
1064
1065   g_mutex_unlock (&sink->display_lock);
1066
1067   if (filter) {
1068     GstCaps *intersection;
1069
1070     intersection =
1071         gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
1072     gst_caps_unref (caps);
1073     caps = intersection;
1074   }
1075
1076   return caps;
1077 }
1078
1079 static gboolean
1080 gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
1081 {
1082   GstWaylandSink *sink;
1083   GstBufferPool *newpool;
1084   GstVideoInfo info;
1085 #ifdef GST_WLSINK_ENHANCEMENT
1086   uint32_t tbm_format;
1087 #endif
1088   enum wl_shm_format format;
1089
1090   GArray *formats;
1091   gint i;
1092   GstStructure *structure;
1093   GstWlShmAllocator *self = NULL;
1094
1095   FUNCTION;
1096
1097   sink = GST_WAYLAND_SINK (bsink);
1098
1099   GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
1100
1101   /* extract info from caps */
1102   if (!gst_video_info_from_caps (&info, caps))
1103     goto invalid_format;
1104 #ifdef GST_WLSINK_ENHANCEMENT
1105   if (sink->USE_TBM) {
1106     tbm_format =
1107         gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
1108     if ((gint) tbm_format == -1)
1109       goto invalid_format;
1110   } else {
1111     format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1112     if ((gint) format == -1)
1113       goto invalid_format;
1114   }
1115 #else /* open source */
1116   format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
1117
1118   if ((gint) format == -1)
1119     goto invalid_format;
1120 #endif
1121
1122   /* verify we support the requested format */
1123 #ifdef GST_WLSINK_ENHANCEMENT
1124   if (sink->display->USE_TBM) {
1125     GST_INFO ("USE TBM FORMAT");
1126     formats = sink->display->tbm_formats;
1127     for (i = 0; i < formats->len; i++) {
1128       if (g_array_index (formats, uint32_t, i) == tbm_format)
1129         break;
1130     }
1131   } else {                      /* USE SHM */
1132     GST_INFO ("USE SHM FORMAT");
1133     formats = sink->display->formats;
1134     for (i = 0; i < formats->len; i++) {
1135       if (g_array_index (formats, uint32_t, i) == format)
1136         break;
1137     }
1138   }
1139 #else /* open source */
1140
1141   formats = sink->display->formats;
1142   for (i = 0; i < formats->len; i++) {
1143     if (g_array_index (formats, uint32_t, i) == format)
1144       break;
1145   }
1146 #endif
1147   if (i >= formats->len)
1148     goto unsupported_format;
1149
1150 #ifdef GST_WLSINK_ENHANCEMENT
1151   if (sink->USE_TBM) {
1152     if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
1153         GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
1154       sink->display->is_native_format = TRUE;
1155
1156       /* store the video info */
1157       sink->video_info = info;
1158       sink->video_info_changed = TRUE;
1159     } else {
1160       sink->display->is_native_format = FALSE;
1161       self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1162       self->display = sink->display;
1163       /* create a new pool for the new configuration */
1164       newpool = gst_video_buffer_pool_new ();
1165       if (!newpool)
1166         goto pool_failed;
1167
1168       structure = gst_buffer_pool_get_config (newpool);
1169       gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1170       gst_buffer_pool_config_set_allocator (structure,
1171           gst_wl_shm_allocator_get (), NULL);
1172       if (!gst_buffer_pool_set_config (newpool, structure))
1173         goto config_failed;
1174
1175       /* store the video info */
1176       sink->video_info = info;
1177       sink->video_info_changed = TRUE;
1178
1179       gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1180       gst_object_unref (newpool);
1181     }
1182   } else {                      /* USE SHM */
1183
1184     self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
1185     self->display = sink->display;
1186
1187     /* create a new pool for the new configuration */
1188     newpool = gst_video_buffer_pool_new ();
1189     if (!newpool)
1190       goto pool_failed;
1191
1192     structure = gst_buffer_pool_get_config (newpool);
1193     gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1194     gst_buffer_pool_config_set_allocator (structure,
1195         gst_wl_shm_allocator_get (), NULL);
1196     if (!gst_buffer_pool_set_config (newpool, structure))
1197       goto config_failed;
1198
1199     /* store the video info */
1200     sink->video_info = info;
1201     sink->video_info_changed = TRUE;
1202
1203     gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1204     gst_object_unref (newpool);
1205   }
1206 #else /*open source */
1207   /* create a new pool for the new configuration */
1208   newpool = gst_video_buffer_pool_new ();
1209   if (!newpool)
1210     goto pool_failed;
1211
1212   structure = gst_buffer_pool_get_config (newpool);
1213   gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
1214   gst_buffer_pool_config_set_allocator (structure,
1215       gst_wl_shm_allocator_get (), NULL);
1216   if (!gst_buffer_pool_set_config (newpool, structure))
1217     goto config_failed;
1218
1219   /* store the video info */
1220   sink->video_info = info;
1221   sink->video_info_changed = TRUE;
1222
1223   gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
1224   gst_object_unref (newpool);
1225 #endif
1226
1227   return TRUE;
1228
1229 invalid_format:
1230   {
1231     GST_DEBUG_OBJECT (sink,
1232         "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
1233     return FALSE;
1234   }
1235 unsupported_format:
1236   {
1237 #ifdef GST_WLSINK_ENHANCEMENT
1238     if (sink->USE_TBM)
1239       GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1240           gst_wl_tbm_format_to_string (tbm_format));
1241     else                        /*USE SHM */
1242       GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1243           gst_wl_shm_format_to_string (format));
1244 #else /*open source */
1245     GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
1246         gst_wl_shm_format_to_string (format));
1247 #endif
1248     return FALSE;
1249   }
1250 pool_failed:
1251   {
1252     GST_DEBUG_OBJECT (sink, "Failed to create new pool");
1253     return FALSE;
1254   }
1255 config_failed:
1256   {
1257     GST_DEBUG_OBJECT (bsink, "failed setting config");
1258     gst_object_unref (newpool);
1259     return FALSE;
1260   }
1261 }
1262
1263 static gboolean
1264 gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
1265 {
1266   GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1267   GstStructure *config;
1268   guint size, min_bufs, max_bufs;
1269 #ifdef GST_WLSINK_ENHANCEMENT
1270   gboolean need_pool;
1271   GstCaps *caps;
1272   FUNCTION;
1273
1274   if (sink->USE_TBM) {
1275     if (sink->display->is_native_format == TRUE)
1276       return TRUE;
1277
1278     gst_query_parse_allocation (query, &caps, &need_pool);
1279
1280     if (caps == NULL) {
1281       GST_DEBUG_OBJECT (bsink, "no caps specified");
1282       return FALSE;
1283     }
1284   }
1285 #endif
1286   config = gst_buffer_pool_get_config (sink->pool);
1287   gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
1288
1289   /* we do have a pool for sure (created in set_caps),
1290    * so let's propose it anyway, but also propose the allocator on its own */
1291   gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
1292   gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
1293
1294   gst_structure_free (config);
1295
1296   return TRUE;
1297 }
1298
1299 static GstFlowReturn
1300 gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
1301 {
1302   FUNCTION;
1303   GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
1304   return gst_wayland_sink_render (bsink, buffer);
1305 }
1306
1307 static void
1308 frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
1309 {
1310   GstWaylandSink *sink = data;
1311   FUNCTION;
1312
1313   GST_LOG ("frame_redraw_cb");
1314
1315   g_atomic_int_set (&sink->redraw_pending, FALSE);
1316   wl_callback_destroy (callback);
1317 #ifdef GST_WLSINK_ENHANCEMENT
1318   if (gst_wayland_sink_check_use_gapless (sink) || sink->keep_camera_preview) {
1319     g_mutex_lock (&sink->render_flush_buffer_lock);
1320     g_cond_signal (&sink->render_flush_buffer_cond);
1321     g_mutex_unlock (&sink->render_flush_buffer_lock);
1322   }
1323 #endif
1324 }
1325
1326 static const struct wl_callback_listener frame_callback_listener = {
1327   frame_redraw_callback
1328 };
1329
1330 #ifdef GST_WLSINK_ENHANCEMENT
1331 static void
1332 gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
1333 {
1334   FUNCTION;
1335   g_return_if_fail (sink != NULL);
1336   g_return_if_fail (sink->window != NULL);
1337
1338   gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
1339   gst_wl_window_set_disp_geo_method (sink->window,
1340       sink->display_geometry_method);
1341   gst_wl_window_set_orientation (sink->window, sink->orientation);
1342   gst_wl_window_set_flip (sink->window, sink->flip);
1343 }
1344 #endif
1345 /* must be called with the render lock */
1346 static void
1347 render_last_buffer (GstWaylandSink * sink)
1348 {
1349   GstWlBuffer *wlbuffer;
1350   const GstVideoInfo *info = NULL;
1351   struct wl_surface *surface;
1352   struct wl_callback *callback;
1353   FUNCTION;
1354 #ifdef GST_WLSINK_ENHANCEMENT
1355   g_return_if_fail (sink->last_buffer != NULL);
1356   g_return_if_fail (sink->window != NULL);
1357 #endif
1358
1359   wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
1360   surface = gst_wl_window_get_wl_surface (sink->window);
1361
1362   g_atomic_int_set (&sink->redraw_pending, TRUE);
1363   callback = wl_surface_frame (surface);
1364   /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
1365   wl_callback_add_listener (callback, &frame_callback_listener, sink);
1366
1367   if (G_UNLIKELY (sink->video_info_changed)) {
1368 #ifdef GST_WLSINK_ENHANCEMENT
1369       gst_wl_window_set_video_info_change (sink->window, TRUE);
1370 #endif
1371     info = &sink->video_info;
1372     sink->video_info_changed = FALSE;
1373   }
1374   gst_wl_window_render (sink->window, wlbuffer, info);
1375 }
1376
1377 static GstFlowReturn
1378 gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
1379 {
1380   GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
1381   GstBuffer *to_render;
1382   GstWlBuffer *wlbuffer;
1383   GstFlowReturn ret = GST_FLOW_OK;
1384   FUNCTION;
1385
1386   g_mutex_lock (&sink->render_lock);
1387
1388   GST_LOG_OBJECT (sink, "render buffer %p", buffer);
1389
1390   if (G_UNLIKELY (!sink->window)) {
1391     /* ask for window handle. Unlock render_lock while doing that because
1392      * set_window_handle & friends will lock it in this context */
1393     g_mutex_unlock (&sink->render_lock);
1394     gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
1395     g_mutex_lock (&sink->render_lock);
1396
1397     if (!sink->window) {
1398       /* if we were not provided a window, create one ourselves */
1399       sink->window =
1400           gst_wl_window_new_toplevel (sink->display, &sink->video_info);
1401     }
1402 #ifdef GST_WLSINK_ENHANCEMENT
1403     gst_wayland_sink_update_window_geometry (sink);
1404 #endif
1405   }
1406   /* drop buffers until we get a frame callback */
1407   if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
1408     goto done;
1409   /* make sure that the application has called set_render_rectangle() */
1410   if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
1411     goto no_window_size;
1412
1413 #ifdef GST_WLSINK_ENHANCEMENT
1414
1415   wlbuffer = gst_buffer_get_wl_buffer (buffer);
1416   if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)
1417       && !(gst_wayland_sink_check_use_gapless (sink))
1418       && !sink->keep_camera_preview) {
1419     GST_LOG_OBJECT (sink, "buffer %p has a wl_buffer from our display, " "writing directly", buffer);   //buffer is from our  pool and have wl_buffer
1420     GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1421     to_render = buffer;
1422 #ifdef DUMP_BUFFER
1423     GstMemory *mem;
1424     GstMapInfo mem_info = GST_MAP_INFO_INIT;
1425     int size = GST_VIDEO_INFO_SIZE (&sink->video_info);
1426     mem = gst_buffer_peek_memory (to_render, 0);
1427     gst_memory_map (mem, &mem_info, GST_MAP_READ);
1428     void *data;
1429     data = mem_info.data;
1430     int ret;
1431     char file_name[128];
1432
1433     sprintf (file_name, "/home/owner/DUMP/_WLSINK_OUT_DUMP_%2.2d.dump",
1434         dump__cnt++);
1435     ret = __write_rawdata (file_name, data, size);
1436     if (ret) {
1437       GST_ERROR ("_write_rawdata() failed");
1438     }
1439     GST_INFO ("DUMP IMAGE %d, size (%d)", dump__cnt, size);
1440     gst_memory_unmap (mem, &mem_info);
1441 #endif
1442   } else {
1443     GstMemory *mem;
1444     struct wl_buffer *wbuf = NULL;
1445
1446     GST_LOG_OBJECT (sink, "buffer %p does not have a wl_buffer from our " "display, creating it", buffer);      //buffer is from our pool but have not wl_buffer
1447     mem = gst_buffer_peek_memory (buffer, 0);
1448     if (gst_is_wl_shm_memory (mem)) {
1449       FUNCTION;
1450       wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1451           &sink->video_info);
1452       if (wbuf) {
1453         gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); //careat GstWlBuffer and add  gstbuffer, wlbuffer, display and etc
1454         to_render = buffer;
1455       }
1456     } else {                    //buffer is not from our pool and have not wl_buffer
1457       GstMapInfo src;
1458       /* we don't know how to create a wl_buffer directly from the provided
1459        * memory, so we have to copy the data to a memory that we know how
1460        * to handle... */
1461
1462       GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1463       GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1464           buffer);
1465
1466       if (sink->USE_TBM && sink->display->is_native_format) {
1467         /* in case of SN12 or ST12 */
1468         if (!gst_wayland_sink_get_mm_video_buf_info (sink, buffer))
1469           return GST_FLOW_ERROR;
1470
1471         wlbuffer = gst_buffer_get_wl_buffer (buffer);
1472         /* last_buffer from gaplasee have wlbuffer */
1473         if (G_UNLIKELY (!wlbuffer)
1474             || (gst_wayland_sink_check_use_gapless (sink))
1475             || sink->keep_camera_preview) {
1476           wbuf =
1477               gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1478               &sink->video_info);
1479           if (G_UNLIKELY (!wbuf))
1480             goto no_wl_buffer;
1481           gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1482         }
1483       } else if (sink->USE_TBM && !sink->display->is_native_format) {
1484
1485         /* sink->pool always exists (created in set_caps), but it may not
1486          * be active if upstream is not using it */
1487         if (!gst_buffer_pool_is_active (sink->pool)
1488             && !gst_buffer_pool_set_active (sink->pool, TRUE))
1489           goto activate_failed;
1490
1491         ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1492         if (ret != GST_FLOW_OK)
1493           goto no_buffer;
1494
1495         //GstMemory *mem;
1496         //mem = gst_buffer_peek_memory (to_render, 0);
1497         //if (gst_is_wl_shm_memory (mem)) {
1498         GST_INFO ("to_render buffer is our buffer");
1499         //}
1500         /* the first time we acquire a buffer,
1501          * we need to attach a wl_buffer on it */
1502         wlbuffer = gst_buffer_get_wl_buffer (buffer);
1503         if (G_UNLIKELY (!wlbuffer)) {
1504           mem = gst_buffer_peek_memory (to_render, 0);
1505           wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1506               &sink->video_info);
1507           if (G_UNLIKELY (!wbuf))
1508             goto no_wl_buffer;
1509
1510           wlbuffer = gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1511         }
1512
1513         gst_buffer_map (buffer, &src, GST_MAP_READ);
1514         gst_buffer_fill (to_render, 0, src.data, src.size);
1515         gst_buffer_unmap (buffer, &src);
1516       } else {                  /* USE SHM */
1517         /* sink->pool always exists (created in set_caps), but it may not
1518          * be active if upstream is not using it */
1519         if (!gst_buffer_pool_is_active (sink->pool) &&
1520             !gst_buffer_pool_set_active (sink->pool, TRUE))
1521           goto activate_failed;
1522         ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1523         if (ret != GST_FLOW_OK)
1524           goto no_buffer;
1525         /* the first time we acquire a buffer,
1526          * we need to attach a wl_buffer on it */
1527         wlbuffer = gst_buffer_get_wl_buffer (buffer);
1528         if (G_UNLIKELY (!wlbuffer)) {
1529           mem = gst_buffer_peek_memory (to_render, 0);
1530           wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1531               &sink->video_info);
1532           if (G_UNLIKELY (!wbuf))
1533             goto no_wl_buffer;
1534
1535           gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1536
1537         }
1538
1539         gst_buffer_map (buffer, &src, GST_MAP_READ);
1540         gst_buffer_fill (to_render, 0, src.data, src.size);
1541         gst_buffer_unmap (buffer, &src);
1542       }
1543     }
1544   }
1545
1546   if (sink->USE_TBM && sink->display->is_native_format) {
1547     if ((G_UNLIKELY (buffer == sink->last_buffer)
1548             && !(gst_wayland_sink_check_use_gapless (sink)))
1549         || (G_UNLIKELY (buffer == sink->last_buffer)
1550             && !sink->keep_camera_preview)) {
1551       GST_LOG_OBJECT (sink, "Buffer already being rendered");
1552       goto done;
1553     }
1554     gst_buffer_replace (&sink->last_buffer, buffer);
1555
1556     if (sink->visible)
1557       render_last_buffer (sink);
1558
1559     goto done;
1560
1561   } else {                      /* USE SHM or normal format */
1562     /* drop double rendering */
1563     if (G_UNLIKELY (buffer == sink->last_buffer)) {
1564       GST_LOG_OBJECT (sink, "Buffer already being rendered");
1565       goto done;
1566     }
1567     gst_buffer_replace (&sink->last_buffer, to_render);
1568
1569     if (sink->visible)
1570       render_last_buffer (sink);
1571
1572     if (buffer != to_render)
1573       gst_buffer_unref (to_render);
1574
1575     goto done;
1576   }
1577
1578 #else /* open source */
1579
1580   wlbuffer = gst_buffer_get_wl_buffer (buffer);
1581
1582   if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
1583     GST_LOG_OBJECT (sink,
1584         "buffer %p has a wl_buffer from our display, " "writing directly",
1585         buffer);
1586     GST_INFO ("wl_buffer (%p)", wlbuffer->wlbuffer);
1587     to_render = buffer;
1588
1589   } else {
1590     GstMemory *mem;
1591     struct wl_buffer *wbuf = NULL;
1592
1593     GST_LOG_OBJECT (sink,
1594         "buffer %p does not have a wl_buffer from our " "display, creating it",
1595         buffer);
1596     mem = gst_buffer_peek_memory (buffer, 0);
1597     if (gst_is_wl_shm_memory (mem)) {
1598       FUNCTION;
1599       wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1600           &sink->video_info);
1601     }
1602     if (wbuf) {
1603       gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
1604       to_render = buffer;
1605
1606     } else {
1607       GstMapInfo src;
1608       /* we don't know how to create a wl_buffer directly from the provided
1609        * memory, so we have to copy the data to a memory that we know how
1610        * to handle... */
1611
1612       GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
1613       GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
1614           buffer);
1615       /* sink->pool always exists (created in set_caps), but it may not
1616        * be active if upstream is not using it */
1617       if (!gst_buffer_pool_is_active (sink->pool) &&
1618           !gst_buffer_pool_set_active (sink->pool, TRUE))
1619         goto activate_failed;
1620
1621       ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
1622       if (ret != GST_FLOW_OK)
1623         goto no_buffer;
1624
1625       /* the first time we acquire a buffer,
1626        * we need to attach a wl_buffer on it */
1627       wlbuffer = gst_buffer_get_wl_buffer (buffer);
1628       if (G_UNLIKELY (!wlbuffer)) {
1629         mem = gst_buffer_peek_memory (to_render, 0);
1630         wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
1631             &sink->video_info);
1632         if (G_UNLIKELY (!wbuf))
1633           goto no_wl_buffer;
1634
1635         gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
1636       }
1637
1638       gst_buffer_map (buffer, &src, GST_MAP_READ);
1639       gst_buffer_fill (to_render, 0, src.data, src.size);
1640       gst_buffer_unmap (buffer, &src);
1641     }
1642   }
1643   /* drop double rendering */
1644   if (G_UNLIKELY (buffer == sink->last_buffer)) {
1645     GST_LOG_OBJECT (sink, "Buffer already being rendered");
1646     goto done;
1647   }
1648
1649   gst_buffer_replace (&sink->last_buffer, to_render);
1650   render_last_buffer (sink);
1651
1652   if (buffer != to_render)
1653     gst_buffer_unref (to_render);
1654
1655   goto done;
1656
1657 #endif /* GST_WLSINK_ENHANCEMENT */
1658
1659 no_window_size:
1660   {
1661     GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
1662         ("Window has no size set"),
1663         ("Make sure you set the size after calling set_window_handle"));
1664     ret = GST_FLOW_ERROR;
1665     goto done;
1666   }
1667 no_buffer:
1668   {
1669     GST_WARNING_OBJECT (sink, "could not create buffer");
1670     goto done;
1671   }
1672 no_wl_buffer:
1673   {
1674     GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
1675     ret = GST_FLOW_ERROR;
1676     goto done;
1677   }
1678 activate_failed:
1679   {
1680     GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
1681     ret = GST_FLOW_ERROR;
1682     goto done;
1683   }
1684 done:
1685   {
1686     g_mutex_unlock (&sink->render_lock);
1687     return ret;
1688   }
1689 }
1690
1691 static void
1692 gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
1693 {
1694   iface->set_window_handle = gst_wayland_sink_set_window_handle;
1695   iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
1696   iface->expose = gst_wayland_sink_expose;
1697 #ifdef GST_WLSINK_ENHANCEMENT   /* use  unique_id */
1698   iface->set_wl_window_wl_surface_id =
1699       gst_wayland_sink_set_wl_window_wl_surface_id;
1700 #endif
1701 }
1702
1703 #ifdef GST_WLSINK_ENHANCEMENT   /* use  unique_id */
1704 static void
1705 gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
1706     guintptr wl_surface_id)
1707 {
1708   GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1709   FUNCTION;
1710   g_return_if_fail (sink != NULL);
1711
1712   if (sink->window != NULL) {
1713     GST_WARNING_OBJECT (sink, "changing window handle is not supported");
1714     return;
1715   }
1716   g_mutex_lock (&sink->render_lock);
1717   g_clear_object (&sink->window);
1718
1719   GST_INFO ("wl_surface_id %d %x", (int) wl_surface_id,
1720       (guintptr) wl_surface_id);
1721
1722   if (wl_surface_id) {
1723     if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
1724       /* we cannot use our own display with an external window handle */
1725       if (G_UNLIKELY (sink->display->own_display)) {
1726         sink->display->wl_surface_id = (int) wl_surface_id;
1727         sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
1728       }
1729     } else {
1730       GST_ERROR_OBJECT (sink, "Failed to find display handle, "
1731           "ignoring window handle");
1732     }
1733   }
1734   gst_wayland_sink_update_window_geometry (sink);
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 #ifdef GST_WLSINK_ENHANCEMENT
1781   gst_wayland_sink_update_window_geometry (sink);
1782 #endif
1783   g_mutex_unlock (&sink->render_lock);
1784
1785 }
1786
1787 static void
1788 gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
1789     gint x, gint y, gint w, gint h)
1790 {
1791   GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1792   FUNCTION;
1793
1794   g_return_if_fail (sink != NULL);
1795
1796   g_mutex_lock (&sink->render_lock);
1797   if (!sink->window) {
1798     g_mutex_unlock (&sink->render_lock);
1799     GST_WARNING_OBJECT (sink,
1800         "set_render_rectangle called without window, ignoring");
1801     return;
1802   }
1803
1804   GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
1805       x, y, w, h);
1806   gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
1807
1808   g_mutex_unlock (&sink->render_lock);
1809 }
1810
1811 static void
1812 gst_wayland_sink_expose (GstVideoOverlay * overlay)
1813 {
1814   GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
1815   FUNCTION;
1816
1817   g_return_if_fail (sink != NULL);
1818
1819   GST_DEBUG_OBJECT (sink, "expose");
1820
1821   g_mutex_lock (&sink->render_lock);
1822   if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
1823     GST_DEBUG_OBJECT (sink, "redrawing last buffer");
1824     render_last_buffer (sink);
1825   }
1826   g_mutex_unlock (&sink->render_lock);
1827 }
1828
1829 static void
1830 gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
1831 {
1832   iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
1833   iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
1834 }
1835
1836 static void
1837 gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
1838 {
1839   GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1840   FUNCTION;
1841   g_return_if_fail (sink != NULL);
1842
1843   g_mutex_lock (&sink->render_lock);
1844   if (!sink->window || !sink->window->area_subsurface) {
1845     g_mutex_unlock (&sink->render_lock);
1846     GST_INFO_OBJECT (sink,
1847         "begin_geometry_change called without window, ignoring");
1848     return;
1849   }
1850
1851   wl_subsurface_set_sync (sink->window->area_subsurface);
1852   g_mutex_unlock (&sink->render_lock);
1853 }
1854
1855 static void
1856 gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
1857 {
1858   GstWaylandSink *sink = GST_WAYLAND_SINK (video);
1859   FUNCTION;
1860   g_return_if_fail (sink != NULL);
1861
1862   g_mutex_lock (&sink->render_lock);
1863   if (!sink->window || !sink->window->area_subsurface) {
1864     g_mutex_unlock (&sink->render_lock);
1865     GST_INFO_OBJECT (sink,
1866         "end_geometry_change called without window, ignoring");
1867     return;
1868   }
1869
1870   wl_subsurface_set_desync (sink->window->area_subsurface);
1871   g_mutex_unlock (&sink->render_lock);
1872 }
1873
1874 static gboolean
1875 plugin_init (GstPlugin * plugin)
1876 {
1877   GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "waylandsink", 0,
1878       " wayland video sink");
1879
1880   gst_wl_shm_allocator_register ();
1881
1882   return gst_element_register (plugin, "waylandsink", GST_RANK_MARGINAL,
1883       GST_TYPE_WAYLAND_SINK);
1884 }
1885
1886 GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
1887     GST_VERSION_MINOR,
1888     waylandsink,
1889     "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
1890     GST_PACKAGE_ORIGIN)