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