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