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