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