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