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
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 \
AC_INIT(gst-plugins-tizen, 1.0)
-
+
dnl versions of gstreamer and plugins-base
GST_MAJORMINOR=1.0
GST_REQUIRED=1.2.0
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
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
wfdtsdemux/Makefile
waylandsrc/Makefile
waylandsrc/src/Makefile
+drmdecryptor/Makefile
+drmdecryptor/src/Makefile
+waylandsink/Makefile
+waylandsink/src/Makefile
)
--- /dev/null
+SUBDIRS = src\r
--- /dev/null
+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
+
--- /dev/null
+/*\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
--- /dev/null
+/*\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
+%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
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)
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)
%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}
--- /dev/null
+SUBDIRS = src
--- /dev/null
+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
--- /dev/null
+/* 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, ¶ms);
+ 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, ¶ms);
+ 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, ¶ms);
+ 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)
--- /dev/null
+/*
+ * 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__ */
--- /dev/null
+<?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>
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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__*/
--- /dev/null
+/* 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, ®istry_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;
+}
--- /dev/null
+/* 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__ */
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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
--- /dev/null
+/* 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__ */