add temp waylandsink for 1.6.1 and drmdecryptor 18/52718/2 submit/tizen/20151127.020604 submit/tizen/20151127.065352
authorEunhae Choi <eunhae1.choi@samsung.com>
Thu, 26 Nov 2015 07:11:07 +0000 (16:11 +0900)
committerEunhae Choi <eunhae1.choi@samsung.com>
Thu, 26 Nov 2015 07:26:06 +0000 (16:26 +0900)
Change-Id: I5717632b04e687fe188c1aaa776dc4e0e6f292bb

22 files changed:
Makefile.am
configure.ac
drmdecryptor/Makefile.am [new file with mode: 0644]
drmdecryptor/src/Makefile.am [new file with mode: 0644]
drmdecryptor/src/gstdrmdecryptor.c [new file with mode: 0644]
drmdecryptor/src/gstdrmdecryptor.h [new file with mode: 0644]
packaging/gst-plugins-tizen.spec
waylandsink/Makefile.am [new file with mode: 0644]
waylandsink/src/Makefile.am [new file with mode: 0644]
waylandsink/src/gstwaylandsink.c [new file with mode: 0644]
waylandsink/src/gstwaylandsink.h [new file with mode: 0644]
waylandsink/src/scaler.xml [new file with mode: 0644]
waylandsink/src/tizen-wlvideoformat.c [new file with mode: 0644]
waylandsink/src/tizen-wlvideoformat.h [new file with mode: 0644]
waylandsink/src/waylandpool.c [new file with mode: 0644]
waylandsink/src/waylandpool.h [new file with mode: 0644]
waylandsink/src/wldisplay.c [new file with mode: 0644]
waylandsink/src/wldisplay.h [new file with mode: 0644]
waylandsink/src/wlvideoformat.c [new file with mode: 0644]
waylandsink/src/wlvideoformat.h [new file with mode: 0644]
waylandsink/src/wlwindow.c [new file with mode: 0644]
waylandsink/src/wlwindow.h [new file with mode: 0644]

index 2b9ad84..d47c423 100644 (file)
@@ -57,6 +57,14 @@ if GST_TIZEN_USE_WAYLANDSRC
 SUBDIRS += waylandsrc
 endif
 
+if GST_TIZEN_USE_DRMDECRYPTOR
+SUBDIRS += drmdecryptor
+endif
+
+if GST_TIZEN_USE_WAYLANDSINK
+SUBDIRS += waylandsink
+endif
+
 DIST_SUBDIRS = common
 
 if GST_TIZEN_USE_ENCODEBIN
@@ -96,6 +104,14 @@ if GST_TIZEN_USE_WAYLANDSRC
 DIST_SUBDIRS += waylandsrc
 endif
 
+if GST_TIZEN_USE_DRMDECRYPTOR
+DIST_SUBDIRS += drmdecryptor
+endif
+
+if GST_TIZEN_USE_WAYLANDSINK
+DIST_SUBDIRS += waylandsink
+endif
+
 EXTRA_DIST = \
        gstreamer.spec gstreamer.spec.in \
        configure.ac autogen.sh depcomp \
index ade2163..1425242 100644 (file)
@@ -1,6 +1,6 @@
 
 AC_INIT(gst-plugins-tizen, 1.0)
+
 dnl versions of gstreamer and plugins-base
 GST_MAJORMINOR=1.0
 GST_REQUIRED=1.2.0
@@ -39,10 +39,10 @@ AC_PROG_LIBTOOL
 
 dnl decide on error flags
 AS_COMPILER_FLAG(-Wall, GST_WALL="yes", GST_WALL="no")
-                                                                                
+
 if test "x$GST_WALL" = "xyes"; then
    GST_ERROR="$GST_ERROR -Wall"
-                                                                                
+
 #   if test "x$GST_PLUGIN_CVS" = "xyes"; then
 #     AS_COMPILER_FLAG(-Werror,GST_ERROR="$GST_ERROR -Werror",GST_ERROR="$GST_ERROR")
 #   fi
@@ -466,6 +466,38 @@ AC_SUBST(WAYLAND_CLIENT_CFLAGS)
 AC_SUBST(WAYLAND_CLIENT_LIBS)
 fi
 
+dnl use drmdecryptor --------------------------------------------------------------------------
+AC_ARG_ENABLE(drmdecryptor, AC_HELP_STRING([--enable-drmdecryptor], [using drmdecryptor]),
+[
+ case "${enableval}" in
+  yes) GST_TIZEN_USE_DRMDECRYPTOR=yes ;;
+  no)  GST_TIZEN_USE_DRMDECRYPTOR=no ;;
+  *)   AC_MSG_ERROR(bad value ${enableval} for --enable-drmdecryptor) ;;
+ esac
+ ],
+ [GST_TIZEN_USE_DRMDECRYPTOR=yes])
+AM_CONDITIONAL(GST_TIZEN_USE_DRMDECRYPTOR, test "x$GST_TIZEN_USE_DRMDECRYPTOR" = "xyes")
+
+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(GST_WAYLAND, gstreamer-wayland-1.0 >= 1.2.0)
+AC_SUBST(GST_WAYLAND_CFLAGS)
+AC_SUBST(GST_WAYLAND_LIBS)
+
+PKG_CHECK_MODULES(WAYLAND, wayland-client >= 1.4.0 wayland-tbm-client tizen-extension-client wayland-scanner)
+AC_PATH_PROG([wayland_scanner], [wayland-scanner])
+fi
+
 AC_OUTPUT(
 Makefile
 common/Makefile
@@ -494,4 +526,8 @@ wfdmanager/wfdbase/Makefile
 wfdtsdemux/Makefile
 waylandsrc/Makefile
 waylandsrc/src/Makefile
+drmdecryptor/Makefile
+drmdecryptor/src/Makefile
+waylandsink/Makefile
+waylandsink/src/Makefile
 )
diff --git a/drmdecryptor/Makefile.am b/drmdecryptor/Makefile.am
new file mode 100644 (file)
index 0000000..308a09c
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src\r
diff --git a/drmdecryptor/src/Makefile.am b/drmdecryptor/src/Makefile.am
new file mode 100644 (file)
index 0000000..24d47ec
--- /dev/null
@@ -0,0 +1,16 @@
+plugin_LTLIBRARIES = libgstdrmdecryptor.la
+
+libgstdrmdecryptor_la_SOURCES =        gstdrmdecryptor.c
+
+libgstdrmdecryptor_la_CFLAGS = \
+       $(GST_PLUGINS_BASE_CFLAGS) \
+       $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstdrmdecryptor_la_LIBADD = \
+       $(GST_PLUGINS_BASE_LIBS) \
+       $(GST_BASE_LIBS) \
+       $(GST_LIBS)
+libgstdrmdecryptor_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgstdrmdecryptor_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = gstdrmdecryptor.h
+
diff --git a/drmdecryptor/src/gstdrmdecryptor.c b/drmdecryptor/src/gstdrmdecryptor.c
new file mode 100644 (file)
index 0000000..7f0ef2f
--- /dev/null
@@ -0,0 +1,350 @@
+/*\r
+ * drmdecryptor\r
+ *\r
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.\r
+ *\r
+ * This library is free software; you can redistribute it and/or modify it under\r
+ * the terms of the GNU Lesser General Public License as published by the\r
+ * Free Software Foundation; either version 2.1 of the License, or (at your option)\r
+ * any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY\r
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public\r
+ * License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with this library; if not, write to the Free Software Foundation, Inc., 51\r
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+ *\r
+ */\r
+#ifdef HAVE_CONFIG_H\r
+#include <config.h>\r
+#endif\r
+\r
+#include <gst/gst.h>\r
+#include <gst/gstelement.h>\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+#include <memory.h>\r
+\r
+#include "gstdrmdecryptor.h"\r
+\r
+/* TODO replace with input caps */\r
+#define GST_STATIC_CAPS_SINK GST_STATIC_CAPS("application/encrypted-xxx")\r
+\r
+static GstStaticPadTemplate sinktemplate =\r
+    GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, GST_PAD_ALWAYS,\r
+    GST_STATIC_CAPS_SINK);\r
+\r
+static GstStaticPadTemplate srctemplate =\r
+    GST_STATIC_PAD_TEMPLATE ("src", GST_PAD_SRC, GST_PAD_ALWAYS,\r
+    GST_STATIC_CAPS_ANY);\r
+\r
+GST_DEBUG_CATEGORY_STATIC (gst_drm_decryptor_debug);\r
+#define GST_CAT_DEFAULT gst_drm_decryptor_debug\r
+static void\r
+_do_init (void)\r
+{\r
+  /* TODO change to the debug category of your element */\r
+  GST_DEBUG_CATEGORY_INIT (gst_drm_decryptor_debug, "DrmDecryptor", 0,\r
+      "DrmDecryptor element");\r
+}\r
+\r
+static gboolean\r
+drmdecryptor_init (GstPlugin * drm)\r
+{\r
+  /* TODO change to the name of your element */\r
+  return gst_element_register (drm, "drm_decryptor", GST_RANK_PRIMARY,\r
+      GST_DRM_DECRYPTOR_TYPE);\r
+}\r
+\r
+#define gst_drm_decryptor_parent_class parent_class\r
+G_DEFINE_TYPE_WITH_CODE (GstDrmDecryptor, gst_drm_decryptor, GST_TYPE_ELEMENT,\r
+    _do_init ());\r
+\r
+\r
+static gboolean gst_drm_decryptor_handle_sink_event (GstPad * pad, GstObject * parent,\r
+    GstEvent * event);\r
+static GstStateChangeReturn gst_drm_decryptor_change_state (GstElement * element,\r
+    GstStateChange transition);\r
+\r
+static void gst_drm_decryptor_set_property (GObject * object, guint prop_id,\r
+    const GValue * value, GParamSpec * pspec);\r
+static void gst_drm_decryptor_get_property (GObject * object, guint prop_id,\r
+    GValue * value, GParamSpec * pspec);\r
+static void gst_drm_decryptor_finalize (GObject * object);\r
+\r
+static GstFlowReturn gst_drm_decryptor_chain (GstPad * pad, GstObject * parent, GstBuffer * buffer);\r
+\r
+static void\r
+gst_drm_decryptor_class_init (GstDrmDecryptorClass * klass)\r
+{\r
+  GObjectClass *gobject_class;\r
+  GstElementClass *gstelement_class;\r
+  gobject_class = (GObjectClass *) klass;\r
+  gstelement_class = (GstElementClass *) klass;\r
+\r
+  gst_element_class_add_pad_template (gstelement_class,\r
+      gst_static_pad_template_get (&sinktemplate));\r
+  gst_element_class_add_pad_template (gstelement_class,\r
+      gst_static_pad_template_get (&srctemplate));\r
+\r
+  gstelement_class->change_state =\r
+      GST_DEBUG_FUNCPTR (gst_drm_decryptor_change_state);\r
+\r
+  gobject_class->finalize = gst_drm_decryptor_finalize;\r
+  gobject_class->set_property = gst_drm_decryptor_set_property;\r
+  gobject_class->get_property = gst_drm_decryptor_get_property;\r
+\r
+  /* TODO install any needed properties */\r
+\r
+  gst_element_class_set_static_metadata (gstelement_class,\r
+      "drm decryptor template plugin",\r
+      "DRM/Decryptor", "Decryption Plugin", "xxx@samsung.com>");\r
+}\r
+\r
+static void\r
+gst_drm_decryptor_init (GstDrmDecryptor * drm)\r
+{\r
+  drm->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");\r
+  drm->srcpad = gst_pad_new_from_static_template (&srctemplate, "src");\r
+  gst_pad_set_chain_function (drm->sinkpad, gst_drm_decryptor_chain);\r
+  gst_pad_set_event_function (drm->sinkpad, gst_drm_decryptor_handle_sink_event);\r
+  gst_pad_set_active (drm->sinkpad, TRUE);\r
+  gst_pad_set_active (drm->srcpad, TRUE);\r
+  GST_PAD_SET_ACCEPT_TEMPLATE (drm->sinkpad);\r
+  gst_element_add_pad (GST_ELEMENT (drm), drm->sinkpad);\r
+  gst_element_add_pad (GST_ELEMENT (drm), drm->srcpad);\r
+\r
+  /* TODO initialize your element's data */\r
+}\r
+\r
+static gboolean\r
+gst_drm_decryptor_set_format (GstDrmDecryptor * drm, const GstCaps * caps)\r
+{\r
+  GstCaps *output_caps;\r
+  const GstStructure *structure;\r
+  const gchar *original_type;\r
+  gboolean ret;\r
+\r
+  structure = gst_caps_get_structure (caps, 0);\r
+\r
+  /* It is also possible that we store a full caps inside the caps, in this\r
+   * case, it would be better to name it 'original-media-caps' */\r
+  original_type = gst_structure_get_string (structure, "original-media-type");\r
+\r
+  /* TODO get any other needed parameter from caps */\r
+\r
+  /* TODO If possible, set the output caps */\r
+  output_caps = gst_caps_new_simple (original_type, NULL);\r
+\r
+  ret = gst_pad_set_caps (drm->srcpad, output_caps);\r
+  gst_caps_unref (output_caps);\r
+\r
+  return ret;\r
+}\r
+\r
+static void\r
+gst_drm_decryptor_set_property (GObject * object, guint prop_id,\r
+    const GValue * value, GParamSpec * pspec)\r
+{\r
+  switch (prop_id) {\r
+    /* TODO fill with properties */\r
+    default:\r
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);\r
+      break;\r
+  }\r
+}\r
+\r
+static void\r
+gst_drm_decryptor_get_property (GObject * object, guint prop_id, GValue * value,\r
+    GParamSpec * pspec)\r
+{\r
+  switch (prop_id) {\r
+    /* TODO fill with properties */\r
+    default:\r
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);\r
+      break;\r
+  }\r
+}\r
+\r
+static gboolean\r
+gst_drm_decryptor_open (GstDrmDecryptor * drm)\r
+{\r
+  /* TODO Open any resources / library that your element requires\r
+   * If none is needed, just leave this as blank or remove this function */\r
+}\r
+\r
+static void\r
+gst_drm_decryptor_close (GstDrmDecryptor * drm)\r
+{\r
+  /* TODO close resources / library\r
+   * (should be symetrical to _open() */\r
+}\r
+\r
+static gboolean\r
+gst_drm_decryptor_start (GstDrmDecryptor * drm)\r
+{\r
+  /* TODO Start your decryption engine, after this call it must be ready\r
+   * for keys configuration and starting to decrypt. */\r
+}\r
+\r
+static void\r
+gst_drm_decryptor_stop (GstDrmDecryptor * drm)\r
+{\r
+  /* TODO Stop the decryption engine (symetrical to _start()) */\r
+}\r
+\r
+static GstStateChangeReturn\r
+gst_drm_decryptor_change_state (GstElement * element, GstStateChange transition)\r
+{\r
+  GstDrmDecryptor *drm = (GstDrmDecryptor *) element;\r
+  GstStateChangeReturn result = GST_STATE_CHANGE_FAILURE;\r
+\r
+  switch (transition) {\r
+    case GST_STATE_CHANGE_NULL_TO_READY:\r
+      if (!gst_drm_decryptor_open (drm))\r
+        result = GST_STATE_CHANGE_FAILURE;\r
+      break;\r
+    case GST_STATE_CHANGE_READY_TO_PAUSED:\r
+      if (!gst_drm_decryptor_start (drm))\r
+        result = GST_STATE_CHANGE_FAILURE;\r
+      break;\r
+    default:\r
+      break;\r
+  }\r
+  if (result == GST_STATE_CHANGE_FAILURE)\r
+    return result;\r
+\r
+  result = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);\r
+  if (result == GST_STATE_CHANGE_FAILURE)\r
+    return result;\r
+\r
+  switch (transition) {\r
+    case GST_STATE_CHANGE_READY_TO_NULL:\r
+      gst_drm_decryptor_close (drm);\r
+      break;\r
+    case GST_STATE_CHANGE_PAUSED_TO_READY:\r
+      gst_drm_decryptor_stop (drm);\r
+      break;\r
+  }\r
+\r
+  return result;\r
+}\r
+\r
+static gboolean\r
+gst_drm_decryptor_finish (GstDrmDecryptor * drm)\r
+{\r
+  /* TODO finish decryption of any pending data and push it downstream */\r
+  return TRUE;\r
+}\r
+\r
+static void\r
+gst_drm_decryptor_flush (GstDrmDecryptor * drm)\r
+{\r
+ /* TODO Flush any data in the decryptor */\r
+}\r
+\r
+static gboolean\r
+gst_drm_decryptor_handle_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)\r
+{\r
+  GstDrmDecryptor *drm;\r
+  gboolean ret = TRUE;\r
+\r
+  drm = GST_DRM_DECRYPTOR (parent);\r
+\r
+  switch (GST_EVENT_TYPE (event)) {\r
+    case GST_EVENT_PROTECTION:\r
+    {\r
+      const gchar *system_id;\r
+      GstBuffer *data;\r
+      const gchar *origin;\r
+\r
+      gst_event_parse_protection (event, &system_id, &data, &origin);\r
+\r
+      /* TODO the protection event contains the keys for decryption that\r
+       * upstream elements might have found\r
+       *\r
+       * The system_id contains information about the type of encryption\r
+       * data contains binary data needed for decryption (e.g. keys)\r
+       * origin is a string describing where this data was found (e.g. mpd,\r
+       * playlist, container ...)\r
+       *\r
+       * This data should be used as parameters for the decryptor\r
+       *\r
+       * In some situations multiple keys are needed, like AES128 that needs\r
+       * the IV and the key. Multiple protection events can be used to signal\r
+       * different decryption configuration parameters. It might also\r
+       * be possible to extend the protection event to hold a structure to\r
+       * contain all needed configuration in a single event but this is not\r
+       * yet implemented.\r
+       *\r
+       * For now, one could (ab)use system_id to be AES128:key and AES128:IV\r
+       * in 2 separate events to signal the parameters.\r
+       */\r
+      break;\r
+    }\r
+    case GST_EVENT_CAPS:\r
+    {\r
+      GstCaps *caps;\r
+      gst_event_parse_caps (event, &caps);\r
+      ret = gst_drm_decryptor_set_format (drm, caps);\r
+      break;\r
+    }\r
+    case GST_EVENT_EOS:\r
+    {\r
+      gst_drm_decryptor_finish (drm);\r
+      ret = gst_pad_push_event (drm->srcpad, event);\r
+      break;\r
+    }\r
+    case GST_EVENT_FLUSH_STOP:\r
+    {\r
+      gst_drm_decryptor_flush (drm);\r
+      ret = gst_pad_push_event (drm->srcpad, event);\r
+      break;\r
+    }\r
+    default:\r
+    {\r
+      ret = gst_pad_event_default (drm->sinkpad, parent, event);\r
+      break;\r
+    }\r
+  }\r
+\r
+  return ret;\r
+}\r
+\r
+static GstFlowReturn\r
+gst_drm_decryptor_chain (GstPad * pad, GstObject * parent, GstBuffer * buf)\r
+{\r
+  GstDrmDecryptor *drm;\r
+  GstBuffer *out_buf = NULL;\r
+\r
+  drm = GST_DRM_DECRYPTOR (parent);\r
+\r
+  /* TODO do your decryption that will create output data into\r
+   * out_buf */\r
+\r
+  /* TODO it might be required to signal per-buffer decryption information.\r
+   * For this purpose, the protection meta can be used and attached to buffers.\r
+   * If your element supports this, it can do:\r
+   *\r
+   * protection_meta = gst_buffer_get_meta (buf, GST_PROTECTION_META_INFO);\r
+   *\r
+   * The protection meta has a structure containing cryptographic parameters\r
+   * for this buffer\r
+   */\r
+\r
+  return gst_pad_push (drm->srcpad, out_buf);\r
+\r
+}\r
+\r
+static void\r
+gst_drm_decryptor_finalize (GObject * object)\r
+{\r
+  /* TODO final instance cleanup */\r
+}\r
+\r
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, GST_VERSION_MINOR, "drmdecryptordecrypt",\r
+    "Gstreamer DrmDecryptor plugin", drmdecryptor_init, VERSION, "Some License",\r
+    "gst-plugins-drmdecryptor", "Unknown package origin")\r
diff --git a/drmdecryptor/src/gstdrmdecryptor.h b/drmdecryptor/src/gstdrmdecryptor.h
new file mode 100644 (file)
index 0000000..4b87b8e
--- /dev/null
@@ -0,0 +1,66 @@
+/*\r
+ * drmdecryptor\r
+ *\r
+ * Copyright (c) 2012 Samsung Electronics Co., Ltd. All rights reserved.\r
+ *\r
+ * This library is free software; you can redistribute it and/or modify it under\r
+ * the terms of the GNU Lesser General Public License as published by the\r
+ * Free Software Foundation; either version 2.1 of the License, or (at your option)\r
+ * any later version.\r
+ *\r
+ * This library is distributed in the hope that it will be useful, but WITHOUT ANY\r
+ * WARRANTY; without even the implied warranty of MERCHANTABILITY or\r
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public\r
+ * License for more details.\r
+ *\r
+ * You should have received a copy of the GNU Lesser General Public License\r
+ * along with this library; if not, write to the Free Software Foundation, Inc., 51\r
+ * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA\r
+ *\r
+ */\r
+#ifndef __GST_DRM_DECRYPTOR_H__\r
+#define __GST_DRM_DECRYPTOR_H__\r
+\r
+#define VERSION "1.0"\r
+#ifdef PACKAGE\r
+#undef PACKAGE\r
+#endif\r
+#define PACKAGE "gstplugindrmdecryptor"\r
+#include <gst/gst.h>\r
+#include <gst/gstelement.h>\r
+#include <glib.h>\r
+\r
+G_BEGIN_DECLS\r
+\r
+#define GST_DRM_DECRYPTOR(obj) (GstDrmDecryptor *) (obj)\r
+#define GST_DRM_DECRYPTOR_TYPE (gst_drm_decryptor_get_type ())\r
+\r
+typedef struct _GstDrmDecryptor GstDrmDecryptor;\r
+typedef struct _GstDrmDecryptorClass GstDrmDecryptorClass;\r
+\r
+enum\r
+{\r
+  PROP_0,\r
+};\r
+\r
+struct _GstDrmDecryptor\r
+{\r
+  GstElement     element;\r
+  GstPad        *sinkpad;\r
+  GstPad        *srcpad;\r
+\r
+  /*< private >*/\r
+  /* TODO add your private data here */\r
+};\r
+\r
+struct _GstDrmDecryptorClass\r
+{\r
+  GstElementClass parent_class;\r
+};\r
+\r
+GType gst_drm_decryptor_get_type (void);\r
+\r
+G_END_DECLS\r
+\r
+#endif /* __GST_DRM_DECRYPTOR_H__ */\r
+\r
index fdfcabb..78c54e6 100644 (file)
@@ -1,10 +1,11 @@
+%bcond_with wayland
 %bcond_with x
 %define gst_branch 1.0
 
 Name:       gst-plugins-tizen
 Version:    1.0.0
 Summary:    GStreamer tizen plugins (common)
