tizenwlsink: get source from gst-plugins-bad/ext/wayland and create new tizen wayland... 66/159466/3 submit/tizen/20171110.011647 submit/tizen/20171113.003957
authorHyunil <hyunil46.park@samsung.com>
Thu, 9 Nov 2017 05:51:36 +0000 (14:51 +0900)
committerHyunil <hyunil46.park@samsung.com>
Thu, 9 Nov 2017 05:58:04 +0000 (14:58 +0900)
Change-Id: Id60188662450ac0c142b19ebff59df08fd4b9423
Signed-off-by: Hyunil <hyunil46.park@samsung.com>
21 files changed:
Makefile.am
configure.ac [changed mode: 0755->0644]
packaging/gst-plugins-tizen.spec
tizenwlsink/Makefile.am [new file with mode: 0644]
tizenwlsink/src/.gitignore [new file with mode: 0644]
tizenwlsink/src/Makefile.am [new file with mode: 0644]
tizenwlsink/src/gstwaylandsink.c [new file with mode: 0755]
tizenwlsink/src/gstwaylandsink.h [new file with mode: 0644]
tizenwlsink/src/scaler.xml [new file with mode: 0644]
tizenwlsink/src/tizen-wlvideoformat.c [new file with mode: 0644]
tizenwlsink/src/tizen-wlvideoformat.h [new file with mode: 0755]
tizenwlsink/src/wlbuffer.c [new file with mode: 0644]
tizenwlsink/src/wlbuffer.h [new file with mode: 0644]
tizenwlsink/src/wldisplay.c [new file with mode: 0644]
tizenwlsink/src/wldisplay.h [new file with mode: 0644]
tizenwlsink/src/wlshmallocator.c [new file with mode: 0644]
tizenwlsink/src/wlshmallocator.h [new file with mode: 0644]
tizenwlsink/src/wlvideoformat.c [new file with mode: 0644]
tizenwlsink/src/wlvideoformat.h [new file with mode: 0644]
tizenwlsink/src/wlwindow.c [new file with mode: 0644]
tizenwlsink/src/wlwindow.h [new file with mode: 0644]

index ffad5e7..7dfb351 100755 (executable)
@@ -61,6 +61,10 @@ if GST_TIZEN_USE_VIDEO360
 SUBDIRS += video360
 endif
 
+if GST_TIZEN_USE_WAYLANDSINK
+SUBDIRS += tizenwlsink
+endif
+
 DIST_SUBDIRS = common
 
 if GST_TIZEN_USE_ENCODEBIN
@@ -104,6 +108,10 @@ if GST_TIZEN_USE_VIDEO360
 DIST_SUBDIRS += video360
 endif
 
+if GST_TIZEN_USE_WAYLANDSINK
+DIST_SUBDIRS += tizenwlsink
+endif
+
 EXTRA_DIST = \
        gstreamer.spec gstreamer.spec.in \
        configure.ac autogen.sh depcomp \
old mode 100755 (executable)
new mode 100644 (file)
index 2f59780..a385065
@@ -386,6 +386,24 @@ AS_IF([test "x$with_gles2" = "xyes"], [
     CFLAGS="$CFLAGS -DGST_TIZEN_GL_API_GLES2"
 ])
 
+dnl use waylandsink --------------------------------------------------------------------------
+AC_ARG_ENABLE(waylandsink, AC_HELP_STRING([--enable-waylandsink], [using waylandsink]),
+[
+ case "${enableval}" in
+         yes) GST_TIZEN_USE_WAYLANDSINK=yes ;;
+         no)  GST_TIZEN_USE_WAYLANDSINK=no ;;
+         *)   AC_MSG_ERROR(bad value ${enableval} for --enable-waylandsink) ;;
+ esac
+ ],
+ [GST_TIZEN_USE_WAYLANDSINK=yes])
+AM_CONDITIONAL([GST_TIZEN_USE_WAYLANDSINK], [test "x$GST_TIZEN_USE_WAYLANDSINK" = "xyes"])
+if test "x$GST_TIZEN_USE_WAYLANDSINK" = "xyes"; then
+PKG_CHECK_MODULES(WAYLAND, wayland-client >= 1.4.0 wayland-tbm-client tizen-extension-client wayland-scanner)
+AC_PATH_PROG([wayland_scanner], [wayland-scanner])
+AC_SUBST(WAYLAND_CFLAGS)
+AC_SUBST(WAYLAND_LIBS)
+fi
+
 AC_OUTPUT(
 Makefile
 common/Makefile
@@ -415,4 +433,6 @@ wfdtizenmanager/Makefile
 alfec/Makefile
 video360/Makefile
 video360/src/Makefile
+tizenwlsink/Makefile
+tizenwlsink/src/Makefile
 )
index b9ed39d..30bd6c5 100644 (file)
@@ -9,7 +9,7 @@
 Name:       gst-plugins-tizen
 Version:    1.0.0
 Summary:    GStreamer tizen plugins (common)
-Release:    49
+Release:    50
 Group:      Multimedia/Framework
 Url:        http://gstreamer.freedesktop.org/
 License:    LGPL-2.1+
@@ -42,7 +42,6 @@ BuildRequires:  pkgconfig(gles20)
 BuildRequires:  pkgconfig(wayland-client) >= 1.0.0
 BuildRequires:  pkgconfig(wayland-tbm-client)
 BuildRequires:  pkgconfig(tizen-extension-client)
-BuildRequires:  pkgconfig(gstreamer-wayland-1.0)
 %endif
 
 %description
@@ -67,7 +66,7 @@ GStreamer tizen plugins Extension for mobile TM1
 
 
 %build
-export CFLAGS+=" -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" "
+export CFLAGS+=" -DTIZEN_FEATURE_WLSINK_ENHANCEMENT -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" "
 export CFLAGS_DEFAULT="$CFLAGS"
 
 %ifarch %{arm}
