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