-Release:    17
+Release:    18
 Group:      Multimedia/Framework
 Url:        http://gstreamer.freedesktop.org/
 License:    LGPL-2.1+ and Apache-2.0
@@ -27,10 +28,6 @@ BuildRequires:       pkgconfig(xv)
 BuildRequires: pkgconfig(xdamage)
 BuildRequires: pkgconfig(xfixes)
 BuildRequires: pkgconfig(dri2proto)
-%else
-BuildRequires: pkgconfig(wayland-client)
-BuildRequires: pkgconfig(wayland-tbm-client)
-BuildRequires: pkgconfig(tizen-extension-client)
 %endif
 BuildRequires: pkgconfig(libdrm)
 BuildRequires: pkgconfig(libdrm_exynos)
@@ -38,6 +35,12 @@ BuildRequires:  pkgconfig(libtbm)
 BuildRequires: libdrm-devel
 BuildRequires:  pkgconfig(vconf)
 BuildRequires:  pkgconfig(mm-common)
+%if %{with wayland}
+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
 GStreamer tizen plugins (common)
@@ -47,15 +50,17 @@ GStreamer tizen plugins (common)
 
 
 %build
-export CFLAGS+=" -DGST_EXT_TIME_ANALYSIS -DGST_EXT_XV_ENHANCEMENT -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" "
+export CFLAGS+=" -DGST_EXT_TIME_ANALYSIS -DGST_EXT_XV_ENHANCEMENT -DGST_WLSINK_ENHANCEMENT -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" "
 
 ./autogen.sh --disable-static
 %configure \
 %if %{with x}
        --disable-waylandsrc\
+       --disable-waylandsink\
 %else
        --disable-xvimagesrc\
 %endif
+       --disable-drmdecryptor\
        --disable-static
 
 make %{?jobs:-j%jobs}