diff --git a/tizenwlsink/Makefile.am b/tizenwlsink/Makefile.am
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/tizenwlsink/src/.gitignore b/tizenwlsink/src/.gitignore
new file mode 100644 (file)
index 0000000..44cd427
--- /dev/null
@@ -0,0 +1,2 @@
+*-protocol.c
+*-client-protocol.h
diff --git a/tizenwlsink/src/Makefile.am b/tizenwlsink/src/Makefile.am
new file mode 100644 (file)
index 0000000..998787f
--- /dev/null
@@ -0,0 +1,48 @@
+plugin_LTLIBRARIES = libgsttizenwlsink.la
+
+libgsttizenwlsink_la_SOURCES =  \
+       gstwaylandsink.c \
+       wlshmallocator.c \
+       wlbuffer.c \
+       wldisplay.c \
+       wlwindow.c \
+       scaler-protocol.c \
+       wlvideoformat.c \
+       tizen-wlvideoformat.c
+
+libgsttizenwlsink_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)$ $(GST_PLUGINS_BASE_CFLAGS) $(GST_VIDEO_CFLAGS) \
+                               $(WAYLAND_CFLAGS) $(DRM_CFLAGS) $(TBM_CFLAGS) $(MMCOMMON_CFLAGS)
+libgsttizenwlsink_la_LIBADD = \
+       $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_VIDEO_LIBS)\
+       $(WAYLAND_LIBS) $(DRM_LIBS) $(TBM_LIBS) $(MMCOMMON_LIBS)
+libgsttizenwlsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgsttizenwlsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = \
+       gstwaylandsink.h \
+       wlshmallocator.h \
+       wlbuffer.h \
+       wldisplay.h \
+       wlwindow.h \
+       scaler-client-protocol.h \
+       wlvideoformat.h \
+       tizen-wlvideoformat.h
+
+EXTRA_DIST = scaler.xml
+CLEANFILES = scaler-protocol.c scaler-client-protocol.h
+
+%-protocol.c : %.xml
+       $(wayland_scanner) code < $< > $@
+
+%-client-protocol.h : %.xml
+       $(wayland_scanner) client-header < $< > $@
+
+gstwaylandsink.c: scaler-client-protocol.h
+
+wlshmallocator.c: scaler-client-protocol.h
+
+wlbuffer.c: scaler-client-protocol.h
+
+wldisplay.c: scaler-client-protocol.h
+
+wlwindow.c: scaler-client-protocol.h
diff --git a/tizenwlsink/src/gstwaylandsink.c b/tizenwlsink/src/gstwaylandsink.c
new file mode 100755 (executable)
index 0000000..4a33e8c
--- /dev/null
@@ -0,0 +1,2713 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2012 Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/**
+ * SECTION:element-waylandsink
+ *
+ *  The waylandsink is creating its own window and render the decoded video frames to that.
+ *  Setup the Wayland environment as described in
+ *  <ulink url="http://wayland.freedesktop.org/building.html">Wayland</ulink> home page.
+ *  The current implementaion is based on weston compositor.
+ *
+ * <refsect2>
+ * <title>Example pipelines</title>
+ * |[
+ * gst-launch -v videotestsrc ! waylandsink
+ * ]| test the video rendering in wayland
+ * </refsect2>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "gstwaylandsink.h"
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+#include <mm_types.h>
+#include "tizen-wlvideoformat.h"
+#endif
+#include "wlvideoformat.h"
+#include "wlbuffer.h"
+#include "wlshmallocator.h"
+
+#include <gst/video/videooverlay.h>
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+#define GST_APP_EVENT_FLUSH_BUFFER_NAME "application/flush-buffer"
+
+#define GST_TYPE_WAYLANDSINK_DISPLAY_GEOMETRY_METHOD (gst_waylandsink_display_geometry_method_get_type())
+#define GST_TYPE_WAYLANDSINK_ROTATE_ANGLE (gst_waylandsink_rotate_angle_get_type())
+#define GST_TYPE_WAYLANDSINK_FLIP (gst_waylandsink_flip_get_type())
+
+static GType
+gst_waylandsink_rotate_angle_get_type (void)
+{
+  static GType waylandsink_rotate_angle_type = 0;
+  static const GEnumValue rotate_angle_type[] = {
+    {0, "No rotate", "DEGREE_0"},
+    {1, "Rotate 90 degree", "DEGREE_90"},
+    {2, "Rotate 180 degree", "DEGREE_180"},
+    {3, "Rotate 270 degree", "DEGREE_270"},
+    {4, NULL, NULL},
+  };
+
+  if (!waylandsink_rotate_angle_type) {
+    waylandsink_rotate_angle_type =
+        g_enum_register_static ("GstWaylandSinkRotateAngleType",
+        rotate_angle_type);
+  }
+
+  return waylandsink_rotate_angle_type;
+}
+
+
+static GType
+gst_waylandsink_display_geometry_method_get_type (void)
+{
+  static GType waylandsink_display_geometry_method_type = 0;
+  static const GEnumValue display_geometry_method_type[] = {
+    {0, "Letter box", "LETTER_BOX"},
+    {1, "Origin size", "ORIGIN_SIZE"},
+    {2, "Full-screen", "FULL_SCREEN"},
+    {3, "Cropped full-screen", "CROPPED_FULL_SCREEN"},
+    {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"},
+    {5, "Specially described destination ROI", "DISP_GEO_METHOD_CUSTOM_ROI"},
+    {6, NULL, NULL},
+  };
+
+  if (!waylandsink_display_geometry_method_type) {
+    waylandsink_display_geometry_method_type =
+        g_enum_register_static ("GstWaylandSinkDisplayGeometryMethodType",
+        display_geometry_method_type);
+  }
+  return waylandsink_display_geometry_method_type;
+}
+
+static GType
+gst_waylandsink_flip_get_type (void)
+{
+  static GType waylandsink_flip_type = 0;
+  static const GEnumValue flip_type[] = {
+    {FLIP_NONE, "Flip NONE", "FLIP_NONE"},
+    {FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"},
+    {FLIP_VERTICAL, "Flip VERTICAL", "FLIP_VERTICAL"},
+    {FLIP_BOTH, "Flip BOTH", "FLIP_BOTH"},
+    {FLIP_NUM, NULL, NULL},
+  };
+
+  if (!waylandsink_flip_type) {
+    waylandsink_flip_type =
+        g_enum_register_static ("GstWaylandSinkFlipType", flip_type);
+  }
+
+  return waylandsink_flip_type;
+}
+
+#endif
+
+/* signals */
+enum
+{
+  SIGNAL_0,
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  SIGNAL_HANDOFF,
+  SIGNAL_PREROLL_HANDOFF,
+#endif
+  LAST_SIGNAL
+};
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_DISPLAY,
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  PROP_DUMP_VIDEO,
+  PROP_DISABLE_OVERLAY,
+  PROP_DUMP_COUNT,
+  PROP_SIGNAL_HANDOFFS,
+  PROP_USE_GAPLESS,
+  PROP_KEEP_CAMERA_PREVIEW,
+  PROP_USE_TBM,
+  PROP_ROTATE_ANGLE,
+  PROP_DISPLAY_GEOMETRY_METHOD,
+  PROP_FLIP,
+  PROP_VISIBLE,
+  PROP_FOLLOW_PARENT_TRANSFORM,
+  PROP_CROP_X,
+  PROP_CROP_Y,
+  PROP_CROP_WIDTH,
+  PROP_CROP_HEIGHT,
+  PROP_RATIO_WIDTH,
+  PROP_RATIO_HEIGHT,
+  PROP_SCALE_WIDTH,
+  PROP_SCALE_HEIGHT,
+  PROP_OFFSET_X,
+  PROP_OFFSET_Y,
+  PROP_OFFSET_WIDTH,
+  PROP_OFFSET_HEIGHT,
+  PROP_ALIGN_WIDTH,
+  PROP_ALIGN_HEIGHT
+#endif
+};
+
+GST_DEBUG_CATEGORY (gstwayland_debug);
+#define GST_CAT_DEFAULT gstwayland_debug
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
+        ("{BGRx, BGRA, I420, NV12, NV12MT, NV21, SN12, ST12, SN21, SR32, S420}")));
+#else
+    GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE
+        ("{ BGRx, BGRA, RGBx, xBGR, xRGB, RGBA, ABGR, ARGB, RGB, BGR, "
+            "RGB16, BGR16, YUY2, YVYU, UYVY, AYUV, NV12, NV21, NV16, "
+            "YUV9, YVU9, Y41B, I420, YV12, Y42B, v308 }")));
+#endif
+
+static void gst_wayland_sink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+static void gst_wayland_sink_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_wayland_sink_finalize (GObject * object);
+
+static GstStateChangeReturn gst_wayland_sink_change_state (GstElement * element,
+    GstStateChange transition);
+static GstCaps *gst_wayland_sink_get_caps (GstBaseSink * bsink,
+    GstCaps * filter);
+static gboolean gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps);
+static gboolean gst_wayland_sink_preroll (GstBaseSink * bsink,
+    GstBuffer * buffer);
+static gboolean
+gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query);
+static gboolean gst_wayland_sink_render (GstBaseSink * bsink,
+    GstBuffer * buffer);
+
+/* VideoOverlay interface */
+static void gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface *
+    iface);
+static void gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay,
+    guintptr handle);
+static void
+gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
+    guintptr wl_surface_id);
+static void gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
+    gint x, gint y, gint w, gint h);
+static void gst_wayland_sink_expose (GstVideoOverlay * overlay);
+
+/* WaylandVideo interface */
+#if 0
+static void gst_wayland_sink_set_context (GstElement * element,
+    GstContext * context);
+static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface *
+    iface);
+static void gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video);
+static void gst_wayland_sink_end_geometry_change (GstWaylandVideo * video);
+#endif
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+static gboolean gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event);
+static void gst_wayland_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+    GstClockTime * start, GstClockTime * end);
+static void gst_wayland_sink_update_window_geometry (GstWaylandSink * sink);
+static void render_last_buffer (GstWaylandSink * sink);
+
+static guint gst_waylandsink_signals[LAST_SIGNAL] = { 0 };
+
+#endif
+#define gst_wayland_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstWaylandSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
+        gst_wayland_sink_videooverlay_init)
+#if 0
+    G_IMPLEMENT_INTERFACE (GST_TYPE_WAYLAND_VIDEO,
+        gst_wayland_sink_waylandvideo_init)
+#endif
+);
+
+static void
+gst_wayland_sink_class_init (GstWaylandSinkClass * klass)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+  FUNCTION;
+
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+  gstbasesink_class = (GstBaseSinkClass *) klass;
+
+  gobject_class->set_property = gst_wayland_sink_set_property;
+  gobject_class->get_property = gst_wayland_sink_get_property;
+  gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_wayland_sink_finalize);
+
+  gst_element_class_add_pad_template (gstelement_class,
+      gst_static_pad_template_get (&sink_template));
+
+  gst_element_class_set_static_metadata (gstelement_class,
+      "wayland video sink", "Sink/Video",
+      "Output to wayland surface",
+      "Hyunil Park <hyunil46.park@samsung.com>, "
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
+      "George Kiagiadakis <george.kiagiadakis@collabora.com>");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_wayland_sink_change_state);
+#if 0
+  gstelement_class->set_context =
+      GST_DEBUG_FUNCPTR (gst_wayland_sink_set_context);
+#endif
+  gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_get_caps);
+  gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_set_caps);
+  gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_wayland_sink_preroll);
+  gstbasesink_class->propose_allocation =
+      GST_DEBUG_FUNCPTR (gst_wayland_sink_propose_allocation);
+  gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_wayland_sink_render);
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_wayland_sink_event);
+  gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_wayland_sink_get_times);
+#endif
+
+  g_object_class_install_property (gobject_class, PROP_DISPLAY,
+      g_param_spec_string ("display", "Wayland Display name", "Wayland "
+          "display name to connect to, if not supplied via the GstContext",
+          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  g_object_class_install_property (gobject_class, PROP_DUMP_VIDEO,
+      g_param_spec_boolean ("dump-video", "dump raw video buffer",
+          "Dump raw video buffer", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DUMP_COUNT,
+      g_param_spec_uint ("dump-video-count", "dump video count",
+          "Dump video count", 1, G_MAXUINT, DEFAULT_DUMP_COUNT,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DISABLE_OVERLAY,
+      g_param_spec_boolean ("disable-overlay", "disable overlay",
+          "Stop using overlay by destroying wl_window and wl_display, "
+          "Use gst_video_overlay_set_wl_window_wl_surface_id before setting FALSE "
+          "to use overlay", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_KEEP_CAMERA_PREVIEW,
+      g_param_spec_boolean ("keep-camera-preview", "use flush buffer mechanism",
+          "Last tbm buffer is copied and returned to camerasrc immediately "
+          "when state change(PAUSED_TO_READY)", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_USE_TBM,
+      g_param_spec_boolean ("use-tbm", "use tbm buffer",
+          "Use Tizen Buffer Memory insted of Shared memory, "
+          "Memory is alloced by TBM insted of SHM when enabled", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ROTATE_ANGLE,
+      g_param_spec_enum ("rotate", "Rotate angle",
+          "Rotate angle of display output",
+          GST_TYPE_WAYLANDSINK_ROTATE_ANGLE, DEGREE_0,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_DISPLAY_GEOMETRY_METHOD,
+      g_param_spec_enum ("display-geometry-method", "Display geometry method",
+          "Geometrical method for display",
+          GST_TYPE_WAYLANDSINK_DISPLAY_GEOMETRY_METHOD,
+          DEF_DISPLAY_GEOMETRY_METHOD,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FLIP,
+      g_param_spec_enum ("flip", "Display flip",
+          "Flip for display",
+          GST_TYPE_WAYLANDSINK_FLIP, DEF_DISPLAY_FLIP,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_VISIBLE,
+      g_param_spec_boolean ("visible", "Visible",
+          "Draws screen or blacks out, true means visible, false blacks out",
+          TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+#ifdef ENABLE_FUNCTION
+  g_object_class_install_property (gobject_class, PROP_SCALE_WIDTH,
+      g_param_spec_double ("scale-w", "ratio width",
+          "scale width for rendering video,"
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0.0,
+          G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_SCALE_HEIGHT,
+      g_param_spec_double ("scale-h", "scale height",
+          "scale width for rendering video, "
+          "Function is not support in DISP_GEO_METHOD_CUSTOM_ROI. ", 0.0,
+          G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_FOLLOW_PARENT_TRANSFORM,
+      g_param_spec_boolean ("follow-parent-transform",
+          "follow parent transform",
+          "Video is rotated automatically without setting rotate property by rotating Display"
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", TRUE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CROP_X,
+      g_param_spec_uint ("crop-x", "crop x",
+          "x-coordinate for cropping video. "
+          "Please set crop-x, crop-y, crop-w and crop-h togethrer. "
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0,
+          G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CROP_Y,
+      g_param_spec_uint ("crop-y", "crop y",
+          "y-coordinate for cropping video. "
+          "Please set crop-x, crop-y, crop-w and crop-h togethrer. "
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0,
+          G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CROP_WIDTH,
+      g_param_spec_uint ("crop-w", "crop width",
+          "width for cropping video. "
+          "If value is not set or is set 0, Width is set to video width after set_caps. "
+          "Please set crop-x, crop-y, crop-w and crop-h togethrer. "
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0,
+          G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_CROP_HEIGHT,
+      g_param_spec_uint ("crop-h", "crop height",
+          "height for cropping video. "
+          "If value is not set or is set 0, Hight is set to video height after set_caps. "
+          "Please set crop-x, crop-y, crop-w and crop-h togethrer. "
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0,
+          G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RATIO_WIDTH,
+      g_param_spec_double ("ratio-w", "ratio width",
+          "ratio width for rendering video,"
+          "If value is set, Original video ratio is ignored. to restore original size, set to -1"
+          "Please set ratio-w and ratio-h togethrer. "
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", -1.0,
+          G_MAXDOUBLE, -1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_RATIO_HEIGHT,
+      g_param_spec_double ("ratio-h", "ratio height",
+          "ratio width for rendering video, "
+          "If value is set, Original video ratio is ignored. to restore original size, set to -1"
+          "Please set ratio-w and ratio-h togethrer. "
+          "Function is not support in DISP_GEO_METHOD_CUSTOM_ROI. ", -1.0,
+          G_MAXDOUBLE, -1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_OFFSET_X,
+      g_param_spec_uint ("offset-x", "offset x",
+          "x offset for moving x-coordinate of video pixel, "
+          "Please set x, y, w and h offset togethrer"
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0,
+          G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_OFFSET_Y,
+      g_param_spec_uint ("offset-y", "offset y",
+          "y offset for moving y-coordinate of video pixel, "
+          "Please set x, y, w and h offset togethrer"
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0,
+          G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_OFFSET_WIDTH,
+      g_param_spec_uint ("offset-w", "offset width",
+          "width offset for adjusting width of of video pixel, "
+          "Please set x, y, w and h offset togethrer"
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0,
+          G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_OFFSET_HEIGHT,
+      g_param_spec_uint ("offset-h", "offset height",
+          "height offset for adjusting height of of video pixel"
+          "Please set x, y, w and h offset togethrer"
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0,
+          G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ALIGN_WIDTH,
+      g_param_spec_double ("align-w", "align width",
+          "Align with, Left: 0.0, Middle: 0.5, Right: 1.0, "
+          "Please set align-w and align-h togethrer"
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0.0,
+          1.0, 0.5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  g_object_class_install_property (gobject_class, PROP_ALIGN_HEIGHT,
+      g_param_spec_double ("align-h", "align height",
+          "Align height, Left: 0.0, Middle: 0.5, Right: 1.0, "
+          "Please set align-w and align-h togethrer"
+          "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0.0,
+          1.0, 0.5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+#endif
+
+  /* fakesink function for stream callback of MSL with browser */
+  g_object_class_install_property (gobject_class, PROP_SIGNAL_HANDOFFS,
+      g_param_spec_boolean ("signal-handoffs", "Signal handoffs",
+          "Send a signal before unreffing the buffer", FALSE,
+          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
+
+  gst_waylandsink_signals[SIGNAL_HANDOFF] =
+      g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
+      G_STRUCT_OFFSET (GstWaylandSinkClass, handoff), NULL, NULL,
+      g_cclosure_marshal_generic, G_TYPE_NONE, 2,
+      GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
+
+  gst_waylandsink_signals[SIGNAL_PREROLL_HANDOFF] =
+      g_signal_new ("preroll-handoff", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstWaylandSinkClass, preroll_handoff),
+      NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2,
+      GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD);
+
+#endif
+}
+
+static void
+gst_wayland_sink_dump_raw_video (GstWaylandSink * sink, GstBuffer * buffer,
+    guint dump_count, guint dump_total)
+{
+  GstMemory *mem;
+  GstMapInfo mem_info = GST_MAP_INFO_INIT;
+  gpointer data;
+  gint ret, size;
+  gchar file_name[128];
+
+  g_return_if_fail (sink != NULL);
+  g_return_if_fail (buffer != NULL);
+
+  if (dump_count > dump_total) {
+    sink->dump_video = FALSE;
+    return;
+  }
+
+  size = GST_VIDEO_INFO_SIZE (&sink->video_info);
+  mem = gst_buffer_peek_memory (buffer, 0);
+  gst_memory_map (mem, &mem_info, GST_MAP_READ);
+
+  data = mem_info.data;
+  snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump",
+      dump_count);
+  ret = gst_wl_fwrite_data (file_name, data, size);
+  if (ret) {
+    GST_ERROR ("_write_rawdata() failed");
+  }
+
+  GST_LOG ("DUMP IMAGE %d, size (%d)", dump_count, size);
+  gst_memory_unmap (mem, &mem_info);
+}
+
+static void
+gst_wayland_sink_init (GstWaylandSink * sink)
+{
+  FUNCTION;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  sink->dump_video = FALSE;
+  sink->total_dump = DEFAULT_DUMP_COUNT;
+  sink->disable_overlay = FALSE;
+  sink->signal_handoffs = FALSE;
+  sink->request_camera_flush_buf = FALSE;
+  sink->keep_camera_preview = FALSE;
+  sink->got_costum_event = FALSE;
+  sink->USE_TBM = TRUE;
+  sink->is_native_format = FALSE;
+  sink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
+  sink->flip = DEF_DISPLAY_FLIP;
+  sink->rotate_angle = DEGREE_0;
+  sink->visible = TRUE;
+  sink->crop_x = sink->crop_y = sink->crop_w = sink->crop_h = 0;
+#ifdef ENABLE_FUNCTION
+  sink->follow_parent_transform = FALSE;
+  sink->ratio_w = sink->ratio_h = -1.0; //need to set -1.0 for original video ratio
+  sink->align_w = sink->align_h = 0.5;
+  sink->scale_w = sink->scale_h = 1.0;
+  sink->offset_x = sink->offset_y = sink->offset_w = sink->offset_h = 0;
+#endif
+#endif
+  g_mutex_init (&sink->display_lock);
+  g_mutex_init (&sink->render_lock);
+}
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+static void
+gst_wayland_sink_recover_display_window_info (GstWaylandSink * sink)
+{
+  GstWlShmAllocator *self = NULL;
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+  g_return_if_fail (sink->display != NULL);
+  g_return_if_fail (sink->window != NULL);
+
+  sink->display->USE_TBM = sink->USE_TBM;
+  sink->display->is_native_format = sink->is_native_format;
+  self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
+  self->display = sink->display;
+
+  gst_wayland_sink_update_window_geometry (sink);
+  sink->video_info_changed = TRUE;
+}
+
+static gboolean
+gst_wayland_sink_is_disabled_overlay (GstWaylandSink * sink)
+{
+  g_return_val_if_fail (sink != NULL, FALSE);
+  //Ensure display is null and the display info has been copied by unsetting disable_overlay
+  //If using the toplevel window, window is null
+  if (!sink->disable_overlay && sink->display) {
+    return FALSE;
+  }
+  sink->redraw_pending = FALSE;
+  return TRUE;
+}
+
+static void
+gst_wayland_sink_stop_video (GstWaylandSink * sink)
+{
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+  gst_wl_window_render (sink->window, NULL, NULL);
+}
+
+static int
+gst_wayland_sink_is_gapless (GstWaylandSink * sink)
+{
+  g_return_val_if_fail (sink != NULL, FALSE);
+  g_return_val_if_fail (sink->display != NULL, FALSE);
+
+  if (sink->got_costum_event && sink->USE_TBM
+      && sink->display->is_native_format)
+    return TRUE;
+
+  return FALSE;
+}
+
+static int
+gst_wayland_sink_need_flush_buffer (GstWaylandSink * sink)
+{
+  g_return_val_if_fail (sink != NULL, FALSE);
+  g_return_val_if_fail (sink->display != NULL, FALSE);
+
+  if ((gst_wayland_sink_is_gapless (sink))
+      || sink->request_camera_flush_buf || sink->display->flush_request == 1) {
+    sink->display->flush_request = TRUE;
+    return TRUE;
+  }
+  return FALSE;
+}
+
+static void
+gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink)
+{
+  GstWlBuffer *wlbuffer;
+  gboolean no_render_buffer = FALSE;
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+  g_return_if_fail (sink->last_buffer != NULL);
+  wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
+
+  g_return_if_fail (wlbuffer != NULL);
+
+  if (wlbuffer->used_by_compositor) {
+    /* used last buffer by compositor don't receive buffer-release-event when attach */
+    wlbuffer->used_by_compositor = FALSE;
+  } else {
+    /* unused last buffer by compositor will receive buffer release event when attach */
+    no_render_buffer = TRUE;
+  }
+
+  GST_LOG ("gstbuffer(%p) ref_count(%d)", sink->last_buffer,
+      GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer));
+
+  if (sink->visible) {
+    /* need to render last buffer, reuse current GstWlBuffer */
+    render_last_buffer (sink);
+
+    /* ref count is incresed in gst_wl_buffer_attach() of render_last_buffer(),
+       to call gst_wl_buffer_finalize(), we need to decrease buffer ref count.
+       wayland server can not release buffer if we attach same buffer and
+       videosink can not receive buffer-release-event. if we use no visible,
+       we need to attach null buffer and videosink can receive buffer-release-event */
+
+    /* need to decrease buffer ref_count, if no_render_buffer is TRUE,
+       buffer is attached firstly so, videosink can receive buffer-release-event */
+    if (no_render_buffer) {
+      GST_LOG ("skip unref.. will get buffer-release-event");
+    } else {
+      gst_buffer_unref (wlbuffer->gstbuffer);
+    }
+
+  } else {
+    GST_LOG ("skip rendering");
+  }
+
+  GST_LOG ("gstbuffer(%p) ref_count(%d)", sink->last_buffer,
+      GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer));
+
+}
+
+#ifdef USE_WL_FLUSH_BUFFER
+static int
+gst_wayland_sink_make_flush_buffer (GstWlDisplay * display,
+    MMVideoBuffer * mm_video_buf)
+{
+  GstWlFlushBuffer *flush_buffer = NULL;
+  tbm_bo bo = NULL;
+  int bo_size = 0;
+  int i;
+  FUNCTION;
+
+  g_return_val_if_fail (display != NULL, FALSE);
+  g_return_val_if_fail (mm_video_buf != NULL, FALSE);
+
+  flush_buffer = (GstWlFlushBuffer *) malloc (sizeof (GstWlFlushBuffer));
+  if (G_UNLIKELY (!flush_buffer)) {
+    GST_ERROR ("GstWlFlushBuffer alloc faile");
+    return FALSE;
+  }
+  memset (flush_buffer, 0x0, sizeof (GstWlFlushBuffer));
+
+  display->flush_tbm_bufmgr =
+      wayland_tbm_client_get_bufmgr (display->tbm_client);
+  g_return_val_if_fail (display->flush_tbm_bufmgr != NULL, FALSE);
+
+  for (i = 0; i < display->tbm_bo_num; i++) {
+    if (mm_video_buf->handle.bo[i] != NULL) {
+      tbm_bo_handle src;
+      tbm_bo_handle dst;
+      gchar err_str[256];
+
+      /* get bo size */
+      bo_size = tbm_bo_size (mm_video_buf->handle.bo[i]);
+      GST_LOG ("tbm bo size: %d", bo_size);
+      /* alloc bo */
+      bo = tbm_bo_alloc (display->flush_tbm_bufmgr, bo_size, TBM_DEVICE_CPU);
+      if (G_UNLIKELY (!bo)) {
+        strerror_r (errno, err_str, sizeof (err_str));
+        GST_ERROR ("alloc tbm bo(size:%d) failed: %s(%d)", bo_size, err_str,
+            errno);
+        return FALSE;
+      }
+      GST_LOG ("flush buffer tbm_bo =(%p)", bo);
+      flush_buffer->bo[i] = bo;
+      /* get virtual address */
+      src.ptr = dst.ptr = NULL;
+      /* bo map, we can use tbm_bo_map too. */
+      src =
+          tbm_bo_map (mm_video_buf->handle.bo[i], TBM_DEVICE_CPU,
+          TBM_OPTION_READ);
+      dst = tbm_bo_map (bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE);
+      if (G_UNLIKELY ((!src.ptr || !dst.ptr))) {
+        strerror_r (errno, err_str, sizeof (err_str));
+        GST_ERROR ("get tbm bo handle failed src(%p) dst(%p): %s(%d)", src.ptr,
+            dst.ptr, err_str, errno);
+        if (src.ptr)
+          tbm_bo_unmap (mm_video_buf->handle.bo[i]);
+        if (dst.ptr)
+          tbm_bo_unmap (bo);
+        return FALSE;
+      }
+      /* copy */
+      memcpy (dst.ptr, src.ptr, bo_size);
+      /* bo unmap */
+      tbm_bo_unmap (mm_video_buf->handle.bo[i]);
+      tbm_bo_unmap (bo);
+    }
+  }
+  display->flush_buffer = flush_buffer;
+  return TRUE;
+}
+
+static int
+gst_wayland_sink_copy_mm_video_buf_info_to_flush_buffer (GstWlDisplay * display,
+    MMVideoBuffer * mm_video_buf)
+{
+  int ret = FALSE;
+  g_return_val_if_fail (display != NULL, FALSE);
+  g_return_val_if_fail (mm_video_buf != NULL, FALSE);
+  FUNCTION;
+
+  display->plane_num = mm_video_buf->plane_num;
+  display->tbm_bo_num = mm_video_buf->handle_num;
+  ret = gst_wayland_sink_make_flush_buffer (display, mm_video_buf);
+  if (ret) {
+    int i;
+    for (i = 0; i < display->plane_num; i++) {
+      if (display->flush_buffer->bo[i] != NULL) {
+        display->bo[i] = display->flush_buffer->bo[i];
+        GST_LOG ("bo %p", display->bo[i]);
+      } else {
+        display->bo[i] = 0;
+      }
+      display->plane_size[i] = mm_video_buf->size[i];
+      display->width[i] = mm_video_buf->width[i];
+      display->height[i] = mm_video_buf->height[i];
+      display->stride_width[i] = mm_video_buf->stride_width[i];
+      display->stride_height[i] = mm_video_buf->stride_height[i];
+      display->native_video_size += display->plane_size[i];
+      GST_LOG ("TBM bo[%d]:%p", i, display->bo[i]);
+      GST_LOG ("width[%d]:%d, height[%d]:%d", i, display->width[i], i,
+          display->height[i]);
+      GST_LOG ("stride_width[%d]:%d, stride_height[%d]:%d", i,
+          display->stride_width[i], i, display->stride_height[i]);
+      GST_LOG ("plane size[%d]:%d", i, display->plane_size[i]);
+    }
+    memset (mm_video_buf, 0, sizeof (MMVideoBuffer));
+  }
+  return ret;
+}
+#endif
+
+static void
+gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display,
+    MMVideoBuffer * mm_video_buf)
+{
+  int i;
+  g_return_if_fail (display != NULL);
+  g_return_if_fail (mm_video_buf != NULL);
+  FUNCTION;
+
+  display->plane_num = mm_video_buf->plane_num;
+  display->tbm_bo_num = mm_video_buf->handle_num;
+  for (i = 0; i < display->plane_num; i++) {
+    if (mm_video_buf->handle.bo[i] != NULL) {
+      display->bo[i] = mm_video_buf->handle.bo[i];
+    } else {
+      display->bo[i] = 0;
+    }
+    display->plane_size[i] = mm_video_buf->size[i];
+    display->width[i] = mm_video_buf->width[i];
+    display->height[i] = mm_video_buf->height[i];
+    display->stride_width[i] = mm_video_buf->stride_width[i];
+    display->stride_height[i] = mm_video_buf->stride_height[i];
+    display->native_video_size += display->plane_size[i];
+    GST_LOG ("TBM bo[%d]:%p", i, display->bo[i]);
+    GST_LOG ("width[%d]:%d, height[%d]:%d", i, display->width[i], i,
+        display->height[i]);
+    GST_LOG ("stride_width[%d]:%d, stride_height[%d]:%d", i,
+        display->stride_width[i], i, display->stride_height[i]);
+    GST_LOG ("plane size[%d]:%d", i, display->plane_size[i]);
+  }
+}
+
+static MMVideoBuffer *
+gst_wayland_sink_get_mm_video_buf (GstBuffer * buffer)
+{
+  GstMemory *mem;
+  GstMapInfo mem_info = GST_MAP_INFO_INIT;
+  MMVideoBuffer *mm_video_buf = NULL;
+
+  g_return_val_if_fail (buffer != NULL, NULL);
+  FUNCTION;
+
+  mem = gst_buffer_peek_memory (buffer, 1);
+  gst_memory_map (mem, &mem_info, GST_MAP_READ);
+  mm_video_buf = (MMVideoBuffer *) mem_info.data;
+  gst_memory_unmap (mem, &mem_info);
+
+  if (mm_video_buf == NULL) {
+    GST_WARNING ("mm_video_buf of gstbuffer(@%p) is NULL.", buffer);
+    return NULL;
+  }
+
+  if (mm_video_buf->type != MM_VIDEO_BUFFER_TYPE_TBM_BO) {
+    GST_ERROR ("Buffer type is not TBM");
+    return NULL;
+  }
+  GST_DEBUG ("TBM bo: handle.bo[0]:%p, handle.bo[1]:%p, handle.bo[2]:%p",
+      mm_video_buf->handle.bo[0], mm_video_buf->handle.bo[1],
+      mm_video_buf->handle.bo[2]);
+  GST_DEBUG ("Number of TBM bo is %d", mm_video_buf->handle_num);
+  GST_DEBUG ("Number of plane is %d", mm_video_buf->plane_num);
+  return mm_video_buf;
+}
+
+static int
+gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink,
+    GstBuffer * buffer)
+{
+  GstWlDisplay *display;
+  MMVideoBuffer *mm_video_buf = NULL;
+
+  g_return_val_if_fail (sink != NULL, FALSE);
+  g_return_val_if_fail (buffer != NULL, FALSE);
+
+  FUNCTION;
+  display = sink->display;
+  g_return_val_if_fail (sink->display != NULL, FALSE);
+
+  /* get MMVideoBuffer from buffer */
+  mm_video_buf = gst_wayland_sink_get_mm_video_buf (buffer);
+  g_return_val_if_fail (mm_video_buf != NULL, FALSE);
+
+  /* assign mm_video_buf info */
+  display->native_video_size = 0;
+  display->flush_request = 0;
+  display->flush_request = mm_video_buf->flush_request;
+  GST_DEBUG ("flush_request value is %d", display->flush_request);
+#ifdef USE_WL_FLUSH_BUFFER
+  if (gst_wayland_sink_need_flush_buffer (sink)) {
+    /* Sometimes there isn't video data in MMVideoBuffer from buffer
+       when flush_request is true */
+    if (mm_video_buf->flush_request && !mm_video_buf->size[0]
+        && sink->last_buffer) {
+      /* replace MMVideoBuffer from last buffer */
+      mm_video_buf = gst_wayland_sink_get_mm_video_buf (sink->last_buffer);
+      g_return_val_if_fail (mm_video_buf != NULL, FALSE);
+    }
+    if (!gst_wayland_sink_copy_mm_video_buf_info_to_flush_buffer (display,
+            mm_video_buf)) {
+      GST_ERROR ("cat not copy mm_video_buf info to flush");
+      return FALSE;
+    }
+  } else
+#endif
+    /* normal routine */
+    gst_wayland_sink_add_mm_video_buf_info (display, mm_video_buf);
+
+  return TRUE;
+}
+
+static void
+gst_wayland_sink_render_flush_buffer (GstBaseSink * bsink)
+{
+  GstWaylandSink *sink;
+  sink = GST_WAYLAND_SINK (bsink);
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+  g_return_if_fail (sink->last_buffer != NULL);
+
+  gst_wayland_sink_render (bsink, sink->last_buffer);
+}
+
+static void
+gst_wayland_sink_render_last_sample (GstWaylandSink * sink)
+{
+  GstSample *last_sample = NULL;
+  GstBuffer *last_buffer = NULL;
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+
+  g_object_get (G_OBJECT (sink), "last-sample", &last_sample, NULL);
+  if (last_sample) {
+    last_buffer = gst_sample_get_buffer (last_sample);
+    if (last_buffer) {
+      GST_LOG ("PAUSED state : last buffer %p", last_buffer);
+      gst_buffer_ref (last_buffer);
+      gst_wayland_sink_render (GST_BASE_SINK (sink), last_buffer);
+      gst_buffer_unref (last_buffer);
+      last_buffer = NULL;
+    }
+    gst_sample_unref (last_sample);
+    last_sample = NULL;
+  }
+}
+
+#endif
+
+static void
+gst_wayland_sink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (object);
+  FUNCTION;
+
+  switch (prop_id) {
+    case PROP_DISPLAY:
+      GST_OBJECT_LOCK (sink);
+      g_value_set_string (value, sink->display_name);
+      GST_OBJECT_UNLOCK (sink);
+      break;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+    case PROP_DUMP_VIDEO:
+      g_value_set_boolean (value, sink->dump_video);
+      break;
+    case PROP_DUMP_COUNT:
+      g_value_set_uint (value, sink->total_dump);
+      break;
+    case PROP_DISABLE_OVERLAY:
+      g_value_set_boolean (value, sink->disable_overlay);
+      break;
+    case PROP_KEEP_CAMERA_PREVIEW:
+      g_value_set_boolean (value, sink->keep_camera_preview);
+      break;
+    case PROP_SIGNAL_HANDOFFS:
+      g_value_set_boolean (value, sink->signal_handoffs);
+      break;
+    case PROP_USE_TBM:
+      g_value_set_boolean (value, sink->USE_TBM);
+      break;
+    case PROP_ROTATE_ANGLE:
+      g_value_set_enum (value, sink->rotate_angle);
+      break;
+    case PROP_DISPLAY_GEOMETRY_METHOD:
+      g_value_set_enum (value, sink->display_geometry_method);
+      break;
+    case PROP_FLIP:
+      g_value_set_enum (value, sink->flip);
+      break;
+    case PROP_VISIBLE:
+      g_value_set_boolean (value, sink->visible);
+      break;
+#ifdef ENABLE_FUNCTION
+    case PROP_SCALE_WIDTH:
+      g_value_set_double (value, sink->scale_w);
+      break;
+    case PROP_SCALE_HEIGHT:
+      g_value_set_double (value, sink->scale_h);
+      break;
+    case PROP_FOLLOW_PARENT_TRANSFORM:
+      g_value_set_boolean (value, sink->follow_parent_transform);
+      break;
+    case PROP_CROP_X:
+      g_value_set_uint (value, sink->crop_x);
+      break;
+    case PROP_CROP_Y:
+      g_value_set_uint (value, sink->crop_y);
+      break;
+    case PROP_CROP_WIDTH:
+      g_value_set_uint (value, sink->crop_w);
+      break;
+    case PROP_CROP_HEIGHT:
+      g_value_set_uint (value, sink->crop_h);
+      break;
+    case PROP_RATIO_WIDTH:
+      g_value_set_double (value, sink->ratio_w);
+      break;
+    case PROP_RATIO_HEIGHT:
+      g_value_set_double (value, sink->ratio_h);
+      break;
+    case PROP_OFFSET_X:
+      g_value_set_uint (value, sink->offset_x);
+      break;
+    case PROP_OFFSET_Y:
+      g_value_set_uint (value, sink->offset_y);
+      break;
+    case PROP_OFFSET_WIDTH:
+      g_value_set_uint (value, sink->offset_w);
+      break;
+    case PROP_OFFSET_HEIGHT:
+      g_value_set_uint (value, sink->offset_h);
+      break;
+    case PROP_ALIGN_WIDTH:
+      g_value_set_double (value, sink->align_w);
+      break;
+    case PROP_ALIGN_HEIGHT:
+      g_value_set_double (value, sink->align_h);
+      break;
+#endif
+#endif
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_wayland_sink_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (object);
+  FUNCTION;
+  g_mutex_lock (&sink->render_lock);
+
+  switch (prop_id) {
+    case PROP_DISPLAY:
+      GST_OBJECT_LOCK (sink);
+      sink->display_name = g_value_dup_string (value);
+      GST_OBJECT_UNLOCK (sink);
+      break;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+    case PROP_DUMP_VIDEO:
+      sink->dump_video = g_value_get_boolean (value);
+      if (sink->display) {
+        sink->display->dump_video = sink->dump_video;
+        GST_LOG ("Dump video set (%d):", sink->dump_video);
+      }
+      break;
+    case PROP_DUMP_COUNT:
+      sink->total_dump = g_value_get_uint (value);
+      if (sink->display)
+        sink->display->total_dump = sink->total_dump;
+      break;
+    case PROP_DISABLE_OVERLAY:
+      sink->disable_overlay = g_value_get_boolean (value);
+      if (sink->window && sink->display) {
+        if (sink->disable_overlay) {
+          g_clear_object (&sink->window);
+          g_clear_object (&sink->display);
+        } else
+          gst_wayland_sink_recover_display_window_info (sink);
+      }
+      break;
+    case PROP_SIGNAL_HANDOFFS:
+      sink->signal_handoffs = g_value_get_boolean (value);
+      GST_LOG ("set signal_handoffs(%d)", sink->signal_handoffs);
+      if (sink->window) {
+        if (sink->signal_handoffs) {
+          /* overlay -> hand-off */
+          if (GST_STATE (sink) == GST_STATE_PAUSED) {
+            /* check if the prerolled buffer has been rendered in GST_STATE_PAUSED */
+            if (sink->last_buffer) {
+              GST_LOG ("g_signal_emit: preroll-handoff");
+              g_signal_emit (sink,
+                  gst_waylandsink_signals[SIGNAL_PREROLL_HANDOFF], 0,
+                  sink->last_buffer, GST_BASE_SINK (object)->sinkpad);
+            }
+          }
+          gst_wayland_sink_stop_video (sink);
+        } else {
+          if (GST_STATE (sink) == GST_STATE_PAUSED) {
+            g_mutex_unlock (&sink->render_lock);
+            /* scenario: inline video mode->paused->fullscreen mode->signal_handoffs(0)
+               we need to update preroll buffer on wayland surface */
+            gst_wayland_sink_render_last_sample (sink);
+            g_mutex_lock (&sink->render_lock);
+          }
+        }
+      }
+      break;
+    case PROP_KEEP_CAMERA_PREVIEW:
+      sink->keep_camera_preview = g_value_get_boolean (value);
+      GST_LOG ("keep_camera_preview (%d)", sink->keep_camera_preview);
+      break;
+    case PROP_USE_TBM:
+      sink->USE_TBM = g_value_get_boolean (value);
+      GST_LOG ("1:USE TBM 0: USE SHM set(%d)", sink->USE_TBM);
+      break;
+    case PROP_ROTATE_ANGLE:
+      if (sink->rotate_angle == g_value_get_enum (value))
+        break;
+      sink->rotate_angle = g_value_get_enum (value);
+      GST_WARNING_OBJECT (sink, "Rotate angle is set (%d)", sink->rotate_angle);
+      sink->video_info_changed = TRUE;
+      if (sink->window) {
+        gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
+      }
+      break;
+    case PROP_DISPLAY_GEOMETRY_METHOD:
+      if (sink->display_geometry_method == g_value_get_enum (value))
+        break;
+      sink->display_geometry_method = g_value_get_enum (value);
+      GST_WARNING_OBJECT (sink, "Display geometry method is set (%d)",
+          sink->display_geometry_method);
+      sink->video_info_changed = TRUE;
+      if (sink->window) {
+        gst_wl_window_set_destination_mode (sink->window,
+            sink->display_geometry_method);
+      }
+      break;
+    case PROP_FLIP:
+      if (sink->flip == g_value_get_enum (value))
+        break;
+      sink->flip = g_value_get_enum (value);
+      GST_WARNING_OBJECT (sink, "flip is set (%d)", sink->flip);
+      sink->video_info_changed = TRUE;
+      if (sink->window) {
+        gst_wl_window_set_flip (sink->window, sink->flip);
+      }
+      break;
+    case PROP_VISIBLE:
+      if (sink->visible == g_value_get_boolean (value))
+        break;
+      sink->visible = g_value_get_boolean (value);
+      GST_WARNING_OBJECT (sink, "visible is set (%d)", sink->visible);
+      if (sink->visible && GST_STATE (sink) == GST_STATE_PAUSED) {
+        /* need to attatch last buffer */
+        sink->video_info_changed = TRUE;
+      } else if (!sink->visible && GST_STATE (sink) >= GST_STATE_PAUSED) {
+        /* video stop */
+        if (sink->window) {
+          gst_wayland_sink_stop_video (sink);
+        }
+      }
+      break;
+#ifdef ENABLE_FUNCTION
+    case PROP_SCALE_WIDTH:
+      if (sink->scale_w == g_value_get_double (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->scale_w = g_value_get_double (value);
+      GST_WARNING_OBJECT (sink, "scale-w is set (%f)", sink->scale_w);
+      sink->video_info_changed = TRUE;
+      if (sink->window)
+        gst_wl_window_set_destination_mode_scale (sink->window, sink->scale_w,
+            sink->scale_h);
+      break;
+    case PROP_SCALE_HEIGHT:
+      if (sink->scale_h == g_value_get_double (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->scale_h = g_value_get_double (value);
+      GST_WARNING_OBJECT (sink, "scale-h is set (%f)", sink->scale_h);
+      sink->video_info_changed = TRUE;
+      if (sink->window)
+        gst_wl_window_set_destination_mode_scale (sink->window, sink->scale_w,
+            sink->scale_h);
+      break;
+    case PROP_FOLLOW_PARENT_TRANSFORM:
+      if (sink->follow_parent_transform == g_value_get_boolean (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->follow_parent_transform = g_value_get_boolean (value);
+      GST_WARNING_OBJECT (sink, "follow parent transform is set (%d)",
+          sink->follow_parent_transform);
+      sink->video_info_changed = TRUE;
+      if (sink->window) {
+        gst_wl_window_set_destination_mode_follow_parent_transform
+            (sink->window, sink->follow_parent_transform);
+      }
+      break;
+    case PROP_CROP_X:
+      if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->crop_x = g_value_get_uint (value);
+      GST_WARNING_OBJECT (sink, "crop-x is set (%d)", sink->crop_x);
+      break;
+    case PROP_CROP_Y:
+      if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->crop_y = g_value_get_uint (value);
+      GST_WARNING_OBJECT (sink, "crop-y is set (%d)", sink->crop_y);
+      break;
+    case PROP_CROP_WIDTH:
+      if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->crop_w = g_value_get_uint (value);
+      GST_WARNING_OBJECT (sink, "crop_w is set (%d)", sink->crop_w);
+      /* crop-w is unset by 0, set to video width size */
+      if (sink->crop_w == 0 && sink->video_info.width > 0) {
+        sink->crop_w =
+            gst_util_uint64_scale_int_round (sink->video_info.width,
+            sink->video_info.par_n, sink->video_info.par_d);
+        GST_LOG ("crop-w is unset by 0, set to video width size(%d)",
+            sink->crop_w);
+      }
+      break;
+    case PROP_CROP_HEIGHT:
+      if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->crop_h = g_value_get_uint (value);
+      GST_WARNING_OBJECT (sink, "crop-h is set (%d)", sink->crop_h);
+      /* crop-h unset by 0, set to video height size */
+      if (sink->crop_h == 0 && sink->video_info.height > 0) {
+        sink->crop_h = sink->video_info.height;
+        GST_LOG ("crop-h is unset by 0, set to video height size(%d)",
+            sink->crop_h);
+      }
+      sink->video_info_changed = TRUE;
+      if (sink->window && sink->crop_w > 0 && sink->crop_h > 0) {
+        gst_wl_window_set_destination_mode_crop_wl_buffer (sink->window,
+            sink->crop_x, sink->crop_y, sink->crop_w, sink->crop_h);
+      }
+      break;
+    case PROP_RATIO_WIDTH:
+      if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->ratio_w = g_value_get_double (value);
+      GST_WARNING_OBJECT (sink, "ratio-w is set (%f)", sink->ratio_w);
+      break;
+    case PROP_RATIO_HEIGHT:
+      if (sink->scale_w == g_value_get_double (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->ratio_h = g_value_get_double (value);
+      GST_WARNING_OBJECT (sink, "ratio-h is set (%f)", sink->ratio_h);
+      sink->video_info_changed = TRUE;
+      if (sink->window)
+        gst_wl_window_set_destination_mode_ratio (sink->window, sink->ratio_w,
+            sink->ratio_h);
+      break;
+    case PROP_OFFSET_X:
+      if (sink->offset_x == g_value_get_uint (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->offset_x = g_value_get_uint (value);
+      GST_WARNING_OBJECT (sink, "offset-x is set (%d)", sink->offset_x);
+      break;
+    case PROP_OFFSET_Y:
+      if (sink->offset_y == g_value_get_uint (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->offset_y = g_value_get_uint (value);
+      GST_WARNING_OBJECT (sink, "offset-y is set (%d)", sink->offset_y);
+      break;
+    case PROP_OFFSET_WIDTH:
+      if (sink->offset_w == g_value_get_uint (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->offset_w = g_value_get_uint (value);
+      GST_WARNING_OBJECT (sink, "offset-w is set (%d)", sink->offset_w);
+      break;
+    case PROP_OFFSET_HEIGHT:
+      if (sink->offset_h == g_value_get_uint (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->offset_h = g_value_get_uint (value);
+      GST_WARNING_OBJECT (sink, "offset-h is set (%d)", sink->offset_h);
+      sink->video_info_changed = TRUE;
+      if (sink->window)
+        gst_wl_window_set_destination_mode_offset (sink->window, sink->offset_x,
+            sink->offset_y, sink->offset_w, sink->offset_h);
+      break;
+    case PROP_ALIGN_WIDTH:
+      if (sink->align_w == g_value_get_double (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->align_w = g_value_get_double (value);
+      GST_WARNING_OBJECT (sink, "align_w is set (%f)", sink->align_w);
+      break;
+    case PROP_ALIGN_HEIGHT:
+      if (sink->align_h == g_value_get_double (value)
+          || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI)
+        break;
+      sink->align_h = g_value_get_double (value);
+      GST_WARNING_OBJECT (sink, "align_h is set (%f)", sink->align_h);
+      sink->video_info_changed = TRUE;
+      if (sink->window)
+        gst_wl_window_set_destination_mode_align (sink->window, sink->align_w,
+            sink->align_h);
+      break;
+#endif
+#endif
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (sink->video_info_changed && sink->window) {
+    gst_wl_window_set_video_info_change (sink->window, TRUE);
+    if (GST_STATE (sink) == GST_STATE_PAUSED)
+      gst_wayland_sink_update_last_buffer_geometry (sink);
+  }
+#endif
+  g_mutex_unlock (&sink->render_lock);
+
+}
+
+static void
+gst_wayland_sink_finalize (GObject * object)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (object);
+  FUNCTION;
+  GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
+
+  if (sink->last_buffer)
+    gst_buffer_unref (sink->last_buffer);
+  if (sink->display)
+    g_object_unref (sink->display);
+  if (sink->window)
+    g_object_unref (sink->window);
+  if (sink->pool)
+    gst_object_unref (sink->pool);
+
+  if (sink->display_name)
+    g_free (sink->display_name);
+
+  g_mutex_clear (&sink->display_lock);
+  g_mutex_clear (&sink->render_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+static gboolean
+gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event)
+{
+  GstWaylandSink *sink;
+  const GstStructure *s;
+
+  sink = GST_WAYLAND_SINK (bsink);
+
+  switch (GST_EVENT_TYPE (event)) {
+    case GST_EVENT_EOS:
+      GST_LOG ("get GST_EVENT_EOS event..state is %d", GST_STATE (sink));
+      break;
+    case GST_EVENT_CUSTOM_DOWNSTREAM:
+      s = gst_event_get_structure (event);
+      if (s == NULL
+          || !gst_structure_has_name (s, GST_APP_EVENT_FLUSH_BUFFER_NAME))
+        break;
+
+      GST_LOG ("get GST_EVENT_CUSTOM_DOWNSTREAM EVENT: %s..state is %d",
+          gst_structure_get_name (s), GST_STATE (sink));
+
+      sink->got_costum_event = TRUE;
+      if (gst_wayland_sink_is_gapless (sink)) {
+        gst_wayland_sink_render_flush_buffer (bsink);
+        sink->got_costum_event = FALSE;
+      }
+      sink->got_costum_event = FALSE;
+      break;
+    default:
+      break;
+  }
+  return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event);
+}
+
+static void
+gst_wayland_sink_get_times (GstBaseSink * bsink, GstBuffer * buf,
+    GstClockTime * start, GstClockTime * end)
+{
+  /* If basesink need to drop buffer, basesink ask waylandsink to start and end */
+  GstWaylandSink *sink;
+
+  sink = GST_WAYLAND_SINK (bsink);
+
+  if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) {
+    *start = GST_BUFFER_TIMESTAMP (buf);
+    if (GST_BUFFER_DURATION_IS_VALID (buf)) {
+      *end = *start + GST_BUFFER_DURATION (buf);
+    } else {
+      if (sink->fps_n > 0) {
+        *end =
+            *start + gst_util_uint64_scale_int (GST_SECOND, sink->fps_d,
+            sink->fps_n);
+      }
+    }
+  }
+}
+#endif
+
+#if 0
+/* must be called with the display_lock */
+static void
+gst_wayland_sink_set_display_from_context (GstWaylandSink * sink,
+    GstContext * context)
+{
+  struct wl_display *display;
+  GError *error = NULL;
+  FUNCTION;
+
+  display = gst_wayland_display_handle_context_get_handle (context);
+  sink->display = gst_wl_display_new_existing (display, FALSE, &error);
+
+  if (error) {
+    GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
+        ("Could not set display handle"),
+        ("Failed to use the external wayland display: '%s'", error->message));
+    g_error_free (error);
+  }
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  sink->display->USE_TBM = sink->USE_TBM;
+#endif
+}
+#endif
+static gboolean
+gst_wayland_sink_find_display (GstWaylandSink * sink)
+{
+//  GstQuery *query;
+//  GstMessage *msg;
+//  GstContext *context = NULL;
+  GError *error = NULL;
+  gboolean ret = TRUE;
+  FUNCTION;
+
+  g_mutex_lock (&sink->display_lock);
+
+  if (!sink->display) {
+#if 0
+    /* first query upstream for the needed display handle */
+    query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
+    if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) {
+      gst_query_parse_context (query, &context);
+      gst_wayland_sink_set_display_from_context (sink, context);
+    }
+    gst_query_unref (query);
+#endif
+    if (G_LIKELY (!sink->display)) {
+#if 0
+      /* now ask the application to set the display handle */
+      msg = gst_message_new_need_context (GST_OBJECT_CAST (sink),
+          GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE);
+
+      g_mutex_unlock (&sink->display_lock);
+      gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
+      /* at this point we expect gst_wayland_sink_set_context
+       * to get called and fill sink->display */
+      g_mutex_lock (&sink->display_lock);
+#endif
+      if (!sink->display) {
+        /* if the application didn't set a display, let's create it ourselves */
+        GST_OBJECT_LOCK (sink);
+        sink->display = gst_wl_display_new (sink->display_name, &error);
+        GST_OBJECT_UNLOCK (sink);
+
+        if (error) {
+          GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
+              ("Could not initialise Wayland output"),
+              ("Failed to create GstWlDisplay: '%s'", error->message));
+          g_error_free (error);
+          ret = FALSE;
+        }
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+        if (G_LIKELY (sink->display))
+          sink->display->USE_TBM = sink->USE_TBM;
+#endif
+      }
+    }
+  }
+
+  g_mutex_unlock (&sink->display_lock);
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (element);
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+  FUNCTION;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      GST_LOG ("WAYLANDSINK TRANSITION: NULL_TO_READY");
+      if (!gst_wayland_sink_find_display (sink))
+        return GST_STATE_CHANGE_FAILURE;
+      break;
+    case GST_STATE_CHANGE_READY_TO_PAUSED:
+      GST_LOG ("WAYLANDSINK TRANSITION: READY_TO_PAUSED");
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
+      GST_LOG ("WAYLANDSINK TRANSITION: PAUSED_TO_PLAYING");
+      break;
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+  if (ret == GST_STATE_CHANGE_FAILURE)
+    return ret;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+      GST_LOG ("WAYLANDSINK TRANSITION: PLAYING_TO_PAUSED");
+      break;
+    case GST_STATE_CHANGE_PAUSED_TO_READY:
+      GST_LOG ("WAYLANDSINK TRANSITION: PAUSED_TO_READY");
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+      if (sink->keep_camera_preview) {
+        if (sink->window) {
+          if (!gst_wl_window_is_toplevel (sink->window)) {
+            GstBaseSink *bsink = GST_BASE_SINK (element);
+            if (sink->USE_TBM && sink->display->is_native_format
+                && !sink->display->flush_buffer) {
+              /* To avoid duplicate request by App, check flush_buffer by flush_request of MMVideoBuffer */
+              sink->request_camera_flush_buf = TRUE;
+              gst_wayland_sink_render_flush_buffer (bsink);
+              sink->request_camera_flush_buf = FALSE;
+            }
+            break;
+          }
+        }
+      }
+#endif
+      gst_buffer_replace (&sink->last_buffer, NULL);
+      if (sink->window) {
+        if (gst_wl_window_is_toplevel (sink->window)) {
+          GST_DEBUG ("internal window");
+          g_clear_object (&sink->window);
+        } else {
+          /* remove buffer from surface, show nothing */
+          GST_DEBUG ("external window");
+          gst_wl_window_render (sink->window, NULL, NULL);
+        }
+      }
+      break;
+    case GST_STATE_CHANGE_READY_TO_NULL:
+      GST_LOG ("WAYLANDSINK TRANSITION: READY_TO_NULL");
+      g_mutex_lock (&sink->display_lock);
+      /* If we had a toplevel window, we most likely have our own connection
+       * to the display too, and it is a good idea to disconnect and allow
+       * potentially the application to embed us with GstVideoOverlay
+       * (which requires to re-use the same display connection as the parent
+       * surface). If we didn't have a toplevel window, then the display
+       * connection that we have is definitely shared with the application
+       * and it's better to keep it around (together with the window handle)
+       * to avoid requesting them again from the application if/when we are
+       * restarted (GstVideoOverlay behaves like that in other sinks)
+       */
+      if (sink->display && !sink->window) {     /* -> the window was toplevel */
+        g_clear_object (&sink->display);
+      }
+      g_mutex_unlock (&sink->display_lock);
+      g_clear_object (&sink->pool);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+#if 0
+static void
+gst_wayland_sink_set_context (GstElement * element, GstContext * context)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (element);
+  FUNCTION;
+
+  if (gst_context_has_context_type (context,
+          GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) {
+    g_mutex_lock (&sink->display_lock);
+    if (G_LIKELY (!sink->display))
+      gst_wayland_sink_set_display_from_context (sink, context);
+    else {
+      GST_WARNING_OBJECT (element, "changing display handle is not supported");
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+      g_mutex_unlock (&sink->display_lock);
+      return;
+#endif
+    }
+    g_mutex_unlock (&sink->display_lock);
+  }
+
+  if (GST_ELEMENT_CLASS (parent_class)->set_context)
+    GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
+}
+#endif
+static GstCaps *
+gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
+{
+  GstWaylandSink *sink;
+  GstCaps *caps;
+  FUNCTION;
+
+  sink = GST_WAYLAND_SINK (bsink);
+
+  caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  /* To Do : When caps negotiation is newly needed by such as gapless,
+     waylandsink may have to make display when disable-overlay is TRUE in here */
+#endif
+  g_mutex_lock (&sink->display_lock);
+
+  if (sink->display) {
+    GValue list = G_VALUE_INIT;
+    GValue value = G_VALUE_INIT;
+    GArray *formats;
+    gint i;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+    uint32_t tbm_fmt;
+#endif
+    enum wl_shm_format fmt;
+
+    g_value_init (&list, GST_TYPE_LIST);
+    g_value_init (&value, G_TYPE_STRING);
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+    if (sink->USE_TBM)
+      formats = sink->display->tbm_formats;
+    else                        /* SHM */
+#endif
+      formats = sink->display->formats;
+
+    for (i = 0; i < formats->len; i++) {
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+      if (sink->USE_TBM) {
+        tbm_fmt = g_array_index (formats, uint32_t, i);
+        g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt));
+        gst_value_list_append_value (&list, &value);
+
+        /* TBM doesn't support Native formats(SN12, ST12, SN21, SR32 and S420),
+           So we add Native formats manually as supported format. */
+        if (tbm_fmt == TBM_FORMAT_NV12) {
+          g_value_set_string (&value,
+              gst_video_format_to_string (GST_VIDEO_FORMAT_SN12));
+          gst_value_list_append_value (&list, &value);
+        } else if (tbm_fmt == TBM_FORMAT_NV12MT) {
+          g_value_set_string (&value,
+              gst_video_format_to_string (GST_VIDEO_FORMAT_ST12));
+          gst_value_list_append_value (&list, &value);
+        } else if (tbm_fmt == TBM_FORMAT_NV21) {
+          g_value_set_string (&value,
+              gst_video_format_to_string (GST_VIDEO_FORMAT_SN21));
+          gst_value_list_append_value (&list, &value);
+        } else if (tbm_fmt == TBM_FORMAT_ARGB8888) {
+          g_value_set_string (&value,
+              gst_video_format_to_string (GST_VIDEO_FORMAT_SR32));
+          gst_value_list_append_value (&list, &value);
+        } else if (tbm_fmt == TBM_FORMAT_YUV420) {
+          g_value_set_string (&value,
+              gst_video_format_to_string (GST_VIDEO_FORMAT_S420));
+          gst_value_list_append_value (&list, &value);
+        }
+      } else {                  /* USE SHM */
+        fmt = g_array_index (formats, uint32_t, i);
+        g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
+        gst_value_list_append_value (&list, &value);
+      }
+#else /* open source */
+      fmt = g_array_index (formats, uint32_t, i);
+      g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
+      gst_value_list_append_value (&list, &value);
+#endif
+    }
+
+    caps = gst_caps_make_writable (caps);
+    gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);
+
+    GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
+    g_value_unset (&value);
+    g_value_unset (&list);
+
+  }
+
+  g_mutex_unlock (&sink->display_lock);
+
+  if (filter) {
+    GstCaps *intersection;
+
+    intersection =
+        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
+    gst_caps_unref (caps);
+    caps = intersection;
+  }
+
+  return caps;
+}
+
+static gboolean
+gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
+{
+  GstWaylandSink *sink;
+  GstBufferPool *newpool;
+  GstVideoInfo info;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  uint32_t tbm_format = -1;
+#endif
+  enum wl_shm_format format = -1;
+
+  GArray *formats;
+  gint i;
+  GstStructure *structure;
+  GstWlShmAllocator *self = NULL;
+
+  FUNCTION;
+
+  sink = GST_WAYLAND_SINK (bsink);
+
+  GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);
+
+  /* extract info from caps */
+  if (!gst_video_info_from_caps (&info, caps))
+    goto invalid_format;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (sink->USE_TBM) {
+    tbm_format =
+        gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info));
+    if ((gint) tbm_format == -1)
+      goto invalid_format;
+  } else {
+    format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
+    if ((gint) format == -1)
+      goto invalid_format;
+  }
+#else /* open source */
+  format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
+
+  if ((gint) format == -1)
+    goto invalid_format;
+#endif
+
+  /* verify we support the requested format */
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (sink->USE_TBM) {
+    GST_LOG ("USE TBM FORMAT");
+    formats = sink->display->tbm_formats;
+    for (i = 0; i < formats->len; i++) {
+      if (g_array_index (formats, uint32_t, i) == tbm_format)
+        break;
+    }
+  } else {                      /* USE SHM */
+    GST_LOG ("USE SHM FORMAT");
+    formats = sink->display->formats;
+    for (i = 0; i < formats->len; i++) {
+      if (g_array_index (formats, uint32_t, i) == format)
+        break;
+    }
+  }
+#else /* open source */
+  formats = sink->display->formats;
+  for (i = 0; i < formats->len; i++) {
+    if (g_array_index (formats, uint32_t, i) == format)
+      break;
+  }
+#endif
+  if (i >= formats->len)
+    goto unsupported_format;
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  /* init frame rate for baseink */
+  sink->fps_n = info.fps_n;
+  sink->fps_d = info.fps_d;
+
+  /* init value for set source */
+  sink->crop_x = sink->crop_y = sink->crop_w = sink->crop_h = 0;
+
+  if (sink->USE_TBM) {
+    if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
+        GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12 ||
+        GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN21 ||
+        GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SR32 ||
+        GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_S420) {
+      sink->display->is_native_format = TRUE;
+
+      /* store the video info */
+      sink->video_info = info;
+      sink->video_info_changed = TRUE;
+    } else {
+      sink->display->is_native_format = FALSE;
+      self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
+      self->display = sink->display;
+      /* create a new pool for the new configuration */
+      newpool = gst_video_buffer_pool_new ();
+      if (!newpool)
+        goto pool_failed;
+
+      structure = gst_buffer_pool_get_config (newpool);
+      gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
+      gst_buffer_pool_config_set_allocator (structure,
+          gst_wl_shm_allocator_get (), NULL);
+      if (!gst_buffer_pool_set_config (newpool, structure))
+        goto config_failed;
+
+      /* store the video info */
+      sink->video_info = info;
+      sink->video_info_changed = TRUE;
+
+      gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
+      gst_object_unref (newpool);
+    }
+  } else {                      /* USE SHM */
+
+    self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
+    self->display = sink->display;
+
+    /* create a new pool for the new configuration */
+    newpool = gst_video_buffer_pool_new ();
+    if (!newpool)
+      goto pool_failed;
+
+    structure = gst_buffer_pool_get_config (newpool);
+    gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
+    gst_buffer_pool_config_set_allocator (structure,
+        gst_wl_shm_allocator_get (), NULL);
+    if (!gst_buffer_pool_set_config (newpool, structure))
+      goto config_failed;
+
+    /* store the video info */
+    sink->video_info = info;
+    sink->video_info_changed = TRUE;
+
+    gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
+    gst_object_unref (newpool);
+  }
+
+  sink->is_native_format = sink->display->is_native_format;
+
+  if (sink->window)
+    gst_wayland_sink_update_window_geometry (sink);
+
+
+#else /*open source */
+  /* create a new pool for the new configuration */
+  newpool = gst_video_buffer_pool_new ();
+  if (!newpool)
+    goto pool_failed;
+
+  structure = gst_buffer_pool_get_config (newpool);
+  gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0);
+  gst_buffer_pool_config_set_allocator (structure,
+      gst_wl_shm_allocator_get (), NULL);
+  if (!gst_buffer_pool_set_config (newpool, structure))
+    goto config_failed;
+
+  /* store the video info */
+  sink->video_info = info;
+  sink->video_info_changed = TRUE;
+
+  gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
+  gst_object_unref (newpool);
+#endif
+
+  return TRUE;
+
+invalid_format:
+  {
+    GST_DEBUG_OBJECT (sink,
+        "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+unsupported_format:
+  {
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+    if (sink->USE_TBM)
+      GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
+          gst_wl_tbm_format_to_string (tbm_format));
+    else                        /*USE SHM */
+      GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
+          gst_wl_shm_format_to_string (format));
+#else /*open source */
+    GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
+        gst_wl_shm_format_to_string (format));
+#endif
+    return FALSE;
+  }
+pool_failed:
+  {
+    GST_DEBUG_OBJECT (sink, "Failed to create new pool");
+    return FALSE;
+  }
+config_failed:
+  {
+    GST_DEBUG_OBJECT (bsink, "failed setting config");
+    gst_object_unref (newpool);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
+  GstStructure *config;
+  guint size, min_bufs, max_bufs;
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  gboolean need_pool;
+  GstCaps *caps;
+  FUNCTION;
+
+  if (sink->USE_TBM) {
+    if (sink->display->is_native_format == TRUE)
+      return FALSE;
+
+    gst_query_parse_allocation (query, &caps, &need_pool);
+
+    if (caps == NULL) {
+      GST_DEBUG_OBJECT (bsink, "no caps specified");
+      return FALSE;
+    }
+  }
+#endif
+  config = gst_buffer_pool_get_config (sink->pool);
+  gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs);
+
+  /* we do have a pool for sure (created in set_caps),
+   * so let's propose it anyway, but also propose the allocator on its own */
+  gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs);
+  gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL);
+
+  gst_structure_free (config);
+
+  return TRUE;
+}
+
+static GstFlowReturn
+gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
+{
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
+  FUNCTION;
+
+  GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
+
+  if (sink->signal_handoffs) {
+    GST_LOG ("g_signal_emit: preroll-handoff");
+    g_signal_emit (sink,
+        gst_waylandsink_signals[SIGNAL_PREROLL_HANDOFF], 0, buffer,
+        bsink->sinkpad);
+
+    return GST_FLOW_OK;
+  }
+#endif
+  return gst_wayland_sink_render (bsink, buffer);
+}
+
+static void
+frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
+{
+  GstWaylandSink *sink = data;
+  FUNCTION;
+
+  GST_LOG ("frame_redraw_cb");
+
+  g_atomic_int_set (&sink->redraw_pending, FALSE);
+  GST_INFO ("wl_callback_destroy (wl_callback@%p)", callback);
+  wl_callback_destroy (callback);
+}
+
+static const struct wl_callback_listener frame_callback_listener = {
+  frame_redraw_callback
+};
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+static void
+gst_wayland_sink_update_window_geometry (GstWaylandSink * sink)
+{
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+  g_return_if_fail (sink->window != NULL);
+
+  gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
+  gst_wl_window_set_destination_mode (sink->window,
+      sink->display_geometry_method);
+  gst_wl_window_set_flip (sink->window, sink->flip);
+  if (sink->crop_w == 0 && sink->crop_h == 0) {
+    sink->crop_w =
+        gst_util_uint64_scale_int_round (sink->video_info.width,
+        sink->video_info.par_n, sink->video_info.par_d);
+    sink->crop_h = sink->video_info.height;
+  }
+  gst_wl_window_set_destination_mode_crop_wl_buffer (sink->window, sink->crop_x,
+      sink->crop_y, sink->crop_w, sink->crop_h);
+#ifdef ENABLE_FUNCTION
+  gst_wl_window_set_destination_mode_follow_parent_transform (sink->window,
+      sink->follow_parent_transform);
+  gst_wl_window_set_destination_mode_ratio (sink->window, sink->ratio_w,
+      sink->ratio_h);
+  gst_wl_window_set_destination_mode_scale (sink->window, sink->scale_w,
+      sink->scale_h);
+  gst_wl_window_set_destination_mode_offset (sink->window, sink->offset_x,
+      sink->offset_y, sink->offset_w, sink->offset_h);
+  gst_wl_window_set_destination_mode_align (sink->window, sink->align_w,
+      sink->align_h);
+#endif
+}
+#endif
+/* must be called with the render lock */
+static void
+render_last_buffer (GstWaylandSink * sink)
+{
+  GstWlBuffer *wlbuffer;
+  const GstVideoInfo *info = NULL;
+  struct wl_surface *surface;
+  struct wl_callback *callback;
+  FUNCTION;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  g_return_if_fail (sink->last_buffer != NULL);
+  g_return_if_fail (sink->window != NULL);
+#endif
+
+  wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer);
+  surface = gst_wl_window_get_wl_surface (sink->window);
+
+  g_atomic_int_set (&sink->redraw_pending, TRUE);
+  callback = wl_surface_frame (surface);
+  GST_INFO ("wl_callback@%p = wl_surface_frame (video_surface@%p)", callback,
+      surface);
+
+  /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */
+  GST_INFO
+      ("wl_callback_add_listener (wl_callback@%p, wl_callback_listener@%p, GstWaylandSink@%p)",
+      callback, &frame_callback_listener, sink);
+  wl_callback_add_listener (callback, &frame_callback_listener, sink);
+
+  if (G_UNLIKELY (sink->video_info_changed)) {
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+    gst_wl_window_set_video_info_change (sink->window, TRUE);
+#endif
+    info = &sink->video_info;
+    sink->video_info_changed = FALSE;
+  }
+  gst_wl_window_render (sink->window, wlbuffer, info);
+}
+
+
+static gboolean
+gst_wayland_sink_has_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer)
+{
+  GstWlBuffer *gstwlbuffer;
+  FUNCTION;
+  g_return_val_if_fail (sink != NULL, FALSE);
+  g_return_val_if_fail (buffer != NULL, FALSE);
+
+  gstwlbuffer = gst_buffer_get_wl_buffer (buffer);
+  if (gstwlbuffer && gstwlbuffer->display == sink->display
+      && !gst_wayland_sink_is_gapless (sink)
+      && !sink->request_camera_flush_buf) {
+    /* gstbuffer has wlbuffer */
+    /* e.g) last_buffer, buffer is created by previous plugin or waylandsink with BufferPool */
+    GST_LOG ("buffer(%p) has GstWlBuffer(%p):wlbuffer(%p)", buffer, gstwlbuffer,
+        gstwlbuffer->wlbuffer);
+    return TRUE;
+  }
+  GST_LOG ("buffer(%p) has not wlbuffer", buffer);
+  return FALSE;
+}
+
+static GstFlowReturn
+gst_wayland_sink_no_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer)
+{
+  GstMemory *mem;
+  MMVideoBuffer *mm_video_buf = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  FUNCTION;
+  g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
+
+  /* the last_buffer for flushing has wlbuffer or
+     buffer is created by previous plugins or waylandsink has wlbuffer */
+  mem = gst_buffer_peek_memory (buffer, 0);
+  if (gst_is_wl_memory (mem)) {
+    GST_LOG ("buffer(%p) is created by waylandsink has a wl_buffer, "
+        "writing directly", buffer);
+  } else {
+    GST_LOG
+        ("buffer(%p) is created by previous plugins with BufferPool has a wl_buffer, "
+        "writing directly", buffer);
+    GST_LOG ("previous plugins must manage buffer index well");
+    /* check MMVideoBuffer */
+    mm_video_buf = gst_wayland_sink_get_mm_video_buf (buffer);
+    if (mm_video_buf != NULL) {
+      GST_LOG ("GstBuffer(%p) has MMVideoBuffer(%p)", buffer, mm_video_buf);
+    } else {
+      GST_ERROR ("GstBuffer(%p) has not MMVideoBuffer(%p)", buffer,
+          mm_video_buf);
+      return GST_FLOW_ERROR;
+    }
+  }
+
+  sink->to_render = buffer;
+
+  if (sink->dump_video && !sink->display->is_native_format)
+    gst_wayland_sink_dump_raw_video (sink, sink->to_render,
+        sink->display->dump_count++, sink->total_dump);
+
+  return ret;
+}
+
+static void
+gst_wayland_sink_create_wlbuffer_with_wl_mem (GstWaylandSink * sink,
+    GstBuffer * buffer)
+{
+  GstMemory *mem;
+  struct wl_buffer *wbuf = NULL;
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+  g_return_if_fail (buffer != NULL);
+
+  GST_LOG ("gstbuffer(%p) is created by wayland has not wlbuffer", buffer);
+  mem = gst_buffer_peek_memory (buffer, 0);
+  wbuf =
+      gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
+      &sink->video_info);
+  if (wbuf) {
+    gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
+    sink->to_render = buffer;
+  }
+}
+
+static GstFlowReturn
+gst_wayland_sink_create_wlbuffer_with_previous_plugin_tbm (GstWaylandSink *
+    sink, GstBuffer * buffer)
+{
+  GstMemory *mem;
+  GstWlBuffer *wlbuffer;
+  struct wl_buffer *wbuf = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  FUNCTION;
+  g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
+  sink->flush_gstbuf = NULL;
+
+  GST_LOG
+      ("buffer(%p) is created by previous plugin with no BufferPool does not have a wl_buffer",
+      buffer);
+  GST_LOG ("Use native format with previous plugins TBM");
+  /* in case of native format (SN12, ST12, SN21, SR32 and S420) */
+  if (!gst_wayland_sink_get_mm_video_buf_info (sink, buffer)) {
+    return GST_FLOW_ERROR;
+  }
+
+  wlbuffer = gst_buffer_get_wl_buffer (buffer);
+  /* last_buffer from gaplasee have wlbuffer */
+  if (G_UNLIKELY (!wlbuffer) || sink->display->flush_request) {
+    mem = gst_buffer_peek_memory (buffer, 0);
+    wbuf =
+        gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
+        &sink->video_info);
+    if (G_UNLIKELY (!wbuf)) {
+      GST_ERROR ("could not create wl_buffer");
+      return GST_FLOW_ERROR;
+    }
+    if (sink->display->flush_request) {
+      sink->flush_gstbuf = gst_buffer_new ();
+      GST_LOG ("To flush, new gstBuffer(%p)", sink->flush_gstbuf);
+      gst_buffer_add_wl_buffer (sink->flush_gstbuf, wbuf, sink->display);
+    } else {
+      gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
+    }
+  }
+  return ret;
+}
+
+static GstFlowReturn
+    gst_wayland_sink_copy_input_gstbuffer_to_wl_gstbuffer_with_wl_mem
+    (GstWaylandSink * sink, GstBuffer * buffer)
+{
+  GstWlBuffer *wlbuffer;
+  GstMemory *mem;
+  GstWlShmMemory *shm_mem;
+  GstMapInfo src;
+  struct wl_buffer *wbuf = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+  FUNCTION;
+  g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
+
+  GST_LOG ("Use normal format with wayland TBM or SHM");
+  /* sink->pool always exists (created in set_caps), but it may not
+   * be active if upstream is not using it */
+  if (!gst_buffer_pool_is_active (sink->pool) &&
+      !gst_buffer_pool_set_active (sink->pool, TRUE)) {
+    GST_ERROR ("failed to activate bufferpool.");
+    return GST_FLOW_ERROR;
+  }
+
+  ret = gst_buffer_pool_acquire_buffer (sink->pool, &sink->to_render, NULL);
+  if (ret != GST_FLOW_OK) {
+    GST_WARNING ("could not create buffer");
+    return ret;
+  }
+  /* the first time we acquire a buffer,
+   * we need to attach a wl_buffer on it */
+  wlbuffer = gst_buffer_get_wl_buffer (buffer);
+  if (G_UNLIKELY (!wlbuffer)) {
+    mem = gst_buffer_peek_memory (sink->to_render, 0);
+    shm_mem = (GstWlShmMemory *) mem;
+    GST_LOG ("to_render(%p), shm_mem->fd(%d)", sink->to_render, shm_mem->fd);
+    wbuf =
+        gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
+        &sink->video_info);
+    if (G_UNLIKELY (!wbuf)) {
+      GST_ERROR ("could not create wl_buffer out of wl memory");
+      return GST_FLOW_ERROR;
+    }
+    wlbuffer = gst_buffer_add_wl_buffer (sink->to_render, wbuf, sink->display);
+  }
+
+  gst_buffer_map (buffer, &src, GST_MAP_READ);
+  gst_buffer_fill (sink->to_render, 0, src.data, src.size);
+  gst_buffer_unmap (buffer, &src);
+
+  return ret;
+}
+
+static GstFlowReturn
+gst_wayland_sink_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer)
+{
+  GstMemory *mem;
+  GstFlowReturn ret = GST_FLOW_OK;
+  FUNCTION;
+  g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR);
+  g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR);
+
+  sink->to_render = NULL;
+
+  if (gst_wayland_sink_has_wlbuffer (sink, buffer)) {
+    ret = gst_wayland_sink_no_create_wlbuffer (sink, buffer);
+  } else {
+    mem = gst_buffer_peek_memory (buffer, 0);
+    if (gst_is_wl_memory (mem)) {
+      /* SHM or TBM */
+      gst_wayland_sink_create_wlbuffer_with_wl_mem (sink, buffer);
+    } else {
+      /* gstbuffer is not wl memory */
+      if (sink->USE_TBM && sink->display->is_native_format) {
+        /* Use tbm of buffer directly */
+        ret =
+            gst_wayland_sink_create_wlbuffer_with_previous_plugin_tbm (sink,
+            buffer);
+      } else {
+        /* Copy virtual addr to wayland SHM or TBM */
+        ret =
+            gst_wayland_sink_copy_input_gstbuffer_to_wl_gstbuffer_with_wl_mem
+            (sink, buffer);
+      }
+    }
+  }
+  return ret;
+}
+
+static void
+gst_wayland_sink_buffer_replace (GstWaylandSink * sink, GstBuffer * buffer)
+{
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+
+  if (sink->USE_TBM && sink->display->is_native_format) {
+    if (sink->flush_gstbuf && sink->display->flush_request) {
+      GST_LOG_OBJECT (sink, "replace last_buffer:(%p)->(%p)", sink->last_buffer,
+          sink->flush_gstbuf);
+      /* increase ref count of sink->fflush_gstbuf, decrease  ref count of sink->last_buffer */
+      gst_buffer_replace (&sink->last_buffer, sink->flush_gstbuf);
+      GST_LOG_OBJECT (sink, "after gst_buffer_replace buffer %p, ref_count(%d)",
+          sink->flush_gstbuf, GST_OBJECT_REFCOUNT_VALUE (sink->flush_gstbuf));
+      /* decrease  ref count of flush_buffer */
+      gst_buffer_unref (sink->flush_gstbuf);
+    } else {
+      /* normal case */
+      GST_LOG_OBJECT (sink, "replace last_buffer:(%p)->(%p)", sink->last_buffer,
+          buffer);
+      /* increase ref count of buffer decrease  ref count of sink->last_buffer */
+      gst_buffer_replace (&sink->last_buffer, buffer);
+      GST_LOG_OBJECT (sink, "after gst_buffer_replace buffer %p, ref_count(%d)",
+          buffer, GST_OBJECT_REFCOUNT_VALUE (buffer));
+    }
+  } else {
+    gst_buffer_replace (&sink->last_buffer, sink->to_render);
+    GST_LOG_OBJECT (sink, "after gst_buffer_replace buffer %p, ref_count(%d)",
+        sink->to_render, GST_OBJECT_REFCOUNT_VALUE (sink->to_render));
+  }
+}
+
+static void
+gst_wayland_sink_get_window (GstWaylandSink * sink)
+{
+  g_return_if_fail (sink != NULL);
+  FUNCTION;
+
+  /* ask for window handle. Unlock render_lock while doing that because
+   * set_window_handle & friends will lock it in this context */
+  g_mutex_unlock (&sink->render_lock);
+  gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
+  g_mutex_lock (&sink->render_lock);
+
+  if (!sink->window) {
+    /* if we were not provided a window, create one ourselves */
+    sink->window =
+        gst_wl_window_new_toplevel (sink->display, &sink->video_info);
+  }
+  gst_wayland_sink_update_window_geometry (sink);
+}
+
+static GstFlowReturn
+gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
+{
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+
+  GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
+  GstFlowReturn ret = GST_FLOW_OK;
+  FUNCTION;
+
+  g_mutex_lock (&sink->render_lock);
+
+  GST_LOG_OBJECT (sink, "input gstbuffer %p, ref_count(%d)", buffer,
+      GST_OBJECT_REFCOUNT_VALUE (buffer));
+
+  /* check overlay */
+  if (gst_wayland_sink_is_disabled_overlay (sink)) {
+    GST_LOG ("set disable_overlay, so skip");
+    goto done;
+  }
+
+  /* check window */
+  if (G_UNLIKELY (!sink->window)) {
+    gst_wayland_sink_get_window (sink);
+  }
+
+  /* fakesink function for media stream callback case */
+  if (sink->signal_handoffs) {
+    GST_LOG ("g_signal_emit: hand-off ");
+    g_signal_emit (sink, gst_waylandsink_signals[SIGNAL_HANDOFF], 0, buffer,
+        bsink->sinkpad);
+    goto done;
+  }
+
+  /* drop buffers until we get a frame callback */
+  if (g_atomic_int_get (&sink->redraw_pending) == TRUE
+      && !gst_wayland_sink_is_gapless (sink))
+    goto done;
+
+  /* create wl_buffer */
+  ret = gst_wayland_sink_create_wlbuffer (sink, buffer);
+  if (ret != GST_FLOW_OK)
+    goto done;
+
+  /* drop double rendering */
+  if ((G_UNLIKELY (buffer == sink->last_buffer)
+          && !(sink->display->flush_request))) {
+    GST_LOG_OBJECT (sink, "Buffer already being rendered");
+    goto done;
+  }
+
+  /* replace last_buffer */
+  gst_wayland_sink_buffer_replace (sink, buffer);
+
+  /* rendering */
+  if (sink->visible) {
+    render_last_buffer (sink);
+  } else {
+    GST_LOG ("skip rendering");
+  }
+
+  if (sink->to_render) {
+    if (buffer != sink->to_render)
+      gst_buffer_unref (sink->to_render);
+  }
+
+  goto done;
+
+#else /* open source */
+
+  GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
+  GstBuffer *to_render = NULL;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+  g_mutex_lock (&sink->render_lock);
+
+  if (G_UNLIKELY (!sink->window)) {
+    /* ask for window handle. Unlock render_lock while doing that because
+     * set_window_handle & friends will lock it in this context */
+    g_mutex_unlock (&sink->render_lock);
+    gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
+    g_mutex_lock (&sink->render_lock);
+
+    if (!sink->window) {
+      /* if we were not provided a window, create one ourselves */
+      sink->window =
+          gst_wl_window_new_toplevel (sink->display, &sink->video_info);
+    }
+  }
+
+  /* drop buffers until we get a frame callback */
+  if (g_atomic_int_get (&sink->redraw_pending) == TRUE
+      && !gst_wayland_sink_is_gapless (sink))
+    goto done;
+
+  /* make sure that the application has called set_render_rectangle() */
+  if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
+    goto no_window_size;
+
+  wlbuffer = gst_buffer_get_wl_buffer (buffer);
+
+  if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
+    GST_LOG_OBJECT (sink,
+        "buffer %p has a wl_buffer from our display, " "writing directly",
+        buffer);
+    GST_LOG ("wl_buffer (%p)", wlbuffer->wlbuffer);
+    to_render = buffer;
+
+  } else {
+    GstMemory *mem;
+    struct wl_buffer *wbuf = NULL;
+
+    GST_LOG_OBJECT (sink,
+        "buffer %p does not have a wl_buffer from our " "display, creating it",
+        buffer);
+    mem = gst_buffer_peek_memory (buffer, 0);
+    if (gst_is_wl_shm_memory (mem)) {   /* is wayland memory */
+      FUNCTION;
+      wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
+          &sink->video_info);
+    }
+    if (wbuf) {
+      gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
+      to_render = buffer;
+
+    } else {
+      GstMapInfo src;
+      /* we don't know how to create a wl_buffer directly from the provided
+       * memory, so we have to copy the data to a memory that we know how
+       * to handle... */
+
+      GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer);
+      GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying",
+          buffer);
+      /* sink->pool always exists (created in set_caps), but it may not
+       * be active if upstream is not using it */
+      if (!gst_buffer_pool_is_active (sink->pool) &&
+          !gst_buffer_pool_set_active (sink->pool, TRUE))
+        goto activate_failed;
+
+      ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
+      if (ret != GST_FLOW_OK)
+        goto no_buffer;
+
+      /* the first time we acquire a buffer,
+       * we need to attach a wl_buffer on it */
+      wlbuffer = gst_buffer_get_wl_buffer (buffer);
+      if (G_UNLIKELY (!wlbuffer)) {
+        mem = gst_buffer_peek_memory (to_render, 0);
+        wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
+            &sink->video_info);
+        if (G_UNLIKELY (!wbuf))
+          goto no_wl_buffer;
+
+        gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
+      }
+
+      gst_buffer_map (buffer, &src, GST_MAP_READ);
+      gst_buffer_fill (to_render, 0, src.data, src.size);
+      gst_buffer_unmap (buffer, &src);
+    }
+  }
+  /* drop double rendering */
+  if (G_UNLIKELY (buffer == sink->last_buffer)) {
+    GST_LOG_OBJECT (sink, "Buffer already being rendered");
+    goto done;
+  }
+
+  gst_buffer_replace (&sink->last_buffer, to_render);
+  render_last_buffer (sink);
+
+  if (buffer != to_render)
+    gst_buffer_unref (to_render);
+
+  goto done;
+
+#endif /* TIZEN_FEATURE_WLSINK_ENHANCEMENT */
+
+#ifndef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+no_window_size:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
+        ("Window has no size set"),
+        ("Make sure you set the size after calling set_window_handle"));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+no_buffer:
+  {
+    GST_WARNING_OBJECT (sink, "could not create buffer");
+    goto done;
+  }
+no_wl_buffer:
+  {
+    GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+activate_failed:
+  {
+    GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+#endif
+done:
+  {
+    g_mutex_unlock (&sink->render_lock);
+    return ret;
+  }
+}
+
+static void
+gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
+{
+  iface->set_window_handle = gst_wayland_sink_set_window_handle;
+  iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle;
+  iface->expose = gst_wayland_sink_expose;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT /* use unique_id */
+  iface->set_wl_window_wl_surface_id =
+      gst_wayland_sink_set_wl_window_wl_surface_id;
+#endif
+}
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+/* use  unique_id */
+static void
+gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay,
+    guintptr wl_surface_id)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+
+  if (sink->window != NULL) {
+    GST_WARNING_OBJECT (sink, "changing window handle is not supported");
+    return;
+  }
+  g_mutex_lock (&sink->render_lock);
+  g_clear_object (&sink->window);
+
+  GST_LOG ("wl_surface_id %d %x", (int) wl_surface_id,
+      (guintptr) wl_surface_id);
+
+  if (wl_surface_id) {
+    if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
+      /* we can use our own display with an external window handle */
+      if (G_LIKELY (sink->display->own_display)) {
+        sink->display->wl_surface_id = (int) wl_surface_id;
+        sink->window = gst_wl_window_new_in_surface (sink->display, NULL);
+      }
+    } else {
+      GST_ERROR_OBJECT (sink, "Failed to find display handle, "
+          "ignoring window handle");
+    }
+  }
+  g_mutex_unlock (&sink->render_lock);
+
+}
+#endif
+
+static void
+gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
+  struct wl_surface *surface = (struct wl_surface *) handle;
+  FUNCTION;
+
+  g_return_if_fail (sink != NULL);
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT /* use  unique_id */
+  if (sink->window != NULL) {
+    GST_WARNING_OBJECT (sink, "changing window handle is not supported");
+    return;
+  }
+#endif
+  g_mutex_lock (&sink->render_lock);
+
+  GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT,
+      (void *) handle);
+
+  g_clear_object (&sink->window);
+
+  if (handle) {
+    if (G_LIKELY (gst_wayland_sink_find_display (sink))) {
+      /* we cannot use our own display with an external window handle */
+      if (G_UNLIKELY (sink->display->own_display)) {
+        GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE,
+            ("Application did not provide a wayland display handle"),
+            ("Now waylandsink use internal display handle "
+                "which is created ourselves. Consider providing a "
+                "display handle from your application with GstContext"));
+        sink->window = gst_wl_window_new_in_surface (sink->display, surface);
+      } else {
+        sink->window = gst_wl_window_new_in_surface (sink->display, surface);
+      }
+    } else {
+      GST_ERROR_OBJECT (sink, "Failed to find display handle, "
+          "ignoring window handle");
+    }
+  }
+  g_mutex_unlock (&sink->render_lock);
+}
+
+static void
+gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
+    gint x, gint y, gint w, gint h)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
+  FUNCTION;
+
+  g_return_if_fail (sink != NULL);
+
+  g_mutex_lock (&sink->render_lock);
+  if (!sink->window) {
+    g_mutex_unlock (&sink->render_lock);
+    GST_WARNING_OBJECT (sink,
+        "set_render_rectangle called without window, ignoring");
+    return;
+  }
+
+  GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d",
+      x, y, w, h);
+  if (gst_wl_window_set_render_rectangle (sink->window, x, y, w, h)) {
+    sink->video_info_changed = TRUE;
+    if (sink->window && GST_STATE (sink) == GST_STATE_PAUSED)
+      gst_wayland_sink_update_last_buffer_geometry (sink);
+  }
+  g_mutex_unlock (&sink->render_lock);
+}
+
+static void
+gst_wayland_sink_expose (GstVideoOverlay * overlay)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (overlay);
+  FUNCTION;
+
+  g_return_if_fail (sink != NULL);
+
+  GST_DEBUG_OBJECT (sink, "expose");
+
+  g_mutex_lock (&sink->render_lock);
+  if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) {
+    GST_DEBUG_OBJECT (sink, "redrawing last buffer");
+    render_last_buffer (sink);
+  }
+  g_mutex_unlock (&sink->render_lock);
+}
+#if 0
+static void
+gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
+{
+  iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change;
+  iface->end_geometry_change = gst_wayland_sink_end_geometry_change;
+}
+
+static void
+gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (video);
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+
+  g_mutex_lock (&sink->render_lock);
+  if (!sink->window || !sink->window->area_subsurface) {
+    g_mutex_unlock (&sink->render_lock);
+    GST_INFO_OBJECT (sink,
+        "begin_geometry_change called without window, ignoring");
+    return;
+  }
+
+  wl_subsurface_set_sync (sink->window->area_subsurface);
+  g_mutex_unlock (&sink->render_lock);
+}
+
+static void
+gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
+{
+  GstWaylandSink *sink = GST_WAYLAND_SINK (video);
+  FUNCTION;
+  g_return_if_fail (sink != NULL);
+
+  g_mutex_lock (&sink->render_lock);
+  if (!sink->window || !sink->window->area_subsurface) {
+    g_mutex_unlock (&sink->render_lock);
+    GST_INFO_OBJECT (sink,
+        "end_geometry_change called without window, ignoring");
+    return;
+  }
+
+  wl_subsurface_set_desync (sink->window->area_subsurface);
+  g_mutex_unlock (&sink->render_lock);
+}
+#endif
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "tizenwlsink", 0,
+      " tizen wayland video sink");
+
+  gst_wl_shm_allocator_register ();
+
+  return gst_element_register (plugin, "tizenwlsink", GST_RANK_MARGINAL,
+      GST_TYPE_WAYLAND_SINK);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    tizenwlsink,
+    "Tizen Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+    GST_PACKAGE_ORIGIN)
diff --git a/tizenwlsink/src/gstwaylandsink.h b/tizenwlsink/src/gstwaylandsink.h
new file mode 100644 (file)
index 0000000..58c1e11
--- /dev/null
@@ -0,0 +1,130 @@
+/*
+ * GStreamer Wayland video sink
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GST_WAYLAND_VIDEO_SINK_H__
+#define __GST_WAYLAND_VIDEO_SINK_H__
+
+#include <gst/gst.h>
+#include <gst/video/video.h>
+
+#include <wayland-client.h>
+
+#include "wldisplay.h"
+#include "wlwindow.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAYLAND_SINK \
+           (gst_wayland_sink_get_type())
+#define GST_WAYLAND_SINK(obj) \
+           (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAYLAND_SINK,GstWaylandSink))
+#define GST_WAYLAND_SINK_CLASS(klass) \
+           (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAYLAND_SINK,GstWaylandSinkClass))
+#define GST_IS_WAYLAND_SINK(obj) \
+           (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAYLAND_SINK))
+#define GST_IS_WAYLAND_SINK_CLASS(klass) \
+           (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAYLAND_SINK))
+#define GST_WAYLAND_SINK_GET_CLASS(inst) \
+        (G_TYPE_INSTANCE_GET_CLASS ((inst), GST_TYPE_WAYLAND_SINK, GstWaylandSinkClass))
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+enum
+{
+  DISP_GEO_METHOD_LETTER_BOX = 0,
+  DISP_GEO_METHOD_ORIGIN_SIZE,
+  DISP_GEO_METHOD_FULL_SCREEN,
+  DISP_GEO_METHOD_CROPPED_FULL_SCREEN,
+  DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX,
+  DISP_GEO_METHOD_CUSTOM_ROI,
+  DISP_GEO_METHOD_NUM,
+};
+
+#define DEF_DISPLAY_FLIP            FLIP_NONE
+#define DEF_DISPLAY_GEOMETRY_METHOD         DISP_GEO_METHOD_LETTER_BOX
+#define DEFAULT_DUMP_COUNT 10
+#endif
+
+typedef struct _GstWaylandSink GstWaylandSink;
+typedef struct _GstWaylandSinkClass GstWaylandSinkClass;
+
+struct _GstWaylandSink
+{
+  GstVideoSink parent;
+
+  GMutex display_lock;
+  GstWlDisplay *display;
+  GstWlWindow *window;
+  GstBufferPool *pool;
+
+  gboolean video_info_changed;
+  GstVideoInfo video_info;
+
+  gchar *display_name;
+
+  gboolean redraw_pending;
+  GMutex render_lock;
+  GstBuffer *last_buffer;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  GstBuffer *to_render;
+  GstBuffer *flush_gstbuf;
+  /* Framerate numerator and denominator */
+  gint fps_n;
+  gint fps_d;
+
+  gboolean dump_video;
+  gboolean signal_handoffs;
+  gboolean request_camera_flush_buf;
+  gboolean keep_camera_preview;
+  gboolean got_costum_event;
+  gboolean visible;
+  gboolean follow_parent_transform;
+  gboolean USE_TBM;
+  gboolean is_native_format;
+  gboolean flush_request;
+  gboolean disable_overlay;
+  guint total_dump;
+  guint rotate_angle;
+  guint display_geometry_method;
+  guint flip;
+  guint crop_x, crop_y, crop_w, crop_h;
+#ifdef ENABLE_FUNCTION
+  guint offset_x, offset_y, offset_w, offset_h;
+  gdouble ratio_w, ratio_h;
+  gdouble scale_w, scale_h;
+  gdouble align_w, align_h;
+#endif
+#endif
+};
+
+struct _GstWaylandSinkClass
+{
+  GstVideoSinkClass parent;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  /* signals */
+  void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
+  void (*preroll_handoff) (GstElement *element, GstBuffer *buf, GstPad *pad);
+#endif
+};
+
+GType
+gst_wayland_sink_get_type (void)
+    G_GNUC_CONST;
+
+G_END_DECLS
+#endif /* __GST_WAYLAND_VIDEO_SINK_H__ */
diff --git a/tizenwlsink/src/scaler.xml b/tizenwlsink/src/scaler.xml
new file mode 100644 (file)
index 0000000..e21ae5b
--- /dev/null
@@ -0,0 +1,210 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="scaler">
+
+  <copyright>
+    Copyright Â© 2013-2014 Collabora, Ltd.
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+  <interface name="wl_scaler" version="2">
+    <description summary="surface cropping and scaling">
+      The global interface exposing surface cropping and scaling
+      capabilities is used to instantiate an interface extension for a
+      wl_surface object. This extended interface will then allow
+      cropping and scaling the surface contents, effectively
+      disconnecting the direct relationship between the buffer and the
+      surface size.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the cropping and scaling interface">
+       Informs the server that the client will not be using this
+       protocol object anymore. This does not affect any other objects,
+       wl_viewport objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="viewport_exists" value="0"
+             summary="the surface already has a viewport object associated"/>
+    </enum>
+
+    <request name="get_viewport">
+      <description summary="extend surface interface for crop and scale">
+       Instantiate an interface extension for the given wl_surface to
+       crop and scale its content. If the given wl_surface already has
+       a wl_viewport object associated, the viewport_exists
+       protocol error is raised.
+      </description>
+
+      <arg name="id" type="new_id" interface="wl_viewport"
+           summary="the new viewport interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="wl_viewport" version="2">
+    <description summary="crop and scale interface to a wl_surface">
+      An additional interface to a wl_surface object, which allows the
+      client to specify the cropping and scaling of the surface
+      contents.
+
+      This interface allows to define the source rectangle (src_x,
+      src_y, src_width, src_height) from where to take the wl_buffer
+      contents, and scale that to destination size (dst_width,
+      dst_height). This state is double-buffered, and is applied on the
+      next wl_surface.commit.
+
+      The two parts of crop and scale state are independent: the source
+      rectangle, and the destination size. Initially both are unset, that
+      is, no scaling is applied. The whole of the current wl_buffer is
+      used as the source, and the surface size is as defined in
+      wl_surface.attach.
+
+      If the destination size is set, it causes the surface size to become
+      dst_width, dst_height. The source (rectangle) is scaled to exactly
+      this size. This overrides whatever the attached wl_buffer size is,
+      unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
+      has no content and therefore no size. Otherwise, the size is always
+      at least 1x1 in surface coordinates.
+
+      If the source rectangle is set, it defines what area of the
+      wl_buffer is taken as the source. If the source rectangle is set and
+      the destination size is not set, the surface size becomes the source
+      rectangle size rounded up to the nearest integer. If the source size
+      is already exactly integers, this results in cropping without scaling.
+
+      The coordinate transformations from buffer pixel coordinates up to
+      the surface-local coordinates happen in the following order:
+        1. buffer_transform (wl_surface.set_buffer_transform)
+        2. buffer_scale (wl_surface.set_buffer_scale)
+        3. crop and scale (wl_viewport.set*)
+      This means, that the source rectangle coordinates of crop and scale
+      are given in the coordinates after the buffer transform and scale,
+      i.e. in the coordinates that would be the surface-local coordinates
+      if the crop and scale was not applied.
+
+      If the source rectangle is partially or completely outside of the
+      wl_buffer, then the surface contents are undefined (not void), and
+      the surface size is still dst_width, dst_height.
+
+      The x, y arguments of wl_surface.attach are applied as normal to
+      the surface. They indicate how many pixels to remove from the
+      surface size from the left and the top. In other words, they are
+      still in the surface-local coordinate system, just like dst_width
+      and dst_height are.
+
+      If the wl_surface associated with the wl_viewport is destroyed,
+      the wl_viewport object becomes inert.
+
+      If the wl_viewport object is destroyed, the crop and scale
+      state is removed from the wl_surface. The change will be applied
+      on the next wl_surface.commit.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove scaling and cropping from the surface">
+       The associated wl_surface's crop and scale state is removed.
+       The change is applied on the next wl_surface.commit.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_value" value="0"
+             summary="negative or zero values in width or height"/>
+    </enum>
+
+    <request name="set">
+      <description summary="set the crop and scale state">
+       Set both source rectangle and destination size of the associated
+       wl_surface. See wl_viewport for the description, and relation to
+       the wl_buffer size.
+
+       The bad_value protocol error is raised if src_width or
+       src_height is negative, or if dst_width or dst_height is not
+       positive.
+
+       The crop and scale state is double-buffered state, and will be
+       applied on the next wl_surface.commit.
+
+       Arguments dst_x and dst_y do not exist here, use the x and y
+       arguments to wl_surface.attach. The x, y, dst_width, and dst_height
+       define the surface-local coordinate system irrespective of the
+       attached wl_buffer size.
+      </description>
+
+      <arg name="src_x" type="fixed" summary="source rectangle x"/>
+      <arg name="src_y" type="fixed" summary="source rectangle y"/>
+      <arg name="src_width" type="fixed" summary="source rectangle width"/>
+      <arg name="src_height" type="fixed" summary="source rectangle height"/>
+      <arg name="dst_width" type="int" summary="surface width"/>
+      <arg name="dst_height" type="int" summary="surface height"/>
+    </request>
+
+    <request name="set_source" since="2">
+      <description summary="set the source rectangle for cropping">
+       Set the source rectangle of the associated wl_surface. See
+       wl_viewport for the description, and relation to the wl_buffer
+       size.
+
+       If width is -1.0 and height is -1.0, the destination size is unset
+       instead. Any other pair of values for width and height that
+       contains zero or negative values raises the bad_value protocol
+       error.
+
+       The crop and scale state is double-buffered state, and will be
+       applied on the next wl_surface.commit.
+      </description>
+
+      <arg name="x" type="fixed" summary="source rectangle x"/>
+      <arg name="y" type="fixed" summary="source rectangle y"/>
+      <arg name="width" type="fixed" summary="source rectangle width"/>
+      <arg name="height" type="fixed" summary="source rectangle height"/>
+    </request>
+
+    <request name="set_destination" since="2">
+      <description summary="set the surface size for scaling">
+       Set the destination size of the associated wl_surface. See
+       wl_viewport for the description, and relation to the wl_buffer
+       size.
+
+       If width is -1 and height is -1, the destination size is unset
+       instead. Any other pair of values for width and height that
+       contains zero or negative values raises the bad_value protocol
+       error.
+
+       The crop and scale state is double-buffered state, and will be
+       applied on the next wl_surface.commit.
+
+       Arguments x and y do not exist here, use the x and y arguments to
+       wl_surface.attach. The x, y, width, and height define the
+       surface-local coordinate system irrespective of the attached
+       wl_buffer size.
+      </description>
+
+      <arg name="width" type="int" summary="surface width"/>
+      <arg name="height" type="int" summary="surface height"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/tizenwlsink/src/tizen-wlvideoformat.c b/tizenwlsink/src/tizen-wlvideoformat.c
new file mode 100644 (file)
index 0000000..8ebf505
--- /dev/null
@@ -0,0 +1,115 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2012 Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#include "tizen-wlvideoformat.h"
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+
+GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
+#define GST_CAT_DEFAULT gstwayland_debug
+
+typedef struct
+{
+  uint32_t wl_format;
+  GstVideoFormat gst_format;
+} wl_TbmVideoFormat;
+
+static const wl_TbmVideoFormat tbm_formats[] = {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  {TBM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_xRGB},
+  {TBM_FORMAT_XBGR8888, GST_VIDEO_FORMAT_xBGR},
+  {TBM_FORMAT_RGBX8888, GST_VIDEO_FORMAT_RGBx},
+  {TBM_FORMAT_BGRX8888, GST_VIDEO_FORMAT_BGRx},
+  {TBM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_ARGB},
+  {TBM_FORMAT_ABGR8888, GST_VIDEO_FORMAT_RGBA},
+  {TBM_FORMAT_RGBA8888, GST_VIDEO_FORMAT_RGBA},
+  {TBM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_BGRA},
+  {TBM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_SR32},
+#else
+  {TBM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_BGRx},
+  {TBM_FORMAT_XBGR8888, GST_VIDEO_FORMAT_RGBx},
+  {TBM_FORMAT_RGBX8888, GST_VIDEO_FORMAT_xBGR},
+  {TBM_FORMAT_BGRX8888, GST_VIDEO_FORMAT_xRGB},
+  {TBM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_BGRA},
+  {TBM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_SR32},
+  {TBM_FORMAT_ABGR8888, GST_VIDEO_FORMAT_RGBA},
+  {TBM_FORMAT_RGBA8888, GST_VIDEO_FORMAT_ABGR},
+  {TBM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_ARGB},
+#endif
+  {TBM_FORMAT_RGB565, GST_VIDEO_FORMAT_RGB16},
+  {TBM_FORMAT_BGR565, GST_VIDEO_FORMAT_BGR16},
+  {TBM_FORMAT_RGB888, GST_VIDEO_FORMAT_RGB},
+  {TBM_FORMAT_BGR888, GST_VIDEO_FORMAT_BGR},
+  {TBM_FORMAT_YUYV, GST_VIDEO_FORMAT_YUY2},
+  {TBM_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU},
+  {TBM_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY},
+  {TBM_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV},
+  {TBM_FORMAT_NV12, GST_VIDEO_FORMAT_NV12},
+  {TBM_FORMAT_NV21, GST_VIDEO_FORMAT_NV21},
+  {TBM_FORMAT_NV16, GST_VIDEO_FORMAT_NV16},
+  {TBM_FORMAT_YUV410, GST_VIDEO_FORMAT_YUV9},
+  {TBM_FORMAT_YVU410, GST_VIDEO_FORMAT_YVU9},
+  {TBM_FORMAT_YUV411, GST_VIDEO_FORMAT_Y41B},
+  {TBM_FORMAT_YUV420, GST_VIDEO_FORMAT_I420},
+  {TBM_FORMAT_YVU420, GST_VIDEO_FORMAT_YV12},
+  {TBM_FORMAT_YUV422, GST_VIDEO_FORMAT_Y42B},
+  {TBM_FORMAT_YUV444, GST_VIDEO_FORMAT_v308},
+  {TBM_FORMAT_NV12MT, GST_VIDEO_FORMAT_ST12},
+  {TBM_FORMAT_NV12, GST_VIDEO_FORMAT_SN12},
+  {TBM_FORMAT_NV21, GST_VIDEO_FORMAT_SN21},
+  {TBM_FORMAT_YUV420, GST_VIDEO_FORMAT_S420}
+};
+
+uint32_t
+gst_video_format_to_wl_tbm_format (GstVideoFormat format)
+{
+  guint i;
+  for (i = 0; i < G_N_ELEMENTS (tbm_formats); i++)
+    if (tbm_formats[i].gst_format == format)
+      return tbm_formats[i].wl_format;
+  GST_WARNING ("wayland tbm video format not found");
+  return -1;
+}
+
+GstVideoFormat
+gst_wl_tbm_format_to_video_format (uint32_t wl_format)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (tbm_formats); i++)
+    if (tbm_formats[i].wl_format == wl_format)
+      return tbm_formats[i].gst_format;
+
+  GST_WARNING ("gst video format not found");
+  return GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+const gchar *
+gst_wl_tbm_format_to_string (uint32_t wl_format)
+{
+  return gst_video_format_to_string
+      (gst_wl_tbm_format_to_video_format (wl_format));
+}
+#endif
diff --git a/tizenwlsink/src/tizen-wlvideoformat.h b/tizenwlsink/src/tizen-wlvideoformat.h
new file mode 100755 (executable)
index 0000000..711c154
--- /dev/null
@@ -0,0 +1,41 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2012 Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GST_TIZEN_WL_VIDEO_FORMAT_H__
+#define __GST_TIZEN_WL_VIDEO_FORMAT_H__
+
+#include <wayland-client.h>
+#include <gst/video/video.h>
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+#include <tbm_surface.h>
+
+G_BEGIN_DECLS
+    uint32_t gst_video_format_to_wl_tbm_format (GstVideoFormat format);
+GstVideoFormat gst_wl_tbm_format_to_video_format (uint32_t wl_format);
+
+const gchar *gst_wl_tbm_format_to_string (uint32_t wl_format);
+
+G_END_DECLS
+#endif
+#endif
diff --git a/tizenwlsink/src/wlbuffer.c b/tizenwlsink/src/wlbuffer.c
new file mode 100644 (file)
index 0000000..c37e61e
--- /dev/null
@@ -0,0 +1,327 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+/* GstWlBuffer wraps wl_buffer and provides a mechanism for preventing
+ * buffers from being re-used while the compositor is using them. This
+ * is achieved by adding a reference to the GstBuffer as soon as its
+ * associated wl_buffer is sent to the compositor and by removing this
+ * reference as soon as the compositor sends a wl_buffer::release message.
+ *
+ * This mechanism is a bit complicated, though, because it adds cyclic
+ * references that can be dangerous. The reference cycles looks like:
+ *
+ *   ----------------
+ *   | GstWlDisplay | ---------------------------->
+ *   ----------------                              |
+ *                                                 |
+ *                                                 V
+ *   -----------------     -------------     ---------------
+ *   | GstBufferPool | --> | GstBuffer | ==> | GstWlBuffer |
+ *   |               | <-- |           | <-- |             |
+ *   -----------------     -------------     ---------------
+ *
+ * A GstBufferPool normally holds references to its GstBuffers and each buffer
+ * holds a reference to a GstWlBuffer (saved in the GstMiniObject qdata).
+ * When a GstBuffer is in use, it holds a reference back to the pool and the
+ * pool doesn't hold a reference to the GstBuffer. When the GstBuffer is unrefed
+ * externally, it returns back to the pool and the pool holds again a reference
+ * to the buffer.
+ *
+ * Now when the compositor is using a buffer, the GstWlBuffer also holds a ref
+ * to the GstBuffer, which prevents it from returning to the pool. When the
+ * last GstWlBuffer receives a release event and unrefs the last GstBuffer,
+ * the GstBufferPool will be able to stop and if no-one is holding a strong
+ * ref to it, it will be destroyed. This will destroy the pool's GstBuffers and
+ * also the GstWlBuffers. This will all happen in the same context of the last
+ * gst_buffer_unref, which will be called from the buffer_release() callback.
+ *
+ * The problem here lies in the fact that buffer_release() will be called
+ * from the event loop thread of GstWlDisplay, so it's as if the display
+ * holds a reference to the GstWlBuffer, but without having an actual reference.
+ * When we kill the display, there is no way for the GstWlBuffer, the associated
+ * GstBuffer and the GstBufferPool to get destroyed, so we are going to leak a
+ * fair ammount of memory.
+ *
+ * Normally, this rarely happens, because the compositor releases buffers
+ * almost immediately and when waylandsink stops, they are already released.
+ *
+ * However, we want to be absolutely certain, so a solution is introduced
+ * by registering all the GstWlBuffers with the display and explicitly
+ * releasing all the buffer references as soon as the display is destroyed.
+ *
+ * When the GstWlDisplay is finalized, it takes a reference to all the
+ * registered GstWlBuffers and then calls gst_wl_buffer_force_release_and_unref,
+ * which releases the potential reference to the GstBuffer, destroys the
+ * underlying wl_buffer and removes the reference that GstWlDisplay is holding.
+ * At that point, either the GstBuffer is alive somewhere and still holds a ref
+ * to the GstWlBuffer, which it will release when it gets destroyed, or the
+ * GstBuffer was destroyed in the meantime and the GstWlBuffer gets destroyed
+ * as soon as we remove the reference that GstWlDisplay holds.
+ */
+
+#include "wlbuffer.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
+#define GST_CAT_DEFAULT gstwayland_debug
+
+G_DEFINE_TYPE (GstWlBuffer, gst_wl_buffer, G_TYPE_OBJECT);
+
+static G_DEFINE_QUARK (GstWlBufferQDataQuark, gst_wl_buffer_qdata);
+
+static void
+gst_wl_buffer_dispose (GObject * gobject)
+{
+  GstWlBuffer *self = GST_WL_BUFFER (gobject);
+  FUNCTION;
+  GST_LOG ("GstWlBuffer:%p", self);
+  GST_TRACE_OBJECT (self, "dispose");
+
+  /* if the display is shutting down and we are trying to dipose
+   * the GstWlBuffer from another thread, unregister_buffer() will
+   * block and in the end the display will increase the refcount
+   * of this GstWlBuffer, so it will not be finalized */
+  if (self->display)
+    gst_wl_display_unregister_buffer (self->display, self);
+
+  G_OBJECT_CLASS (gst_wl_buffer_parent_class)->dispose (gobject);
+}
+
+static void
+gst_wl_buffer_finalize (GObject * gobject)
+{
+  GstWlBuffer *self = GST_WL_BUFFER (gobject);
+  int i;
+
+  FUNCTION;
+
+  GST_TRACE_OBJECT (self, "finalize");
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (self->tsurface) {
+    GST_LOG ("tbm_surface_destroy (tbm_surface_h@%p)", self->tsurface);
+    tbm_surface_destroy (self->tsurface);
+  }
+#endif
+  if (self->wlbuffer) {
+    GST_INFO ("wl_buffer_destroy (wl_buffer@%p)", self->wlbuffer);
+    wl_buffer_destroy (self->wlbuffer);
+  }
+#ifdef USE_WL_FLUSH_BUFFER
+  if (self->display) {
+    if (self->is_flush_request) {
+      self->display->flush_tbm_bufmgr = NULL;
+      if (self->display->flush_buffer) {
+        for (i = 0; i < self->display->tbm_bo_num; i++) {
+          if (self->display->flush_buffer->bo[i]) {
+            GST_LOG ("flush buffer: tbm_bo_unref (bo@%p)",
+                self->display->flush_buffer->bo[i]);
+            tbm_bo_unref (self->display->flush_buffer->bo[i]);
+            self->display->flush_buffer->bo[i] = NULL;
+          }
+        }
+        g_free (self->display->flush_buffer);
+        self->display->flush_buffer = NULL;
+      }
+    }
+  }
+#endif
+
+  G_OBJECT_CLASS (gst_wl_buffer_parent_class)->finalize (gobject);
+}
+
+static void
+gst_wl_buffer_class_init (GstWlBufferClass * klass)
+{
+  GObjectClass *object_class = (GObjectClass *) klass;
+  FUNCTION;
+  object_class->dispose = gst_wl_buffer_dispose;
+  object_class->finalize = gst_wl_buffer_finalize;
+}
+
+static void
+gst_wl_buffer_init (GstWlBuffer * self)
+{
+}
+
+static void
+buffer_release (void *data, struct wl_buffer *wl_buffer)
+{
+  GstWlBuffer *self = data;
+  FUNCTION;
+  g_return_if_fail (self != NULL);
+
+  GST_INFO_OBJECT (self,
+      "get event : wl_buffer@%p ::release GstBuffer@%p:: tsurface@%p",
+      wl_buffer, self->gstbuffer, self->tsurface);
+
+  self->used_by_compositor = FALSE;
+
+#ifdef USE_WL_FLUSH_BUFFER
+  /* unref should be last, because it may end up destroying the GstWlBuffer */
+  if (!self->is_flush_request) {
+    /*in case of is_flush_request, gstbuffer ref-count has already decreased. */
+    GST_LOG_OBJECT (self, "gstbuffer(%p), ref_count(%d)", self->gstbuffer,
+        GST_OBJECT_REFCOUNT_VALUE (self->gstbuffer));
+    gst_buffer_unref (self->gstbuffer);
+    if (self->gstbuffer) {
+      GST_LOG_OBJECT (self,
+          "buffer is our pool..so is kept by bufferpool :: gstbuffer(%p), ref_count(%d)",
+          self->gstbuffer, GST_OBJECT_REFCOUNT_VALUE (self->gstbuffer));
+    }
+  } else {
+    /*we blocked below code at gstbuffer_disposed() */
+    /* unref(GstWlBuffer), now gst_wl_buffer_dispose() will be called by below code */
+    g_object_unref (self);
+  }
+#else
+  gst_buffer_unref (self->gstbuffer);
+#endif
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+  buffer_release
+};
+
+static void
+gstbuffer_disposed (GstWlBuffer * self)
+{
+  FUNCTION;
+  g_assert (!self->used_by_compositor);
+  GST_INFO ("GstBuffer: %p", self->gstbuffer);
+  self->gstbuffer = NULL;
+
+  GST_TRACE_OBJECT (self, "owning GstBuffer was finalized");
+
+  /* this will normally destroy the GstWlBuffer, unless the display is
+   * finalizing and it has taken an additional reference to it */
+#ifdef USE_WL_FLUSH_BUFFER
+  /* in case of normal routine, gstbuffer_disposed() is called by buffer_release()
+     but in case of is_flush_request, this func() is called when basesink unref gstbuffer.
+     buffer_release() is not called  if we do 'g_object_unref (self)' */
+  if (!self->is_flush_request)
+#endif
+    g_object_unref (self);
+}
+
+GstWlBuffer *
+gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, struct wl_buffer *wlbuffer,
+    GstWlDisplay * display)
+{
+  GstWlBuffer *self;
+  FUNCTION;
+
+  self = g_object_new (GST_TYPE_WL_BUFFER, NULL);
+  self->gstbuffer = gstbuffer;
+  self->wlbuffer = wlbuffer;
+  self->display = display;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (display->tsurface)
+    self->tsurface = display->tsurface;
+  else
+    self->tsurface = NULL;
+  GST_LOG ("self->tsurface(%p)", self->tsurface);
+#endif
+#ifdef USE_WL_FLUSH_BUFFER
+  self->is_flush_request = FALSE;
+  if (display->flush_request)
+    self->is_flush_request = TRUE;
+#endif
+
+  gst_wl_display_register_buffer (self->display, self); //register GstWlBuffer
+
+  GST_INFO
+      ("wl_buffer_add_listener (wl_buffer@%p, wl_buffer_listener@%p, GstWlBuffer@%p)",
+      self->wlbuffer, &buffer_listener, self);
+  wl_buffer_add_listener (self->wlbuffer, &buffer_listener, self);
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT //need to contribute to upstream !!
+  wl_proxy_set_queue ((struct wl_proxy *) self->wlbuffer, self->display->queue);
+#endif
+  /* called gstbuffer_disposed when the gstbuffer is disposed,
+     or the same gstbuffer is being overwritten by below api */
+  gst_mini_object_set_qdata ((GstMiniObject *) gstbuffer,
+      gst_wl_buffer_qdata_quark (), self, (GDestroyNotify) gstbuffer_disposed);
+  GST_LOG ("GstWlBuffer (%p)", self);
+  return self;
+}
+
+GstWlBuffer *
+gst_buffer_get_wl_buffer (GstBuffer * gstbuffer)
+{
+  FUNCTION;
+  return gst_mini_object_get_qdata ((GstMiniObject *) gstbuffer,
+      gst_wl_buffer_qdata_quark ());
+}
+
+void
+gst_wl_buffer_force_release_and_unref (GstWlBuffer * self)
+{
+  FUNCTION;
+  /* Force a buffer release.
+   * At this point, the GstWlDisplay has killed its event loop,
+   * so we don't need to worry about buffer_release() being called
+   * at the same time from the event loop thread */
+  if (self->used_by_compositor) {
+    GST_DEBUG_OBJECT (self, "forcing wl_buffer::release (GstBuffer: %p)",
+        self->gstbuffer);
+    self->used_by_compositor = FALSE;
+    gst_buffer_unref (self->gstbuffer);
+  }
+
+  /* Finalize this GstWlBuffer early.
+   * This method has been called as a result of the display shutting down,
+   * so we need to stop using any wayland resources and disconnect from
+   * the display. The GstWlBuffer stays alive, though, to avoid race
+   * conditions with the GstBuffer being destroyed from another thread.
+   * The last reference is either owned by the GstBuffer or by us and
+   * it will be released at the end of this function. */
+  GST_TRACE_OBJECT (self, "finalizing early");
+  wl_buffer_destroy (self->wlbuffer);
+  self->wlbuffer = NULL;
+  self->display = NULL;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  GST_LOG ("self->tsurface(%p)", self->tsurface);
+  if (self->tsurface)
+    tbm_surface_destroy (self->tsurface);
+#endif
+  /* remove the reference that the caller (GstWlDisplay) owns */
+  g_object_unref (self);
+}
+
+void
+gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface)
+{
+  FUNCTION;
+  g_return_if_fail (self->used_by_compositor == FALSE);
+  GST_INFO ("wl_surface_attach (video_surface@%p, wl_buffer@%p, 0, 0)", surface,
+      self->wlbuffer);
+  wl_surface_attach (surface, self->wlbuffer, 0, 0);
+
+  /* Add a reference to the buffer. This represents the fact that
+   * the compositor is using the buffer and it should not return
+   * back to the pool and be re-used until the compositor releases it. */
+#ifdef USE_WL_FLUSH_BUFFER
+  /* in case of is_flush_request, we need to copy info and unref gstbuffer
+     so, we need not to increase ref count. */
+  if (!self->is_flush_request)
+#endif
+    gst_buffer_ref (self->gstbuffer);
+  GST_LOG_OBJECT (self, "gstbuffer(%p), ref_count(%d)", self->gstbuffer,
+      GST_OBJECT_REFCOUNT_VALUE (self->gstbuffer));
+  self->used_by_compositor = TRUE;
+}
diff --git a/tizenwlsink/src/wlbuffer.h b/tizenwlsink/src/wlbuffer.h
new file mode 100644 (file)
index 0000000..d9713eb
--- /dev/null
@@ -0,0 +1,69 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GST_WL_BUFFER_H__
+#define __GST_WL_BUFFER_H__
+
+#include "wldisplay.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_WL_BUFFER                  (gst_wl_buffer_get_type ())
+#define GST_WL_BUFFER(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_BUFFER, GstWlBuffer))
+#define GST_IS_WL_BUFFER(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_BUFFER))
+#define GST_WL_BUFFER_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_BUFFER, GstWlBufferClass))
+#define GST_IS_WL_BUFFER_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_BUFFER))
+#define GST_WL_BUFFER_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_BUFFER, GstWlBufferClass))
+typedef struct _GstWlBuffer GstWlBuffer;
+typedef struct _GstWlBufferClass GstWlBufferClass;
+
+struct _GstWlBuffer
+{
+  GObject parent_instance;
+
+  struct wl_buffer *wlbuffer;
+  GstBuffer *gstbuffer;
+
+  GstWlDisplay *display;
+
+  gboolean used_by_compositor;
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  gboolean is_flush_request;
+  tbm_surface_h tsurface;
+#endif
+};
+
+struct _GstWlBufferClass
+{
+  GObjectClass parent_class;
+};
+
+GType gst_wl_buffer_get_type (void);
+
+GstWlBuffer *gst_buffer_add_wl_buffer (GstBuffer * gstbuffer,
+    struct wl_buffer *wlbuffer, GstWlDisplay * display);
+GstWlBuffer *gst_buffer_get_wl_buffer (GstBuffer * gstbuffer);
+
+void gst_wl_buffer_force_release_and_unref (GstWlBuffer * self);
+
+void gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface);
+
+G_END_DECLS
+#endif /* __GST_WL_BUFFER_H__ */
diff --git a/tizenwlsink/src/wldisplay.c b/tizenwlsink/src/wldisplay.c
new file mode 100644 (file)
index 0000000..7e9e39e
--- /dev/null
@@ -0,0 +1,468 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "wldisplay.h"
+#include "wlbuffer.h"
+
+#include <errno.h>
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+#include <fcntl.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <string.h>
+#include <stdlib.h>
+
+#define TBM_BO_MAX_IDX 6
+
+static void
+handle_tizen_video_format (void *data, struct tizen_video *tizen_video,
+    uint32_t format)
+{
+  GstWlDisplay *self = data;
+  FUNCTION;
+
+  g_return_if_fail (self != NULL);
+
+  GST_LOG ("format is %d", format);
+  g_array_append_val (self->tbm_formats, format);
+}
+
+static const struct tizen_video_listener tizen_video_listener = {
+  handle_tizen_video_format
+};
+#endif
+
+GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
+#define GST_CAT_DEFAULT gstwayland_debug
+
+G_DEFINE_TYPE (GstWlDisplay, gst_wl_display, G_TYPE_OBJECT);
+
+static void gst_wl_display_finalize (GObject * gobject);
+
+static void
+gst_wl_display_class_init (GstWlDisplayClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  FUNCTION;
+  gobject_class->finalize = gst_wl_display_finalize;
+}
+
+static void
+gst_wl_display_init (GstWlDisplay * self)
+{
+  FUNCTION;
+  self->formats = g_array_new (FALSE, FALSE, sizeof (uint32_t));
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  self->tbm_formats = g_array_new (FALSE, FALSE, sizeof (uint32_t));
+#endif
+  self->wl_fd_poll = gst_poll_new (TRUE);
+  self->buffers = g_hash_table_new (g_direct_hash, g_direct_equal);
+  g_mutex_init (&self->buffers_mutex);
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  self->tbm_bo_idx = 0;
+  self->wl_surface_id = -1;
+  self->dump_count = 1;
+#endif
+}
+
+static void
+gst_wl_display_finalize (GObject * gobject)
+{
+  GstWlDisplay *self = GST_WL_DISPLAY (gobject);
+  FUNCTION;
+
+  gst_poll_set_flushing (self->wl_fd_poll, TRUE);
+  g_thread_join (self->thread);
+
+  /* to avoid buffers being unregistered from another thread
+   * at the same time, take their ownership */
+  g_mutex_lock (&self->buffers_mutex);
+  self->shutting_down = TRUE;
+  g_hash_table_foreach (self->buffers, (GHFunc) g_object_ref, NULL);
+  g_mutex_unlock (&self->buffers_mutex);
+
+  g_hash_table_foreach (self->buffers,
+      (GHFunc) gst_wl_buffer_force_release_and_unref, NULL);
+  g_hash_table_remove_all (self->buffers);
+
+  g_array_unref (self->formats);
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  g_array_unref (self->tbm_formats);
+#endif
+  gst_poll_free (self->wl_fd_poll);
+  g_hash_table_unref (self->buffers);
+  g_mutex_clear (&self->buffers_mutex);
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (self->USE_TBM) {
+    if (self->is_native_format == FALSE) {
+      /*in case of normal video format */
+      for (int i = 0; i < TBM_BO_NUM; i++) {
+        if (self->tbm_bo[i])
+          tbm_bo_unref (self->tbm_bo[i]);
+        self->tbm_bo[i] = NULL;
+      }
+    }
+    self->tbm_bufmgr = NULL;
+  }
+  if (self->tbm_client) {
+    wayland_tbm_client_deinit (self->tbm_client);
+    self->tbm_client = NULL;
+  }
+#endif
+  if (self->shm)
+    wl_shm_destroy (self->shm);
+
+  if (self->shell)
+    wl_shell_destroy (self->shell);
+
+  if (self->scaler)
+    wl_scaler_destroy (self->scaler);
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (self->tizen_policy)
+    tizen_policy_destroy (self->tizen_policy);
+
+  if (self->tizen_video)
+    tizen_video_destroy (self->tizen_video);
+#endif
+
+  if (self->compositor)
+    wl_compositor_destroy (self->compositor);
+
+  if (self->subcompositor)
+    wl_subcompositor_destroy (self->subcompositor);
+
+  if (self->registry)
+    wl_registry_destroy (self->registry);
+
+  if (self->queue)
+    wl_event_queue_destroy (self->queue);
+
+  if (self->own_display) {
+    wl_display_flush (self->display);
+    wl_display_disconnect (self->display);
+  }
+
+  G_OBJECT_CLASS (gst_wl_display_parent_class)->finalize (gobject);
+}
+
+static void
+sync_callback (void *data, struct wl_callback *callback, uint32_t serial)
+{
+  gboolean *done = data;
+  *done = TRUE;
+}
+
+static const struct wl_callback_listener sync_listener = {
+  sync_callback
+};
+
+static gint
+gst_wl_display_roundtrip (GstWlDisplay * self)
+{
+  struct wl_callback *callback;
+  gint ret = 0;
+  gboolean done = FALSE;
+  FUNCTION;
+
+  g_return_val_if_fail (self != NULL, -1);
+
+  /* We don't own the display, process only our queue */
+  callback = wl_display_sync (self->display);
+  GST_INFO ("wl_callback@%p = wl_display_sync (wl_display@%p)", callback,
+      self->display);
+  wl_callback_add_listener (callback, &sync_listener, &done);
+  GST_INFO
+      ("wl_callback_add_listener (wl_callback@%p, sync_listener@%p, done@%p)",
+      callback, &sync_listener, &done);
+  wl_proxy_set_queue ((struct wl_proxy *) callback, self->queue);
+  GST_INFO ("wl_proxy_set_queue (wl_callback@%p, wl_event_queue@%p)", callback,
+      self->queue);
+  while (ret != -1 && !done) {
+    ret = wl_display_dispatch_queue (self->display, self->queue);
+    GST_INFO
+        ("ret(%d) = wl_display_dispatch_queue (wl_display@%p, wl_event_queue@%p)",
+        ret, self->display, self->queue);
+  }
+  GST_INFO ("wl_callback_destroy (wl_callback@%p)", callback);
+  wl_callback_destroy (callback);
+
+  return ret;
+}
+
+static void
+shm_format (void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+  GstWlDisplay *self = data;
+
+  g_array_append_val (self->formats, format);
+}
+
+static const struct wl_shm_listener shm_listener = {
+  shm_format
+};
+
+static void
+registry_handle_global (void *data, struct wl_registry *registry,
+    uint32_t id, const char *interface, uint32_t version)
+{
+  GstWlDisplay *self = data;
+  FUNCTION;
+
+  if (g_strcmp0 (interface, "wl_compositor") == 0) {
+    self->compositor = wl_registry_bind (registry, id, &wl_compositor_interface,
+        MIN (version, 4));
+    GST_INFO
+        ("wl_compositor@%p = wl_registry_bind (wl_registry@%p, id@%d, wl_compositor_interface@%p, version@%d)",
+        self->compositor, registry, id, &wl_compositor_interface, MIN (version,
+            4));
+  } else if (g_strcmp0 (interface, "wl_subcompositor") == 0) {
+    self->subcompositor =
+        wl_registry_bind (registry, id, &wl_subcompositor_interface, 1);
+    GST_INFO
+        ("wl_subcompositor@%p = wl_registry_bind (wl_registry@%p, id@%d, wl_subcompositor_interface@%p, version@%d)",
+        self->subcompositor, registry, id, &wl_subcompositor_interface, 1);
+  } else if (g_strcmp0 (interface, "wl_shell") == 0) {
+    self->shell = wl_registry_bind (registry, id, &wl_shell_interface, 1);
+    GST_INFO
+        ("wl_shell@%p = wl_registry_bind (wl_registry@%p, id@%d, wl_shell_interface@%p, version@%d)",
+        self->shell, registry, id, &wl_shell_interface, 1);
+  } else if (g_strcmp0 (interface, "wl_shm") == 0) {
+    self->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1);
+    GST_INFO
+        ("wl_shm@%p = wl_registry_bind (wl_registry@%p, id@%d, wl_shm_interface@%p, version@%d)",
+        self->shm, registry, id, &wl_shm_interface, 1);
+    GST_INFO
+        ("wl_shm_add_listener (wl_shm@%p, wl_shm_listener@%p, GstWlDisplay@%p)",
+        self->shm, &shm_listener, self);
+    wl_shm_add_listener (self->shm, &shm_listener, self);
+
+
+  } else if (g_strcmp0 (interface, "wl_scaler") == 0) {
+    self->scaler = wl_registry_bind (registry, id, &wl_scaler_interface, 2);
+    GST_INFO
+        ("wl_scaler@%p = wl_registry_bind (wl_registry@%p, id@%d, wl_scaler_interface@%p, version@%d)",
+        self->scaler, registry, id, &wl_scaler_interface, 2);
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  } else if (g_strcmp0 (interface, "tizen_policy") == 0) {
+    self->tizen_policy =
+        wl_registry_bind (registry, id, &tizen_policy_interface, 7);
+    GST_INFO
+        ("tizen_policy@%p = wl_registry_bind (wl_registry@%p, id@%d, tizen_policy_interface@%p, version@%d)",
+        self->tizen_policy, registry, id, &tizen_policy_interface, 7);
+  } else if (g_strcmp0 (interface, "tizen_video") == 0) {
+    self->tizen_video =
+        wl_registry_bind (registry, id, &tizen_video_interface, version);
+    g_return_if_fail (self->tizen_video != NULL);
+    GST_INFO
+        ("tizen_video@%p = wl_registry_bind (wl_registry@%p, id@%d, tizen_video_interface@%p, version@%d)",
+        self->tizen_video, registry, id, &tizen_video_interface, version);
+
+    GST_INFO
+        ("tizen_video_add_listener (tizen_video@%p, tizen_video_listener@%p, GstWlDisplay@%p)",
+        self->tizen_video, &tizen_video_listener, self);
+    tizen_video_add_listener (self->tizen_video, &tizen_video_listener, self);
+#endif
+  }
+}
+
+static const struct wl_registry_listener registry_listener = {
+  registry_handle_global
+};
+
+static gpointer
+gst_wl_display_thread_run (gpointer data)
+{
+  GstWlDisplay *self = data;
+  GstPollFD pollfd = GST_POLL_FD_INIT;
+  FUNCTION;
+
+  pollfd.fd = wl_display_get_fd (self->display);
+  gst_poll_add_fd (self->wl_fd_poll, &pollfd);
+  gst_poll_fd_ctl_read (self->wl_fd_poll, &pollfd, TRUE);
+
+  /* main loop */
+  while (1) {
+    GST_INFO
+        ("while (wl_display_prepare_read_queue (display@%p, queue@%p != 0)",
+        self->display, self->queue);
+    while (wl_display_prepare_read_queue (self->display, self->queue) != 0) {
+      GST_INFO ("wl_display_dispatch_queue_pending (display@%p, queue@%p)",
+          self->display, self->queue);
+      wl_display_dispatch_queue_pending (self->display, self->queue);
+    }
+    GST_INFO ("wl_display_flush (display@%p)", self->display);
+    wl_display_flush (self->display);
+
+    if (gst_poll_wait (self->wl_fd_poll, GST_CLOCK_TIME_NONE) < 0) {
+      gboolean normal = (errno == EBUSY);
+      GST_INFO ("wl_display_cancel_read (display@%p)", self->display);
+      wl_display_cancel_read (self->display);
+      if (normal)
+        break;
+      else
+        goto error;
+    } else {
+      GST_INFO ("wl_display_read_events (display@%p)", self->display);
+      wl_display_read_events (self->display);
+      GST_INFO ("wl_display_dispatch_queue_pending (display@%p, queue@%p)",
+          self->display, self->queue);
+      wl_display_dispatch_queue_pending (self->display, self->queue);
+    }
+  }
+
+  return NULL;
+
+error:
+  GST_ERROR ("Error communicating with the wayland server");
+  return NULL;
+}
+
+GstWlDisplay *
+gst_wl_display_new (const gchar * name, GError ** error)
+{
+  struct wl_display *display;
+  FUNCTION;
+
+  display = wl_display_connect (name);
+  GST_INFO ("wl_display@%p = wl_display_connect (name@%p)", display, name);
+  if (!display) {
+    *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0,
+        "Failed to connect to the wayland display '%s'",
+        name ? name : "(default)");
+    return NULL;
+  } else {
+    return gst_wl_display_new_existing (display, TRUE, error);
+  }
+}
+
+GstWlDisplay *
+gst_wl_display_new_existing (struct wl_display * display,
+    gboolean take_ownership, GError ** error)
+{
+  GstWlDisplay *self;
+  GError *err = NULL;
+  gint i;
+  FUNCTION;
+
+  g_return_val_if_fail (display != NULL, NULL);
+
+  self = g_object_new (GST_TYPE_WL_DISPLAY, NULL);
+  self->display = display;
+  self->own_display = take_ownership;
+
+  self->queue = wl_display_create_queue (self->display);
+  GST_INFO ("wl_event_queue@%p = wl_display_create_queue (wl_display@%p)",
+      self->queue, self->display);
+  self->registry = wl_display_get_registry (self->display);
+  GST_INFO ("wl_registry@%p = wl_display_get_registry (wl_display@%p)",
+      self->registry, self->display);
+  wl_proxy_set_queue ((struct wl_proxy *) self->registry, self->queue);
+  GST_INFO ("wl_proxy_set_queue (wl_registry@%p, wl_event_queue@%p)",
+      self->registry, self->queue);
+  wl_registry_add_listener (self->registry, &registry_listener, self);
+  GST_INFO
+      ("wl_registry_add_listener (wl_registry@%p, wl_registry_listener@%p, GstWlDisplay@%p)",
+      self->registry, &registry_listener, self);
+
+  /* we need exactly 2 roundtrips to discover global objects and their state */
+  for (i = 0; i < 2; i++) {
+    if (gst_wl_display_roundtrip (self) < 0) {
+      *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0,
+          "Error communicating with the wayland display");
+      g_object_unref (self);
+      return NULL;
+    }
+  }
+
+  /* verify we got all the required interfaces */
+#define VERIFY_INTERFACE_EXISTS(var, interface) \
+  if (!self->var) { \
+    g_set_error (error, g_quark_from_static_string ("GstWlDisplay"), 0, \
+        "Could not bind to " interface ". Either it is not implemented in " \
+        "the compositor, or the implemented version doesn't match"); \
+    g_object_unref (self); \
+    return NULL; \
+  }
+
+  VERIFY_INTERFACE_EXISTS (compositor, "wl_compositor");
+  VERIFY_INTERFACE_EXISTS (subcompositor, "wl_subcompositor");
+  VERIFY_INTERFACE_EXISTS (shell, "wl_shell");
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  VERIFY_INTERFACE_EXISTS (tizen_video, "tizen_video");
+
+  self->tbm_client = wayland_tbm_client_init (self->display);
+  GST_INFO ("tbm_client@%p = wayland_tbm_client_init (wl_display@%p)",
+      self->tbm_client, self->display);
+
+  if (!self->tbm_client) {
+    *error = g_error_new (g_quark_from_static_string ("GstWlDisplay"), 0,
+        "Error initializing wayland-tbm");
+    g_object_unref (self);
+    return NULL;
+  }
+  GST_LOG ("tbm_client(%p)", self->tbm_client);
+#endif
+  VERIFY_INTERFACE_EXISTS (shm, "wl_shm");
+  VERIFY_INTERFACE_EXISTS (scaler, "wl_scaler");
+
+#undef VERIFY_INTERFACE_EXISTS
+
+  self->thread = g_thread_try_new ("GstWlDisplay", gst_wl_display_thread_run,
+      self, &err);
+  if (err) {
+    g_propagate_prefixed_error (error, err,
+        "Failed to start thread for the display's events");
+    g_object_unref (self);
+    return NULL;
+  }
+
+  return self;
+}
+
+void
+gst_wl_display_register_buffer (GstWlDisplay * self, gpointer buf)
+{
+  FUNCTION;
+  g_assert (!self->shutting_down);
+
+  GST_TRACE_OBJECT (self, "registering GstWlBuffer %p", buf);
+
+  g_mutex_lock (&self->buffers_mutex);
+  g_hash_table_add (self->buffers, buf);
+  g_mutex_unlock (&self->buffers_mutex);
+}
+
+void
+gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer buf)
+{
+  FUNCTION;
+  GST_TRACE_OBJECT (self, "unregistering GstWlBuffer %p", buf);
+
+  g_mutex_lock (&self->buffers_mutex);
+  if (G_LIKELY (!self->shutting_down))
+    g_hash_table_remove (self->buffers, buf);
+  g_mutex_unlock (&self->buffers_mutex);
+}
diff --git a/tizenwlsink/src/wldisplay.h b/tizenwlsink/src/wldisplay.h
new file mode 100644 (file)
index 0000000..c3e4481
--- /dev/null
@@ -0,0 +1,141 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GST_WL_DISPLAY_H__
+#define __GST_WL_DISPLAY_H__
+
+#include <gst/gst.h>
+#include <wayland-client.h>
+#include "scaler-client-protocol.h"
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+#include <gst/video/video.h>
+#include <tbm_bufmgr.h>
+#include <wayland-tbm-client.h>
+#include <tizen-extension-client-protocol.h>
+#define USE_WL_FLUSH_BUFFER
+#endif
+
+G_BEGIN_DECLS
+#define GST_TYPE_WL_DISPLAY                  (gst_wl_display_get_type ())
+#define GST_WL_DISPLAY(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_DISPLAY, GstWlDisplay))
+#define GST_IS_WL_DISPLAY(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_DISPLAY))
+#define GST_WL_DISPLAY_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_DISPLAY, GstWlDisplayClass))
+#define GST_IS_WL_DISPLAY_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_DISPLAY))
+#define GST_WL_DISPLAY_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_DISPLAY, GstWlDisplayClass))
+#define FUNCTION GST_LOG ("<ENTER>")
+
+#ifdef USE_WL_FLUSH_BUFFER
+typedef struct
+{
+  void *bo[GST_VIDEO_MAX_PLANES];
+} GstWlFlushBuffer;
+#endif
+
+#define TBM_BO_NUM 20
+
+struct _GstWlDisplay
+{
+  GObject parent_instance;
+
+  /* public objects */
+  struct wl_display *display;
+  struct wl_event_queue *queue;
+
+  /* globals */
+  struct wl_registry *registry;
+  struct wl_compositor *compositor;
+  struct wl_subcompositor *subcompositor;
+  struct wl_shell *shell;
+  struct wl_shm *shm;
+  struct wl_scaler *scaler;
+  GArray *formats;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  GArray *tbm_formats;
+#endif
+  /* private */
+  gboolean own_display;
+  GThread *thread;
+  GstPoll *wl_fd_poll;
+
+  GMutex buffers_mutex;
+  GHashTable *buffers;
+  gboolean shutting_down;
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  /*video output layer */
+  struct tizen_policy *tizen_policy;
+  struct tizen_video *tizen_video;
+
+  struct wayland_tbm_client *tbm_client;
+  tbm_bufmgr tbm_bufmgr;
+  tbm_bo tbm_bo[TBM_BO_NUM];
+  gint tbm_bo_idx;
+  tbm_surface_h tsurface;
+  gboolean USE_TBM;
+
+#ifdef USE_WL_FLUSH_BUFFER
+  GstWlFlushBuffer *flush_buffer;
+  tbm_bufmgr flush_tbm_bufmgr;
+  gint flush_request;
+#endif
+  gboolean dump_video;
+  guint total_dump;
+  guint dump_count;
+
+  gboolean is_native_format;    /*SN12, ST12, SR32, S420 */
+  gpointer bo[GST_VIDEO_MAX_PLANES];
+  gint plane_size[GST_VIDEO_MAX_PLANES];
+  gint stride_width[GST_VIDEO_MAX_PLANES];
+  gint stride_height[GST_VIDEO_MAX_PLANES];
+  gint width[GST_VIDEO_MAX_PLANES];
+  gint height[GST_VIDEO_MAX_PLANES];
+  gint native_video_size;
+  guint wl_surface_id;
+  gint buffer_width, buffer_height;
+  gint plane_num;
+  gint tbm_bo_num;
+#endif
+
+#if 1
+  gboolean need_shell_surface;
+  gboolean use_parent_wl_surface;
+#endif
+};
+
+struct _GstWlDisplayClass
+{
+  GObjectClass parent_class;
+};
+
+typedef struct _GstWlDisplay GstWlDisplay;
+typedef struct _GstWlDisplayClass GstWlDisplayClass;
+
+GType gst_wl_display_get_type (void);
+
+GstWlDisplay *gst_wl_display_new (const gchar * name, GError ** error);
+GstWlDisplay *gst_wl_display_new_existing (struct wl_display *display,
+    gboolean take_ownership, GError ** error);
+
+/* see wlbuffer.c for explanation */
+void gst_wl_display_register_buffer (GstWlDisplay * self, gpointer buf);
+void gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer buf);
+
+G_END_DECLS
+#endif /* __GST_WL_DISPLAY_H__ */
diff --git a/tizenwlsink/src/wlshmallocator.c b/tizenwlsink/src/wlshmallocator.c
new file mode 100644 (file)
index 0000000..81e2cfd
--- /dev/null
@@ -0,0 +1,545 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "wlshmallocator.h"
+#include "wlvideoformat.h"
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+#include "tizen-wlvideoformat.h"
+#include <tbm_surface_internal.h>
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
+#define GST_CAT_DEFAULT gstwayland_debug
+
+G_DEFINE_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST_TYPE_ALLOCATOR);
+
+gint
+gst_wl_fwrite_data (gchar * file, gpointer data, guint size)
+{
+  FILE *fp;
+
+  fp = fopen (file, "wb");
+  if (fp == NULL)
+    return -1;
+
+  fwrite ((gchar *) data, sizeof (gchar), size, fp);
+  fclose (fp);
+
+  return 0;
+}
+
+static void
+gst_wl_tbm_dump_normal_raw_video (gpointer bo, guint size, guint dump_count,
+    guint dump_total)
+{
+  tbm_bo_handle virtual_addr;
+  gint ret;
+  gchar file_name[128];
+  gchar err_str[256];
+  g_return_if_fail (bo != NULL);
+
+  virtual_addr = tbm_bo_get_handle (bo, TBM_DEVICE_CPU);
+  if (!virtual_addr.ptr) {
+    strerror_r (errno, err_str, sizeof (err_str));
+    GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno);
+    return;
+  }
+
+  snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump",
+      dump_count);
+  ret = gst_wl_fwrite_data (file_name, virtual_addr.ptr, size);
+  if (ret) {
+    GST_ERROR ("_write_rawdata() failed");
+  }
+
+}
+
+static void
+gst_wl_tbm_dump_native_raw_video (GstWlDisplay * display, guint dump_count)
+{
+  gchar file_name[128];
+  gchar err_str[256];
+  FILE *fp;
+  tbm_bo_handle virtual_addr;
+  gchar *data;
+  int i;
+  g_return_if_fail (display != NULL);
+
+  if (dump_count > display->total_dump) {
+    display->dump_video = FALSE;
+    return;
+  }
+  /* get virtual addr with bo and TBM_DEVICD_CPU */
+  virtual_addr = tbm_bo_get_handle (display->bo[0], TBM_DEVICE_CPU);
+  if (!virtual_addr.ptr) {
+    strerror_r (errno, err_str, sizeof (err_str));
+    GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno);
+    return;
+  }
+
+  snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump",
+      dump_count);
+
+  fp = fopen (file_name, "wb");
+  if (fp == NULL)
+    return;
+  data = (gchar *) virtual_addr.ptr;
+
+  /* Y */
+  for (i = 0; i < display->height[0]; i++) {
+    fwrite (data, display->width[0], 1, fp);
+    data += display->stride_width[0];
+  }
+
+  if (display->bo[1] == NULL) {
+    /* sprd */
+    data = (gchar *) virtual_addr.ptr +
+        (display->stride_width[0] * display->stride_height[0]);
+    GST_LOG ("UV: virtual_addr.ptr(%p)", data);
+  } else {
+    /* omx */
+    virtual_addr = tbm_bo_get_handle (display->bo[1], TBM_DEVICE_CPU);
+    if (!virtual_addr.ptr) {
+      strerror_r (errno, err_str, sizeof (err_str));
+      GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno);
+      fclose (fp);
+      return;
+    }
+    data = (gchar *) virtual_addr.ptr;
+  }
+
+  /* UV */
+  for (i = 0; i < display->height[1]; i++) {
+    fwrite (data, display->width[1], 1, fp);
+    data += display->stride_width[1];
+  }
+
+  fclose (fp);
+}
+
+static GstMemory *
+gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size,
+    GstAllocationParams * params)
+{
+  GstWlShmAllocator *self = GST_WL_SHM_ALLOCATOR (allocator);
+  char filename[1024];
+  static int init = 0;
+  int fd;
+  int idx;
+  gpointer data;
+  GstWlShmMemory *mem;
+  gchar err_str[256];
+  FUNCTION;
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (self->display->USE_TBM) {
+    tbm_bo_handle virtual_addr;
+
+    idx = self->display->tbm_bo_idx++;
+
+    self->display->tbm_bufmgr =
+        wayland_tbm_client_get_bufmgr (self->display->tbm_client);
+    g_return_val_if_fail (self->display->tbm_bufmgr != NULL, NULL);
+
+    self->display->tbm_bo[idx] =
+        tbm_bo_alloc (self->display->tbm_bufmgr, size, TBM_BO_DEFAULT);
+    if (G_UNLIKELY (!self->display->tbm_bo[idx])) {
+      strerror_r (errno, err_str, sizeof (err_str));
+      GST_ERROR_OBJECT (self, "alloc tbm bo(size:%d) failed: %s(%d)", size,
+          err_str, errno);
+      return FALSE;
+    }
+    GST_LOG ("display->tbm_bo[%d]=(%p)", idx, self->display->tbm_bo[idx]);
+    virtual_addr.ptr = NULL;
+    virtual_addr =
+        tbm_bo_get_handle (self->display->tbm_bo[idx], TBM_DEVICE_CPU);
+    if (G_UNLIKELY (!virtual_addr.ptr)) {
+      strerror_r (errno, err_str, sizeof (err_str));
+      GST_ERROR_OBJECT (self, "get tbm bo handle failed: %s(%d)", err_str,
+          errno);
+      tbm_bo_unref (self->display->tbm_bo[idx]);
+      self->display->tbm_bo[idx] = NULL;
+      self->display->tbm_bo_idx--;
+      return FALSE;
+    }
+
+    mem = g_slice_new0 (GstWlShmMemory);
+    gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator,
+        NULL, size, 0, 0, size);
+    mem->data = virtual_addr.ptr;
+    mem->tbm_bo_ptr = self->display->tbm_bo[idx];
+    GST_LOG ("mem(%p) mem->data(%p) virtual_addr.ptr(%p) size(%d)", mem,
+        mem->data, virtual_addr.ptr, size);
+
+    return (GstMemory *) mem;
+
+  } else {                      /* USE SHM */
+    /* TODO: make use of the allocation params, if necessary */
+
+    /* allocate shm pool */
+    snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
+        "wayland-shm", init++, "XXXXXX");
+    GST_LOG ("opening temp file %s", filename);
+
+    fd = g_mkstemp (filename);
+    if (fd < 0) {
+      GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename,
+          strerror (errno));
+      return NULL;
+    }
+    if (ftruncate (fd, size) < 0) {
+      GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno));
+      close (fd);
+      return NULL;
+    }
+
+    data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+    if (data == MAP_FAILED) {
+      GST_ERROR_OBJECT (self, "mmap failed: %s", strerror (errno));
+      close (fd);
+      return NULL;
+    }
+
+    unlink (filename);
+
+    mem = g_slice_new0 (GstWlShmMemory);
+    gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator,
+        NULL, size, 0, 0, size);
+    mem->data = data;
+    mem->fd = fd;
+
+    return (GstMemory *) mem;
+  }
+
+#else /* open source */
+  /* TODO: make use of the allocation params, if necessary */
+
+  /* allocate shm pool */
+  snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
+      "wayland-shm", init++, "XXXXXX");
+
+  fd = g_mkstemp (filename);
+  if (fd < 0) {
+    GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename,
+        strerror (errno));
+    return NULL;
+  }
+  if (ftruncate (fd, size) < 0) {
+    GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno));
+    close (fd);
+    return NULL;
+  }
+
+  data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (data == MAP_FAILED) {
+    GST_ERROR_OBJECT (self, "mmap failed: %s", strerror (errno));
+    close (fd);
+    return NULL;
+  }
+
+  unlink (filename);
+
+  mem = g_slice_new0 (GstWlShmMemory);
+  gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL,
+      size, 0, 0, size);
+  mem->data = data;
+  mem->fd = fd;
+
+  return (GstMemory *) mem;
+#endif
+}
+
+static void
+gst_wl_shm_allocator_free (GstAllocator * allocator, GstMemory * memory)
+{
+  GstWlShmMemory *shm_mem = (GstWlShmMemory *) memory;
+  FUNCTION;
+  GST_LOG ("shm_mem->fd(%d)", shm_mem->fd);
+  if (shm_mem->fd != -1)
+    close (shm_mem->fd);
+  munmap (shm_mem->data, memory->maxsize);
+
+  g_slice_free (GstWlShmMemory, shm_mem);
+}
+
+static gpointer
+gst_wl_shm_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags)
+{
+  FUNCTION;
+  return ((GstWlShmMemory *) mem)->data;
+}
+
+static void
+gst_wl_shm_mem_unmap (GstMemory * mem)
+{
+}
+
+static void
+gst_wl_shm_allocator_class_init (GstWlShmAllocatorClass * klass)
+{
+  GstAllocatorClass *alloc_class = (GstAllocatorClass *) klass;
+  FUNCTION;
+
+  alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_alloc);
+  alloc_class->free = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_free);
+}
+
+static void
+gst_wl_shm_allocator_init (GstWlShmAllocator * self)
+{
+  FUNCTION;
+  self->parent_instance.mem_type = GST_ALLOCATOR_WL_SHM;
+  self->parent_instance.mem_map = gst_wl_shm_mem_map;
+  self->parent_instance.mem_unmap = gst_wl_shm_mem_unmap;
+
+  GST_OBJECT_FLAG_SET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC);
+}
+
+void
+gst_wl_shm_allocator_register (void)
+{
+  FUNCTION;
+  gst_allocator_register (GST_ALLOCATOR_WL_SHM,
+      g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL));
+}
+
+GstAllocator *
+gst_wl_shm_allocator_get (void)
+{
+  FUNCTION;
+  return gst_allocator_find (GST_ALLOCATOR_WL_SHM);
+}
+
+gboolean
+gst_is_wl_shm_memory (GstMemory * mem)
+{
+  FUNCTION;
+  return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM);
+}
+
+gboolean
+gst_is_wl_memory (GstMemory * mem)
+{
+  FUNCTION;
+  return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM);
+}
+
+struct wl_buffer *
+gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
+    const GstVideoInfo * info)
+{
+  GstWlShmMemory *shm_mem = (GstWlShmMemory *) mem;
+  gint width, height, stride;
+  gsize size;
+  gint plane_size[GST_VIDEO_MAX_PLANES], n_planes, i;
+  enum wl_shm_format format;
+  struct wl_shm_pool *wl_pool;
+  struct wl_buffer *wbuffer;
+  FUNCTION;
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (display->USE_TBM) {
+    tbm_surface_info_s ts_info;
+    int offset[GST_VIDEO_MAX_PLANES];
+
+    if (display->is_native_format == TRUE) {
+      /* In case of native format, use MMVideoBuffer data instead of GstVideoInfo */
+      if (display->dump_video)
+        gst_wl_tbm_dump_native_raw_video (display, display->dump_count++);
+
+      width = display->width[0];
+      height = display->height[0];
+      format = gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (info));
+      ts_info.width = width;
+      ts_info.height = height;
+      ts_info.format = format;
+      ts_info.bpp = tbm_surface_internal_get_bpp (ts_info.format);
+      ts_info.num_planes = tbm_surface_internal_get_num_planes (ts_info.format);
+
+      for (i = 0; i < display->plane_num; i++) {
+        ts_info.planes[i].size = display->plane_size[i];
+        ts_info.planes[i].stride = display->stride_width[i];
+        offset[i] = display->stride_width[i] * display->stride_height[i];
+      }
+
+      if (display->tbm_bo_num == 1) {
+        ts_info.planes[0].offset = 0;
+        ts_info.planes[1].offset = offset[0];
+        if (display->plane_num == 3)
+          ts_info.planes[2].offset = offset[0] + offset[1];
+      } else if (display->tbm_bo_num == 2) {
+        ts_info.planes[0].offset = 0;
+        ts_info.planes[1].offset = 0;
+        if (display->plane_num == 3)
+          ts_info.planes[2].offset = offset[1];
+      } else if (display->tbm_bo_num == 3) {
+        ts_info.planes[0].offset = 0;
+        ts_info.planes[1].offset = 0;
+        ts_info.planes[2].offset = 0;
+      }
+
+      GST_LOG
+          ("set tbm_surface_info_s: width(%d) height(%d) format(%s) bpp(%d) num_planes(%d)",
+          ts_info.width, ts_info.height, gst_wl_tbm_format_to_string (format),
+          ts_info.bpp, ts_info.num_planes);
+      GST_LOG
+          ("set tbm_surface_info_s: planse[0].stride(%d) planes[1].stride(%d) planes[2].stride(%d) planes[0].offset(%d) planes[1].offset(%d) planes[2].offset(%d)",
+          ts_info.planes[0].stride, ts_info.planes[1].stride,
+          ts_info.planes[2].stride, ts_info.planes[0].offset,
+          ts_info.planes[1].offset, ts_info.planes[2].offset);
+
+      display->tsurface =
+          tbm_surface_internal_create_with_bos (&ts_info,
+          (tbm_bo *) display->bo, display->tbm_bo_num);
+      GST_LOG ("create tbm surface(%p)", display->tsurface);
+      wbuffer =
+          wayland_tbm_client_create_buffer (display->tbm_client,
+          display->tsurface);
+    } else {
+
+      width = GST_VIDEO_INFO_WIDTH (info);
+      height = GST_VIDEO_INFO_HEIGHT (info);
+      stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
+      size = GST_VIDEO_INFO_SIZE (info);
+
+      format = gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (info));
+      g_return_val_if_fail (gst_is_wl_memory (mem), NULL);
+      g_return_val_if_fail (size <= mem->size, NULL);
+      g_return_val_if_fail (shm_mem->fd != -1, NULL);
+
+      GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
+          G_GSSIZE_FORMAT " (%d x %d, stride %d)", size, width, height, stride);
+
+      if (display->dump_video) {
+        gst_wl_tbm_dump_normal_raw_video (shm_mem->tbm_bo_ptr, size,
+            display->dump_count++, display->total_dump);
+        if (display->dump_count > display->total_dump)
+          display->dump_video = FALSE;
+      }
+
+      n_planes = GST_VIDEO_INFO_N_PLANES (info);
+      switch (n_planes) {
+        case 1:
+          plane_size[0] = info->size;
+          break;
+        case 2:
+          plane_size[0] = GST_VIDEO_INFO_PLANE_OFFSET (info, 1);
+          plane_size[1] = info->size - plane_size[0];
+          break;
+        case 3:
+          plane_size[0] = GST_VIDEO_INFO_PLANE_OFFSET (info, 1);
+          plane_size[1] = GST_VIDEO_INFO_PLANE_OFFSET (info, 2) - plane_size[0];
+          plane_size[2] = info->size - GST_VIDEO_INFO_PLANE_OFFSET (info, 2);
+          break;
+        case 4:
+          plane_size[0] = GST_VIDEO_INFO_PLANE_OFFSET (info, 1);
+          plane_size[1] = GST_VIDEO_INFO_PLANE_OFFSET (info, 2) - plane_size[0];
+          plane_size[2] = GST_VIDEO_INFO_PLANE_OFFSET (info, 3)
+              - GST_VIDEO_INFO_PLANE_OFFSET (info, 2);
+          plane_size[3] = info->size - GST_VIDEO_INFO_PLANE_OFFSET (info, 3);
+          break;
+
+        default:
+          break;
+      }
+
+      ts_info.width = width;
+      ts_info.height = height;
+      ts_info.format = format;
+      ts_info.bpp = tbm_surface_internal_get_bpp (ts_info.format);
+      ts_info.num_planes = tbm_surface_internal_get_num_planes (ts_info.format);
+
+      for (i = 0; i < n_planes; i++) {
+        ts_info.planes[i].stride = GST_VIDEO_INFO_PLANE_STRIDE (info, i);
+        ts_info.planes[i].offset = GST_VIDEO_INFO_PLANE_OFFSET (info, i);
+        ts_info.planes[i].size = plane_size[i];
+      }
+
+      GST_LOG ("tbm_bo (%p)", shm_mem->tbm_bo_ptr);
+
+      display->tsurface =
+          tbm_surface_internal_create_with_bos (&ts_info,
+          (tbm_bo *) & shm_mem->tbm_bo_ptr, 1);
+      wbuffer =
+          wayland_tbm_client_create_buffer (display->tbm_client,
+          display->tsurface);
+    }
+    GST_LOG ("create wbuffer(%p)", wbuffer);
+
+  } else {                      /* USE SHM */
+    width = GST_VIDEO_INFO_WIDTH (info);
+    height = GST_VIDEO_INFO_HEIGHT (info);
+    stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
+    size = GST_VIDEO_INFO_SIZE (info);
+    format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));
+    g_return_val_if_fail (gst_is_wl_memory (mem), NULL);
+    g_return_val_if_fail (size <= mem->size, NULL);
+    g_return_val_if_fail (shm_mem->fd != -1, NULL);
+
+    GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
+        G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
+        stride, gst_wl_shm_format_to_string (format));
+
+    wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size);
+    wbuffer =
+        wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride, format);
+
+    wl_shm_pool_destroy (wl_pool);
+  }
+  display->buffer_width = width;
+  display->buffer_height = height;
+  GST_LOG ("buffer_width(%d) buffer_height(%d)", display->buffer_width,
+      display->buffer_height);
+  return wbuffer;
+
+#else /* open source */
+  width = GST_VIDEO_INFO_WIDTH (info);
+  height = GST_VIDEO_INFO_HEIGHT (info);
+  stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
+  size = GST_VIDEO_INFO_SIZE (info);
+  format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));
+  g_return_val_if_fail (gst_is_wl_shm_memory (mem), NULL);
+  g_return_val_if_fail (size <= mem->size, NULL);
+  g_return_val_if_fail (shm_mem->fd != -1, NULL);
+
+  GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
+      G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
+      stride, gst_wl_shm_format_to_string (format));
+
+  wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size);
+  wbuffer = wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride,
+      format);
+
+  close (shm_mem->fd);
+  shm_mem->fd = -1;
+  wl_shm_pool_destroy (wl_pool);
+
+  return wbuffer;
+#endif
+}
diff --git a/tizenwlsink/src/wlshmallocator.h b/tizenwlsink/src/wlshmallocator.h
new file mode 100644 (file)
index 0000000..9f111d3
--- /dev/null
@@ -0,0 +1,79 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2012 Intel Corporation
+ * Copyright (C) 2012 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#ifndef __GST_WL_SHM_ALLOCATOR_H__
+#define __GST_WL_SHM_ALLOCATOR_H__
+
+#include <wayland-client-protocol.h>
+#include "wldisplay.h"
+
+G_BEGIN_DECLS
+#define GST_TYPE_WL_SHM_ALLOCATOR                  (gst_wl_shm_allocator_get_type ())
+#define GST_WL_SHM_ALLOCATOR(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocator))
+#define GST_IS_WL_SHM_ALLOCATOR(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_SHM_ALLOCATOR))
+#define GST_WL_SHM_ALLOCATOR_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass))
+#define GST_IS_WL_SHM_ALLOCATOR_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_SHM_ALLOCATOR))
+#define GST_WL_SHM_ALLOCATOR_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass))
+#define GST_ALLOCATOR_WL_SHM "wl_shm"
+typedef struct _GstWlShmMemory GstWlShmMemory;
+typedef struct _GstWlShmAllocator GstWlShmAllocator;
+typedef struct _GstWlShmAllocatorClass GstWlShmAllocatorClass;
+
+struct _GstWlShmMemory
+{
+  GstMemory parent;
+
+  gpointer data;
+  gint fd;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  gpointer tbm_bo_ptr;
+#endif
+};
+
+struct _GstWlShmAllocator
+{
+  GstAllocator parent_instance;
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  GstWlDisplay *display;
+#endif
+};
+
+struct _GstWlShmAllocatorClass
+{
+  GstAllocatorClass parent_class;
+};
+
+GType gst_wl_shm_allocator_get_type (void);
+
+void gst_wl_shm_allocator_register (void);
+GstAllocator *gst_wl_shm_allocator_get (void);
+
+gboolean gst_is_wl_shm_memory (GstMemory * mem);
+struct wl_buffer *gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem,
+    GstWlDisplay * display, const GstVideoInfo * info);
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+gint gst_wl_fwrite_data (gchar * file, gpointer data, guint size);
+gboolean gst_is_wl_memory (GstMemory * mem);
+#endif
+G_END_DECLS
+#endif /* __GST_WL_SHM_ALLOCATOR_H__ */
diff --git a/tizenwlsink/src/wlvideoformat.c b/tizenwlsink/src/wlvideoformat.c
new file mode 100644 (file)
index 0000000..59e9c95
--- /dev/null
@@ -0,0 +1,113 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2012 Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "wlvideoformat.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
+#define GST_CAT_DEFAULT gstwayland_debug
+#define FUNCTION GST_LOG ("<ENTER>")
+typedef struct
+{
+  enum wl_shm_format wl_format;
+  GstVideoFormat gst_format;
+} wl_VideoFormat;
+
+static const wl_VideoFormat formats[] = {
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+  {WL_SHM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_xRGB},
+  {WL_SHM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_ARGB},
+  {WL_SHM_FORMAT_XBGR8888, GST_VIDEO_FORMAT_xBGR},
+  {WL_SHM_FORMAT_RGBX8888, GST_VIDEO_FORMAT_RGBx},
+  {WL_SHM_FORMAT_BGRX8888, GST_VIDEO_FORMAT_BGRx},
+  {WL_SHM_FORMAT_ABGR8888, GST_VIDEO_FORMAT_ABGR},
+  {WL_SHM_FORMAT_RGBA8888, GST_VIDEO_FORMAT_RGBA},
+  {WL_SHM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_BGRA},
+#else
+  {WL_SHM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_BGRx},
+  {WL_SHM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_BGRA},
+  {WL_SHM_FORMAT_XBGR8888, GST_VIDEO_FORMAT_RGBx},
+  {WL_SHM_FORMAT_RGBX8888, GST_VIDEO_FORMAT_xBGR},
+  {WL_SHM_FORMAT_BGRX8888, GST_VIDEO_FORMAT_xRGB},
+  {WL_SHM_FORMAT_ABGR8888, GST_VIDEO_FORMAT_RGBA},
+  {WL_SHM_FORMAT_RGBA8888, GST_VIDEO_FORMAT_ABGR},
+  {WL_SHM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_ARGB},
+#endif
+  {WL_SHM_FORMAT_RGB888, GST_VIDEO_FORMAT_RGB},
+  {WL_SHM_FORMAT_BGR888, GST_VIDEO_FORMAT_BGR},
+  {WL_SHM_FORMAT_RGB565, GST_VIDEO_FORMAT_RGB16},
+  {WL_SHM_FORMAT_BGR565, GST_VIDEO_FORMAT_BGR16},
+
+  {WL_SHM_FORMAT_YUYV, GST_VIDEO_FORMAT_YUY2},
+  {WL_SHM_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU},
+  {WL_SHM_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY},
+  {WL_SHM_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV},
+  {WL_SHM_FORMAT_NV12, GST_VIDEO_FORMAT_NV12},
+  {WL_SHM_FORMAT_NV21, GST_VIDEO_FORMAT_NV21},
+  {WL_SHM_FORMAT_NV16, GST_VIDEO_FORMAT_NV16},
+  {WL_SHM_FORMAT_YUV410, GST_VIDEO_FORMAT_YUV9},
+  {WL_SHM_FORMAT_YVU410, GST_VIDEO_FORMAT_YVU9},
+  {WL_SHM_FORMAT_YUV411, GST_VIDEO_FORMAT_Y41B},
+  {WL_SHM_FORMAT_YUV420, GST_VIDEO_FORMAT_I420},
+  {WL_SHM_FORMAT_YVU420, GST_VIDEO_FORMAT_YV12},
+  {WL_SHM_FORMAT_YUV422, GST_VIDEO_FORMAT_Y42B},
+  {WL_SHM_FORMAT_YUV444, GST_VIDEO_FORMAT_v308},
+};
+
+enum wl_shm_format
+gst_video_format_to_wl_shm_format (GstVideoFormat format)
+{
+  guint i;
+  FUNCTION;
+
+  for (i = 0; i < G_N_ELEMENTS (formats); i++)
+    if (formats[i].gst_format == format)
+      return formats[i].wl_format;
+
+  GST_WARNING ("wayland shm video format not found");
+  return -1;
+}
+
+GstVideoFormat
+gst_wl_shm_format_to_video_format (enum wl_shm_format wl_format)
+{
+  guint i;
+  FUNCTION;
+
+  for (i = 0; i < G_N_ELEMENTS (formats); i++)
+    if (formats[i].wl_format == wl_format)
+      return formats[i].gst_format;
+
+  GST_WARNING ("gst video format not found");
+  return GST_VIDEO_FORMAT_UNKNOWN;
+}
+
+const gchar *
+gst_wl_shm_format_to_string (enum wl_shm_format wl_format)
+{
+  FUNCTION;
+  return gst_video_format_to_string
+      (gst_wl_shm_format_to_video_format (wl_format));
+}
diff --git a/tizenwlsink/src/wlvideoformat.h b/tizenwlsink/src/wlvideoformat.h
new file mode 100644 (file)
index 0000000..7377cd1
--- /dev/null
@@ -0,0 +1,37 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2012 Wim Taymans <wim.taymans@gmail.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+#ifndef __GST_WL_VIDEO_FORMAT_H__
+#define __GST_WL_VIDEO_FORMAT_H__
+
+#include <wayland-client-protocol.h>
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+    enum wl_shm_format gst_video_format_to_wl_shm_format (GstVideoFormat
+    format);
+GstVideoFormat gst_wl_shm_format_to_video_format (enum wl_shm_format wl_format);
+
+const gchar *gst_wl_shm_format_to_string (enum wl_shm_format wl_format);
+
+G_END_DECLS
+#endif
diff --git a/tizenwlsink/src/wlwindow.c b/tizenwlsink/src/wlwindow.c
new file mode 100644 (file)
index 0000000..c8d8366
--- /dev/null
@@ -0,0 +1,1103 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2011 Intel Corporation
+ * Copyright (C) 2011 Sreerenj Balachandran <sreerenj.balachandran@intel.com>
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+#include "gstwaylandsink.h"
+#else
+#include "wlwindow.h"
+#endif
+#include "wlshmallocator.h"
+#include "wlbuffer.h"
+
+GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug);
+#define GST_CAT_DEFAULT gstwayland_debug
+
+G_DEFINE_TYPE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT);
+
+static void gst_wl_window_finalize (GObject * gobject);
+
+static void
+handle_ping (void *data, struct wl_shell_surface *shell_surface,
+    uint32_t serial)
+{
+  wl_shell_surface_pong (shell_surface, serial);
+}
+
+static void
+handle_configure (void *data, struct wl_shell_surface *shell_surface,
+    uint32_t edges, int32_t width, int32_t height)
+{
+}
+
+static void
+handle_popup_done (void *data, struct wl_shell_surface *shell_surface)
+{
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener = {
+  handle_ping,
+  handle_configure,
+  handle_popup_done
+};
+
+static void
+gst_wl_window_class_init (GstWlWindowClass * klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  FUNCTION;
+  gobject_class->finalize = gst_wl_window_finalize;
+}
+
+static void
+gst_wl_window_init (GstWlWindow * self)
+{
+  g_return_if_fail (self != NULL);
+  self->buffer_width = self->buffer_height = 0;
+  self->buffer_x = self->buffer_y = 0;
+  self->roi.x = self->roi.y = self->roi.w = self->roi.h = 0;
+  self->flip.changed = FALSE;
+}
+
+static void
+gst_wl_window_finalize (GObject * gobject)
+{
+  GstWlWindow *self = GST_WL_WINDOW (gobject);
+  FUNCTION;
+
+  if (self->shell_surface) {
+    wl_shell_surface_destroy (self->shell_surface);
+  }
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (self->video_object)
+    tizen_video_object_destroy (self->video_object);
+  if (self->tizen_area_viewport)
+    tizen_viewport_destroy (self->tizen_area_viewport);
+  if (self->tizen_video_viewport)
+    tizen_viewport_destroy (self->tizen_video_viewport);
+  if (self->tizen_video_dest_mode)
+    tizen_destination_mode_destroy (self->tizen_video_dest_mode);
+  if (self->tizen_area_dest_mode)
+    tizen_destination_mode_destroy (self->tizen_area_dest_mode);
+#else
+  wl_viewport_destroy (self->video_viewport);
+  wl_viewport_destroy (self->area_viewport);
+#endif
+  wl_subsurface_destroy (self->video_subsurface);
+  wl_surface_destroy (self->video_surface);
+
+  if (self->area_subsurface) {
+    wl_subsurface_destroy (self->area_subsurface);
+  }
+
+  wl_surface_destroy (self->area_surface);
+  g_clear_object (&self->display);
+
+  G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject);
+}
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+static void
+gst_wl_window_map_sub_surface (GstWlDisplay * display, GstWlWindow * window,
+    GstVideoInfo * info)
+{
+  /* A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+   * and the parent surface is mapped */
+  GstBuffer *buf;
+  GstMapInfo mapinfo;
+  struct wl_buffer *wlbuf;
+  GstWlBuffer *gwlbuf;
+  GstWlShmAllocator *self = NULL;
+  FUNCTION;
+
+  g_return_if_fail (display != NULL);
+  g_return_if_fail (window != NULL);
+  g_return_if_fail (info != NULL);
+
+  self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ());
+  self->display = display;
+
+  buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info->size, NULL);
+  gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE);
+  *((guint32 *) mapinfo.data) = 0;      /* paint it black */
+  gst_buffer_unmap (buf, &mapinfo);
+  wlbuf =
+      gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0),
+      display, info);
+
+  gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, display);
+  gst_wl_buffer_attach (gwlbuf, window->area_surface);
+
+  /* for tizen view port
+     When change area_surface, we don't need to commit anymore if we do below code.
+     such as gst_wl_window_set_render_rectangle() and */
+  GST_INFO
+      ("wl_surface_damage_buffer (area_surface(wl_surface)@%p, x@%d, y@%d, w@%d, h@%d)",
+      window->area_surface, 0, 0, info->width, info->height);
+  wl_surface_damage_buffer (window->area_surface, 0, 0, info->width,
+      info->height);
+  GST_INFO ("wl_surface_commit (area_surface(wl_surface)@%p)",
+      window->area_surface);
+  wl_surface_commit (window->area_surface);
+
+  /* at this point, the GstWlBuffer keeps the buffer
+   * alive and will free it on wl_buffer::release */
+  gst_buffer_unref (buf);
+}
+#endif
+
+static GstWlWindow *
+#if 1
+/* for enlightment, we need to get parent to create  area_subsurface */
+gst_wl_window_new_internal (GstWlDisplay * display, struct wl_surface *parent)
+#else
+gst_wl_window_new_internal (GstWlDisplay * display)
+#endif
+{
+  GstWlWindow *window;
+  GstVideoInfo info;
+#ifndef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  GstBuffer *buf;
+  GstMapInfo mapinfo;
+  struct wl_buffer *wlbuf;
+  GstWlBuffer *gwlbuf;
+#endif
+  struct wl_region *region;
+  FUNCTION;
+
+  window = g_object_new (GST_TYPE_WL_WINDOW, NULL);
+  window->display = g_object_ref (display);
+
+  window->area_surface = wl_compositor_create_surface (display->compositor);
+  GST_INFO
+      ("area_surface(wl_surface)@%p = wl_compositor_create_surface(wl_compositor@%p)",
+      window->area_surface, display->compositor);
+  window->video_surface = wl_compositor_create_surface (display->compositor);
+  GST_INFO
+      ("video_surface(wl_surface)@%p = wl_compositor_create_surface(wl_compositor@%p)",
+      window->video_surface, display->compositor);
+
+  GST_INFO ("wl_proxy_set_queue (area_surface@%p, wl_event_queue@%p)",
+      window->area_surface, display->queue);
+  wl_proxy_set_queue ((struct wl_proxy *) window->area_surface, display->queue);
+  GST_INFO ("wl_proxy_set_queue (video_surface@%p, wl_event_queue@%p)",
+      window->video_surface, display->queue);
+  wl_proxy_set_queue ((struct wl_proxy *) window->video_surface,
+      display->queue);
+
+#if 1                           /* create shell_surface here for enlightenment */
+  /* go toplevel */
+  if (display->need_shell_surface) {
+    /* for internal window */
+    GST_INFO
+        ("wl_shell_surface@%p =  wl_shell_get_shell_surface (wl_shell@%p, area_subsurface(wl_surface)@%p)",
+        window->shell_surface, display->shell, window->area_surface);
+    window->shell_surface =
+        wl_shell_get_shell_surface (display->shell, window->area_surface);
+  } else if (display->use_parent_wl_surface) {
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+    if (display->wl_surface_id && parent == NULL) {
+      window->area_subsurface =
+          tizen_policy_get_subsurface (display->tizen_policy,
+          window->area_surface, display->wl_surface_id);
+      GST_INFO
+          ("area_subsurface(wl_subsurface)@%p = tizen_policy_get_subsurface(tizen_policy@%p, area_surface(wl_surface)@%p, wl_surface_id@%d)",
+          window->area_subsurface, display->tizen_policy, window->area_surface,
+          display->wl_surface_id);
+      GST_INFO ("wl_subsurface_set_desync (area_subsurface(wl_subsurface)@%p)",
+          window->area_subsurface);
+      wl_subsurface_set_desync (window->area_subsurface);
+      GST_INFO ("wl_surface_commit (%p)", window->area_surface);
+      wl_surface_commit (window->area_surface);
+    } else {
+      GST_INFO (" wl_surface parent %p", parent);
+      window->area_subsurface =
+          wl_subcompositor_get_subsurface (display->subcompositor,
+          window->area_surface, parent);
+      GST_INFO
+          ("area_subsurface(wl_subsurface)@%p = wl_subcompositor_get_subsurface(wl_subcompositor@%p, area_surface(wl_surface)@%p, parent@%p)",
+          window->area_subsurface, display->subcompositor, window->area_surface,
+          parent);
+      GST_INFO ("wl_subsurface_set_desync (area_subsurface(wl_subsurface)@%p)",
+          window->area_subsurface);
+      wl_subsurface_set_desync (window->area_subsurface);
+    }
+#else
+    /*for enlightment , below code is moved */
+    window->area_subsurface =
+        wl_subcompositor_get_subsurface (display->subcompositor,
+        window->area_surface, parent);
+    wl_subsurface_set_desync (window->area_subsurface);
+#endif
+  }
+#endif
+
+  /* embed video_surface in area_surface */
+  window->video_subsurface =
+      wl_subcompositor_get_subsurface (display->subcompositor,
+      window->video_surface, window->area_surface);
+  GST_INFO
+      ("video_subsurface(wl_subsurface)@%p = wl_subcompositor_get_subsurface(wl_subcompositor@%p, video_surface(wl_surface)@%p, area_surface(wl_surface)@%p)",
+      window->video_subsurface, display->subcompositor, window->video_surface,
+      window->area_surface);
+
+  GST_INFO ("wl_subsurface_set_desync (video_subsurface(wl_subsurface)@%p)",
+      window->video_subsurface);
+  wl_subsurface_set_desync (window->video_subsurface);
+  GST_INFO ("wl_surface_commit (%p)", window->video_surface);
+  wl_surface_commit (window->video_surface);
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  window->tizen_area_viewport =
+      tizen_video_get_viewport (display->tizen_video, window->area_surface);
+  GST_INFO
+      ("tizen_area_viewport(tizen_viewport)@%p = tizen_video_get_viewport(tizen_video@%p, area_surface(wl_surface)@%p)",
+      window->tizen_area_viewport, display->tizen_video, window->area_surface);
+  window->tizen_video_viewport =
+      tizen_video_get_viewport (display->tizen_video, window->video_surface);
+  GST_INFO
+      ("tizen_video_viewport(tizen_viewport)@%p = tizen_video_get_viewport(tizen_video@%p, video_surface(wl_surface)@%p)",
+      window->tizen_video_viewport, display->tizen_video,
+      window->video_surface);
+  window->tizen_video_dest_mode =
+      tizen_viewport_get_destination_mode (window->tizen_video_viewport);
+  GST_INFO
+      ("tizen_video_dest_mode(tizen_destination_mode)@%p = tizen_viewport_get_destination_mode (tizen_video_viewport@%p)",
+      window->tizen_video_dest_mode, window->tizen_video_viewport);
+  /* video surface always follow area surface by below code. */
+  GST_INFO ("tizen_viewport_follow_parent_transform(tizen_video_viewport@%p)",
+      window->tizen_video_viewport);
+  tizen_viewport_follow_parent_transform (window->tizen_video_viewport);
+
+#else
+  window->area_viewport = wl_scaler_get_viewport (display->scaler,
+      window->area_surface);
+  window->video_viewport = wl_scaler_get_viewport (display->scaler,
+      window->video_surface);
+#endif
+  /* draw the area_subsurface */
+  gst_video_info_set_format (&info,
+      /* we want WL_SHM_FORMAT_XRGB8888 */
+#if G_BYTE_ORDER == G_BIG_ENDIAN
+      GST_VIDEO_FORMAT_xRGB,
+#else
+      GST_VIDEO_FORMAT_BGRx,
+#endif
+      1, 1);
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  if (window->display->USE_TBM) {
+    /* Inform enlightenment of surface which render video */
+    /* tizen_video(tbm) render on video_surface */
+    window->video_object =
+        tizen_video_get_object (display->tizen_video, window->video_surface);
+
+    /* to use shm memory for mapping sub-surface, set FALSE to USE_TBM */
+    window->display->USE_TBM = FALSE;
+    gst_wl_window_map_sub_surface (display, window, &info);
+    /*restore USE_TBM */
+    window->display->USE_TBM = TRUE;
+  } else {
+    gst_wl_window_map_sub_surface (display, window, &info);
+  }
+#else /* open source */
+  buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info.size, NULL);
+  gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE);
+  *((guint32 *) mapinfo.data) = 0;      /* paint it black */
+  gst_buffer_unmap (buf, &mapinfo);
+  wlbuf =
+      gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0),
+      display, &info);
+  gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, display);
+  gst_wl_buffer_attach (gwlbuf, window->area_surface);
+
+  /* at this point, the GstWlBuffer keeps the buffer
+   * alive and will free it on wl_buffer::release */
+  gst_buffer_unref (buf);
+#endif
+
+  /* do not accept input */
+  region = wl_compositor_create_region (display->compositor);
+  GST_INFO ("wl_region@%p = wl_compositor_create_region (wl_compositor@%p)",
+      region, display->compositor);
+  GST_INFO ("wl_surface_set_input_region (area_surface@%p, wl_region@%p)",
+      window->area_surface, region);
+  wl_surface_set_input_region (window->area_surface, region);
+  GST_INFO ("wl_region_destroy (wl_region@%p)", region);
+  wl_region_destroy (region);
+
+  region = wl_compositor_create_region (display->compositor);
+  GST_INFO ("wl_region@%p = wl_compositor_create_region (wl_compositor@%p)",
+      region, display->compositor);
+  GST_INFO ("wl_surface_set_input_region (video_surface@%p, wl_region@%p)",
+      window->video_surface, region);
+  wl_surface_set_input_region (window->video_surface, region);
+  GST_INFO ("wl_region_destroy (wl_region@%p)", region);
+  wl_region_destroy (region);
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  /* set area surface size by full mode(full size of parent window) , toplevel is set to fullmode too for convenient test */
+  if (window->tizen_area_viewport) {
+    int tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_FULL;
+
+    window->tizen_area_dest_mode =
+        tizen_viewport_get_destination_mode (window->tizen_area_viewport);
+    GST_INFO
+        ("tizen_area_dest_mode(tizen_destination_mode)@%p = tizen_viewport_get_destination_mode (tizen_area_viewport@%p)",
+        window->tizen_area_dest_mode, window->tizen_area_viewport);
+    if (window->tizen_area_dest_mode) {
+      GST_INFO
+          ("tizen_destination_mode_set (tizen_destination_mode@%p, @%d, 3 is FULL)",
+          window->tizen_area_dest_mode, tizen_disp_mode);
+      tizen_destination_mode_set (window->tizen_area_dest_mode,
+          tizen_disp_mode);
+    }
+    GST_INFO ("wl_surface_commit (area_surface@%p)", window->area_surface);
+    wl_surface_commit (window->area_surface);
+  }
+#endif
+  return window;
+}
+
+GstWlWindow *
+gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info)
+{
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  GstWlWindow *window;
+  FUNCTION;
+
+/* not create shell_surface here for enlightenment */
+  display->need_shell_surface = TRUE;
+  window = gst_wl_window_new_internal (display, NULL);
+
+  /* for tizen enlightenment */
+#if 0
+  /* go toplevel */
+  window->shell_surface = wl_shell_get_shell_surface (display->shell,
+      window->area_surface);
+#endif
+  if (window->shell_surface) {
+    GST_INFO
+        ("wl_shell_surface_add_listener (shell_surface@%p, wl_shell_surface_listener@%p, GstWlWindow@%p",
+        window->shell_surface, &shell_surface_listener, window);
+    wl_shell_surface_add_listener (window->shell_surface,
+        &shell_surface_listener, window);
+    GST_INFO ("wl_shell_surface_set_toplevel (shell_surface@%p",
+        window->shell_surface);
+    wl_shell_surface_set_toplevel (window->shell_surface);
+  } else {
+    GST_ERROR ("Unable to get wl_shell_surface");
+
+    g_object_unref (window);
+    return NULL;
+  }
+
+  /* toplevel is set to fullmode for convenient test in tizen_viewport enviroment, don't use below code */
+#if 0
+  /* set the initial size to be the same as the reported video size */
+  width =
+      gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
+  gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height);
+#endif
+  return window;
+
+#else /* open source */
+  GstWlWindow *window;
+  gint width;
+
+  window = gst_wl_window_new_internal (display);
+
+  /* go toplevel */
+  window->shell_surface = wl_shell_get_shell_surface (display->shell,
+      window->area_surface);
+
+  if (window->shell_surface) {
+    wl_shell_surface_add_listener (window->shell_surface,
+        &shell_surface_listener, window);
+    wl_shell_surface_set_toplevel (window->shell_surface);
+  } else {
+    GST_ERROR ("Unable to get wl_shell_surface");
+
+    g_object_unref (window);
+    return NULL;
+  }
+
+  /* set the initial size to be the same as the reported video size */
+  width =
+      gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
+  gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height);
+
+  return window;
+#endif
+}
+
+
+GstWlWindow *
+gst_wl_window_new_in_surface (GstWlDisplay * display,
+    struct wl_surface * parent)
+{
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  /* use App window */
+  GstWlWindow *window;
+  FUNCTION;
+
+  display->use_parent_wl_surface = TRUE;
+  if (parent) {
+    /*use wl_surface */
+    window = gst_wl_window_new_internal (display, parent);
+  } else {
+    /* use wl_surface id */
+    window = gst_wl_window_new_internal (display, NULL);
+  }
+
+  /*Area surface from App need to be under parent surface */
+  if (display->tizen_policy) {
+    GST_INFO
+        ("tizen_policy_place_subsurface_below_parent (tizen_policy@%p, area_subsurface@%p)",
+        display->tizen_policy, window->area_subsurface);
+    tizen_policy_place_subsurface_below_parent (display->tizen_policy,
+        window->area_subsurface);
+    GST_INFO
+        ("tizen_policy_place_subsurface_below_parent (tizen_policy@%p, video_subsurface@%p)",
+        display->tizen_policy, window->video_subsurface);
+    tizen_policy_place_subsurface_below_parent (display->tizen_policy,
+        window->video_subsurface);
+  }
+  return window;
+
+#else /* open source */
+
+  GstWlWindow *window;
+  window = gst_wl_window_new_internal (display, parent);        //add parent for enlightment
+
+  /*for enlightment , move to gst_wl_window_new_internal() */
+#if 0
+  /* embed in parent */
+  window->area_subsurface =
+      wl_subcompositor_get_subsurface (display->subcompositor,
+      window->area_surface, parent);
+  wl_subsurface_set_desync (window->area_subsurface);
+#endif
+
+  return window;
+
+#endif
+}
+
+GstWlDisplay *
+gst_wl_window_get_display (GstWlWindow * window)
+{
+  FUNCTION;
+  g_return_val_if_fail (window != NULL, NULL);
+
+  return g_object_ref (window->display);
+}
+
+struct wl_surface *
+gst_wl_window_get_wl_surface (GstWlWindow * window)
+{
+  FUNCTION;
+  g_return_val_if_fail (window != NULL, NULL);
+
+  return window->video_surface;
+}
+
+gboolean
+gst_wl_window_is_toplevel (GstWlWindow * window)
+{
+  FUNCTION;
+  g_return_val_if_fail (window != NULL, FALSE);
+
+  return (window->shell_surface != NULL);
+}
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+static gint
+gst_wl_window_find_rotate_transform (guint rotate_angle)
+{
+  gint transform = WL_OUTPUT_TRANSFORM_NORMAL;
+  FUNCTION;
+
+  GST_DEBUG ("rotate (%d)", rotate_angle);
+  switch (rotate_angle) {
+    case DEGREE_0:
+      transform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    case DEGREE_90:
+      transform = WL_OUTPUT_TRANSFORM_90;
+      break;
+    case DEGREE_180:
+      transform = WL_OUTPUT_TRANSFORM_180;
+      break;
+    case DEGREE_270:
+      transform = WL_OUTPUT_TRANSFORM_270;
+      break;
+  }
+  return transform;
+}
+
+static gint
+gst_wl_window_find_flip_transform (guint flip)
+{
+  gint transform = WL_OUTPUT_TRANSFORM_NORMAL;
+  FUNCTION;
+
+  GST_DEBUG ("flip (%d)", flip);
+  switch (flip) {
+    case FLIP_NONE:
+      transform = WL_OUTPUT_TRANSFORM_NORMAL;
+      break;
+    case FLIP_HORIZONTAL:
+      transform = WL_OUTPUT_TRANSFORM_FLIPPED;
+      break;
+    case FLIP_VERTICAL:
+      transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
+      break;
+    case FLIP_BOTH:
+      transform = WL_OUTPUT_TRANSFORM_180;
+      break;
+  }
+  return transform;
+
+}
+
+#endif
+#if TIZEN_FEATURE_WLSINK_ENHANCEMENT
+static void
+gst_wl_window_resize_tizen_video_viewport (GstWlWindow * window,
+    gboolean commit)
+{
+  gint transform = WL_OUTPUT_TRANSFORM_NORMAL;
+
+  FUNCTION;
+  g_return_if_fail (window->tizen_video_viewport != NULL);
+  g_return_if_fail (window->tizen_video_dest_mode != NULL);
+
+  /* Set source, wayland need to set "tizen_viewport_set_source" always when change video info,
+     aligned video issue=> ex) 854 x 480 video : aligned buffer size 864 x 480, so we need to set original video size by set source */
+  if (window->mode_crop.changed) {
+    /* we have known issue about mobile team kernel, when set orign green line can be shown with tbm */
+    GST_INFO
+        ("tizen_viewport_set_source (tizen_video_viewport@%p, x@%d, y@%d, w@%d, h@%d)",
+        window->tizen_video_viewport, window->mode_crop.x, window->mode_crop.y,
+        window->mode_crop.w, window->mode_crop.h);
+    tizen_viewport_set_source (window->tizen_video_viewport,
+        window->mode_crop.x, window->mode_crop.y, window->mode_crop.w,
+        window->mode_crop.h);
+    window->mode_crop.changed = FALSE;
+  }
+
+  /*set tizen destination mode */
+  if (window->disp_geo_method.changed || window->roi_area_changed) {
+    int tizen_disp_mode = -1;
+    switch (window->disp_geo_method.value) {
+
+      case DISP_GEO_METHOD_LETTER_BOX:
+        GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_LETTER_BOX");
+        tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_LETTER_BOX;
+        break;
+      case DISP_GEO_METHOD_ORIGIN_SIZE:
+        GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_ORIGIN");
+        tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_ORIGIN;
+        break;
+      case DISP_GEO_METHOD_FULL_SCREEN:
+        GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_FULL");
+        tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_FULL;
+        break;
+      case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
+        GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_CROPPED_FULL");
+        tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_CROPPED_FULL;
+        break;
+      case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
+        GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_ORIGIN_OR_LETTER");
+        tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_ORIGIN_OR_LETTER;
+        break;
+      case DISP_GEO_METHOD_CUSTOM_ROI:
+        GST_LOG ("DISP_GEO_METHOD_CUSTOM_ROI..need to set destination ROI");
+        tizen_disp_mode = -1;
+        break;
+      default:
+        break;
+    }
+    if (tizen_disp_mode > -1) {
+      GST_INFO
+          ("tizen_destination_mode_set (tizen_destination_mode@%p, tizen_disp_mode@%d)",
+          window->tizen_video_dest_mode, tizen_disp_mode);
+      tizen_destination_mode_set (window->tizen_video_dest_mode,
+          tizen_disp_mode);
+    }
+    if (window->disp_geo_method.value == DISP_GEO_METHOD_CUSTOM_ROI) {
+      /* set ROI destination */
+      GST_INFO
+          ("tizen_viewport_set_destination (tizen_video_viewport(tizen_viewport)@%p, x@%d, y@%d, w@%d, h@%d)",
+          window->tizen_video_viewport, window->roi.x, window->roi.y,
+          window->roi.w, window->roi.h);
+      tizen_viewport_set_destination (window->tizen_video_viewport,
+          window->roi.x, window->roi.y, window->roi.w, window->roi.h);
+      window->roi_area_changed = FALSE;
+    }
+    window->disp_geo_method.changed = FALSE;
+  }
+
+
+  goto done;
+
+  /* Even though area_viewport is set to ROI mode, we can set below functions too if video_viewport is set to tizen_destination_mode_set. */
+#ifdef ENABLE_FUNCTION
+  /* set or unset follow parent transform */
+  if (window->follow_parent_transform.changed
+      && !gst_wl_window_is_toplevel (window)) {
+    if (window->follow_parent_transform.value) {
+      GST_INFO
+          ("tizen_destination_mode_follow_parent_transform (tizen_destination_mode@%p)",
+          window->tizen_area_dest_mode);
+      tizen_destination_mode_follow_parent_transform
+          (window->tizen_area_dest_mode);
+      GST_INFO
+          ("tizen_destination_mode_follow_parent_transform (tizen_destination_mode@%p)",
+          window->tizen_video_dest_mode);
+      tizen_destination_mode_follow_parent_transform
+          (window->tizen_video_dest_mode);
+
+    } else {
+      GST_INFO
+          ("tizen_destination_mode_unfollow_parent_transform (tizen_destination_mode@%p)",
+          window->tizen_area_dest_mode);
+      tizen_destination_mode_unfollow_parent_transform
+          (window->tizen_area_dest_mode);
+      GST_INFO
+          ("tizen_destination_mode_unfollow_parent_transform (tizen_destination_mode@%p)",
+          window->tizen_video_dest_mode);
+      tizen_destination_mode_unfollow_parent_transform
+          (window->tizen_video_dest_mode);
+    }
+    window->follow_parent_transform.changed = FALSE;
+  }
+
+  /* set ratio */
+  if (window->mode_ratio.changed) {
+    wl_fixed_t f_width, f_height;
+    f_width = wl_fixed_from_double (window->mode_ratio.w);
+    f_height = wl_fixed_from_double (window->mode_ratio.h);
+
+    GST_INFO
+        ("tizen_destination_mode_set_ratio (tizen_destination_mode@%p, wl_fixed width@%f, wl_fixed height@%f)",
+        window->tizen_video_dest_mode, window->mode_ratio.w,
+        window->mode_ratio.h);
+    tizen_destination_mode_set_ratio (window->tizen_video_dest_mode, f_width,
+        f_height);
+    window->mode_ratio.changed = FALSE;
+  }
+
+  /* set offset */
+  if (window->mode_offset.changed) {
+    GST_INFO
+        ("tizen_destination_mode_set_offset (tizen_destination_mode@%p, x@%d, y@%d, w@%d, h@%d)",
+        window->tizen_video_dest_mode, window->mode_offset.x,
+        window->mode_offset.y, window->mode_offset.w, window->mode_offset.h);
+    tizen_destination_mode_set_offset (window->tizen_video_dest_mode,
+        window->mode_offset.x, window->mode_offset.y, window->mode_offset.w,
+        window->mode_offset.h);
+    window->mode_offset.changed = FALSE;
+  }
+
+  /* set scale */
+  if (window->mode_scale.changed) {
+    wl_fixed_t f_width, f_height;
+    f_width = wl_fixed_from_double (window->mode_scale.w);
+    f_height = wl_fixed_from_double (window->mode_scale.h);
+
+    GST_INFO
+        ("tizen_destination_mode_set_scale (tizen_destination_mode@%p, wl_fixed width@%f, wl_fixed height@%f)",
+        window->tizen_video_dest_mode, window->mode_scale.w,
+        window->mode_scale.h);
+    tizen_destination_mode_set_scale (window->tizen_video_dest_mode, f_width,
+        f_height);
+    window->mode_scale.changed = FALSE;
+  }
+
+  /* set align */
+  if (window->mode_align.changed) {
+    wl_fixed_t f_width, f_height;
+    f_width = wl_fixed_from_double (window->mode_align.w);
+    f_height = wl_fixed_from_double (window->mode_align.h);
+    GST_INFO
+        ("tizen_destination_mode_set_align (tizen_destination_mode@%p, wl_fixed_width@%f, wl_fixed_height@%f)",
+        window->tizen_video_dest_mode, window->mode_align.w,
+        window->mode_align.h);
+    tizen_destination_mode_set_align (window->tizen_video_dest_mode, f_width,
+        f_height);
+    window->mode_align.changed = FALSE;
+  }
+#endif
+
+done:
+  /* set rotate */
+  if (window->rotate_angle.changed) {
+    GST_LOG ("set rotate_angle(%d)", window->rotate_angle.value);
+    transform =
+        gst_wl_window_find_rotate_transform (window->rotate_angle.value);
+    GST_INFO
+        ("tizen_viewport_set_transform(tizen_area_viewport@%p, transform@%d)",
+        window->tizen_area_viewport, transform);
+    tizen_viewport_set_transform (window->tizen_area_viewport, transform);
+    window->rotate_angle.changed = FALSE;
+  }
+  /* set flip */
+  if (window->flip.changed) {
+    GST_LOG ("set flip(%d)", window->flip.value);
+
+    transform = gst_wl_window_find_flip_transform (window->flip.value);
+    GST_INFO
+        ("tizen_viewport_set_transform(tizen_video_viewport@%p, transform@%d)",
+        window->tizen_video_viewport, transform);
+    tizen_viewport_set_transform (window->tizen_video_viewport, transform);
+    window->flip.changed = FALSE;
+  }
+
+  if (commit) {
+    GST_LOG ("need to commit");
+    GST_INFO
+        ("wl_surface_damage_buffer (video_surface@%p, buffer_@x%d, buffer_y@%d, buffer_w@%d, buffer_h@%d)",
+        window->video_surface, window->buffer_x, window->buffer_y,
+        window->buffer_width, window->buffer_height);
+    wl_surface_damage_buffer (window->video_surface, window->buffer_x,
+        window->buffer_y, window->buffer_width, window->buffer_height);
+    GST_INFO ("wl_surface_commit (video_surface@%p)", window->video_surface);
+    wl_surface_commit (window->video_surface);
+  }
+}
+#else
+static void
+gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit)
+{
+  GstVideoRectangle src = { 0, };
+  GstVideoRectangle dst = { 0, };
+  GstVideoRectangle res;
+
+  /* center the video_subsurface inside area_subsurface */
+  src.w = window->video_width;
+  src.h = window->video_height;
+  dst.w = window->render_rectangle.w;
+  dst.h = window->render_rectangle.h;
+  gst_video_sink_center_rect (src, dst, &res, TRUE);
+
+  wl_subsurface_set_position (window->video_subsurface, res.x, res.y);
+  wl_viewport_set_destination (window->video_viewport, res.w, res.h);
+
+  if (commit) {
+    wl_surface_damage (window->video_surface, 0, 0, res.w, res.h);
+    wl_surface_commit (window->video_surface);
+  }
+
+  if (gst_wl_window_is_toplevel (window)) {
+    struct wl_region *region;
+
+    region = wl_compositor_create_region (window->display->compositor);
+    wl_region_add (region, 0, 0, window->render_rectangle.w,
+        window->render_rectangle.h);
+    wl_surface_set_input_region (window->area_surface, region);
+    wl_region_destroy (region);
+  }
+
+  /* this is saved for use in wl_surface_damage */
+  window->surface_width = res.w;
+  window->surface_height = res.h;
+}
+#endif
+void
+gst_wl_window_render (GstWlWindow * window, GstWlBuffer * buffer,
+    const GstVideoInfo * info)
+{
+#if TIZEN_FEATURE_WLSINK_ENHANCEMENT
+  FUNCTION;
+  /* check video buffer size for wl_surface_damage_buffer */
+  if (window->buffer_width != window->display->buffer_width
+      || window->buffer_height != window->display->buffer_height) {
+    window->buffer_width = window->display->buffer_width;
+    window->buffer_height = window->display->buffer_height;
+    GST_LOG ("buffer_width(%d) buffer_height(%d)",
+        window->display->buffer_width, window->display->buffer_height);
+  }
+  GST_LOG ("buffer_width(%d) buffer_height(%d)", window->display->buffer_width,
+      window->display->buffer_height);
+
+  if (G_UNLIKELY (info)) {
+    window->video_width =
+        gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
+    window->video_height = info->height;
+
+    wl_subsurface_set_sync (window->video_subsurface);
+    GST_INFO ("wl_subsurface_set_sync (video_subsurface@%p)",
+        window->video_subsurface);
+    /* check video_info_changed to remove repetitive IPC */
+    if (window->video_info_changed) {
+      gst_wl_window_resize_tizen_video_viewport (window, FALSE);
+      window->video_info_changed = FALSE;
+    }
+  }
+
+  GST_LOG ("GstWlBuffer(%p)", buffer);
+  if (G_LIKELY (buffer))
+    gst_wl_buffer_attach (buffer, window->video_surface);
+  else {
+    GST_INFO ("wl_surface_attach (video_surface@%p, NULL, 0, 0)",
+        window->video_surface);
+    wl_surface_attach (window->video_surface, NULL, 0, 0);
+  }
+  /* use tizen view port */
+  GST_INFO
+      ("wl_surface_damage_buffer (video_surface@%p, buffer_x@%d, buffer_y@%d, buffer_w@%d, buffer_h@%d)",
+      window->video_surface, window->buffer_x, window->buffer_y,
+      window->buffer_width, window->buffer_height);
+  wl_surface_damage_buffer (window->video_surface, window->buffer_x,
+      window->buffer_y, window->buffer_width, window->buffer_height);
+  /* wl_surface_commit change surface state, if wl_buffer is not attached newly,  then surface is not changed */
+  GST_INFO ("wl_surface_commit (video_surface@%p)", window->video_surface);
+  wl_surface_commit (window->video_surface);
+
+  if (G_UNLIKELY (info)) {
+    GST_INFO ("wl_surface_commit (area_surface@%p)", window->area_surface);
+    wl_surface_commit (window->area_surface);
+    GST_INFO ("wl_subsurface_set_desync (video_subsurface@%p)",
+        window->video_subsurface);
+    wl_subsurface_set_desync (window->video_subsurface);
+  }
+
+  wl_display_flush (window->display->display);
+
+#else /* open source */
+
+  if (G_UNLIKELY (info)) {
+    window->video_width =
+        gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
+    window->video_height = info->height;
+
+    wl_subsurface_set_sync (window->video_subsurface);
+    gst_wl_window_resize_video_surface (window, FALSE);
+  }
+
+  GST_LOG ("GstWlBuffer(%p)", buffer);
+  if (G_LIKELY (buffer))
+    gst_wl_buffer_attach (buffer, window->video_surface);
+  else
+    wl_surface_attach (window->video_surface, NULL, 0, 0);
+
+  wl_surface_damage (window->video_surface, 0, 0, window->surface_width,
+      window->surface_height);
+  wl_surface_commit (window->video_surface);
+
+  if (G_UNLIKELY (info)) {
+    /* commit also the parent (area_surface) in order to change
+     * the position of the video_subsurface */
+    wl_surface_damage (window->area_surface, 0, 0, window->render_rectangle.w,
+        window->render_rectangle.h);
+    wl_surface_commit (window->area_surface);
+    wl_subsurface_set_desync (window->video_subsurface);
+  }
+
+  wl_display_flush (window->display->display);
+#endif
+}
+
+#if TIZEN_FEATURE_WLSINK_ENHANCEMENT
+gboolean
+gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
+    gint w, gint h)
+{
+  FUNCTION;
+  g_return_val_if_fail (window != NULL, FALSE);
+
+  if (window->disp_geo_method.value != DISP_GEO_METHOD_CUSTOM_ROI) {
+    GST_ERROR
+        ("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle()");
+    return FALSE;
+  }
+
+  if (w < 0 || h < 0) {
+    GST_ERROR ("Error : wrong roi size w(%d), h(%d)", w, h);
+    return FALSE;
+  }
+
+  window->roi.x = x;
+  window->roi.y = y;
+  window->roi.w = w;
+  window->roi.h = h;
+  GST_LOG ("set roi x(%d), y(%d), w(%d), h(%d)", x, y, w, h);
+  window->roi_area_changed = TRUE;
+
+  return TRUE;
+}
+#else /* open source */
+void
+gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
+    gint w, gint h)
+{
+
+  g_return_if_fail (window != NULL);
+
+  window->render_rectangle.x = x;
+  window->render_rectangle.y = y;
+  window->render_rectangle.w = w;
+  window->render_rectangle.h = h;
+
+  /* position the area inside the parent - needs a parent commit to apply */
+  if (window->area_subsurface)
+    wl_subsurface_set_position (window->area_subsurface, x, y);
+
+  /* change the size of the area */
+  wl_viewport_set_destination (window->area_viewport, w, h);
+
+  if (window->video_width != 0) {
+    wl_subsurface_set_sync (window->video_subsurface);
+    gst_wl_window_resize_video_surface (window, TRUE);
+  }
+
+  wl_surface_damage (window->area_surface, 0, 0, w, h);
+  wl_surface_commit (window->area_surface);
+
+  if (window->video_width != 0)
+    wl_subsurface_set_desync (window->video_subsurface);
+
+}
+#endif
+
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+void
+gst_wl_window_set_rotate_angle (GstWlWindow * window, guint rotate_angle)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  window->rotate_angle.value = rotate_angle;
+  GST_LOG ("rotate_angle value is (%d)", window->rotate_angle.value);
+  window->rotate_angle.changed = TRUE;
+}
+
+void
+gst_wl_window_set_destination_mode (GstWlWindow * window, guint disp_geo_method)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  window->disp_geo_method.value = disp_geo_method;
+  GST_LOG ("disp_geo_method value is (%d)", window->disp_geo_method.value);
+  window->disp_geo_method.changed = TRUE;
+}
+
+void
+gst_wl_window_set_flip (GstWlWindow * window, guint flip)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  window->flip.value = flip;
+  GST_LOG ("flip value is (%d)", window->flip.value);
+  window->flip.changed = TRUE;
+}
+
+void
+gst_wl_window_set_destination_mode_crop_wl_buffer (GstWlWindow * window,
+    guint x, guint y, guint w, guint h)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  GST_LOG ("set crop x@%d, y@%d, w@%d, h@%d", x, y, w, h);
+  window->mode_crop.x = x;
+  window->mode_crop.y = y;
+  window->mode_crop.w = w;
+  window->mode_crop.h = h;
+  window->mode_crop.changed = TRUE;
+}
+
+#ifdef ENABLE_FUNCTION
+void
+gst_wl_window_set_destination_mode_follow_parent_transform (GstWlWindow *
+    window, gboolean follow_parent_transform)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  window->follow_parent_transform.value = follow_parent_transform;
+  GST_LOG ("follow_parent_transform value is (%d)",
+      window->follow_parent_transform.value);
+  window->follow_parent_transform.changed = TRUE;
+}
+
+
+void
+gst_wl_window_set_destination_mode_offset (GstWlWindow * window, guint x,
+    guint y, guint w, guint h)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  GST_LOG ("set offset x@%d, y@%d", x, y);
+  window->mode_offset.x = x;
+  window->mode_offset.y = y;
+  window->mode_offset.w = w;
+  window->mode_offset.h = h;
+  window->mode_offset.changed = TRUE;
+}
+
+void
+gst_wl_window_set_destination_mode_ratio (GstWlWindow * window, gdouble w,
+    gdouble h)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  GST_LOG ("set ratio w@%f, h@%f", w, h);
+  window->mode_ratio.w = w;
+  window->mode_ratio.h = h;
+  window->mode_ratio.changed = TRUE;
+}
+
+void
+gst_wl_window_set_destination_mode_scale (GstWlWindow * window, gdouble w,
+    gdouble h)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  GST_LOG ("set scale w@%f, h@%f", w, h);
+  window->mode_scale.w = w;
+  window->mode_scale.h = h;
+  window->mode_scale.changed = TRUE;
+}
+
+void
+gst_wl_window_set_destination_mode_align (GstWlWindow * window, gdouble w,
+    gdouble h)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  GST_LOG ("set align w@%f, h@%f", w, h);
+  window->mode_align.w = w;
+  window->mode_align.h = h;
+  window->mode_align.changed = TRUE;
+}
+#endif
+void
+gst_wl_window_set_video_info_change (GstWlWindow * window, guint changed)
+{
+  FUNCTION;
+  g_return_if_fail (window != NULL);
+  window->video_info_changed = changed;
+  GST_LOG ("video_info_changed value is (%d)", window->video_info_changed);
+}
+#endif
diff --git a/tizenwlsink/src/wlwindow.h b/tizenwlsink/src/wlwindow.h
new file mode 100644 (file)
index 0000000..6f5397d
--- /dev/null
@@ -0,0 +1,167 @@
+/* GStreamer Wayland video sink
+ *
+ * Copyright (C) 2014 Collabora Ltd.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GST_WL_WINDOW_H__
+#define __GST_WL_WINDOW_H__
+
+#include "wldisplay.h"
+#include "wlbuffer.h"
+#include <gst/video/video.h>
+
+G_BEGIN_DECLS
+#define GST_TYPE_WL_WINDOW                  (gst_wl_window_get_type ())
+#define GST_WL_WINDOW(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_WINDOW, GstWlWindow))
+#define GST_IS_WL_WINDOW(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_WINDOW))
+#define GST_WL_WINDOW_CLASS(klass)          (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_WINDOW, GstWlWindowClass))
+#define GST_IS_WL_WINDOW_CLASS(klass)       (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_WINDOW))
+#define GST_WL_WINDOW_GET_CLASS(obj)        (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_WINDOW, GstWlWindowClass))
+
+enum
+{
+  DEGREE_0,
+  DEGREE_90,
+  DEGREE_180,
+  DEGREE_270,
+  DEGREE_NUM,
+};
+
+enum
+{
+  FLIP_NONE = 0,
+  FLIP_HORIZONTAL,
+  FLIP_VERTICAL,
+  FLIP_BOTH,
+  FLIP_NUM,
+};
+
+typedef struct
+{
+  guint value;
+  gboolean changed;
+} WinGeometryValue;
+
+typedef struct
+{
+  guint x;
+  guint y;
+  guint w;
+  guint h;
+  gboolean changed;
+} WinGeometryRect;
+
+typedef struct
+{
+  gdouble w;
+  gdouble h;
+  gboolean changed;
+} WinGeometryRange;
+
+typedef struct _GstWlWindow GstWlWindow;
+typedef struct _GstWlWindowClass GstWlWindowClass;
+
+struct _GstWlWindow
+{
+  GObject parent_instance;
+
+  GstWlDisplay *display;
+  struct wl_surface *area_surface;
+  struct wl_subsurface *area_subsurface;
+  struct wl_surface *video_surface;
+  struct wl_subsurface *video_subsurface;
+  struct wl_shell_surface *shell_surface;
+#ifndef TIZEN_FEATURE_WLSINK_ENHANCEMENT  /* no define */
+  struct wl_viewport *video_viewport;
+  struct wl_viewport *area_viewport;
+#else
+  struct tizen_video_object *video_object;
+  struct tizen_viewport *tizen_area_viewport;
+  struct tizen_viewport *tizen_video_viewport;
+  struct tizen_destination_mode *tizen_video_dest_mode;
+  struct tizen_destination_mode *tizen_area_dest_mode;
+  guint video_info_changed;
+/*Display geometry method */
+  guint buffer_width, buffer_height;
+  guint buffer_x, buffer_y;
+  WinGeometryValue disp_geo_method;
+  WinGeometryValue rotate_angle;
+  WinGeometryValue flip;
+  WinGeometryRect mode_crop;
+#ifdef ENABLE_FUNCTION
+  WinGeometryValue follow_parent_transform;
+  WinGeometryRect mode_offset;
+  WinGeometryRange mode_ratio;
+  WinGeometryRange mode_scale;
+  WinGeometryRange mode_align;
+#endif
+  GstVideoRectangle roi;
+  gboolean roi_area_changed;
+#endif
+
+  /* the size and position of the area_(sub)surface */
+  GstVideoRectangle render_rectangle;
+  /* the size of the video in the buffers */
+  gint video_width, video_height;
+  /* the size of the video_(sub)surface */
+  gint surface_width, surface_height;
+};
+
+struct _GstWlWindowClass
+{
+  GObjectClass parent_class;
+};
+
+GType gst_wl_window_get_type (void);
+
+GstWlWindow *gst_wl_window_new_toplevel (GstWlDisplay * display,
+    const GstVideoInfo * info);
+GstWlWindow *gst_wl_window_new_in_surface (GstWlDisplay * display,
+    struct wl_surface *parent);
+
+GstWlDisplay *gst_wl_window_get_display (GstWlWindow * window);
+struct wl_surface *gst_wl_window_get_wl_surface (GstWlWindow * window);
+gboolean gst_wl_window_is_toplevel (GstWlWindow * window);
+
+void gst_wl_window_render (GstWlWindow * window, GstWlBuffer * buffer,
+    const GstVideoInfo * info);
+#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT
+gboolean gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
+    gint w, gint h);
+void gst_wl_window_set_video_info (GstWlWindow * window,
+    const GstVideoInfo * info);
+void gst_wl_window_set_rotate_angle (GstWlWindow * window, guint rotate_angle);
+void gst_wl_window_set_flip (GstWlWindow * window, guint flip);
+void gst_wl_window_set_destination_mode_crop_wl_buffer (GstWlWindow * window, guint x, guint y, guint w, guint h);
+void gst_wl_window_set_destination_mode (GstWlWindow * window, guint disp_geo_method);
+#ifdef ENABLE_FUNCTION
+/* if video mode is set, below function can use */
+void gst_wl_window_set_destination_mode_follow_parent_transform (GstWlWindow * window, gboolean follow_parent_transform);
+void gst_wl_window_set_destination_mode_offset (GstWlWindow * window, guint x, guint y, guint w, guint h);
+void gst_wl_window_set_destination_mode_ratio (GstWlWindow * window, gdouble w, gdouble h);
+void gst_wl_window_set_destination_mode_scale (GstWlWindow * window, gdouble w, gdouble h);
+void gst_wl_window_set_destination_mode_align (GstWlWindow * window, gdouble w, gdouble h);
+#endif
+void gst_wl_window_set_video_info_change (GstWlWindow * window, guint changed);
+#else
+void gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
+    gint w, gint h);
+#endif
+
+G_END_DECLS
+#endif /* __GST_WL_WINDOW_H__ */