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