diff --git a/waylandsink/Makefile.am b/waylandsink/Makefile.am
new file mode 100644 (file)
index 0000000..af437a6
--- /dev/null
@@ -0,0 +1 @@
+SUBDIRS = src
diff --git a/waylandsink/src/Makefile.am b/waylandsink/src/Makefile.am
new file mode 100644 (file)
index 0000000..9099bca
--- /dev/null
@@ -0,0 +1,46 @@
+plugin_LTLIBRARIES = libgsttizenwlsink.la
+
+libgsttizenwlsink_la_SOURCES =  \
+       gstwaylandsink.c \
+       waylandpool.c \
+       wldisplay.c \
+       wlwindow.c \
+       wlvideoformat.c \
+       scaler-protocol.c \
+       tizen-wlvideoformat.c
+
+libgsttizenwlsink_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) \
+                               $(WAYLAND_CFLAGS) $(GST_PLUGINS_BAD_CFLAGS) $(DRM_CFLAGS) $(TBM_CFLAGS) $(MMCOMMON_CFLAGS) \
+                                                          $(GST_WAYLAND_CFLAGS)
+libgsttizenwlsink_la_LIBADD = \
+       $(GST_PLUGINS_BASE_LIBS) \
+       -lgstvideo-$(GST_MAJORMINOR) \
+       $(WAYLAND_LIBS) $(DRM_LIBS) $(TBM_LIBS) $(GST_WAYLAND_LIBS)
+libgsttizenwlsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
+libgsttizenwlsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS)
+
+noinst_HEADERS = \
+       gstwaylandsink.h \
+       waylandpool.h \
+       wldisplay.h \
+       wlwindow.h \
+       wlvideoformat.h \
+       scaler-client-protocol.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
+
+waylandpool.c: scaler-client-protocol.h
+
+wldisplay.c: scaler-client-protocol.h
+
+wlwindow.c: scaler-client-protocol.h
diff --git a/waylandsink/src/gstwaylandsink.c b/waylandsink/src/gstwaylandsink.c
new file mode 100644 (file)
index 0000000..dd6788a
--- /dev/null
@@ -0,0 +1,1371 @@
+/* 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 GST_WLSINK_ENHANCEMENT
+#include <mm_types.h>
+#include "tizen-wlvideoformat.h"
+#else
+#include "wlvideoformat.h"
+#endif
+#include "waylandpool.h"
+
+#include <gst/wayland/wayland.h>
+#include <gst/video/videooverlay.h>
+
+#ifdef GST_WLSINK_ENHANCEMENT
+#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, 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,
+  LAST_SIGNAL
+};
+
+/* Properties */
+enum
+{
+  PROP_0,
+  PROP_DISPLAY,
+#ifdef GST_WLSINK_ENHANCEMENT
+  PROP_ROTATE_ANGLE,
+  PROP_DISPLAY_GEOMETRY_METHOD,
+  PROP_ORIENTATION,
+  PROP_FLIP
+#endif
+};
+
+GST_DEBUG_CATEGORY (gsttizenwl_debug);
+#define GST_CAT_DEFAULT gsttizenwl_debug
+
+static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
+    GST_PAD_SINK,
+    GST_PAD_ALWAYS,
+    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, "
+#ifdef GST_WLSINK_ENHANCEMENT
+            "SN12, ST12, "
+#endif
+            "YUV9, YVU9, Y41B, I420, YV12, Y42B, v308 }"))
+    );
+
+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 void gst_wayland_sink_set_context (GstElement * element,
+    GstContext * context);
+
+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_render_rectangle (GstVideoOverlay * overlay,
+    gint x, gint y, gint w, gint h);
+static void gst_wayland_sink_expose (GstVideoOverlay * overlay);
+
+/* WaylandVideo interface */
+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);
+#ifdef GST_WLSINK_ENHANCEMENT
+static void gst_wayland_sink_update_window_geometry (GstTizenwlSink * sink);
+static void render_last_buffer (GstTizenwlSink * sink);
+static void gst_wayland_sink_render_last_buffer (GstTizenwlSink * sink);
+
+#endif
+
+#define gst_wayland_sink_parent_class parent_class
+G_DEFINE_TYPE_WITH_CODE (GstTizenwlSink, gst_wayland_sink, GST_TYPE_VIDEO_SINK,
+    G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY,
+        gst_wayland_sink_videooverlay_init)
+    G_IMPLEMENT_INTERFACE (GST_TYPE_WAYLAND_VIDEO,
+        gst_wayland_sink_waylandvideo_init));
+
+static void
+gst_wayland_sink_class_init (GstTizenwlSinkClass * klass)
+{
+  FUNCTION_ENTER ();
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstBaseSinkClass *gstbasesink_class;
+
+  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",
+      "Sreerenj Balachandran <sreerenj.balachandran@intel.com>, "
+      "George Kiagiadakis <george.kiagiadakis@collabora.com>");
+
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_wayland_sink_change_state);
+  gstelement_class->set_context =
+      GST_DEBUG_FUNCPTR (gst_wayland_sink_set_context);
+
+  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);
+
+  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 GST_WLSINK_ENHANCEMENT
+  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_ORIENTATION,
+      g_param_spec_enum ("orientation",
+          "Orientation information used for ROI/ZOOM",
+          "Orientation information for display",
+          GST_TYPE_WAYLANDSINK_ROTATE_ANGLE, DEGREE_0,
+          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));
+
+#endif
+}
+
+static void
+gst_wayland_sink_init (GstTizenwlSink * sink)
+{
+  FUNCTION_ENTER ();
+
+  sink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD;
+  sink->flip = DEF_DISPLAY_FLIP;
+  sink->rotate_angle = DEGREE_0;
+  sink->orientation = DEGREE_0;
+
+  g_mutex_init (&sink->display_lock);
+  g_mutex_init (&sink->render_lock);
+}
+
+static void
+gst_wayland_sink_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (object);
+  switch (prop_id) {
+    case PROP_DISPLAY:
+      GST_OBJECT_LOCK (sink);
+      g_value_set_string (value, sink->display_name);
+      GST_OBJECT_UNLOCK (sink);
+      break;
+#ifdef GST_WLSINK_ENHANCEMENT
+    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_ORIENTATION:
+      g_value_set_enum (value, sink->orientation);
+      break;
+    case PROP_FLIP:
+      g_value_set_enum (value, sink->flip);
+      break;
+#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)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (object);
+  switch (prop_id) {
+    case PROP_DISPLAY:
+      GST_OBJECT_LOCK (sink);
+      sink->display_name = g_value_dup_string (value);
+      GST_OBJECT_UNLOCK (sink);
+      break;
+#ifdef GST_WLSINK_ENHANCEMENT
+    case PROP_ROTATE_ANGLE:
+      sink->rotate_angle = g_value_get_enum (value);
+      GST_INFO_OBJECT (sink, "Rotate angle is set (%d)", sink->rotate_angle);
+      if (sink->window) {
+        gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle);
+      }
+      sink->video_info_changed = TRUE;
+      if (GST_STATE (sink) == GST_STATE_PAUSED) {
+        /*need to render last buffer */
+        gst_wayland_sink_render_last_buffer (sink);
+      }
+      break;
+    case PROP_DISPLAY_GEOMETRY_METHOD:
+      sink->display_geometry_method = g_value_get_enum (value);
+      GST_INFO_OBJECT (sink, "Display geometry method is set (%d)",
+          sink->display_geometry_method);
+      if (sink->window) {
+        gst_wl_window_set_disp_geo_method (sink->window,
+            sink->display_geometry_method);
+      }
+      sink->video_info_changed = TRUE;
+      if (GST_STATE (sink) == GST_STATE_PAUSED) {
+        /*need to render last buffer */
+        gst_wayland_sink_render_last_buffer (sink);
+      }
+      break;
+    case PROP_ORIENTATION:
+      sink->orientation = g_value_get_enum (value);
+      GST_INFO_OBJECT (sink, "Orientation is set (%d)", sink->orientation);
+      if (sink->window) {
+        gst_wl_window_set_orientation (sink->window, sink->orientation);
+      }
+      sink->video_info_changed = TRUE;
+      if (GST_STATE (sink) == GST_STATE_PAUSED) {
+        /*need to render last buffer */
+        gst_wayland_sink_render_last_buffer (sink);
+      }
+      break;
+    case PROP_FLIP:
+      sink->flip = g_value_get_enum (value);
+      GST_INFO_OBJECT (sink, "flip is set (%d)", sink->flip);
+      if (sink->flip) {
+        gst_wl_window_set_flip (sink->window, sink->flip);
+      }
+      sink->video_info_changed = TRUE;
+      if (GST_STATE (sink) == GST_STATE_PAUSED) {
+        /*need to render last buffer */
+        gst_wayland_sink_render_last_buffer (sink);
+      }
+      break;
+#endif
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_wayland_sink_finalize (GObject * object)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (object);
+  GST_DEBUG_OBJECT (sink, "Finalizing the sink..");
+
+  if (sink->last_buffer)
+    gst_buffer_unref (sink->last_buffer);
+  if (sink->display) {
+    /* see comment about this call in gst_wayland_sink_change_state() */
+#ifdef GST_WLSINK_ENHANCEMENT
+    if (sink->pool && !sink->display->is_native_format)
+#else
+    if (sink->pool)
+#endif
+      gst_wayland_compositor_release_all_buffers (GST_WAYLAND_BUFFER_POOL
+          (sink->pool));
+
+    g_object_unref (sink->display);
+    sink->display = NULL;
+  }
+  if (sink->window) {
+    g_object_unref (sink->window);
+    sink->window = NULL;
+  }
+  if (sink->pool) {
+    gst_object_unref (sink->pool);
+    sink->pool = NULL;
+  }
+
+  if (sink->display_name) {
+    g_free (sink->display_name);
+    sink->display_name = NULL;
+  }
+
+  g_mutex_clear (&sink->display_lock);
+  g_mutex_clear (&sink->render_lock);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+/* must be called with the display_lock */
+static void
+gst_wayland_sink_set_display_from_context (GstTizenwlSink * sink,
+    GstContext * context)
+{
+  FUNCTION_ENTER ();
+
+  struct wl_display *display;
+  GError *error = NULL;
+
+  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);
+  }
+}
+
+static gboolean
+gst_wayland_sink_find_display (GstTizenwlSink * sink)
+{
+  FUNCTION_ENTER ();
+
+  GstQuery *query;
+  GstMessage *msg;
+  GstContext *context = NULL;
+  GError *error = NULL;
+  gboolean ret = TRUE;
+
+  g_mutex_lock (&sink->display_lock);
+
+  if (!sink->display) {
+    /* 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);
+
+    if (G_LIKELY (!sink->display)) {
+      /* 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);
+
+      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;
+        } else {
+          /* inform the world about the new display */
+          context =
+              gst_wayland_display_handle_context_new (sink->display->display);
+          msg = gst_message_new_have_context (GST_OBJECT_CAST (sink), context);
+          gst_element_post_message (GST_ELEMENT_CAST (sink), msg);
+        }
+      }
+    }
+  }
+
+  g_mutex_unlock (&sink->display_lock);
+
+  return ret;
+}
+
+static GstStateChangeReturn
+gst_wayland_sink_change_state (GstElement * element, GstStateChange transition)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (element);
+  GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
+
+  switch (transition) {
+    case GST_STATE_CHANGE_NULL_TO_READY:
+      if (!gst_wayland_sink_find_display (sink))
+        return GST_STATE_CHANGE_FAILURE;
+      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_PAUSED_TO_READY:
+      gst_buffer_replace (&sink->last_buffer, NULL);
+      if (sink->window) {
+        if (gst_wl_window_is_toplevel (sink->window)) {
+          g_clear_object (&sink->window);
+        } else {
+          /* remove buffer from surface, show nothing */
+          wl_surface_attach (sink->window->surface, NULL, 0, 0);
+          wl_surface_damage (sink->window->surface, 0, 0,
+              sink->window->surface_width, sink->window->surface_height);
+          wl_surface_commit (sink->window->surface);
+          wl_display_flush (sink->display->display);
+        }
+      }
+      break;
+    case GST_STATE_CHANGE_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 */
+        /* Force all buffers to return to the pool, regardless of
+         * whether the compositor has released them or not. We are
+         * going to kill the display, so we need to return all buffers
+         * to be destroyed before this happens.
+         * Note that this is done here instead of the pool destructor
+         * because the buffers hold a reference to the pool. Also,
+         * the buffers can only be unref'ed from the display's event loop
+         * and the pool holds a reference to the display. If we drop
+         * our references here, when the compositor releases the buffers,
+         * they will be unref'ed from the event loop thread, which will
+         * unref the pool and therefore the display, which will try to
+         * stop the thread from within itself and cause a deadlock.
+         */
+        if (sink->pool) {
+          gst_wayland_compositor_release_all_buffers (GST_WAYLAND_BUFFER_POOL
+              (sink->pool));
+        }
+        g_clear_object (&sink->display);
+        g_clear_object (&sink->pool);
+      }
+      g_mutex_unlock (&sink->display_lock);
+      break;
+    default:
+      break;
+  }
+
+  return ret;
+}
+
+static void
+gst_wayland_sink_set_context (GstElement * element, GstContext * context)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (element);
+  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");
+      g_mutex_unlock (&sink->display_lock);
+      return;
+    }
+    g_mutex_unlock (&sink->display_lock);
+  }
+
+  GST_INFO ("element %p context %p", element, context);
+  if (GST_ELEMENT_CLASS (parent_class)->set_context)
+    GST_ELEMENT_CLASS (parent_class)->set_context (element, context);
+}
+
+static GstCaps *
+gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink;
+  GstCaps *caps;
+  sink = GST_WAYLAND_SINK (bsink);
+
+  caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));
+
+  g_mutex_lock (&sink->display_lock);
+
+  if (sink->display) {
+    GValue list = G_VALUE_INIT;
+    GValue value = G_VALUE_INIT;
+    GArray *formats;
+    gint i;
+#ifdef GST_WLSINK_ENHANCEMENT
+    uint32_t fmt;
+#else
+    enum wl_shm_format fmt;
+#endif
+
+    g_value_init (&list, GST_TYPE_LIST);
+    g_value_init (&value, G_TYPE_STRING);
+
+    formats = sink->display->formats;
+    for (i = 0; i < formats->len; i++) {
+      fmt = g_array_index (formats, uint32_t, i);
+      g_value_set_string (&value, gst_wayland_format_to_string (fmt));
+      gst_value_list_append_value (&list, &value);
+#ifdef GST_WLSINK_ENHANCEMENT
+      /* TBM doesn't support SN12. So we add SN12 manually as supported format.
+       * SN12 is exactly same with NV12.
+       */
+      if (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);
+      }
+#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_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)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink;
+  GstBufferPool *newpool;
+  GstVideoInfo info;
+#ifdef GST_WLSINK_ENHANCEMENT
+  uint32_t format;
+#else
+  enum wl_shm_format format;
+#endif
+  GArray *formats;
+  gint i;
+  GstStructure *structure;
+  static GstAllocationParams params = { 0, 0, 0, 15, };
+  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 GST_WLSINK_ENHANCEMENT
+  sink->caps = gst_caps_copy (caps);
+#endif
+
+  format = gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT (&info));
+  if ((gint) format == -1)
+    goto invalid_format;
+
+  /* verify we support the requested format */
+  formats = sink->display->formats;
+  for (i = 0; i < formats->len; i++) {
+    if (g_array_index (formats, uint32_t, i) == format)
+      break;
+  }
+
+  if (i >= formats->len)
+    goto unsupported_format;
+
+#ifdef GST_WLSINK_ENHANCEMENT
+  if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 ||
+      GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12) {
+    sink->display->is_native_format = TRUE;
+  } else {
+    sink->display->is_native_format = FALSE;
+
+    /* create a new pool for the new configuration */
+    newpool = gst_wayland_buffer_pool_new (sink->display);
+    if (!newpool)
+      goto pool_failed;
+
+    structure = gst_buffer_pool_get_config (newpool);
+    gst_buffer_pool_config_set_params (structure, caps, info.size, 2, 0);
+    gst_buffer_pool_config_set_allocator (structure, NULL, &params);
+    if (!gst_buffer_pool_set_config (newpool, structure))
+      goto config_failed;
+
+    gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
+    gst_object_unref (newpool);
+
+  }
+  /* store the video info */
+  sink->video_info = info;
+  sink->video_info_changed = TRUE;
+#else
+  /* create a new pool for the new configuration */
+  newpool = gst_wayland_buffer_pool_new (sink->display);
+  if (!newpool)
+    goto pool_failed;
+
+  structure = gst_buffer_pool_get_config (newpool);
+  gst_buffer_pool_config_set_params (structure, caps, info.size, 2, 0);
+  gst_buffer_pool_config_set_allocator (structure, NULL, &params);
+  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:
+  {
+    GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
+        gst_wayland_format_to_string (format));
+    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)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (bsink);
+  GstBufferPool *pool = NULL;
+  GstStructure *config;
+  GstCaps *caps;
+  guint size;
+  gboolean need_pool;
+
+  if (sink->display->is_native_format == TRUE)
+    return TRUE;
+
+  gst_query_parse_allocation (query, &caps, &need_pool);
+
+  if (caps == NULL)
+    goto no_caps;
+
+  if (sink->pool)
+    pool = gst_object_ref (sink->pool);
+
+  if (pool != NULL) {
+    GstCaps *pcaps;
+
+    /* we had a pool, check caps */
+    config = gst_buffer_pool_get_config (pool);
+    gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);
+
+    if (!gst_caps_is_equal (caps, pcaps)) {
+      /* different caps, we can't use this pool */
+      gst_object_unref (pool);
+      pool = NULL;
+    }
+    gst_structure_free (config);
+  }
+
+  if (pool == NULL && need_pool) {
+    GstVideoInfo info;
+
+    if (!gst_video_info_from_caps (&info, caps))
+      goto invalid_caps;
+
+    GST_DEBUG_OBJECT (sink, "create new pool");
+    pool = gst_wayland_buffer_pool_new (sink->display);
+
+    /* the normal size of a frame */
+    size = info.size;
+
+    config = gst_buffer_pool_get_config (pool);
+    gst_buffer_pool_config_set_params (config, caps, size, 2, 0);
+    if (!gst_buffer_pool_set_config (pool, config))
+      goto config_failed;
+  }
+  if (pool) {
+    gst_query_add_allocation_pool (query, pool, size, 2, 0);
+    gst_object_unref (pool);
+  }
+
+  return TRUE;
+
+  /* ERRORS */
+no_caps:
+  {
+    GST_DEBUG_OBJECT (bsink, "no caps specified");
+    return FALSE;
+  }
+invalid_caps:
+  {
+    GST_DEBUG_OBJECT (bsink, "invalid caps specified");
+    return FALSE;
+  }
+config_failed:
+  {
+    GST_DEBUG_OBJECT (bsink, "failed setting config");
+    gst_object_unref (pool);
+    return FALSE;
+  }
+}
+
+static GstFlowReturn
+gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer)
+{
+  FUNCTION_ENTER ();
+
+  GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer);
+  return gst_wayland_sink_render (bsink, buffer);
+}
+
+static void
+frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = data;
+
+  GST_LOG ("frame_redraw_cb");
+
+  g_atomic_int_set (&sink->redraw_pending, FALSE);
+  wl_callback_destroy (callback);
+}
+
+static const struct wl_callback_listener frame_callback_listener = {
+  frame_redraw_callback
+};
+
+/* must be called with the render lock */
+static void
+render_last_buffer (GstTizenwlSink * sink)
+{
+  FUNCTION_ENTER ();
+
+  GstWlMeta *meta;
+  struct wl_surface *surface;
+  struct wl_callback *callback;
+
+  meta = gst_buffer_get_wl_meta (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);
+  wl_callback_add_listener (callback, &frame_callback_listener, sink);
+
+  /* Here we essentially 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 reused until the compositor
+   * releases it. The release is handled internally in the pool */
+  gst_wayland_compositor_acquire_buffer (meta->pool, sink->last_buffer);
+
+  GST_DEBUG ("wl_surface_attach wl_buffer %p", meta->wbuffer);
+
+  wl_surface_attach (surface, meta->wbuffer, 0, 0);
+  wl_surface_damage (surface, 0, 0, sink->window->surface_width,
+      sink->window->surface_height);
+
+  wl_surface_commit (surface);
+  wl_display_flush (sink->display->display);
+}
+
+static GstFlowReturn
+gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (bsink);
+  GstBuffer *to_render;
+  GstWlMeta *meta;
+  GstFlowReturn ret = GST_FLOW_OK;
+
+#ifdef GST_WLSINK_ENHANCEMENT
+  GstBufferPool *newpool;
+  GstStructure *structure;
+  static GstAllocationParams params = { 0, 0, 0, 15, };
+#endif
+
+  g_mutex_lock (&sink->render_lock);
+
+  GST_LOG_OBJECT (sink, "render buffer %p", buffer);
+
+  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) {
+      /* inform the window about our caps */
+      gst_wl_window_set_video_info (sink->window, &sink->video_info);
+    } else {
+      /* if we were not provided a window, create one ourselves */
+      sink->window =
+          gst_wl_window_new_toplevel (sink->display, &sink->video_info);
+    }
+#ifdef GST_WLSINK_ENHANCEMENT
+    gst_wayland_sink_update_window_geometry (sink);
+    sink->video_info_changed = TRUE;
+#else
+    sink->video_info_changed = FALSE;
+#endif
+  }
+
+  /* drop buffers until we get a frame callback */
+  if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
+    goto done;
+
+  if (G_UNLIKELY (sink->video_info_changed)) {
+    gst_wl_window_set_video_info (sink->window, &sink->video_info);
+    sink->video_info_changed = FALSE;
+  }
+  GST_INFO ("window->render_rectangle(%d,%d %d x %d)",
+      sink->window->render_rectangle.x,
+      sink->window->render_rectangle.y,
+      sink->window->render_rectangle.w, sink->window->render_rectangle.h);
+  GST_INFO ("window->surface_width(%d),window->surface_height(%d)",
+      sink->window->surface_width, sink->window->surface_height);
+
+  /* now that we have for sure set the video info on the window, it must have
+   * a valid size, otherwise this means that the application has called
+   * set_window_handle() without calling set_render_rectangle(), which is
+   * absolutely necessary for us.
+   */
+  if (G_UNLIKELY (sink->window->surface_width == 0 ||
+          sink->window->surface_height == 0))
+    goto no_window_size;
+
+  meta = gst_buffer_get_wl_meta (buffer);
+
+  if (meta && meta->pool->display == sink->display) {
+    GST_LOG_OBJECT (sink, "buffer %p from our pool, writing directly", buffer);
+    to_render = buffer;
+  } else {
+    GstMapInfo src;
+    GST_LOG_OBJECT (sink, "buffer %p not from our pool, copying", buffer);
+
+#ifdef GST_WLSINK_ENHANCEMENT
+    if (sink->display->is_native_format == TRUE) {
+      /*in case of SN12 or ST12 video  format */
+      GstMemory *mem;
+      GstMapInfo mem_info = GST_MAP_INFO_INIT;
+      MMVideoBuffer *mm_video_buf = NULL;
+         int i = 0;
+
+      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_OBJECT (sink, "mm_video_buf is NULL. Skip rendering");
+        return ret;
+      }
+      /* assign mm_video_buf info */
+      if (mm_video_buf->type == MM_VIDEO_BUFFER_TYPE_TBM_BO) {
+        GST_DEBUG_OBJECT (sink, "TBM bo %p %p %p", mm_video_buf->handle.bo[0],
+            mm_video_buf->handle.bo[1], mm_video_buf->handle.bo[2]);
+
+        sink->display->native_video_size = 0;
+
+        for (i = 0; i < NV_BUF_PLANE_NUM; i++) {
+          if (mm_video_buf->handle.bo[i] != NULL) {
+            sink->display->bo[i] = mm_video_buf->handle.bo[i];
+          } else {
+            sink->display->bo[i] = 0;
+          }
+          sink->display->plane_size[i] = mm_video_buf->size[i];
+          sink->display->stride_width[i] = mm_video_buf->stride_width[i];
+          sink->display->stride_height[i] = mm_video_buf->stride_height[i];
+          sink->display->native_video_size += sink->display->plane_size[i];
+        }
+      } else {
+        GST_ERROR_OBJECT (sink, "Buffer type is not TBM");
+        return ret;
+      }
+
+      if (!sink->pool) {
+
+        /* create a new pool for the new configuration */
+        newpool = gst_wayland_buffer_pool_new (sink->display);
+        if (!newpool) {
+          GST_DEBUG_OBJECT (sink, "Failed to create new pool");
+          return FALSE;
+        }
+        structure = gst_buffer_pool_get_config (newpool);
+        /*When the buffer is released, Core compare size with buffer size,
+           wl_buffer is not created if the size is same. It is a very critical problem
+           So we set 0 to size */
+        gst_buffer_pool_config_set_params (structure, sink->caps, 0, 2, 0);
+        gst_buffer_pool_config_set_allocator (structure, NULL, &params);
+        if (!gst_buffer_pool_set_config (newpool, structure)) {
+          GST_DEBUG_OBJECT (bsink, "failed setting config");
+          gst_object_unref (newpool);
+          return FALSE;
+        }
+
+        gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
+        gst_object_unref (newpool);
+
+      }
+
+      if (!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;
+
+
+      /*add displaying buffer */
+      GstWlMeta *meta;
+      meta = gst_buffer_get_wl_meta (to_render);
+      gst_wayland_buffer_pool_add_displaying_buffer (sink->pool, meta, buffer);
+
+    } else {
+      /*in case of normal video format and pool is not our pool */
+
+      if (!sink->pool)
+        goto no_pool;
+
+      if (!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;
+
+      gst_buffer_map (buffer, &src, GST_MAP_READ);
+      gst_buffer_fill (to_render, 0, src.data, src.size);
+      gst_buffer_unmap (buffer, &src);
+    }
+#else
+    if (!sink->pool)
+      goto no_pool;
+
+    if (!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;
+
+    gst_buffer_map (buffer, &src, GST_MAP_READ);
+    gst_buffer_fill (to_render, 0, src.data, src.size);
+    gst_buffer_unmap (buffer, &src);
+#endif
+  }
+
+  gst_buffer_replace (&sink->last_buffer, to_render);
+  render_last_buffer (sink);
+
+  if (buffer != to_render) {
+    GST_LOG_OBJECT (sink, "Decrease ref count of buffer");
+    gst_buffer_unref (to_render);
+  }
+  goto done;
+
+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 image");
+    goto done;
+  }
+no_pool:
+  {
+    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
+        ("Internal error: can't allocate images"),
+        ("We don't have a bufferpool negotiated"));
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+activate_failed:
+  {
+    GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
+    ret = GST_FLOW_ERROR;
+    goto done;
+  }
+done:
+  {
+    g_mutex_unlock (&sink->render_lock);
+    return ret;
+  }
+}
+
+static void
+gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface)
+{
+  FUNCTION_ENTER ();
+
+  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;
+}
+
+static void
+gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (overlay);
+  struct wl_surface *surface = (struct wl_surface *) handle;
+
+  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);
+
+  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_ERROR (sink, RESOURCE, OPEN_READ_WRITE,
+            ("Application did not provide a wayland display handle"),
+            ("waylandsink cannot use an externally-supplied surface without "
+                "an externally-supplied display handle. Consider providing a "
+                "display handle from your application with GstContext"));
+      } else {
+        sink->window = gst_wl_window_new_in_surface (sink->display, surface);
+        GST_DEBUG ("sink->window %p", sink->window);
+      }
+    } else {
+      GST_ERROR_OBJECT (sink, "Failed to find display handle, "
+          "ignoring window handle");
+    }
+  }
+#ifdef GST_WLSINK_ENHANCEMENT
+  gst_wayland_sink_update_window_geometry (sink);
+#endif
+
+  g_mutex_unlock (&sink->render_lock);
+}
+
+#ifdef GST_WLSINK_ENHANCEMENT
+static void
+gst_wayland_sink_update_window_geometry (GstTizenwlSink * sink)
+{
+  FUNCTION_ENTER ();
+  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_disp_geo_method (sink->window,
+      sink->display_geometry_method);
+  gst_wl_window_set_orientation (sink->window, sink->orientation);
+  gst_wl_window_set_flip (sink->window, sink->flip);
+}
+
+static void
+gst_wayland_sink_render_last_buffer (GstTizenwlSink * sink)
+{
+  FUNCTION_ENTER ();
+  g_return_if_fail (sink != NULL);
+
+  g_mutex_lock (&sink->render_lock);
+  gst_wl_window_set_video_info (sink->window, &sink->video_info);
+  sink->video_info_changed = FALSE;
+  if (sink->last_buffer)
+    render_last_buffer (sink);
+  g_mutex_unlock (&sink->render_lock);
+}
+#endif
+static void
+gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay,
+    gint x, gint y, gint w, gint h)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (overlay);
+
+  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);
+  gst_wl_window_set_render_rectangle (sink->window, x, y, w, h);
+
+  g_mutex_unlock (&sink->render_lock);
+}
+
+static void
+gst_wayland_sink_expose (GstVideoOverlay * overlay)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (overlay);
+
+  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);
+}
+
+static void
+gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface)
+{
+  FUNCTION_ENTER ();
+
+  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)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (video);
+  g_return_if_fail (sink != NULL);
+
+  g_mutex_lock (&sink->render_lock);
+  if (!sink->window || !sink->window->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->subsurface);
+  g_mutex_unlock (&sink->render_lock);
+}
+
+static void
+gst_wayland_sink_end_geometry_change (GstWaylandVideo * video)
+{
+  FUNCTION_ENTER ();
+
+  GstTizenwlSink *sink = GST_WAYLAND_SINK (video);
+  g_return_if_fail (sink != NULL);
+
+  g_mutex_lock (&sink->render_lock);
+  if (!sink->window || !sink->window->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->subsurface);
+  g_mutex_unlock (&sink->render_lock);
+}
+
+static gboolean
+plugin_init (GstPlugin * plugin)
+{
+  FUNCTION_ENTER ();
+
+  GST_DEBUG_CATEGORY_INIT (gsttizenwl_debug, "tizenwlsink", 0,
+      " temporary wayland video sink");
+
+  return gst_element_register (plugin, "tizenwlsink", GST_RANK_MARGINAL,
+      GST_TYPE_WAYLAND_SINK);
+}
+
+GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
+    GST_VERSION_MINOR,
+    tizenwlsink,
+    "Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME,
+    GST_PACKAGE_ORIGIN)
diff --git a/waylandsink/src/gstwaylandsink.h b/waylandsink/src/gstwaylandsink.h
new file mode 100644 (file)
index 0000000..92e8081
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ * 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,GstTizenwlSink))
+#define GST_WAYLAND_SINK_CLASS(klass) \
+           (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAYLAND_SINK,GstTizenwlSinkClass))
+#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, GstTizenwlSinkClass))
+#ifdef GST_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_NUM,
+};
+
+enum
+{
+  DEGREE_0,
+  DEGREE_90,
+  DEGREE_180,
+  DEGREE_270,
+  DEGREE_NUM,
+};
+
+enum
+{
+  FLIP_NONE = 0,
+  FLIP_HORIZONTAL,
+  FLIP_VERTICAL,
+  FLIP_BOTH,
+  FLIP_NUM,
+};
+
+#define DEF_DISPLAY_FLIP            FLIP_NONE
+#define DEF_DISPLAY_GEOMETRY_METHOD         DISP_GEO_METHOD_FULL_SCREEN
+
+#define WL_SCREEN_SIZE_WIDTH 4096
+#define WL_SCREEN_SIZE_HEIGHT 4096
+
+#endif
+#if 1
+#define FUNCTION_ENTER()       GST_INFO("<ENTER>")
+#else
+#define FUNCTION_ENTER()
+#endif
+typedef struct _GstTizenwlSink GstTizenwlSink;
+typedef struct _GstTizenwlSinkClass GstTizenwlSinkClass;
+
+struct _GstTizenwlSink
+{
+  GstVideoSink parent;
+
+  GMutex display_lock;
+  GstWlDisplay *display;
+  GstWlWindow *window;
+  GstBufferPool *pool;
+
+  gboolean video_info_changed;
+  GstVideoInfo video_info;
+
+  /*property */
+  gchar *display_name;
+#ifdef GST_WLSINK_ENHANCEMENT
+  guint rotate_angle;
+  guint display_geometry_method;
+  guint orientation;
+  guint flip;
+  GstCaps *caps;
+#endif
+  gboolean redraw_pending;
+  GMutex render_lock;
+  GstBuffer *last_buffer;
+};
+
+struct _GstTizenwlSinkClass
+{
+  GstVideoSinkClass parent;
+};
+
+GType
+gst_wayland_sink_get_type (void)
+    G_GNUC_CONST;
+
+G_END_DECLS
+#endif /* __GST_WAYLAND_VIDEO_SINK_H__ */
diff --git a/waylandsink/src/scaler.xml b/waylandsink/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/waylandsink/src/tizen-wlvideoformat.c b/waylandsink/src/tizen-wlvideoformat.c
new file mode 100644 (file)
index 0000000..4c78c14
--- /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 "tizen-wlvideoformat.h"
+#ifdef GST_WLSINK_ENHANCEMENT
+
+GST_DEBUG_CATEGORY_EXTERN (gsttizenwl_debug);
+#define GST_CAT_DEFAULT gsttizenwl_debug
+
+typedef struct
+{
+  uint32_t wl_format;
+  GstVideoFormat gst_format;
+} wl_VideoFormat;
+
+static const wl_VideoFormat 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},
+#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_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},
+};
+
+uint32_t
+gst_video_format_to_wayland_format (GstVideoFormat format)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (formats); i++)
+    if (formats[i].gst_format == format)
+      return formats[i].wl_format;
+
+  GST_WARNING ("wayland video format not found");
+  return -1;
+}
+
+GstVideoFormat
+gst_wayland_format_to_video_format (uint32_t wl_format)
+{
+  guint i;
+
+  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_wayland_format_to_string (uint32_t wl_format)
+{
+  return gst_video_format_to_string
+      (gst_wayland_format_to_video_format (wl_format));
+}
+#endif
diff --git a/waylandsink/src/tizen-wlvideoformat.h b/waylandsink/src/tizen-wlvideoformat.h
new file mode 100644 (file)
index 0000000..a62e7d8
--- /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 GST_WLSINK_ENHANCEMENT
+#include <tbm_surface.h>
+
+G_BEGIN_DECLS
+    uint32_t gst_video_format_to_wayland_format (GstVideoFormat format);
+GstVideoFormat gst_wayland_format_to_video_format (uint32_t wl_format);
+
+const gchar *gst_wayland_format_to_string (uint32_t wl_format);
+
+G_END_DECLS
+#endif
+#endif
diff --git a/waylandsink/src/waylandpool.c b/waylandsink/src/waylandpool.c
new file mode 100644 (file)
index 0000000..b36d2e2
--- /dev/null
@@ -0,0 +1,769 @@
+/* GStreamer
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "waylandpool.h"
+#include "wldisplay.h"
+#include "wlvideoformat.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#ifdef GST_WLSINK_ENHANCEMENT
+//#define DUMP_BUFFER
+#ifdef DUMP_BUFFER
+int dump_cnt = 0;
+int _write_rawdata (const char *file, const void *data, unsigned int size);
+#endif
+#endif
+
+GST_DEBUG_CATEGORY_EXTERN (gsttizenwl_debug);
+#define GST_CAT_DEFAULT gsttizenwl_debug
+
+/* wl metadata */
+GType
+gst_wl_meta_api_get_type (void)
+{
+  static volatile GType type;
+  static const gchar *tags[] =
+      { "memory", "size", "colorspace", "orientation", NULL };
+
+  if (g_once_init_enter (&type)) {
+    GType _type = gst_meta_api_type_register ("GstWlMetaAPI", tags);
+    g_once_init_leave (&type, _type);
+  }
+  return type;
+}
+
+static void
+gst_wl_meta_free (GstWlMeta * meta, GstBuffer * buffer)
+{
+#ifdef GST_WLSINK_ENHANCEMENT
+  if (!meta || !meta->pool)
+    return;
+  if (meta->tsurface)
+    tbm_surface_destroy (meta->tsurface);
+  g_hash_table_remove (meta->pool->buffers_map, meta->wbuffer);
+#endif
+  GST_DEBUG ("destroying wl_buffer %p", meta->wbuffer);
+  wl_buffer_destroy (meta->wbuffer);
+}
+
+const GstMetaInfo *
+gst_wl_meta_get_info (void)
+{
+  static const GstMetaInfo *wl_meta_info = NULL;
+
+  if (g_once_init_enter (&wl_meta_info)) {
+    const GstMetaInfo *meta =
+        gst_meta_register (GST_WL_META_API_TYPE, "GstWlMeta",
+        sizeof (GstWlMeta), (GstMetaInitFunction) NULL,
+        (GstMetaFreeFunction) gst_wl_meta_free,
+        (GstMetaTransformFunction) NULL);
+    g_once_init_leave (&wl_meta_info, meta);
+  }
+  return wl_meta_info;
+}
+
+/* bufferpool */
+static void gst_wayland_buffer_pool_finalize (GObject * object);
+static gboolean gst_wayland_buffer_pool_set_config (GstBufferPool * pool,
+    GstStructure * config);
+static gboolean gst_wayland_buffer_pool_start (GstBufferPool * pool);
+static gboolean gst_wayland_buffer_pool_stop (GstBufferPool * pool);
+static GstFlowReturn gst_wayland_buffer_pool_alloc (GstBufferPool * pool,
+    GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
+
+#ifdef GST_WLSINK_ENHANCEMENT
+/*tizen buffer pool*/
+static void gst_wayland_tizen_buffer_pool_finalize (GObject * object);
+static gboolean gst_wayland_tizen_buffer_pool_start (GstBufferPool * pool);
+static gboolean gst_wayland_tizen_buffer_pool_stop (GstBufferPool * pool);
+static GstFlowReturn gst_wayland_tizen_buffer_pool_alloc (GstBufferPool * pool,
+    GstBuffer ** buffer, GstBufferPoolAcquireParams * params);
+void gst_wayland_buffer_pool_remove_displaying_buffer (GstWaylandBufferPool *
+    self, struct wl_buffer *wl_buffer);
+#endif
+
+#define gst_wayland_buffer_pool_parent_class parent_class
+G_DEFINE_TYPE (GstWaylandBufferPool, gst_wayland_buffer_pool,
+    GST_TYPE_BUFFER_POOL);
+
+static void
+gst_wayland_buffer_pool_class_init (GstWaylandBufferPoolClass * klass)
+{
+  FUNCTION_ENTER ();
+
+  GObjectClass *gobject_class = (GObjectClass *) klass;
+  GstBufferPoolClass *gstbufferpool_class = (GstBufferPoolClass *) klass;
+
+  gstbufferpool_class->set_config = gst_wayland_buffer_pool_set_config;
+#ifdef GST_WLSINK_ENHANCEMENT
+  gobject_class->finalize = gst_wayland_tizen_buffer_pool_finalize;
+  gstbufferpool_class->start = gst_wayland_tizen_buffer_pool_start;
+  gstbufferpool_class->alloc_buffer = gst_wayland_tizen_buffer_pool_alloc;
+#else
+  gobject_class->finalize = gst_wayland_buffer_pool_finalize;
+  gstbufferpool_class->start = gst_wayland_buffer_pool_start;
+  gstbufferpool_class->stop = gst_wayland_buffer_pool_stop;
+  gstbufferpool_class->alloc_buffer = gst_wayland_buffer_pool_alloc;
+#endif
+}
+
+static void
+gst_wayland_buffer_pool_init (GstWaylandBufferPool * self)
+{
+  FUNCTION_ENTER ();
+
+  gst_video_info_init (&self->info);
+  g_mutex_init (&self->buffers_map_mutex);
+  self->buffers_map = g_hash_table_new (g_direct_hash, g_direct_equal);
+
+  g_mutex_init (&self->displaying_buffers_map_mutex);
+  self->displaying_buffers_map =
+      g_hash_table_new (g_direct_hash, g_direct_equal);
+}
+
+static void
+gst_wayland_buffer_pool_finalize (GObject * object)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object);
+
+  if (pool->wl_pool)
+    gst_wayland_buffer_pool_stop (GST_BUFFER_POOL (pool));
+
+  g_mutex_clear (&pool->buffers_map_mutex);
+  g_hash_table_unref (pool->buffers_map);
+
+  g_mutex_clear (&pool->displaying_buffers_map_mutex);
+  g_hash_table_unref (pool->displaying_buffers_map);
+
+  g_object_unref (pool->display);
+
+  G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object);
+}
+
+static void
+buffer_release (void *data, struct wl_buffer *wl_buffer)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *self = data;
+  GstBuffer *buffer;
+  GstWlMeta *meta;
+
+  g_mutex_lock (&self->buffers_map_mutex);
+
+#ifdef GST_WLSINK_ENHANCEMENT
+  /*remove displaying buffer */
+  if (self->display->is_native_format == TRUE)
+    gst_wayland_buffer_pool_remove_displaying_buffer (self, wl_buffer);
+#endif
+  buffer = g_hash_table_lookup (self->buffers_map, wl_buffer);
+
+  GST_LOG_OBJECT (self, "wl_buffer::release (GstBuffer: %p)", buffer);
+
+  if (buffer) {
+    meta = gst_buffer_get_wl_meta (buffer);
+    if (meta->used_by_compositor) {
+      meta->used_by_compositor = FALSE;
+      /* unlock before unref because stop() may be called from here */
+      GST_LOG_OBJECT (self, "Decrease ref count of buffer");
+      gst_buffer_unref (buffer);
+    }
+  }
+  g_mutex_unlock (&self->buffers_map_mutex);
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+  buffer_release
+};
+
+void
+gst_wayland_compositor_acquire_buffer (GstWaylandBufferPool * self,
+    GstBuffer * buffer)
+{
+  FUNCTION_ENTER ();
+
+  GstWlMeta *meta;
+
+  meta = gst_buffer_get_wl_meta (buffer);
+  g_return_if_fail (meta != NULL);
+  g_return_if_fail (meta->pool == self);
+  g_return_if_fail (meta->used_by_compositor == FALSE);
+
+  meta->used_by_compositor = TRUE;
+  GST_LOG_OBJECT (self, "Increase ref count of buffer");
+  gst_buffer_ref (buffer);
+}
+
+static void
+unref_used_buffers (gpointer key, gpointer value, gpointer data)
+{
+  FUNCTION_ENTER ();
+
+  GstBuffer *buffer = value;
+  GstWlMeta *meta = gst_buffer_get_wl_meta (buffer);
+  GList **to_unref = data;
+
+  if (meta == NULL)
+    return;
+
+  if (meta->used_by_compositor) {
+    meta->used_by_compositor = FALSE;
+    *to_unref = g_list_prepend (*to_unref, buffer);
+  }
+}
+
+void
+gst_wayland_compositor_release_all_buffers (GstWaylandBufferPool * self)
+{
+  FUNCTION_ENTER ();
+
+  GList *to_unref = NULL;
+
+  g_mutex_lock (&self->buffers_map_mutex);
+  g_hash_table_foreach (self->buffers_map, unref_used_buffers, &to_unref);
+
+  if (to_unref) {
+    g_list_free_full (to_unref, (GDestroyNotify) gst_buffer_unref);
+  }
+  g_mutex_unlock (&self->buffers_map_mutex);
+}
+
+static gboolean
+gst_wayland_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
+  GstCaps *caps;
+
+  if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL))
+    goto wrong_config;
+
+  if (caps == NULL)
+    goto no_caps;
+
+  /* now parse the caps from the config */
+  if (!gst_video_info_from_caps (&self->info, caps))
+    goto wrong_caps;
+
+  GST_LOG_OBJECT (pool, "%dx%d, caps %" GST_PTR_FORMAT,
+      GST_VIDEO_INFO_WIDTH (&self->info), GST_VIDEO_INFO_HEIGHT (&self->info),
+      caps);
+
+  /*Fixme: Enable metadata checking handling based on the config of pool */
+
+  return GST_BUFFER_POOL_CLASS (parent_class)->set_config (pool, config);
+  /* ERRORS */
+wrong_config:
+  {
+    GST_WARNING_OBJECT (pool, "invalid config");
+    return FALSE;
+  }
+no_caps:
+  {
+    GST_WARNING_OBJECT (pool, "no caps in config");
+    return FALSE;
+  }
+wrong_caps:
+  {
+    GST_WARNING_OBJECT (pool,
+        "failed getting geometry from caps %" GST_PTR_FORMAT, caps);
+    return FALSE;
+  }
+}
+
+static gboolean
+gst_wayland_buffer_pool_start (GstBufferPool * pool)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
+
+  GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool");
+
+  guint size = 0;
+  int fd;
+  char filename[1024];
+  static int init = 0;
+
+  GST_DEBUG_OBJECT (self, "Initializing wayland buffer pool");
+
+  /* configure */
+  size = GST_VIDEO_INFO_SIZE (&self->info) * 15;
+
+  /* allocate shm pool */
+  snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (),
+      "wayland-shm", init++, "XXXXXX");
+
+  fd = mkstemp (filename);
+  if (fd < 0) {
+    GST_ERROR_OBJECT (pool, "opening temp file %s failed: %s", filename,
+        strerror (errno));
+    return FALSE;
+  }
+  if (ftruncate (fd, size) < 0) {
+    GST_ERROR_OBJECT (pool, "ftruncate failed: %s", strerror (errno));
+    close (fd);
+    return FALSE;
+  }
+
+  self->data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+  if (self->data == MAP_FAILED) {
+    GST_ERROR_OBJECT (pool, "mmap failed: %s", strerror (errno));
+    close (fd);
+    return FALSE;
+  }
+
+  self->wl_pool = wl_shm_create_pool (self->display->shm, fd, size);
+  unlink (filename);
+  close (fd);
+
+  self->size = size;
+  self->used = 0;
+
+
+  return GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
+}
+
+static gboolean
+gst_wayland_buffer_pool_stop (GstBufferPool * pool)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
+
+  GST_DEBUG_OBJECT (self, "Stopping wayland buffer pool");
+
+  munmap (self->data, self->size);
+  wl_shm_pool_destroy (self->wl_pool);
+
+  self->wl_pool = NULL;
+  self->size = 0;
+  self->used = 0;
+
+  /* all buffers are about to be destroyed;
+   * we should no longer do anything with them */
+  g_mutex_lock (&self->buffers_map_mutex);
+  g_hash_table_remove_all (self->buffers_map);
+  g_mutex_unlock (&self->buffers_map_mutex);
+
+  return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
+}
+
+static GstFlowReturn
+gst_wayland_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
+    GstBufferPoolAcquireParams * params)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
+
+  gint width, height, stride;
+  gsize size;
+  enum wl_shm_format format;
+  gint offset;
+  void *data;
+  GstWlMeta *meta;
+
+  width = GST_VIDEO_INFO_WIDTH (&self->info);
+  height = GST_VIDEO_INFO_HEIGHT (&self->info);
+  stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0);
+  size = GST_VIDEO_INFO_SIZE (&self->info);
+  format =
+      gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT (&self->info));
+
+  GST_DEBUG_OBJECT (self, "Allocating buffer of size %" G_GSSIZE_FORMAT
+      " (%d x %d, stride %d), format %s", size, width, height, stride,
+      gst_wayland_format_to_string (format));
+  /* try to reserve another memory block from the shm pool */
+  if (self->used + size > self->size)
+    goto no_buffer;
+
+  offset = self->used;
+  self->used += size;
+
+  data = ((gchar *) self->data) + offset;
+
+  /* create buffer and its metadata object */
+  *buffer = gst_buffer_new ();
+  meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL);
+  meta->pool = self;
+
+  meta->wbuffer = wl_shm_pool_create_buffer (self->wl_pool, offset,
+      width, height, stride, format);
+  meta->used_by_compositor = FALSE;
+
+  /* configure listening to wl_buffer.release */
+  g_mutex_lock (&self->buffers_map_mutex);
+  g_hash_table_insert (self->buffers_map, meta->wbuffer, *buffer);
+  g_mutex_unlock (&self->buffers_map_mutex);
+
+  wl_buffer_add_listener (meta->wbuffer, &buffer_listener, self);
+
+  /* add the allocated memory on the GstBuffer */
+  gst_buffer_append_memory (*buffer,
+      gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
+          size, 0, size, NULL, NULL));
+
+  return GST_FLOW_OK;
+
+  /* ERROR */
+no_buffer:
+  {
+    GST_WARNING_OBJECT (pool, "can't create buffer");
+    return GST_FLOW_ERROR;
+  }
+}
+
+GstBufferPool *
+gst_wayland_buffer_pool_new (GstWlDisplay * display)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *pool;
+
+  g_return_val_if_fail (GST_IS_WL_DISPLAY (display), NULL);
+  pool = g_object_new (GST_TYPE_WAYLAND_BUFFER_POOL, NULL);
+  pool->display = g_object_ref (display);
+
+  return GST_BUFFER_POOL_CAST (pool);
+}
+
+#ifdef GST_WLSINK_ENHANCEMENT
+
+static gboolean
+gst_wayland_tizen_buffer_pool_start (GstBufferPool * pool)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
+
+  GST_DEBUG_OBJECT (self, "Initializing tizen buffer pool");
+
+  tbm_bo_handle vitual_addr;
+  guint size = 0;
+
+  if (self->display->is_native_format == TRUE) {
+    /*in case of SN12 or ST12 video  format */
+    size = self->display->native_video_size * 15;
+    vitual_addr.ptr = NULL;
+
+  } else {
+    /*in case of normal video format */
+    size = GST_VIDEO_INFO_SIZE (&self->info) * 15;
+
+    self->display->tbm_bufmgr =
+        wayland_tbm_client_get_bufmgr (self->display->tbm_client);
+    g_return_if_fail (self->display->tbm_bufmgr != NULL);
+
+    self->display->tbm_bo =
+        tbm_bo_alloc (self->display->tbm_bufmgr, size, TBM_BO_DEFAULT);
+    if (!self->display->tbm_bo) {
+      GST_ERROR_OBJECT (pool, "alloc tbm bo(size:%d) failed: %s", size,
+          strerror (errno));
+      return FALSE;
+    }
+
+    vitual_addr = tbm_bo_get_handle (self->display->tbm_bo, TBM_DEVICE_CPU);
+    if (!vitual_addr.ptr) {
+      GST_ERROR_OBJECT (pool, "get tbm bo handle failed: %s", strerror (errno));
+      tbm_bo_unref (self->display->tbm_bo);
+      self->display->tbm_bo = NULL;
+      return FALSE;
+    }
+  }
+
+  self->data = vitual_addr.ptr;
+  self->size = size;
+  self->used = 0;
+
+  return GST_BUFFER_POOL_CLASS (parent_class)->start (pool);
+}
+
+static gboolean
+gst_wayland_tizen_buffer_pool_stop (GstBufferPool * pool)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL (pool);
+
+  GST_DEBUG_OBJECT (self, "Stopping tizen buffer pool");
+
+  self->size = 0;
+  self->used = 0;
+
+  self->display->tbm_bufmgr = NULL;
+
+  /* all buffers are about to be destroyed;
+   * we should no longer do anything with them */
+  g_mutex_lock (&self->buffers_map_mutex);
+  g_hash_table_remove_all (self->buffers_map);
+  g_mutex_unlock (&self->buffers_map_mutex);
+
+  g_mutex_lock (&self->displaying_buffers_map_mutex);
+  g_hash_table_remove_all (self->displaying_buffers_map);
+  g_mutex_unlock (&self->displaying_buffers_map_mutex);
+
+  return GST_BUFFER_POOL_CLASS (parent_class)->stop (pool);
+}
+
+static GstFlowReturn
+gst_wayland_tizen_buffer_pool_alloc (GstBufferPool * pool, GstBuffer ** buffer,
+    GstBufferPoolAcquireParams * params)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
+
+  gint width, height;
+  gsize size;
+  uint32_t format;
+  gint data_offset;
+  void *data;
+  GstWlMeta *meta;
+  tbm_bo_handle vitual_addr;
+  tbm_surface_info_s info;
+  int num_bo;
+
+  if (self->display->is_native_format == TRUE) {
+    /*in case of SN12 or ST12 video  format */
+    width = GST_VIDEO_INFO_WIDTH (&self->info);
+    height = GST_VIDEO_INFO_HEIGHT (&self->info);
+    size = self->display->native_video_size;
+
+    format =
+        gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT
+        (&self->info));
+
+
+    vitual_addr = tbm_bo_get_handle (self->display->bo[0], TBM_DEVICE_CPU);
+    if (!vitual_addr.ptr) {
+      GST_ERROR_OBJECT (pool, "get tbm bo handle failed: %s", strerror (errno));
+      return FALSE;
+    }
+    self->data = vitual_addr.ptr;
+    data = ((gchar *) self->data);
+#ifdef DUMP_BUFFER
+    int ret;
+    char file_name[128];
+    if (dump_cnt < 10) {
+      sprintf (file_name, "/root/WLSINK_OUT_DUMP_%2.2d.dump", dump_cnt++);
+      ret = _write_rawdata (file_name, vitual_addr.ptr, size);
+      if (ret) {
+        GST_ERROR_OBJECT (pool, "_write_rawdata() failed");
+      }
+    }
+#endif
+    /* create buffer and its metadata object */
+    *buffer = gst_buffer_new ();
+    meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL);
+    meta->pool = self;
+    GST_DEBUG ("TBM bo %p %p %p", self->display->bo[0],
+        self->display->bo[1], 0);
+
+    info.width = width;
+    info.height = height;
+    info.format = format;
+    info.bpp = tbm_surface_internal_get_bpp (info.format);
+    info.num_planes = tbm_surface_internal_get_num_planes (info.format);
+    info.planes[0].stride = self->display->stride_width[0];
+    info.planes[1].stride = self->display->stride_width[1];
+    info.planes[0].offset = 0;
+    info.planes[1].offset =
+        (self->display->bo[1]) ? 0 : self->display->plane_size[0];
+    num_bo = (self->display->bo[1]) ? 2 : 1;
+
+    meta->tsurface =
+        tbm_surface_internal_create_with_bos (&info, self->display->bo, num_bo);
+    meta->wbuffer =
+        wayland_tbm_client_create_buffer (self->display->tbm_client,
+        meta->tsurface);
+    wl_proxy_set_queue ((struct wl_proxy *) meta->wbuffer,
+        self->display->queue);
+    meta->used_by_compositor = FALSE;
+
+    GST_DEBUG ("tizen_buffer_pool_create_planar_buffer create wl_buffer %p",
+        meta->wbuffer);
+  } else {
+    int stride;
+
+    /*in case of normal video format */
+    width = GST_VIDEO_INFO_WIDTH (&self->info);
+    height = GST_VIDEO_INFO_HEIGHT (&self->info);
+    stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0);
+    size = GST_VIDEO_INFO_SIZE (&self->info);
+    format =
+        gst_video_format_to_wayland_format (GST_VIDEO_INFO_FORMAT
+        (&self->info));
+
+    GST_DEBUG_OBJECT (self, "Allocating buffer of size %" G_GSSIZE_FORMAT
+        " (%d x %d, stride %d), format %s", size, width, height, stride,
+        gst_wayland_format_to_string (format));
+
+    /* try to reserve another memory block from the shm pool */
+    if (self->used + size > self->size)
+      goto no_buffer;
+
+    data_offset = self->used;
+    self->used += size;
+
+    data = ((gchar *) self->data) + data_offset;
+
+    /* create buffer and its metadata object */
+    *buffer = gst_buffer_new ();
+    meta = (GstWlMeta *) gst_buffer_add_meta (*buffer, GST_WL_META_INFO, NULL);
+    meta->pool = self;
+
+    info.width = width;
+    info.height = height;
+    info.format = format;
+    info.bpp = tbm_surface_internal_get_bpp (info.format);
+    info.num_planes = tbm_surface_internal_get_num_planes (info.format);
+    info.planes[0].stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 0);
+    info.planes[1].stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 1);
+    info.planes[2].stride = GST_VIDEO_INFO_PLANE_STRIDE (&self->info, 2);
+    info.planes[0].offset = GST_VIDEO_INFO_PLANE_OFFSET (&self->info, 0);
+    info.planes[1].offset = GST_VIDEO_INFO_PLANE_OFFSET (&self->info, 1);
+    info.planes[2].offset = GST_VIDEO_INFO_PLANE_OFFSET (&self->info, 2);
+
+    meta->tsurface =
+        tbm_surface_internal_create_with_bos (&info, &self->display->tbm_bo, 1);
+    meta->wbuffer =
+        wayland_tbm_client_create_buffer (self->display->tbm_client,
+        meta->tsurface);
+    wl_proxy_set_queue ((struct wl_proxy *) meta->wbuffer,
+        self->display->queue);
+    meta->used_by_compositor = FALSE;
+  }
+
+  /* configure listening to wl_buffer.release */
+  g_mutex_lock (&self->buffers_map_mutex);
+  g_hash_table_insert (self->buffers_map, meta->wbuffer, *buffer);
+  g_mutex_unlock (&self->buffers_map_mutex);
+
+  wl_buffer_add_listener (meta->wbuffer, &buffer_listener, self);
+
+  /* add the allocated memory on the GstBuffer */
+  gst_buffer_append_memory (*buffer,
+      gst_memory_new_wrapped (GST_MEMORY_FLAG_NO_SHARE, data,
+          size, 0, size, NULL, NULL));
+  return GST_FLOW_OK;
+
+  /* ERROR */
+no_buffer:
+  {
+    GST_WARNING_OBJECT (pool, "can't create buffer");
+    return GST_FLOW_ERROR;
+  }
+}
+
+static void
+gst_wayland_tizen_buffer_pool_finalize (GObject * object)
+{
+  FUNCTION_ENTER ();
+
+  GstWaylandBufferPool *pool = GST_WAYLAND_BUFFER_POOL_CAST (object);
+
+  if (pool->display->tbm_bufmgr) {
+    gst_wayland_tizen_buffer_pool_stop (GST_BUFFER_POOL (pool));
+  } else {
+    /*already stop */
+    return;
+  }
+  g_mutex_clear (&pool->buffers_map_mutex);
+  g_hash_table_unref (pool->buffers_map);
+
+  g_mutex_clear (&pool->displaying_buffers_map_mutex);
+  g_hash_table_unref (pool->displaying_buffers_map);
+
+  g_object_unref (pool->display);
+
+  G_OBJECT_CLASS (gst_wayland_buffer_pool_parent_class)->finalize (object);
+}
+
+void
+gst_wayland_buffer_pool_add_displaying_buffer (GstBufferPool * pool,
+    GstWlMeta * meta, GstBuffer * buffer)
+{
+  FUNCTION_ENTER ();
+  g_return_val_if_fail (pool, NULL);
+  g_return_val_if_fail (meta, NULL);
+  g_return_val_if_fail (buffer, NULL);
+
+  GstWaylandBufferPool *self = GST_WAYLAND_BUFFER_POOL_CAST (pool);
+
+  g_mutex_lock (&self->displaying_buffers_map_mutex);
+
+  GST_LOG_OBJECT (self, "key value is meta->wbuffer(%p)", meta->wbuffer);
+  GST_LOG_OBJECT (self, "Increase ref count of buffer(%p) from omx", buffer);
+  gst_buffer_ref (buffer);
+  g_hash_table_insert (self->displaying_buffers_map, meta->wbuffer, buffer);
+
+  g_mutex_unlock (&self->displaying_buffers_map_mutex);
+}
+
+void
+gst_wayland_buffer_pool_remove_displaying_buffer (GstWaylandBufferPool * self,
+    struct wl_buffer *wl_buffer)
+{
+  FUNCTION_ENTER ();
+  g_return_val_if_fail (self, NULL);
+  g_return_val_if_fail (wl_buffer, NULL);
+
+  GstBuffer *buffer;
+  g_mutex_lock (&self->displaying_buffers_map_mutex);
+  buffer = g_hash_table_lookup (self->displaying_buffers_map, wl_buffer);
+  if (buffer) {
+    GST_LOG_OBJECT (self, "Decrease ref count of buffer(%p) from omx", buffer);
+    g_hash_table_remove (self->displaying_buffers_map, wl_buffer);
+    gst_buffer_unref (buffer);
+  }
+  g_mutex_unlock (&self->displaying_buffers_map_mutex);
+}
+#endif
+#ifdef DUMP_BUFFER
+int
+_write_rawdata (const char *file, const void *data, unsigned int size)
+{
+  FILE *fp;
+
+  fp = fopen (file, "wb");
+  if (fp == NULL)
+    return -1;
+
+  fwrite ((char *) data, sizeof (char), size, fp);
+  fclose (fp);
+
+  return 0;
+}
+#endif
diff --git a/waylandsink/src/waylandpool.h b/waylandsink/src/waylandpool.h
new file mode 100644 (file)
index 0000000..85fdd0e
--- /dev/null
@@ -0,0 +1,111 @@
+/* GStreamer Wayland buffer pool
+ * 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_WAYLAND_BUFFER_POOL_H__
+#define __GST_WAYLAND_BUFFER_POOL_H__
+
+#include <gst/video/video.h>
+#include <gst/video/gstvideometa.h>
+
+#include "wldisplay.h"
+#ifdef GST_WLSINK_ENHANCEMENT
+#include <tbm_bufmgr.h>
+#include <tbm_surface.h>
+#include <tbm_surface_internal.h>
+#endif
+
+G_BEGIN_DECLS
+#define GST_TYPE_WAYLAND_BUFFER_POOL      (gst_wayland_buffer_pool_get_type())
+#define GST_IS_WAYLAND_BUFFER_POOL(obj)   (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WAYLAND_BUFFER_POOL))
+#define GST_WAYLAND_BUFFER_POOL(obj)      (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WAYLAND_BUFFER_POOL, GstWaylandBufferPool))
+#define GST_WAYLAND_BUFFER_POOL_CAST(obj) ((GstWaylandBufferPool*)(obj))
+#if 1
+#define FUNCTION_ENTER()       GST_INFO("<ENTER>")
+#else
+#define FUNCTION_ENTER()
+#endif
+typedef struct _GstWaylandBufferPool GstWaylandBufferPool;
+typedef struct _GstWaylandBufferPoolClass GstWaylandBufferPoolClass;
+
+/* buffer meta */
+typedef struct _GstWlMeta GstWlMeta;
+
+GType gst_wl_meta_api_get_type (void);
+#define GST_WL_META_API_TYPE  (gst_wl_meta_api_get_type())
+
+const GstMetaInfo *gst_wl_meta_get_info (void);
+#define GST_WL_META_INFO  (gst_wl_meta_get_info())
+
+#define gst_buffer_get_wl_meta(b) ((GstWlMeta*)gst_buffer_get_meta((b),GST_WL_META_API_TYPE))
+
+struct _GstWlMeta
+{
+  GstMeta meta;
+
+  GstWaylandBufferPool *pool;
+  struct wl_buffer *wbuffer;
+  gboolean used_by_compositor;
+#ifdef GST_WLSINK_ENHANCEMENT
+  tbm_surface_h tsurface;
+#endif
+};
+
+/* buffer pool */
+struct _GstWaylandBufferPool
+{
+  GstBufferPool bufferpool;
+  GstWlDisplay *display;
+
+  /* external configuration */
+  GstVideoInfo info;
+
+  /* allocation data */
+  struct wl_shm_pool *wl_pool;
+  size_t size;
+  size_t used;
+  void *data;
+
+  GMutex buffers_map_mutex;
+  GHashTable *buffers_map;
+#ifdef GST_WLSINK_ENHANCEMENT
+  GMutex displaying_buffers_map_mutex;
+  GHashTable *displaying_buffers_map;
+#endif
+};
+
+struct _GstWaylandBufferPoolClass
+{
+  GstBufferPoolClass parent_class;
+};
+
+GType gst_wayland_buffer_pool_get_type (void);
+
+GstBufferPool *gst_wayland_buffer_pool_new (GstWlDisplay * display);
+
+
+void gst_wayland_compositor_acquire_buffer (GstWaylandBufferPool * self,
+    GstBuffer * buffer);
+void gst_wayland_compositor_release_all_buffers (GstWaylandBufferPool * self);
+void gst_wayland_buffer_pool_add_displaying_buffer (GstBufferPool * pool,
+    GstWlMeta * meta, GstBuffer * buffer);
+
+G_END_DECLS
+#endif /*__GST_WAYLAND_BUFFER_POOL_H__*/
diff --git a/waylandsink/src/wldisplay.c b/waylandsink/src/wldisplay.c
new file mode 100644 (file)
index 0000000..4a1ec63
--- /dev/null
@@ -0,0 +1,358 @@
+/* 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 <errno.h>
+
+#ifdef GST_WLSINK_ENHANCEMENT
+#include <fcntl.h>
+#include <unistd.h>
+#include <xf86drm.h>
+#include <string.h>
+#include <stdlib.h>
+
+static void
+handle_tizen_video_format (void *data, struct tizen_video *tizen_video,
+    uint32_t format)
+{
+  FUNCTION_ENTER ();
+  GstWlDisplay *self = data;
+
+  g_return_if_fail (self != NULL);
+
+  GST_INFO ("format is %d", format);
+  g_array_append_val (self->formats, format);
+}
+
+static const struct tizen_video_listener tz_video_listener = {
+  handle_tizen_video_format
+};
+#endif
+
+GST_DEBUG_CATEGORY_EXTERN (gsttizenwl_debug);
+#define GST_CAT_DEFAULT gsttizenwl_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)
+{
+  FUNCTION_ENTER ();
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = gst_wl_display_finalize;
+}
+
+static void
+gst_wl_display_init (GstWlDisplay * self)
+{
+  FUNCTION_ENTER ();
+
+  self->formats = g_array_new (FALSE, FALSE, sizeof (uint32_t));
+  self->wl_fd_poll = gst_poll_new (TRUE);
+}
+
+static void
+gst_wl_display_finalize (GObject * gobject)
+{
+  FUNCTION_ENTER ();
+
+  GstWlDisplay *self = GST_WL_DISPLAY (gobject);
+
+  gst_poll_set_flushing (self->wl_fd_poll, TRUE);
+
+  if (self->thread)
+    g_thread_join (self->thread);
+
+#ifdef GST_WLSINK_ENHANCEMENT
+  if (self->is_native_format == FALSE) {
+    /*in case of normal video format */
+    if (self->tbm_bo)
+      tbm_bo_unref (self->tbm_bo);
+    self->tbm_bo = NULL;
+  }
+  if (self->tbm_client) {
+    wayland_tbm_client_deinit (self->tbm_client);
+    self->tbm_client = NULL;
+  }
+  self->tbm_bufmgr = NULL;
+#endif
+
+  g_array_unref (self->formats);
+  gst_poll_free (self->wl_fd_poll);
+
+#ifndef GST_WLSINK_ENHANCEMENT
+  if (self->shm)
+    wl_shm_destroy (self->shm);
+#endif
+
+  if (self->shell)
+    wl_shell_destroy (self->shell);
+
+  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);
+  }
+#ifdef GST_WLSINK_ENHANCEMENT
+  if (self->tizen_policy)
+    tizen_policy_destroy (self->tizen_policy);
+  if (self->tizen_video)
+    tizen_video_destroy (self->tizen_video);
+#endif
+
+  G_OBJECT_CLASS (gst_wl_display_parent_class)->finalize (gobject);
+}
+
+static void
+sync_callback (void *data, struct wl_callback *callback, uint32_t serial)
+{
+  FUNCTION_ENTER ();
+
+  gboolean *done = data;
+  *done = TRUE;
+}
+
+static const struct wl_callback_listener sync_listener = {
+  sync_callback
+};
+
+static gint
+gst_wl_display_roundtrip (GstWlDisplay * self)
+{
+  FUNCTION_ENTER ();
+
+  struct wl_callback *callback;
+  gint ret = 0;
+  gboolean done = FALSE;
+
+  g_return_val_if_fail (self != NULL, -1);
+
+  /* We don't own the display, process only our queue */
+  callback = wl_display_sync (self->display);
+  wl_callback_add_listener (callback, &sync_listener, &done);
+  wl_proxy_set_queue ((struct wl_proxy *) callback, self->queue);
+  while (ret != -1 && !done)
+    ret = wl_display_dispatch_queue (self->display, self->queue);
+  wl_callback_destroy (callback);
+
+  return ret;
+}
+
+static void
+shm_format (void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+  FUNCTION_ENTER ();
+
+  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)
+{
+
+  FUNCTION_ENTER ();
+  GstWlDisplay *self = data;
+
+  if (g_strcmp0 (interface, "wl_compositor") == 0) {
+    self->compositor = wl_registry_bind (registry, id, &wl_compositor_interface,
+        MIN (version, 3));
+  } else if (g_strcmp0 (interface, "wl_subcompositor") == 0) {
+    self->subcompositor =
+        wl_registry_bind (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);
+#ifndef GST_WLSINK_ENHANCEMENT
+  } else if (g_strcmp0 (interface, "wl_shm") == 0) {
+    self->shm = wl_registry_bind (registry, id, &wl_shm_interface, 1);
+    wl_shm_add_listener (self->shm, &shm_listener, self);
+#endif
+  } else if (g_strcmp0 (interface, "wl_scaler") == 0) {
+    self->scaler = wl_registry_bind (registry, id, &wl_scaler_interface, 2);
+#ifdef GST_WLSINK_ENHANCEMENT
+  } else if (g_strcmp0 (interface, "tizen_policy") == 0) {
+    self->tizen_policy =
+        wl_registry_bind (registry, id, &tizen_policy_interface, 1);
+  } 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 ("id(%d)", id);
+
+    tizen_video_add_listener (self->tizen_video, &tz_video_listener, self);
+  }
+#endif
+}
+
+static const struct wl_registry_listener registry_listener = {
+  registry_handle_global
+};
+
+static gpointer
+gst_wl_display_thread_run (gpointer data)
+{
+  FUNCTION_ENTER ();
+
+  GstWlDisplay *self = data;
+  GstPollFD pollfd = GST_POLL_FD_INIT;
+
+  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) {
+    while (wl_display_prepare_read_queue (self->display, self->queue) != 0)
+      wl_display_dispatch_queue_pending (self->display, self->queue);
+    wl_display_flush (self->display);
+
+    if (gst_poll_wait (self->wl_fd_poll, GST_CLOCK_TIME_NONE) < 0) {
+      gboolean normal = (errno == EBUSY);
+      wl_display_cancel_read (self->display);
+      if (normal)
+        break;
+      else
+        goto error;
+    } else {
+      wl_display_read_events (self->display);
+      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)
+{
+  FUNCTION_ENTER ();
+
+  struct wl_display *display;
+
+  display = wl_display_connect (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)
+{
+  FUNCTION_ENTER ();
+
+  GstWlDisplay *self;
+  GError *err = NULL;
+  gint i;
+
+  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);
+  self->registry = wl_display_get_registry (self->display);
+  wl_proxy_set_queue ((struct wl_proxy *) self->registry, self->queue);
+  wl_registry_add_listener (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 GST_WLSINK_ENHANCEMENT
+  VERIFY_INTERFACE_EXISTS (tizen_video, "tizen_video");
+  self->tbm_client = wayland_tbm_client_init (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;
+  }
+#else
+  VERIFY_INTERFACE_EXISTS (shm, "wl_shm");
+#endif
+  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;
+}
diff --git a/waylandsink/src/wldisplay.h b/waylandsink/src/wldisplay.h
new file mode 100644 (file)
index 0000000..f782534
--- /dev/null
@@ -0,0 +1,100 @@
+/* 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 GST_WLSINK_ENHANCEMENT
+#include <tbm_bufmgr.h>
+#include <wayland-tbm-client.h>
+#include <tizen-extension-client-protocol.h>
+#define NV_BUF_PLANE_NUM    2   /*SN12 or ST12 has 2 plane */
+#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))
+#if 1
+#define FUNCTION_ENTER()       GST_INFO("<ENTER>")
+#else
+#define FUNCTION_ENTER()
+#endif
+typedef struct _GstWlDisplay GstWlDisplay;
+typedef struct _GstWlDisplayClass GstWlDisplayClass;
+
+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;
+
+  /* private */
+  gboolean own_display;
+  GThread *thread;
+  GstPoll *wl_fd_poll;
+
+#ifdef GST_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;
+
+  gboolean is_native_format;    /*SN12, ST12 */
+  void *bo[NV_BUF_PLANE_NUM];
+  int plane_size[NV_BUF_PLANE_NUM];
+  int stride_width[NV_BUF_PLANE_NUM];
+  int stride_height[NV_BUF_PLANE_NUM];
+  int native_video_size;
+#endif
+};
+
+struct _GstWlDisplayClass
+{
+  GObjectClass parent_class;
+};
+
+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);
+
+G_END_DECLS
+#endif /* __GST_WL_DISPLAY_H__ */
diff --git a/waylandsink/src/wlvideoformat.c b/waylandsink/src/wlvideoformat.c
new file mode 100644 (file)
index 0000000..a0c3ff6
--- /dev/null
@@ -0,0 +1,114 @@
+/* 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 (gsttizenwl_debug);
+#define GST_CAT_DEFAULT gsttizenwl_debug
+
+#ifndef GST_WLSINK_ENHANCEMENT
+
+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_wayland_format (GstVideoFormat format)
+{
+  guint i;
+
+  for (i = 0; i < G_N_ELEMENTS (formats); i++)
+    if (formats[i].gst_format == format)
+      return formats[i].wl_format;
+
+  GST_WARNING ("wayland video format not found");
+  return -1;
+}
+
+GstVideoFormat
+gst_wayland_format_to_video_format (enum wl_shm_format wl_format)
+{
+  guint i;
+
+  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_wayland_format_to_string (enum wl_shm_format wl_format)
+{
+  return gst_video_format_to_string
+      (gst_wayland_format_to_video_format (wl_format));
+}
+#endif
diff --git a/waylandsink/src/wlvideoformat.h b/waylandsink/src/wlvideoformat.h
new file mode 100644 (file)
index 0000000..c03525b
--- /dev/null
@@ -0,0 +1,42 @@
+/* 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.h>
+#include <gst/video/video.h>
+
+#ifndef GST_WLSINK_ENHANCEMENT
+
+G_BEGIN_DECLS
+    enum wl_shm_format gst_video_format_to_wayland_format (GstVideoFormat
+    format);
+GstVideoFormat gst_wayland_format_to_video_format (enum wl_shm_format
+    wl_format);
+
+const gchar *gst_wayland_format_to_string (enum wl_shm_format wl_format);
+
+G_END_DECLS
+#endif
+#endif
diff --git a/waylandsink/src/wlwindow.c b/waylandsink/src/wlwindow.c
new file mode 100644 (file)
index 0000000..9258b81
--- /dev/null
@@ -0,0 +1,484 @@
+/* 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
+
+#include "wlwindow.h"
+#ifdef GST_WLSINK_ENHANCEMENT
+#include "gstwaylandsink.h"
+#define SWAP(a, b) { (a) ^= (b) ^= (a) ^= (b); }
+#endif
+
+GST_DEBUG_CATEGORY_EXTERN (gsttizenwl_debug);
+#define GST_CAT_DEFAULT gsttizenwl_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)
+{
+  FUNCTION_ENTER ();
+
+  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)
+{
+  FUNCTION_ENTER ();
+
+}
+
+static void
+handle_popup_done (void *data, struct wl_shell_surface *shell_surface)
+{
+  FUNCTION_ENTER ();
+
+}
+
+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)
+{
+  FUNCTION_ENTER ();
+
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  gobject_class->finalize = gst_wl_window_finalize;
+}
+
+static void
+gst_wl_window_init (GstWlWindow * self)
+{
+  FUNCTION_ENTER ();
+
+}
+
+static void
+gst_wl_window_finalize (GObject * gobject)
+{
+  FUNCTION_ENTER ();
+
+  GstWlWindow *self = GST_WL_WINDOW (gobject);
+
+  if (self->shell_surface) {
+    wl_shell_surface_destroy (self->shell_surface);
+  }
+
+  if (self->subsurface) {
+    wl_subsurface_destroy (self->subsurface);
+  }
+
+  wl_viewport_destroy (self->viewport);
+  wl_surface_destroy (self->surface);
+
+  g_clear_object (&self->display);
+
+  G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject);
+}
+
+static GstWlWindow *
+gst_wl_window_new_internal (GstWlDisplay * display, struct wl_surface *surface)
+{
+  FUNCTION_ENTER ();
+
+  GstWlWindow *window;
+  struct wl_region *region;
+
+  g_return_val_if_fail (surface != NULL, NULL);
+
+  window = g_object_new (GST_TYPE_WL_WINDOW, NULL);
+  window->display = g_object_ref (display);
+  window->surface = surface;
+
+  /* make sure the surface runs on our local queue */
+  wl_proxy_set_queue ((struct wl_proxy *) surface, display->queue);
+
+  window->viewport = wl_scaler_get_viewport (display->scaler, window->surface);
+
+  /* do not accept input */
+  region = wl_compositor_create_region (display->compositor);
+  wl_surface_set_input_region (surface, region);
+  wl_region_destroy (region);
+
+  return window;
+}
+
+GstWlWindow *
+gst_wl_window_new_toplevel (GstWlDisplay * display, GstVideoInfo * video_info)
+{
+  FUNCTION_ENTER ();
+
+  GstWlWindow *window;
+
+  window = gst_wl_window_new_internal (display,
+      wl_compositor_create_surface (display->compositor));
+
+  gst_wl_window_set_video_info (window, video_info);
+  gst_wl_window_set_render_rectangle (window, 0, 0, window->video_width,
+      window->video_height);
+
+  window->shell_surface = wl_shell_get_shell_surface (display->shell,
+      window->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;
+  }
+
+  return window;
+}
+
+GstWlWindow *
+gst_wl_window_new_in_surface (GstWlDisplay * display,
+    struct wl_surface * parent)
+{
+  FUNCTION_ENTER ();
+
+  GstWlWindow *window;
+
+  window = gst_wl_window_new_internal (display,
+      wl_compositor_create_surface (display->compositor));
+
+  window->subsurface = wl_subcompositor_get_subsurface (display->subcompositor,
+      window->surface, parent);
+  wl_subsurface_set_desync (window->subsurface);
+#ifdef GST_WLSINK_ENHANCEMENT
+  if (display->tizen_policy)
+    tizen_policy_place_subsurface_below_parent (display->tizen_policy,
+        window->subsurface);
+
+  wl_surface_commit (parent);
+#endif
+  return window;
+}
+
+GstWlDisplay *
+gst_wl_window_get_display (GstWlWindow * window)
+{
+  FUNCTION_ENTER ();
+
+  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_ENTER ();
+
+  g_return_val_if_fail (window != NULL, NULL);
+
+  return window->surface;
+}
+
+gboolean
+gst_wl_window_is_toplevel (GstWlWindow * window)
+{
+  FUNCTION_ENTER ();
+
+  g_return_val_if_fail (window != NULL, FALSE);
+
+  return (window->shell_surface != NULL);
+}
+
+static void
+gst_wl_window_resize_internal (GstWlWindow * window, gboolean commit)
+{
+  FUNCTION_ENTER ();
+
+  GstVideoRectangle src = { 0, };
+  GstVideoRectangle res;        //dst
+
+  src.w = window->video_width;
+  src.h = window->video_height;
+#ifdef GST_WLSINK_ENHANCEMENT   // need to change ifndef to ifdef
+
+  GstVideoRectangle src_origin = { 0, 0, 0, 0 };
+  GstVideoRectangle src_input = { 0, 0, 0, 0 };
+  GstVideoRectangle dst = { 0, 0, 0, 0 };
+
+  gint rotate = 0;
+  gint transform = WL_OUTPUT_TRANSFORM_NORMAL;
+
+  src.x = src.y = 0;
+  src_input.w = src_origin.w = window->video_width;
+  src_input.h = src_origin.h = window->video_height;
+  GST_INFO ("video (%d x %d)", window->video_width, window->video_height);
+  GST_INFO ("src_input(%d, %d, %d x %d)", src_input.x, src_input.y, src_input.w,
+      src_input.h);
+  GST_INFO ("src_origin(%d, %d, %d x %d)", src_origin.x, src_origin.y,
+      src_origin.w, src_origin.h);
+
+  if (window->rotate_angle == DEGREE_0 || window->rotate_angle == DEGREE_180) {
+    src.w = window->video_width;        //video_width
+    src.h = window->video_height;       //video_height
+  } else {
+    src.w = window->video_height;
+    src.h = window->video_width;
+  }
+  GST_INFO ("src(%d, %d, %d x %d)", src.x, src.y, src.w, src.h);
+
+  /*default res.w and res.h */
+  dst.w = window->render_rectangle.w;
+  dst.h = window->render_rectangle.h;
+  GST_INFO ("dst(%d,%d,%d x %d)", dst.x, dst.y, dst.w, dst.h);
+  GST_INFO ("window->render_rectangle(%d,%d,%d x %d)",
+      window->render_rectangle.x, window->render_rectangle.y,
+      window->render_rectangle.w, window->render_rectangle.h);
+  switch (window->disp_geo_method) {
+    case DISP_GEO_METHOD_LETTER_BOX:
+      GST_INFO ("DISP_GEO_METHOD_LETTER_BOX");
+      gst_video_sink_center_rect (src, dst, &res, TRUE);
+      gst_video_sink_center_rect (dst, src, &src_input, FALSE);
+      res.x += window->render_rectangle.x;
+      res.y += window->render_rectangle.y;
+      break;
+    case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX:
+      if (src.w > dst.w || src.h > dst.h) {
+        /*LETTER BOX */
+        GST_INFO
+            ("DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX -> set LETTER BOX");
+        gst_video_sink_center_rect (src, dst, &res, TRUE);
+        gst_video_sink_center_rect (dst, src, &src_input, FALSE);
+        res.x += window->render_rectangle.x;
+        res.y += window->render_rectangle.y;
+      } else {
+        /*ORIGIN SIZE */
+        GST_INFO ("DISP_GEO_METHOD_ORIGIN_SIZE");
+        gst_video_sink_center_rect (src, dst, &res, FALSE);
+        gst_video_sink_center_rect (dst, src, &src_input, FALSE);
+      }
+      break;
+    case DISP_GEO_METHOD_ORIGIN_SIZE:  //is working
+      GST_INFO ("DISP_GEO_METHOD_ORIGIN_SIZE");
+      gst_video_sink_center_rect (src, dst, &res, FALSE);
+      gst_video_sink_center_rect (dst, src, &src_input, FALSE);
+      break;
+    case DISP_GEO_METHOD_FULL_SCREEN:  //is working
+      GST_INFO ("DISP_GEO_METHOD_FULL_SCREEN");
+      res.x = res.y = 0;
+      res.w = window->render_rectangle.w;
+      res.h = window->render_rectangle.h;
+      break;
+    case DISP_GEO_METHOD_CROPPED_FULL_SCREEN:
+      GST_INFO ("DISP_GEO_METHOD_CROPPED_FULL_SCREEN");
+      gst_video_sink_center_rect (src, dst, &res, FALSE);
+      gst_video_sink_center_rect (dst, src, &src_input, FALSE);
+      res.x = res.y = 0;
+      res.w = dst.w;
+      res.h = dst.h;
+      break;
+    default:
+      break;
+  }
+
+  switch (window->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;
+
+    default:
+      GST_ERROR ("Unsupported rotation [%d]... set DEGREE 0.",
+          window->rotate_angle);
+      break;
+  }
+
+  switch (window->flip) {
+    case FLIP_NONE:
+      break;
+    case FLIP_VERTICAL:
+      transform = WL_OUTPUT_TRANSFORM_FLIPPED;
+      break;
+    case FLIP_HORIZONTAL:
+      transform = WL_OUTPUT_TRANSFORM_FLIPPED_180;
+      break;
+    case FLIP_BOTH:
+      transform = WL_OUTPUT_TRANSFORM_180;
+      break;
+    default:
+      GST_ERROR ("Unsupported flip [%d]... set FLIP_NONE.", window->flip);
+  }
+
+  GST_INFO
+      ("window[%d x %d] src[%d,%d,%d x %d],dst[%d,%d,%d x %d],input[%d,%d,%d x %d],result[%d,%d,%d x %d]",
+      window->render_rectangle.w, window->render_rectangle.h,
+      src.x, src.y, src.w, src.h,
+      dst.x, dst.y, dst.w, dst.h,
+      src_input.x, src_input.y, src_input.w, src_input.h,
+      res.x, res.y, res.w, res.h);
+
+  GST_INFO ("video (%d x %d)", window->video_width, window->video_height);
+  GST_INFO ("src_input(%d, %d, %d x %d)", src_input.x, src_input.y, src_input.w,
+      src_input.h);
+  GST_INFO ("src_origin(%d, %d, %d x %d)", src_origin.x, src_origin.y,
+      src_origin.w, src_origin.h);
+  GST_INFO ("src(%d, %d, %d x %d)", src.x, src.y, src.w, src.h);
+  GST_INFO ("dst(%d,%d,%d x %d)", dst.x, dst.y, dst.w, dst.h);
+  GST_INFO ("window->render_rectangle(%d,%d,%d x %d)",
+      window->render_rectangle.x, window->render_rectangle.y,
+      window->render_rectangle.w, window->render_rectangle.h);
+  GST_INFO ("res(%d, %d, %d x %d)", res.x, res.y, res.w, res.h);
+
+  if (window->subsurface) {
+    GST_INFO ("have window->subsurface");
+    wl_subsurface_set_position (window->subsurface,
+        window->render_rectangle.x + res.x, window->render_rectangle.y + res.y);
+    GST_INFO ("wl_subsurface_set_position(%d,%d)",
+        window->render_rectangle.x + res.x, window->render_rectangle.y + res.y);
+  }
+  wl_viewport_set_destination (window->viewport, res.w, res.h);
+  GST_INFO ("wl_viewport_set_destination(%d,%d)", res.w, res.h);
+
+  wl_viewport_set_source (window->viewport, wl_fixed_from_int (src_input.x),
+      wl_fixed_from_int (src_input.y), wl_fixed_from_int (src_input.w),
+      wl_fixed_from_int (src_input.h));
+  GST_INFO ("wl_viewport_set_source(%d,%d, %d x %d)", src_input.x, src_input.y,
+      src_input.w, src_input.h);
+
+  wl_surface_set_buffer_transform (window->surface, transform);
+  GST_INFO ("wl_surface_set_buffer_transform (%d)", transform);
+
+  if (commit) {
+    wl_surface_damage (window->surface, 0, 0, res.w, res.h);
+    wl_surface_commit (window->surface);
+  }
+
+  /* this is saved for use in wl_surface_damage */
+  window->surface_width = res.w;
+  window->surface_height = res.h;
+
+#else
+  gst_video_sink_center_rect (src, window->render_rectangle, &res, TRUE);
+  if (window->subsurface)
+    wl_subsurface_set_position (window->subsurface,
+        window->render_rectangle.x + res.x, window->render_rectangle.y + res.y);
+
+  wl_viewport_set_destination (window->viewport, res.w, res.h);
+
+  if (commit) {
+    wl_surface_damage (window->surface, 0, 0, res.w, res.h);
+    wl_surface_commit (window->surface);
+  }
+
+  /* this is saved for use in wl_surface_damage */
+  window->surface_width = res.w;
+  window->surface_height = res.h;
+#endif
+}
+
+void
+gst_wl_window_set_video_info (GstWlWindow * window, GstVideoInfo * info)
+{
+  FUNCTION_ENTER ();
+
+  g_return_if_fail (window != NULL);
+
+  window->video_width =
+      gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d);
+  window->video_height = info->height;
+
+  if (window->render_rectangle.w != 0)
+    gst_wl_window_resize_internal (window, FALSE);
+}
+
+void
+gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
+    gint w, gint h)
+{
+  FUNCTION_ENTER ();
+
+  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;
+
+  if (window->video_width != 0)
+    gst_wl_window_resize_internal (window, TRUE);
+}
+
+#ifdef GST_WLSINK_ENHANCEMENT
+void
+gst_wl_window_set_rotate_angle (GstWlWindow * window, guint rotate_angle)
+{
+  FUNCTION_ENTER ();
+  g_return_if_fail (window != NULL);
+  window->rotate_angle = rotate_angle;
+  GST_INFO ("rotate_angle value is (%d)", window->rotate_angle);
+
+}
+
+void
+gst_wl_window_set_disp_geo_method (GstWlWindow * window, guint disp_geo_method)
+{
+  FUNCTION_ENTER ();
+  g_return_if_fail (window != NULL);
+  window->disp_geo_method = disp_geo_method;
+  GST_INFO ("disp_geo_method value is (%d)", window->disp_geo_method);
+}
+
+void
+gst_wl_window_set_orientation (GstWlWindow * window, guint orientation)
+{
+  FUNCTION_ENTER ();
+  g_return_if_fail (window != NULL);
+  window->orientation = orientation;
+  GST_INFO ("orientation value is (%d)", window->orientation);
+}
+
+void
+gst_wl_window_set_flip (GstWlWindow * window, guint flip)
+{
+  FUNCTION_ENTER ();
+  g_return_if_fail (window != NULL);
+  window->flip = flip;
+  GST_INFO ("flip value is (%d)", window->flip);
+}
+#endif
diff --git a/waylandsink/src/wlwindow.h b/waylandsink/src/wlwindow.h
new file mode 100644 (file)
index 0000000..3dc3cda
--- /dev/null
@@ -0,0 +1,98 @@
+/* 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 <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))
+#if 1
+#define FUNCTION_ENTER()       GST_INFO("<ENTER>")
+#else
+#define FUNCTION_ENTER()
+#endif
+typedef struct _GstWlWindow GstWlWindow;
+typedef struct _GstWlWindowClass GstWlWindowClass;
+
+struct _GstWlWindow
+{
+  GObject parent_instance;
+
+  GstWlDisplay *display;
+  struct wl_surface *surface;
+  struct wl_subsurface *subsurface;
+  struct wl_viewport *viewport;
+  struct wl_shell_surface *shell_surface;
+
+  /* the size of the destination area where we are overlaying our subsurface */
+  GstVideoRectangle render_rectangle;
+  /* the size of the video in the buffers */
+  gint video_width, video_height;
+  /* the size of the (sub)surface */
+  gint surface_width, surface_height;
+#ifdef GST_WLSINK_ENHANCEMENT
+  /*Display geometry method */
+  guint disp_geo_method;
+  guint rotate_angle;
+  guint orientation;
+  guint flip;
+#endif
+};
+
+struct _GstWlWindowClass
+{
+  GObjectClass parent_class;
+};
+
+GType gst_wl_window_get_type (void);
+
+GstWlWindow *gst_wl_window_new_toplevel (GstWlDisplay * display,
+    GstVideoInfo * video_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);
+
+/* functions to manipulate the size on non-toplevel windows */
+void gst_wl_window_set_video_info (GstWlWindow * window, GstVideoInfo * info);
+void gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y,
+    gint w, gint h);
+
+#ifdef GST_WLSINK_ENHANCEMENT
+void gst_wl_window_set_rotate_angle (GstWlWindow * window, guint rotate_angle);
+void gst_wl_window_set_disp_geo_method (GstWlWindow * window,
+    guint disp_geo_method);
+void gst_wl_window_set_orientation (GstWlWindow * window, guint orientation);
+void gst_wl_window_set_flip (GstWlWindow * window, guint flip);
+#endif
+
+
+G_END_DECLS
+#endif /* __GST_WL_WINDOW_H__ */