From a70c2f3570e4736a630076f2affbf528daf2b887 Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Tue, 17 Oct 2017 13:32:09 +0900 Subject: [PATCH 01/16] fix resource leak in RTSP_ERROR case - add g_object_unref in RTSP_ERROR case. - set wfd_msg to NULL after message_free for avoid double free in error case. Signed-off-by: SeokHoon Lee Change-Id: Ieab1eea9c33512bcc60d20666e6bd59ecdec2692 --- packaging/gst-plugins-tizen.spec | 2 +- wfdmanager/wfdbase/gstwfdbasesrc.c | 1 + wfdmanager/wfdsrc/gstwfdsrc.c | 6 +++++- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index a50a2db..7e171cf 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -9,7 +9,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 46 +Release: 47 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c b/wfdmanager/wfdbase/gstwfdbasesrc.c index 16cf91f..9de2017 100644 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c +++ b/wfdmanager/wfdbase/gstwfdbasesrc.c @@ -944,6 +944,7 @@ gst_wfd_base_src_send_request (GstWFDBaseSrc * src) } gst_wfd_message_free (wfd_msg); + wfd_msg = NULL; /* send request message */ GST_DEBUG_OBJECT (src, "send reuest..."); diff --git a/wfdmanager/wfdsrc/gstwfdsrc.c b/wfdmanager/wfdsrc/gstwfdsrc.c index b89c75f..b45cb87 100644 --- a/wfdmanager/wfdsrc/gstwfdsrc.c +++ b/wfdmanager/wfdsrc/gstwfdsrc.c @@ -1193,10 +1193,14 @@ gst_wfd_src_switch_tcp (GstWFDBaseSrc *bsrc) { GstRTSPResult res = GST_RTSP_OK; GstWFDSrc *src = GST_WFD_SRC (bsrc); + GCancellable *cancellable; - if (GST_RTSP_OK != gst_rtsp_connection_accept (src->tcp, &src->tcp_connection, g_cancellable_new())) { + cancellable = g_cancellable_new(); + + if (GST_RTSP_OK != gst_rtsp_connection_accept (src->tcp, &src->tcp_connection, cancellable)) { g_socket_close (src->tcp, NULL); GST_ERROR ("Failed to accept connection"); + g_object_unref(cancellable); return GST_RTSP_ERROR; } else { g_socket_close (src->tcp, NULL); -- 2.7.4 From 902d1cffe70b68ca8904d813630442c89fdf72d8 Mon Sep 17 00:00:00 2001 From: Andriy Martynets Date: Tue, 26 Sep 2017 18:41:31 +0300 Subject: [PATCH 02/16] Video360 plugin implementation added Change-Id: I893ed0a2c35e735fe3476b5d0278dde21228a2fe Signed-off-by: Andriy Martynets --- AUTHORS | 1 + Makefile.am | 8 + PLUGINS | 1 + configure.ac | 30 + packaging/gst-plugins-tizen.spec | 12 +- video360/Makefile.am | 1 + video360/src/Makefile.am | 21 + video360/src/gstvideo360-equirectangular.c | 236 +++++++ video360/src/gstvideo360-formats.c | 293 ++++++++ video360/src/gstvideo360-gl.c | 791 ++++++++++++++++++++++ video360/src/gstvideo360.c | 1014 ++++++++++++++++++++++++++++ video360/src/gstvideo360.h | 359 ++++++++++ video360/src/video360.h | 72 ++ 13 files changed, 2836 insertions(+), 3 deletions(-) create mode 100644 video360/Makefile.am create mode 100644 video360/src/Makefile.am create mode 100644 video360/src/gstvideo360-equirectangular.c create mode 100644 video360/src/gstvideo360-formats.c create mode 100644 video360/src/gstvideo360-gl.c create mode 100644 video360/src/gstvideo360.c create mode 100644 video360/src/gstvideo360.h create mode 100644 video360/src/video360.h diff --git a/AUTHORS b/AUTHORS index 96cbfc8..db30c45 100644 --- a/AUTHORS +++ b/AUTHORS @@ -3,3 +3,4 @@ Seungbae Shin Younghwan Ahn Jeongmo Yang Sangchul Lee +Andriy Martynets diff --git a/Makefile.am b/Makefile.am index 1e6e3c0..ffad5e7 100755 --- a/Makefile.am +++ b/Makefile.am @@ -57,6 +57,10 @@ if GST_TIZEN_USE_ALFEC SUBDIRS += alfec endif +if GST_TIZEN_USE_VIDEO360 +SUBDIRS += video360 +endif + DIST_SUBDIRS = common if GST_TIZEN_USE_ENCODEBIN @@ -96,6 +100,10 @@ if GST_TIZEN_USE_ALFEC DIST_SUBDIRS += alfec endif +if GST_TIZEN_USE_VIDEO360 +DIST_SUBDIRS += video360 +endif + EXTRA_DIST = \ gstreamer.spec gstreamer.spec.in \ configure.ac autogen.sh depcomp \ diff --git a/PLUGINS b/PLUGINS index 02d69f2..4b0758e 100644 --- a/PLUGINS +++ b/PLUGINS @@ -14,6 +14,7 @@ fimcconvert fimcconvert pdpushsrc pdpushsrc Progressive download src plugin tizenipc tizenipcsrc,tizenipcsink toggle toggle Base transform plugin +video360 video360 Spherical video processing plugin waylandsrc waylandsrc wfdmanager wfdsrc,wfdrtpbuffer wfdtsdemux wfdtsparse,wfdtsdemux diff --git a/configure.ac b/configure.ac index 761c244..2f59780 100755 --- a/configure.ac +++ b/configure.ac @@ -358,6 +358,34 @@ AC_ARG_ENABLE(ext-alfec, AC_HELP_STRING([--enable-ext-alfec], [using alfec]), [GST_TIZEN_USE_ALFEC=yes]) AM_CONDITIONAL(GST_TIZEN_USE_ALFEC, test "x$GST_TIZEN_USE_ALFEC" = "xyes") +dnl use video360 -------------------------------------------------------------------------- +AC_ARG_ENABLE(video360, AC_HELP_STRING([--enable-video360], [using video360]), +[ + case "${enableval}" in + yes) GST_TIZEN_USE_VIDEO360=yes ;; + no) GST_TIZEN_USE_VIDEO360=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-video360) ;; + esac + ], + [GST_TIZEN_USE_VIDEO360=yes]) +AM_CONDITIONAL(GST_TIZEN_USE_VIDEO360, test "x$GST_TIZEN_USE_VIDEO360" = "xyes") + +dnl video360 related options --------------------------------------------------------------- +AC_ARG_WITH([native-formats], AS_HELP_STRING([--with-native-formats], + [Build with support for Tizen native video formats])) +AS_IF([test "x$with_native_formats" = "xyes"], [CFLAGS="$CFLAGS -DGST_TIZEN_USE_NATIVE_FORMATS"]) + +AC_ARG_WITH([gles2], AS_HELP_STRING([--with-gles2], [Build with OpenGL ES 2.0])) +AS_IF([test "x$with_gles2" = "xyes"], [ + PKG_CHECK_MODULES(GLES, [ + gles20 + ], [ + AC_SUBST(GLES_CFLAGS) + AC_SUBST(GLES_LIBS) + ]) + CFLAGS="$CFLAGS -DGST_TIZEN_GL_API_GLES2" +]) + AC_OUTPUT( Makefile common/Makefile @@ -385,4 +413,6 @@ tizenipc/Makefile tizenipc/src/Makefile wfdtizenmanager/Makefile alfec/Makefile +video360/Makefile +video360/src/Makefile ) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 7e171cf..386e1aa 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -9,7 +9,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 47 +Release: 48 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ @@ -37,6 +37,7 @@ BuildRequires: pkgconfig(libtbm) BuildRequires: libdrm-devel BuildRequires: pkgconfig(vconf) BuildRequires: pkgconfig(mm-common) +BuildRequires: pkgconfig(gles20) %if %{with wayland} BuildRequires: pkgconfig(wayland-client) >= 1.0.0 BuildRequires: pkgconfig(wayland-tbm-client) @@ -82,7 +83,9 @@ export CFLAGS="$CFLAGS_DEFAULT -DTIZEN_FEATURE_PRODUCT_TM1" --enable-ext-wfdtizenmanager\ --enable-ext-alfec\ --disable-tizenipc\ - --disable-static + --disable-static\ + --with-native-formats\ + --with-gles2 make %{?jobs:-j%jobs} @@ -103,7 +106,10 @@ export CFLAGS="$CFLAGS_DEFAULT" --enable-ext-wfdtizenmanager\ --enable-ext-alfec\ --disable-tizenipc\ - --disable-static + --disable-static\ + --with-native-formats\ + --with-gles2 + make %{?jobs:-j%jobs} diff --git a/video360/Makefile.am b/video360/Makefile.am new file mode 100644 index 0000000..af437a6 --- /dev/null +++ b/video360/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/video360/src/Makefile.am b/video360/src/Makefile.am new file mode 100644 index 0000000..802ea26 --- /dev/null +++ b/video360/src/Makefile.am @@ -0,0 +1,21 @@ +plugin_LTLIBRARIES = libgstvideo360.la + +# sources used to compile this plug-in +libgstvideo360_la_SOURCES = gstvideo360.c\ + gstvideo360-gl.c\ + gstvideo360-equirectangular.c\ + gstvideo360-formats.c + +# compiler and linker flags used to compile this plugin, set in configure.ac +libgstvideo360_la_CFLAGS = $(GST_CFLAGS)\ + $(TBM_CFLAGS)\ + $(MMCOMMON_CFLAGS)\ + $(GLES_CFLAGS)\ + -Wdouble-promotion\ + -fsingle-precision-constant +libgstvideo360_la_LIBADD = $(GST_LIBS) $(TBM_LIBS) $(GLES_LIBS) +libgstvideo360_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgstvideo360_la_LIBTOOLFLAGS = --tag=disable-static + +# headers we need but don't want installed +noinst_HEADERS = gstvideo360.h video360.h diff --git a/video360/src/gstvideo360-equirectangular.c b/video360/src/gstvideo360-equirectangular.c new file mode 100644 index 0000000..3b04fe8 --- /dev/null +++ b/video360/src/gstvideo360-equirectangular.c @@ -0,0 +1,236 @@ +/* + * Video360 GStreamer plug-in + * Copyright (C) 2017 Samsung R&D Institute Ukraine + * All rights reserved. + * + * @author: Andriy Martynets + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstvideo360.h" + +const char *equirectangular_vertex_source = "\ + #version 100 \n\ + \n\ + precision highp float; \n\ + \n\ + attribute vec2 position; \n\ + uniform vec2 fov; /* Horizontal / vertical field of view */ \n\ + uniform float zoom; /* Zoom factor */ \n\ + varying vec2 pos; \n\ + \n\ + void main() \n\ + { \n\ + pos = vec2 (position.x * fov.x * zoom, -position.y * fov.y * zoom); \n\ + gl_Position = vec4 (position, 0.0, 1.0); \n\ + } \n\ +"; + +const char *equirectangular_fragment_source = "\ + #version 100 \n\ + \n\ + #extension GL_OES_EGL_image_external : require \n\ + \n\ + precision highp float; \n\ + \n\ + varying vec2 pos; /* in NDC [-1, 1] */ \n\ + \n\ + uniform samplerExternalOES tex; /* Input texture - video frame */ \n\ + uniform vec3 dov; /* Direction of view */ \n\ + /* Normalized cropped fields: x - left, y - bottom, z - right, w - top */ \n\ + uniform vec4 crops; \n\ + \n\ + #define M_PI 3.14159265358979323846 /* pi */ \n\ + #define lambda0 dov.x \n\ + #define phi1 dov.y \n\ + \n\ + vec2 texel_coordinates (vec2 position) \n\ + { \n\ + float longitude, latitude; /* in radians */ \n\ + float ro; /* radius from projection centre to the point */ \n\ + float c; /* angular distance of the point from the center */ \n\ + float cos_c, sin_c, ctg_c, cos_phi1, sin_phi1; \n\ + float x, y; /* in texture coordinates [0, 1] */ \n\ + /* vec4 gl_FragCoord; (x, y) in screen coordinates with bias of 0.5 */ \n\ + \n\ + sin_phi1 = sin (phi1); \n\ + cos_phi1 = cos (phi1); \n\ + \n\ + /* We don't check for (position.x != 0.0 || position.y != 0.0) as GL \n\ + * seems to kindly skip (0.0, 0.0) coordinate \n\ + */ \n\ + /* Calculate c and ro */ \n\ + ro = length (position); \n\ + c = atan (ro); \n\ + sin_c = sin (c); \n\ + cos_c = cos (c); \n\ + ctg_c = cos_c / sin_c; \n\ + \n\ + /* Calculate longitude and latitude of the point in radians */ \n\ + longitude = lambda0 + \n\ + atan (position.x, \n\ + ro * cos_phi1 * ctg_c - position.y * sin_phi1); \n\ + latitude = asin (cos_c * sin_phi1 + position.y * sin_c * cos_phi1 / ro); \n\ + \n\ +#ifndef GL_FRAGMENT_PRECISION_HIGH \n\ + /* Take small region in the centre as it is. This eliminates 'dot' \n\ + * artifact caused by lack of precision. \n\ + * */ \n\ + if (abs (position.x) <= 1.0 / 128.0 && \n\ + abs (position.y) <= 1.0 / 128.0) { \n\ + longitude = lambda0 + position.x; \n\ + latitude = phi1 + position.y; \n\ + } \n\ +#endif \n\ + \n\ + x = fract (longitude / (M_PI * 2.0) + 1.5); \n\ + y = 0.5 - latitude / M_PI; \n\ + \n\ + if (y > crops.w || y < crops.y || x < crops.x || x > crops.z) { \n\ + /* Discard the fragment if it is outside of the input frame */ \n\ + discard; \n\ + } else { \n\ + /* Convert coordinates to input frame */ \n\ + x -= crops.x; \n\ + y -= crops.y; \n\ + } \n\ + \n\ + return vec2 (x, y); \n\ + } \n\ + \n\ + vec4 get_texel () \n\ + { \n\ +#ifdef GL_FRAGMENT_PRECISION_HIGH \n\ + return texture2D (tex, texel_coordinates (pos)); \n\ +#else \n\ + /* Add some alchemy here to compensate horisontal pixels 'rotation' \n\ + * caused by lack of precision (in arctangent function in particular). \n\ + * */ \n\ + vec4 color; \n\ + vec2 c, c_r, c_rr; \n\ + \n\ + c = texel_coordinates (pos); \n\ + c_r = texel_coordinates (vec2 (pos.x + 1.0/512.0, pos.y)); \n\ + c_rr = texel_coordinates (vec2 (pos.x + 2.0/512.0, pos.y)); \n\ + \n\ + if (c.x == c_r.x) \n\ + color = mix (texture2D (tex, c), texture2D (tex, c_rr), 0.33); \n\ + else if (c.x == c_rr.x) \n\ + color = mix (texture2D (tex, c), texture2D (tex, c_r), 0.67); \n\ + else \n\ + color = mix (texture2D (tex, c), texture2D (tex, c_r), 0.5); \n\ + \n\ + return color; \n\ +#endif \n\ + } \n\ +"; + +const char *direct_colors_fragment_source = "\ + \n\ + vec4 get_texel (); \n\ + \n\ + void main() \n\ + { \n\ + \n\ + gl_FragColor = get_texel (); \n\ + } \n\ +"; + +const char *reverse_colors_fragment_source = "\ + \n\ + vec4 get_texel (); \n\ + \n\ + void main() \n\ + { \n\ + \n\ + gl_FragColor = get_texel ().bgra; \n\ + } \n\ +"; + +gboolean +_equirectangular_bind_vertex_buffers (GstVideo360 * this) +{ + static const float vertices[] = { + -1.0f, 1.0f, + 1.0f, 1.0f, + 1.0f, -1.0f, + -1.0f, -1.0f + }; + static const GLubyte elements[] = { + 0, 1, 2, + 2, 3, 0 + }; + + glGenBuffers (2, this->bo_ids); + glBindBuffer (GL_ARRAY_BUFFER, this->bo_ids[0]); + glBufferData (GL_ARRAY_BUFFER, sizeof (vertices), vertices, GL_STATIC_DRAW); + glBindBuffer (GL_ELEMENT_ARRAY_BUFFER, this->bo_ids[1]); + glBufferData (GL_ELEMENT_ARRAY_BUFFER, sizeof (elements), elements, + GL_STATIC_DRAW); + + return !GL_ERROR; +} + +gboolean +_equirectangular_program_attribs (GstVideo360 * this) +{ + GLint pos_attrib; + + pos_attrib = glGetAttribLocation (this->prog_id, "position"); + glVertexAttribPointer (pos_attrib, 2, GL_FLOAT, GL_FALSE, 2 * sizeof (float), + 0); + glEnableVertexAttribArray (pos_attrib); + + glUniform1i (glGetUniformLocation (this->prog_id, "tex"), 1); + + this->fov_uni = glGetUniformLocation (this->prog_id, "fov"); + gst_video360_set_fov_gl (this); + + this->dov_uni = glGetUniformLocation (this->prog_id, "dov"); + gst_video360_set_dov_gl (this); + + this->crops_uni = glGetUniformLocation (this->prog_id, "crops"); + gst_video360_set_crops_gl (this); + + this->zoom_uni = glGetUniformLocation (this->prog_id, "zoom"); + gst_video360_set_zoom_gl (this); + + return !GL_ERROR; +} diff --git a/video360/src/gstvideo360-formats.c b/video360/src/gstvideo360-formats.c new file mode 100644 index 0000000..79ef74c --- /dev/null +++ b/video360/src/gstvideo360-formats.c @@ -0,0 +1,293 @@ +/* + * Video360 GStreamer plug-in + * Copyright (C) 2017 Samsung R&D Institute Ukraine + * All rights reserved. + * + * @author: Andriy Martynets + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gstvideo360.h" + +gboolean +gst_video360_standard_formats_renderer (GstVideo360 * this, void *in_data, + void *out_data) +{ +#ifdef GST_TIZEN_USE_NATIVE_FORMATS +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_USE_EGLIMAGE + tbm_surface_h out_tbm_surface; + EGLImage out_egl_image; +#endif +#endif +#endif + int i = 0; + gboolean ret = TRUE; + +#ifdef GST_TIZEN_USE_TIMING + struct timespec start_time, stop_time; + + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start_time); +#endif + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_USE_EGLIMAGE + do { + memcpy (this->input_image_ptr[i], in_data, + this->input_frame_planes[i].size); + in_data += this->input_frame_planes[i].size; + } while (++i < this->input_surf_info.num_planes); + +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + if (!(out_tbm_surface = + tbm_surface_internal_create_with_flags (this->output_frame_width, + this->output_frame_height, TBM_FORMAT_XBGR8888, TBM_BO_WC))) { + GST_ERROR ("tbm_surface_create failed"); + ret = FALSE; + } + + out_egl_image = this->eglCreateImage (this->egl_display, + EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, + (EGLClientBuffer) out_tbm_surface, NULL); + + if (ret && out_egl_image == EGL_NO_IMAGE_KHR) { + EGL_ERROR; + GST_ERROR ("eglCreateImageKHR failed"); + ret = FALSE; + } else { + glActiveTexture (GL_TEXTURE0); + this->glEGLImageTargetTexture2D (GL_TEXTURE_2D, + (GLeglImageOES) out_egl_image); + + glActiveTexture (GL_TEXTURE1); + } +#endif + +#else + /* This code is not implemented and must be done in platform specific way. + * As an option a standard GL approach might be considered on systems with + * optimized driver: + * glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, this->input_frame_width, + * this->input_frame_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, in_data); + * ret = !GL_ERROR; + * */ +#error "Sampler texture upload code not implemented" +#endif +#else + /* Space for alternate platform code */ +#endif + +#ifdef GST_TIZEN_USE_TIMING + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &stop_time); + this->uploads_nanoseconds += (stop_time.tv_sec - start_time.tv_sec) * + 1000000000; + this->uploads_nanoseconds += stop_time.tv_nsec - start_time.tv_nsec; +#endif + + ret = ret && gst_video360_draw_gl (this); + +#ifdef GST_TIZEN_USE_TIMING + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start_time); +#endif + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_USE_EGLIMAGE +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + ((MMVideoBuffer *) out_data)->handle.bo[0] = + tbm_bo_ref (tbm_surface_internal_get_bo (out_tbm_surface, 0)); + this->eglDestroyImage (this->egl_display, out_egl_image); + tbm_surface_destroy (out_tbm_surface); +#else + memcpy (out_data, this->output_image_ptr, this->output_frame_buffer_size); +#endif +#else + glReadPixels (0, 0, this->output_frame_width, this->output_frame_height, + GL_RGBA, GL_UNSIGNED_BYTE, out_data); + ret = !GL_ERROR && ret; +#endif +#else + /* Space for alternate platform code */ +#endif + +#ifdef GST_TIZEN_USE_TIMING + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &stop_time); + this->downloads_nanoseconds += (stop_time.tv_sec - start_time.tv_sec) * + 1000000000; + this->downloads_nanoseconds += stop_time.tv_nsec - start_time.tv_nsec; +#endif + + return ret; +} + +#ifdef GST_TIZEN_USE_NATIVE_FORMATS +#if 0 +/* This piece of code is left here for reference purposes only. It explains structure of information for SN12 video format */ +typedef struct +{ + MMVideoBufferType type; /* MM_VIDEO_BUFFER_TYPE_TBM_BO - bo field of MMVideoBufferHandle structure to be used. */ + MMPixelFormatType format; /* MM_PIXEL_FORMAT_NV12 */ + int plane_num; /* 0 */ + int width[MM_VIDEO_BUFFER_PLANE_MAX]; /* buffer width: width[0] - Y plane, width[1] - UV plane */ + int height[MM_VIDEO_BUFFER_PLANE_MAX]; /* buffer height: height[0] - Y plane, height[1] - UV plane */ + int stride_width[MM_VIDEO_BUFFER_PLANE_MAX]; /* buffer horizontal stride (in bytes): stride_width[0] - Y plane, stride_width[1] - UV plane */ + int stride_height[MM_VIDEO_BUFFER_PLANE_MAX]; /* buffer vertical stride (in lines): stride_height[0] - Y plane, stride_height[1] - UV plane */ + int size[MM_VIDEO_BUFFER_PLANE_MAX]; /* size of planes in bytes (stride_width * stride_height): size[0] - Y plane, size[1] - UV plane */ + void *data[MM_VIDEO_BUFFER_PLANE_MAX]; /* pointers to planes: data[0] - Y plane, data[1] - UV plane (data[1] == data[0] + size[0]) */ + int handle_num; /* 0 */ + int handle_size[MM_VIDEO_BUFFER_PLANE_MAX]; /* 0 0 */ + MMVideoBufferHandle handle; /* buffer object addresses handle.bo[0] */ + int is_secured; /* FALSE - user accessible. */ + int flush_request; /* FALSE */ +} MMVideoBuffer; +#endif + +gboolean +gst_video360_native_formats_renderer (GstVideo360 * this, void *in_data, + void *out_data) +{ +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_USE_EGLIMAGE + tbm_surface_h in_tbm_surface = NULL, out_tbm_surface = NULL; + EGLImage in_egl_image, out_egl_image; +#endif +#endif + gboolean ret = TRUE; + +#ifdef GST_TIZEN_USE_TIMING + struct timespec start_time, stop_time; + + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start_time); +#endif + + if (in_data && + ((MMVideoBuffer *) in_data)->type == MM_VIDEO_BUFFER_TYPE_TBM_BO && + ((MMVideoBuffer *) in_data)->size[0]) { + + /* Note: omx provides separate BOs for each plane when sprd provides a + * single one for both. + * */ + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_USE_EGLIMAGE + if (!(in_tbm_surface = + tbm_surface_internal_create_with_bos (&this->input_surf_info, + (tbm_bo *) ((MMVideoBuffer *) in_data)->handle.bo, + ((MMVideoBuffer *) in_data)->handle.bo[1] ? this-> + input_surf_info.num_planes : 1)) || + !(out_tbm_surface = + tbm_surface_internal_create_with_flags (this->output_frame_width, + this->output_frame_height, TBM_FORMAT_XBGR8888, TBM_BO_WC))) { + GST_ERROR ("tbm_surface_create failed"); + ret = FALSE; + } + + in_egl_image = this->eglCreateImage (this->egl_display, + EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, + (EGLClientBuffer) in_tbm_surface, NULL); + + out_egl_image = this->eglCreateImage (this->egl_display, + EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, + (EGLClientBuffer) out_tbm_surface, NULL); + + if (ret + && (in_egl_image == EGL_NO_IMAGE_KHR || + out_egl_image == EGL_NO_IMAGE_KHR)) { + EGL_ERROR; + GST_ERROR ("eglCreateImageKHR failed"); + ret = FALSE; + } else { + glActiveTexture (GL_TEXTURE0); + this->glEGLImageTargetTexture2D (GL_TEXTURE_2D, + (GLeglImageOES) out_egl_image); + + glActiveTexture (GL_TEXTURE1); + this->glEGLImageTargetTexture2D (GL_TEXTURE_EXTERNAL_OES, + (GLeglImageOES) in_egl_image); + } +#else + /* This code is removed as no longer works and must be added if there will + * be a need. + * */ +#endif +#else + /* Space for alternate platform code */ +#endif + +#ifdef GST_TIZEN_USE_TIMING + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &stop_time); + this->uploads_nanoseconds += (stop_time.tv_sec - start_time.tv_sec) * + 1000000000; + this->uploads_nanoseconds += stop_time.tv_nsec - start_time.tv_nsec; +#endif + + ret = ret && gst_video360_draw_gl (this); + +#ifdef GST_TIZEN_USE_TIMING + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start_time); +#endif + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_USE_EGLIMAGE + ((MMVideoBuffer *) out_data)->handle.bo[0] = + tbm_bo_ref (tbm_surface_internal_get_bo (out_tbm_surface, 0)); + this->eglDestroyImage (this->egl_display, in_egl_image); + this->eglDestroyImage (this->egl_display, out_egl_image); + tbm_surface_destroy (in_tbm_surface); + tbm_surface_destroy (out_tbm_surface); +#else + glReadPixels (0, 0, this->output_frame_width, this->output_frame_height, + GL_RGBA, GL_UNSIGNED_BYTE, out_data); + ret = !GL_ERROR && ret; +#endif +#else + /* Space for alternate platform code */ +#endif + +#ifdef GST_TIZEN_USE_TIMING + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &stop_time); + this->downloads_nanoseconds += (stop_time.tv_sec - start_time.tv_sec) * + 1000000000; + this->downloads_nanoseconds += stop_time.tv_nsec - start_time.tv_nsec; +#endif + } + + return ret; +} +#endif diff --git a/video360/src/gstvideo360-gl.c b/video360/src/gstvideo360-gl.c new file mode 100644 index 0000000..1b0c26d --- /dev/null +++ b/video360/src/gstvideo360-gl.c @@ -0,0 +1,791 @@ +/* + * Video360 GStreamer plug-in + * Copyright (C) 2017 Samsung R&D Institute Ukraine + * All rights reserved. + * + * @author: Andriy Martynets + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + +#include "gstvideo360.h" + +/* Below functions return TRUE on success and FALSE otherwise */ +static gboolean _init_gl_platform (GstVideo360 * this); +static gboolean _prepare_gl_framebuffer (GstVideo360 * this); +static gboolean _prepare_gl_program (GstVideo360 * this, + char const *const *vertex_sources, int vertex_count, + char const *const *fragment_sources, int fragment_count); + +/* Below functions return TRUE on errors and FALSE otherwise */ +static gboolean _check_gl_shader_compile_error (GLuint shader, + const char *name); +#define GL_SHADER_ERROR(sh,n) _check_gl_shader_compile_error (sh, n) + +static gboolean _check_gl_program_link_error (GLuint program); +#define GL_PROGRAM_ERROR(prog) _check_gl_program_link_error (prog) + +/* Returns TRUE if framebuffer is complete */ +static gboolean _check_gl_framebuffer (); + +gboolean +gst_video360_init_gl (GstVideo360 * this) +{ + const GLubyte *string; + char const *vertex_sources[1]; + char const *fragment_sources[2]; + GLint param; + + if (!_init_gl_platform (this)) + return FALSE; + + if (!(string = glGetString (GL_VERSION))) { + GST_ERROR ("OpenGL initialization failed"); + return FALSE; + } + GST_INFO ("%s initialized", string); + + string = glGetString (GL_VENDOR); + GST_INFO ("OpenGL ES vendor: %s", string); + + string = glGetString (GL_RENDERER); + GST_INFO ("OpenGL ES renderer: %s", string); + + string = glGetString (GL_SHADING_LANGUAGE_VERSION); + GST_INFO ("%s", string); + + string = glGetString (GL_EXTENSIONS); + GST_INFO ("OpenGL ES extensions supported: %s", string); + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_USE_EGLIMAGE + if (strstr ((const char *) string, "GL_OES_EGL_image_external")) { + /* We need GL_OES_EGL_image_external extension which introduces new texture + * target TEXTURE_EXTERNAL_OES. + * GL_OES_EGL_image introduces the same call but for TEXTURE_2D target only. + * This target doesn't accept YUV EGL images. + * */ + this->glEGLImageTargetTexture2D = (PFNGLEGLIMAGETARGETTEXTURE2DOESPROC) + eglGetProcAddress ("glEGLImageTargetTexture2DOES"); + } + if (!this->glEGLImageTargetTexture2D) { + GST_ERROR ("GL_OES_EGL_image_external isn't supported"); + return FALSE; + } +#endif +#else + /* Space for alternate platform code */ +#endif + +#ifdef GST_TIZEN_USE_MSAA + if (strstr ((const char *) string, "GL_EXT_multisampled_render_to_texture")) { + /* We optionally use GL_EXT_multisampled_render_to_texture extension + * for multi-sampled anti-aliasing (MSAA). + * */ + this->glFramebufferTexture2DMultisample = + (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC) + eglGetProcAddress ("glFramebufferTexture2DMultisampleEXT"); + } +#endif + + if (!_prepare_gl_framebuffer (this)) + return FALSE; + + glGetIntegerv (GL_SAMPLE_BUFFERS, ¶m); + if (param > 0) { + glGetIntegerv (GL_SAMPLES, ¶m); + GST_INFO ("MSAA is enabled with %d samples", param); + } else { + GST_INFO ("No MSAA is used"); + } + + /* TODO(a.martynets): add support for more projection types: + * cubemap and mesh + */ + if (this->projection_type == PROJECTION_TYPE_EQUIRECTANGULAR) { + vertex_sources[0] = equirectangular_vertex_source; + fragment_sources[0] = equirectangular_fragment_source; + fragment_sources[1] = this->input_frame_format == GST_VIDEO_FORMAT_BGRA ? + direct_colors_fragment_source : reverse_colors_fragment_source; + if (!_equirectangular_bind_vertex_buffers (this) || + !_prepare_gl_program (this, vertex_sources, 1, fragment_sources, 2) || + !_equirectangular_program_attribs (this)) + return FALSE; + } else { + GST_ERROR + ("Equirectangular projection is the only supported at the moment"); + return FALSE; + } + + glClearColor (GAP_FILL_COLOUR_RED, GAP_FILL_COLOUR_GREEN, + GAP_FILL_COLOUR_BLUE, 1.0); + glViewport (0, 0, this->output_frame_width, this->output_frame_height); + + return !GL_ERROR; +} + +void +gst_video360_deinit_gl (GstVideo360 * this) +{ + this->fov_uni = this->dov_uni = this->crops_uni = this->zoom_uni = -1; + if (this->prog_id) { + glUseProgram (0); + glDeleteProgram (this->prog_id); + this->prog_id = 0; + } + if (this->bo_ids[0]) { + glDeleteBuffers (2, this->bo_ids); + this->bo_ids[0] = this->bo_ids[1] = 0; + } + if (this->fbo_id) { + glBindFramebuffer (GL_FRAMEBUFFER, 0); + glDeleteFramebuffers (1, &this->fbo_id); + this->fbo_id = 0; + } + if (this->tex_ids[0]) { + glDeleteTextures (2, this->tex_ids); + this->tex_ids[0] = this->tex_ids[1] = 0; + } +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_USE_EGLIMAGE + if (this->input_egl_image != EGL_NO_IMAGE_KHR) { + this->eglDestroyImage (this->egl_display, this->input_egl_image); + this->input_egl_image = EGL_NO_IMAGE_KHR; + } + if (this->output_egl_image != EGL_NO_IMAGE_KHR) { + this->eglDestroyImage (this->egl_display, this->output_egl_image); + this->output_egl_image = EGL_NO_IMAGE_KHR; + } + if (this->input_tbm_surface) { + tbm_surface_destroy (this->input_tbm_surface); + this->input_tbm_surface = NULL; + } + if (this->output_tbm_surface) { + tbm_surface_destroy (this->output_tbm_surface); + this->output_tbm_surface = NULL; + } +#endif + if (this->egl_display != EGL_NO_DISPLAY) { + /* Free-up context */ + eglMakeCurrent (this->egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + this->egl_config = 0; + if (this->egl_surface != EGL_NO_SURFACE) { + eglDestroySurface (this->egl_display, this->egl_surface); + this->egl_surface = EGL_NO_SURFACE; + } + /* Unlink from display and destroy unused resources */ + eglTerminate (this->egl_display); + this->egl_display = EGL_NO_DISPLAY; + } +#ifdef GST_TIZEN_GL_WINDOW_WAYLAND + if (this->wl_display) { + /* Disconnect from the native display */ + wl_display_disconnect (this->wl_display); + this->wl_display = NULL; + } +#else + /* Space for alternate windowing system code */ +#endif /* GL_WINDOW_WAYLAND */ +#else + /* Space for alternate platform code */ +#endif /* GL_PLATFORM_EGL */ +} + +static gboolean +_init_gl_platform (GstVideo360 * this) +{ +#ifdef GST_TIZEN_GL_PLATFORM_EGL + EGLint num_config; + EGLint ver_major; + EGLint ver_minor; + const char *string; + static const EGLint rgb_config_attribs[] = { + EGL_SURFACE_TYPE, EGL_PBUFFER_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_ALPHA_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_NONE + }; + static const EGLint context_attribs[] = { + EGL_CONTEXT_CLIENT_VERSION, 2, + EGL_NONE + }; + + if (eglBindAPI (EGL_OPENGL_ES_API) != EGL_TRUE || EGL_ERROR) { + GST_ERROR ("eglBindAPI failed"); + return FALSE; + } +#ifdef GST_TIZEN_GL_WINDOW_WAYLAND + this->wl_display = wl_display_connect (NULL); + if (this->wl_display == NULL) { + GST_ERROR ("wl_display_connect failed"); + return FALSE; + } + + /* get an EGL display connection */ + this->egl_display = eglGetDisplay (this->wl_display); + if (EGL_ERROR || this->egl_display == EGL_NO_DISPLAY) { + GST_ERROR ("eglGetDisplay failed"); + return FALSE; + } +#else + /* Space for alternate windowing system code */ +#endif /* GL_WINDOW_WAYLAND */ + + /* initialize the EGL display connection */ + eglInitialize (this->egl_display, &ver_major, &ver_minor); + if (EGL_ERROR) { + GST_ERROR ("eglInitialize failed"); + return FALSE; + } + GST_INFO ("EGL platform initialized"); + + string = eglQueryString (this->egl_display, EGL_VERSION); + GST_INFO ("EGL version: %s", string); + + string = eglQueryString (this->egl_display, EGL_VENDOR); + GST_INFO ("EGL vendor: %s", string); + + string = eglQueryString (this->egl_display, EGL_EXTENSIONS); + GST_INFO ("EGL extensions supported: %s", string); + +#ifdef GST_TIZEN_USE_EGLIMAGE + if (!strstr (string, "EGL_TIZEN_image_native_surface")) { + GST_ERROR ("EGL_TIZEN_image_native_surface isn't supported"); + return FALSE; + } + + if (ver_major > 1 || (ver_major == 1 && ver_minor > 4)) { + this->eglCreateImage = + (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress ("eglCreateImage"); + this->eglDestroyImage = + (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress ("eglDestroyImage"); + } else { + /* EGL_TIZEN_image_native_surface assumes EGL_KHR_image_base extension */ + this->eglCreateImage = + (PFNEGLCREATEIMAGEKHRPROC) eglGetProcAddress ("eglCreateImageKHR"); + this->eglDestroyImage = + (PFNEGLDESTROYIMAGEKHRPROC) eglGetProcAddress ("eglDestroyImageKHR"); + } + if (!this->eglCreateImage || !this->eglDestroyImage) { + GST_ERROR ("EGL_KHR_image isn't supported"); + return FALSE; + } +#endif + + /* get an appropriate EGL frame buffer configuration */ + if (eglChooseConfig (this->egl_display, + rgb_config_attribs, &this->egl_config, 1, &num_config) != EGL_TRUE || + num_config != 1 || EGL_ERROR) { + GST_ERROR ("eglChooseConfig failed"); + return FALSE; + } + + /* Create dummy surface - framebuffer will be used instead */ + this->egl_surface = eglCreatePbufferSurface (this->egl_display, + this->egl_config, NULL); + if (EGL_ERROR || this->egl_surface == EGL_NO_SURFACE) { + GST_ERROR ("eglCreatePbufferSurface failed"); + return FALSE; + } + + /* create an EGL rendering context */ + this->egl_context = + eglCreateContext (this->egl_display, this->egl_config, EGL_NO_CONTEXT, + context_attribs); + if (EGL_ERROR || this->egl_context == EGL_NO_CONTEXT) { + GST_ERROR ("eglCreateContext failed"); + return FALSE; + } + + /* Make the context current */ + eglMakeCurrent (this->egl_display, this->egl_surface, this->egl_surface, + this->egl_context); + if (EGL_ERROR) { + GST_ERROR ("eglMakeCurrent failed"); + return FALSE; + } + + EGLint value; + eglGetConfigAttrib (this->egl_display, this->egl_config, EGL_BUFFER_SIZE, + &value); + + return TRUE; +#else + /* Space for alternate platform code */ + return FALSE; +#endif /* GL_PLATFORM_EGL */ +} + +static gboolean +_prepare_gl_framebuffer (GstVideo360 * this) +{ + GLint samples; +#ifdef GST_TIZEN_USE_EGLIMAGE + tbm_surface_info_s out_info; + int i; + + if (!(this->input_tbm_surface = tbm_surface_create (this->input_frame_width, + this->input_frame_height, + this->input_frame_format == GST_VIDEO_FORMAT_BGRA ? + TBM_FORMAT_XBGR8888 : + this->input_frame_format == GST_VIDEO_FORMAT_I420 ? + TBM_FORMAT_YUV420 : TBM_FORMAT_NV12)) || + !(this->output_tbm_surface = tbm_surface_create (this->output_frame_width, + this->output_frame_height, TBM_FORMAT_XBGR8888))) { + GST_ERROR ("tbm_surface_create failed"); + return FALSE; + } + if (tbm_surface_get_info (this->input_tbm_surface, &this->input_surf_info) != + TBM_SURFACE_ERROR_NONE || + tbm_surface_get_info (this->output_tbm_surface, &out_info) != + TBM_SURFACE_ERROR_NONE) { + GST_ERROR ("tbm_surface_get_info failed"); + return FALSE; + } + + /* TODO(a.martynets): add checks for input/output frames stride to match with + * the TBM surfaces strides. + */ + for (i = 0; i < TBM_SURF_PLANE_MAX; i++) { + /* Note: ptr pointer in the tbm_surface_info_s has offset already added */ + this->input_image_ptr[i] = this->input_surf_info.planes[i].ptr; + } + this->input_egl_image = this->eglCreateImage (this->egl_display, + EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, + (EGLClientBuffer) this->input_tbm_surface, NULL); + + this->output_image_ptr = out_info.planes[0].ptr; + this->output_egl_image = this->eglCreateImage (this->egl_display, + EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, + (EGLClientBuffer) this->output_tbm_surface, NULL); + + if (this->input_egl_image == EGL_NO_IMAGE_KHR || + this->output_egl_image == EGL_NO_IMAGE_KHR) { + EGL_ERROR; + return FALSE; + } +#endif + + /* Prepare textures */ + glGenTextures (2, this->tex_ids); + /* Texture to render to */ + glActiveTexture (GL_TEXTURE0); + glBindTexture (GL_TEXTURE_2D, this->tex_ids[0]); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +#ifdef GST_TIZEN_USE_EGLIMAGE + this->glEGLImageTargetTexture2D (GL_TEXTURE_2D, + (GLeglImageOES) this->output_egl_image); +#else + glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, this->output_frame_width, + this->output_frame_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); +#endif + if (GL_ERROR) { + GST_ERROR ("Framebuffer texture preparation failed"); + return FALSE; + } + + /* Input sampler texture */ + glActiveTexture (GL_TEXTURE1); +#ifdef GST_TIZEN_USE_EGLIMAGE + glBindTexture (GL_TEXTURE_EXTERNAL_OES, this->tex_ids[1]); + glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri (GL_TEXTURE_EXTERNAL_OES, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + this->glEGLImageTargetTexture2D (GL_TEXTURE_EXTERNAL_OES, + (GLeglImageOES) this->input_egl_image); +#else + /* Space for alternate code which might start with lines: + * glBindTexture (GL_TEXTURE_2D, this->tex_ids[1]); + * glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + * glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + * */ +#endif + if (GL_ERROR) { + GST_ERROR ("Sampler texture preparation failed"); + return FALSE; + } +#ifndef USE_EGLIMAGE + /* Note: for non-EGLImage based implementation it is critical to switch to + * proper sampler texture unit, e.g.: + * glActiveTexture (GL_TEXTURE1); + * */ +#endif + + /* Prepare framebuffers */ + glGenFramebuffers (1, &this->fbo_id); + glBindFramebuffer (GL_FRAMEBUFFER, this->fbo_id); + if (this->glFramebufferTexture2DMultisample) { + /* Make the framebuffer multisampled with GL_MAX_SAMPLES_EXT samples */ + glGetIntegerv (GL_MAX_SAMPLES_EXT, &samples); + this->glFramebufferTexture2DMultisample (GL_FRAMEBUFFER, + GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, this->tex_ids[0], 0, samples); + } else { + /* Make the framebuffer singlesampled */ + glFramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, + this->tex_ids[0], 0); + } + if (GL_ERROR) { + GST_ERROR ("Framebuffer preparation failed"); + return FALSE; + } + + return _check_gl_framebuffer (); +} + +/* Renderers helper function - performs GL calls. */ +gboolean +gst_video360_draw_gl (GstVideo360 * this) +{ +#ifdef GST_TIZEN_USE_TIMING + struct timespec start_time, stop_time; + + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start_time); +#endif + + glClear (GL_COLOR_BUFFER_BIT); + glDrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0); + glFinish (); + +#ifdef GST_TIZEN_USE_TIMING + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &stop_time); + this->rendering_nanoseconds += (stop_time.tv_sec - start_time.tv_sec) * + 1000000000; + this->rendering_nanoseconds += stop_time.tv_nsec - start_time.tv_nsec; +#endif + return !GL_ERROR; +} + +/* GL uniforms setters */ +void +gst_video360_set_fov_gl (GstVideo360 * this) +{ + if (!this->passthrough && this->fov_uni != -1) { + pthread_mutex_lock (&this->gl_mutex); + glUniform2f (this->fov_uni, (M_PI * this->horizontal_fov_degree) / 360.0, + (M_PI * this->vertical_fov_degree) / 360.0); + GL_ERROR; + pthread_mutex_unlock (&this->gl_mutex); + } +} + +void +gst_video360_set_dov_gl (GstVideo360 * this) +{ + if (!this->passthrough && this->dov_uni != -1) { + pthread_mutex_lock (&this->gl_mutex); + glUniform3f (this->dov_uni, this->pose_yaw_radians, + this->pose_pitch_radians, this->pose_roll_radians); + GL_ERROR; + pthread_mutex_unlock (&this->gl_mutex); + } +} + +void +gst_video360_set_crops_gl (GstVideo360 * this) +{ + if (!this->passthrough && this->crops_uni != -1) { + pthread_mutex_lock (&this->gl_mutex); + glUniform4f (this->crops_uni, + (float) this->projection_bounds_left / (float) this->panorama_width, + (float) this->projection_bounds_bottom / (float) this->panorama_height, + 1.0 - + (float) this->projection_bounds_right / (float) this->panorama_width, + 1.0 - + (float) this->projection_bounds_top / (float) this->panorama_height); + GL_ERROR; + pthread_mutex_unlock (&this->gl_mutex); + } +} + +void +gst_video360_set_zoom_gl (GstVideo360 * this) +{ + if (!this->passthrough && this->zoom_uni != -1) { + pthread_mutex_lock (&this->gl_mutex); + glUniform1f (this->zoom_uni, this->zoom); + GL_ERROR; + pthread_mutex_unlock (&this->gl_mutex); + } +} + +/* GL program compilation and linking */ +static gboolean +_prepare_gl_program (GstVideo360 * this, + char const *const *vertex_sources, int vertex_count, + char const *const *fragment_sources, int fragment_count) +{ + GLuint vert; + GLuint frag; + + vert = glCreateShader (GL_VERTEX_SHADER); + glShaderSource (vert, vertex_count, vertex_sources, NULL); + glCompileShader (vert); + + if (GL_SHADER_ERROR (vert, "Vertex")) + return FALSE; + + frag = glCreateShader (GL_FRAGMENT_SHADER); + glShaderSource (frag, fragment_count, fragment_sources, NULL); + glCompileShader (frag); + + if (GL_SHADER_ERROR (frag, "Fragment")) + return FALSE; + + this->prog_id = glCreateProgram (); + glAttachShader (this->prog_id, vert); + glAttachShader (this->prog_id, frag); + + glLinkProgram (this->prog_id); + glUseProgram (this->prog_id); + glDeleteShader (frag); + glDeleteShader (vert); + + if (GL_PROGRAM_ERROR (this->prog_id) || GL_ERROR) + return FALSE; + + return TRUE; +} + +/* Returns TRUE if framebuffer is complete */ +static gboolean +_check_gl_framebuffer () +{ + GLenum fb_status; + const char *string; + + switch (fb_status = glCheckFramebufferStatus (GL_FRAMEBUFFER)) { + case GL_FRAMEBUFFER_COMPLETE: + break; + case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: + string = "Framebuffer incomplete attachement"; + break; +#ifdef GST_TIZEN_GL_API_GLES2 + case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS: + string = "Framebuffer incomplete dimentions"; + break; +#endif + case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: + string = "Framebuffer incomplete missing attachement"; + break; + case GL_FRAMEBUFFER_UNSUPPORTED: + string = "Framebuffer unsupported"; + break; + case GL_INVALID_ENUM: + string = "Not a framebuffer"; + break; + case GL_INVALID_OPERATION: + string = "Invalid operation"; + break; + case 0: + string = "Internal error"; + break; + default: + string = "Undefined error"; + break; + } + + if (fb_status != GL_FRAMEBUFFER_COMPLETE) { + GST_ERROR ("glCheckFramebufferStatus failed: %s (%#x)", string, fb_status); + return FALSE; + } + + GST_INFO ("OpenGL framebuffer is complete"); + return TRUE; +} + +/* Returns TRUE if there were errors */ +gboolean +_check_gl_error (const char *file, int line) +{ + GLenum err; + const char *error = NULL; + + while ((err = glGetError ()) != GL_NO_ERROR) { + + switch (err) { + case GL_INVALID_ENUM: + error = "INVALID_ENUM"; + break; + case GL_INVALID_VALUE: + error = "INVALID_VALUE"; + break; + case GL_INVALID_OPERATION: + error = "INVALID_OPERATION"; + break; +#ifdef GST_TIZEN_GL_API_OPENGL + case GL_STACK_OVERFLOW: + error = "GL_STACK_OVERFLOW"; + break; + case GL_STACK_UNDERFLOW: + error = "GL_STACK_UNDERFLOW"; + break; +#endif + case GL_OUT_OF_MEMORY: + error = "OUT_OF_MEMORY"; + break; + case GL_INVALID_FRAMEBUFFER_OPERATION: + error = "INVALID_FRAMEBUFFER_OPERATION"; + break; + default: + error = "Unknown error"; + } + GST_ERROR ("%s:%u: GL call failed: %s (%#x)", file, line, error, err); + } + return error != NULL; +} + +/* Returns TRUE if there were errors */ +static gboolean +_check_gl_shader_compile_error (GLuint shader, const char *name) +{ + GLint status; + GLint len; + char *buffer; + + glGetShaderiv (shader, GL_COMPILE_STATUS, &status); + + if (status != GL_TRUE) { + glGetShaderiv (shader, GL_INFO_LOG_LENGTH, &len); + if ((buffer = g_try_malloc (len))) { + glGetShaderInfoLog (shader, len, NULL, buffer); + GST_ERROR ("%s shader compilation failed: %s", name, buffer); + g_free (buffer); + } + return TRUE; + } + + GST_INFO ("%s shader successfully compiled", name); + return FALSE; +} + +/* Returns TRUE if there were errors */ +static gboolean +_check_gl_program_link_error (GLuint program) +{ + GLint status; + GLint len; + char *buffer; + + glGetProgramiv (program, GL_LINK_STATUS, &status); + + if (status != GL_TRUE) { + glGetProgramiv (program, GL_INFO_LOG_LENGTH, &len); + if ((buffer = g_try_malloc (len))) { + glGetProgramInfoLog (program, len, NULL, buffer); + GST_ERROR ("Program link failed: %s", buffer); + g_free (buffer); + } + return TRUE; + } + + GST_INFO ("Program successfully linked"); + return FALSE; +} + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +/* Returns TRUE if there were errors */ +gboolean +_check_egl_error (const char *file, int line) +{ + EGLint err_code; + const char *error; + + switch (err_code = eglGetError ()) { + case EGL_SUCCESS: + break; + case EGL_NOT_INITIALIZED: + error = "EGL_NOT_INITIALIZED"; + break; + case EGL_BAD_ACCESS: + error = "EGL_BAD_ACCESS"; + break; + case EGL_BAD_ALLOC: + error = "EGL_BAD_ALLOC"; + break; + case EGL_BAD_ATTRIBUTE: + error = "EGL_BAD_ATTRIBUTE"; + break; + case EGL_BAD_CONTEXT: + error = "EGL_BAD_CONTEXT"; + break; + case EGL_BAD_CONFIG: + error = "EGL_BAD_CONFIG"; + break; + case EGL_BAD_CURRENT_SURFACE: + error = "EGL_BAD_CURRENT_SURFACE"; + break; + case EGL_BAD_DISPLAY: + error = "EGL_BAD_DISPLAY"; + break; + case EGL_BAD_SURFACE: + error = "EGL_BAD_SURFACE"; + break; + case EGL_BAD_MATCH: + error = "EGL_BAD_MATCH"; + break; + case EGL_BAD_PARAMETER: + error = "EGL_BAD_PARAMETER"; + break; + case EGL_BAD_NATIVE_PIXMAP: + error = "EGL_BAD_NATIVE_PIXMAP"; + break; + case EGL_BAD_NATIVE_WINDOW: + error = "EGL_BAD_NATIVE_WINDOW"; + break; + case EGL_CONTEXT_LOST: + error = "EGL_CONTEXT_LOST"; + break; + default: + error = "Unknown error"; + } + if (err_code != EGL_SUCCESS) { + GST_ERROR ("%s:%u: EGL call failed: %s (%#x)", file, line, error, err_code); + return TRUE; + } + return FALSE; +} +#else + /* Space for alternate platform code */ +#endif diff --git a/video360/src/gstvideo360.c b/video360/src/gstvideo360.c new file mode 100644 index 0000000..2d1bd84 --- /dev/null +++ b/video360/src/gstvideo360.c @@ -0,0 +1,1014 @@ +/* + * Video360 GStreamer plug-in + * Copyright (C) 2017 Samsung R&D Institute Ukraine + * All rights reserved. + * + * @author: Andriy Martynets + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/** + * SECTION:element-video360 + * + * Spatial Video GStreamer plugin + * + * + * Example launch line + * |[ + * gst-launch-1.0 filesrc location="test.mp4" ! decodebin ! video360 ! + * waylandsink rotate=1 display-geometry-method=2 + * ]| + * + */ + +#include "gstvideo360.h" + +/* Debug category definition */ +GST_DEBUG_CATEGORY (video360_debug_category); + +/* Filter signals and args */ +enum +{ + /* FILL ME */ + LAST_SIGNAL +}; + +/* TODO(a.martynets): add vertical and horizontal FOV degrees and aspect ratios + * as element's properties to be settable by the application to keep them the + * same values on both sides. + */ +enum +{ + PROP_0, + PROP_STEREO, + PROP_YAW, + PROP_PITCH, + PROP_ROLL, + PROP_PROJECTION, + PROP_TOP, + PROP_BOTTOM, + PROP_LEFT, + PROP_RIGHT, + PROP_HFOV, + PROP_VFOV, + PROP_ZOOM, + PROP_PASSTHROUGH, +}; + +/* The capabilities of the inputs and outputs. + * + * video/x-raw RGB/NV12/SN12 progressive is the only supported formats here. + */ +static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink", + GST_PAD_SINK, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, " +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + "format = (string) { BGRA, NV12, SN12, I420 }, " +#else + "format = (string) { BGRA, NV12, I420 }, " +#endif + "width = (int) [ 1, max ], " + "height = (int) [ 1, max ], " "framerate = (fraction) [ 0, max ]" + /* Interlaced mode removed from CAPS as this causes SPRD decoder to fail + * to link + * "interlace-mode = (string) progressive" + * */ + ) + ); + +static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", + GST_PAD_SRC, + GST_PAD_ALWAYS, + GST_STATIC_CAPS ("video/x-raw, " +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + "format = (string) { SR32 }, " +#else + "format = (string) { BGRA }, " +#endif + "width = (int) [ 1, max ], " + "height = (int) [ 1, max ], " "framerate = (fraction) [ 0, max ]" + /* Interlaced mode removed from CAPS as this causes SPRD decoder to fail + * to link + * "interlace-mode = (string) progressive" + * */ + ) + ); + +#define gst_video360_parent_class parent_class +G_DEFINE_TYPE (GstVideo360, gst_video360, GST_TYPE_ELEMENT); + +static void gst_video360_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_video360_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); +static GstStateChangeReturn gst_video360_change_state (GstElement * element, + GstStateChange transition); + +static gboolean gst_video360_sink_event (GstPad * pad, GstObject * parent, + GstEvent * event); +static gboolean gst_video360_src_event (GstPad * pad, GstObject * parent, + GstEvent * event); +static GstFlowReturn gst_video360_chain (GstPad * pad, GstObject * parent, + GstBuffer * buf); + +/* Below function returns FALSE on failure and sets + * the video360_error_message string */ +static int allocate_local_resources (GstVideo360 * this); +/* Free up resources */ +static void deallocate_local_resources (GstVideo360 * this); + +/* Register GTtypes for custom enums */ +#define GST_TYPE_VIDEO360_STEREOMODE (gst_video360_stereomode_get_type ()) +#define GST_TYPE_VIDEO360_PROJTYPE (gst_video360_projtype_get_type ()) + +static GType +gst_video360_stereomode_get_type (void) +{ + static GType video360_stereomode_type = 0; + + if (!video360_stereomode_type) { + static GEnumValue stereomode_types[] = { + {MODE_MONOSCOPIC, "Single monoscopic view", "mono"}, + {MODE_STEREOSCOPIC_TOP_BOTTOM, "Stereoscopic view, left eye on top half " + "and right eye at bottom half of the frame", "stereo-top-bottom"}, + {MODE_STEREOSCOPIC_LEFT_RIGHT, "Stereoscopic view, left eye on left " + "half and right eye on right half of the frame", + "stereo-left-right"}, + {MODE_STEREOSCOPIC_STEREO_MESH, + "Stereoscopic view, left and right eyes " + "are encoded in the (u,v) coordinates of two meshes", + "stereo-mesh"}, + {0, NULL, NULL}, + }; + + video360_stereomode_type = + g_enum_register_static ("GstVideo360StereoMode", stereomode_types); + } + + return video360_stereomode_type; +} + +static GType +gst_video360_projtype_get_type (void) +{ + static GType video360_projtype_type = 0; + + if (!video360_projtype_type) { + static GEnumValue projtype_types[] = { + {PROJECTION_TYPE_CUBEMAP, "Cubemap projection", "cubemap"}, + {PROJECTION_TYPE_EQUIRECTANGULAR, "Equirectangular projection", + "equirectangular"}, + {PROJECTION_TYPE_MESH, "Mesh projection", "mesh"}, + {0, NULL, NULL}, + }; + + video360_projtype_type = + g_enum_register_static ("GstVideo360ProjectionType", projtype_types); + } + + return video360_projtype_type; +} + +/* GObject vmethod implementations */ + +/* initialize the video360's class */ +static void +gst_video360_class_init (GstVideo360Class * klass) +{ + + GObjectClass *gobject_class; + GstElementClass *gstelement_class; + + gobject_class = (GObjectClass *) klass; + gstelement_class = (GstElementClass *) klass; + + gobject_class->set_property = gst_video360_set_property; + gobject_class->get_property = gst_video360_get_property; + + gstelement_class->change_state = gst_video360_change_state; + + g_object_class_install_property (gobject_class, PROP_STEREO, + g_param_spec_enum ("stereo-mode", "StereoMode", "Stereo mode: Monoscopic," + " Stereoscopic Top-Bottom, Stereoscopic Left-Right, " + "Stereoscopic Stereo-Mesh", + GST_TYPE_VIDEO360_STEREOMODE, MODE_MONOSCOPIC, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_YAW, + g_param_spec_int ("pose-yaw", "PoseYawDegrees", "Pose Yaw Degrees: " + "counter-clockwise rotation in degrees around the up vector +/-180", + -180, 180, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_PITCH, + g_param_spec_int ("pose-pitch", "PosePitchDegrees", "Pose Pitch Degrees: " + "counter-clockwise rotation in degrees around the right vector +/-90", + -90, 90, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_ROLL, + g_param_spec_int ("pose-roll", "PoseRollDegrees", "Pose Roll Degrees: " + "counter-clockwise rotation in degrees around the forward vector " + "+/-180", -180, 180, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_PROJECTION, + g_param_spec_enum ("projection-type", "ProjectionType", "Projection type:" + " Cubemap, Equirectangular, Mesh", + GST_TYPE_VIDEO360_PROJTYPE, PROJECTION_TYPE_EQUIRECTANGULAR, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_TOP, + g_param_spec_uint ("projection-bounds-top", "ProjectionBoundsTop", + "The amount from the top of the frame to crop", + 0, 0xFFFFFFFF, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_BOTTOM, + g_param_spec_uint ("projection-bounds-bottom", "ProjectionBoundsBottom", + "The amount from the bottom of the frame to crop", + 0, 0xFFFFFFFF, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_LEFT, + g_param_spec_uint ("projection-bounds-left", "ProjectionBoundsLeft", + "The amount from the left of the frame to crop", + 0, 0xFFFFFFFF, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_RIGHT, + g_param_spec_uint ("projection-bounds-right", "ProjectionBoundsRight", + "The amount from the right of the frame to crop", + 0, 0xFFFFFFFF, 0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_HFOV, + g_param_spec_uint ("horizontal-fov", "HorizontalFOV", + "Horizontal field of view in degrees, range 1-360", + 1, 360, HORIZONTAL_FOV_DEGREE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_VFOV, + g_param_spec_uint ("vertical-fov", "VerticalFOV", + "Vertical field of view in degrees, range 1-180", + 1, 180, VERTICAL_FOV_DEGREE, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_ZOOM, + g_param_spec_float ("zoom", "Zoom", + "Zoom in factor, range 1.0-0.0 (default 1.0 - no zoom)", + 0.0, 1.0, 1.0, G_PARAM_READWRITE)); + + g_object_class_install_property (gobject_class, PROP_PASSTHROUGH, + g_param_spec_boolean ("passthrough", "Passthrough", + "Passthrough mode: 0 - perform video 360 transformation (default), " + "1 - pass frames intact", FALSE, G_PARAM_READWRITE)); + + gst_element_class_set_details_simple (gstelement_class, + "Video360", /* Long-name */ + "Effect/Video", /* Klass */ + "Spatial Video GStreamer plugin", /* Description */ + "Andriy Martynets "); /* Author */ + + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&src_factory)); + gst_element_class_add_pad_template (gstelement_class, + gst_static_pad_template_get (&sink_factory)); +} + +/* initialize the new element + * instantiate pads and add them to element + * set pad calback functions + * initialize instance structure + */ +static void +gst_video360_init (GstVideo360 * this) +{ + this->sinkpad = gst_pad_new_from_static_template (&sink_factory, "sink"); + gst_pad_set_event_function (this->sinkpad, + GST_DEBUG_FUNCPTR (gst_video360_sink_event)); + gst_pad_set_chain_function (this->sinkpad, + GST_DEBUG_FUNCPTR (gst_video360_chain)); + /* Make the default CAPS query always return the negotiated caps */ + gst_pad_use_fixed_caps (this->sinkpad); + gst_element_add_pad (GST_ELEMENT (this), this->sinkpad); + + this->srcpad = gst_pad_new_from_static_template (&src_factory, "src"); + gst_pad_set_event_function (this->srcpad, + GST_DEBUG_FUNCPTR (gst_video360_src_event)); + /* Make the default CAPS query always return the negotiated caps */ + gst_pad_use_fixed_caps (this->srcpad); + gst_element_add_pad (GST_ELEMENT (this), this->srcpad); + + this->sinkpad_caps = NULL; + + this->stereo_mode = MODE_MONOSCOPIC; + this->pose_yaw_radians = 0.0; + this->pose_pitch_radians = 0.0; + this->pose_roll_radians = 0.0; + this->projection_type = PROJECTION_TYPE_EQUIRECTANGULAR; + this->projection_bounds_top = 0; + this->projection_bounds_bottom = 0; + this->projection_bounds_left = 0; + this->projection_bounds_right = 0; + this->requested_horizontal_fov_degree = + this->horizontal_fov_degree = HORIZONTAL_FOV_DEGREE; + this->requested_vertical_fov_degree = + this->vertical_fov_degree = VERTICAL_FOV_DEGREE; + this->requested_passthrough = this->passthrough = FALSE; + this->zoom = 1.0; + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_GL_WINDOW_WAYLAND + this->wl_display = NULL; +#endif + this->egl_display = EGL_NO_DISPLAY; + this->egl_surface = EGL_NO_SURFACE; + this->egl_config = 0; +#ifdef GST_TIZEN_USE_EGLIMAGE + this->eglCreateImage = NULL; + this->eglDestroyImage = NULL; + this->glEGLImageTargetTexture2D = NULL; + this->input_egl_image = this->output_egl_image = EGL_NO_IMAGE_KHR; + this->input_tbm_surface = this->output_tbm_surface = NULL; +#endif +#endif + this->glFramebufferTexture2DMultisample = NULL; + this->fov_uni = this->dov_uni = this->crops_uni = this->zoom_uni = -1; + this->tex_ids[0] = this->tex_ids[1] = + this->bo_ids[0] = this->bo_ids[1] = this->fbo_id = this->prog_id = 0; + + pthread_mutex_init (&this->gl_mutex, NULL); + +#ifdef GST_TIZEN_USE_TIMING + this->frames_processed = this->frames_nanoseconds = + this->uploads_nanoseconds = this->downloads_nanoseconds = + this->rendering_nanoseconds = 0; +#endif +} + +static void +gst_video360_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec) +{ + GstVideo360 *this = GST_VIDEO360 (object); + + switch (prop_id) { + case PROP_STEREO: + /* Monoscopic format is the only supported */ + this->stereo_mode = g_value_get_enum (value); + gst_pad_mark_reconfigure (this->sinkpad); + break; + case PROP_YAW: + this->pose_yaw_radians = M_PI * g_value_get_int (value) / 180.0; + gst_video360_set_dov_gl (this); + break; + case PROP_PITCH: + this->pose_pitch_radians = M_PI * g_value_get_int (value) / 180.0; + gst_video360_set_dov_gl (this); + break; + case PROP_ROLL: + this->pose_roll_radians = M_PI * g_value_get_int (value) / 180.0; + gst_video360_set_dov_gl (this); + break; + case PROP_PROJECTION: + /* Equirectangular projection is the only supported */ + this->projection_type = g_value_get_enum (value); + gst_pad_mark_reconfigure (this->sinkpad); + break; + case PROP_TOP: + /* Set max for PROP_BOTTOM property? */ + this->projection_bounds_top = g_value_get_uint (value); + gst_video360_set_crops_gl (this); + break; + case PROP_BOTTOM: + /* must be less than 0xFFFFFFFF - projection_bounds_top */ + this->projection_bounds_bottom = g_value_get_uint (value); + gst_video360_set_crops_gl (this); + break; + case PROP_LEFT: + /* Set max for PROP_RIGHT property? */ + this->projection_bounds_left = g_value_get_uint (value); + gst_video360_set_crops_gl (this); + break; + case PROP_RIGHT: + /* must be less than 0xFFFFFFFF - projection_bounds_left */ + this->projection_bounds_right = g_value_get_uint (value); + gst_video360_set_crops_gl (this); + break; + case PROP_HFOV: + this->requested_horizontal_fov_degree = g_value_get_uint (value); + gst_pad_mark_reconfigure (this->sinkpad); + break; + case PROP_VFOV: + this->requested_vertical_fov_degree = g_value_get_uint (value); + gst_pad_mark_reconfigure (this->sinkpad); + break; + case PROP_ZOOM: + this->zoom = g_value_get_float (value); + gst_video360_set_zoom_gl (this); + break; + case PROP_PASSTHROUGH: + this->requested_passthrough = g_value_get_boolean (value); + gst_pad_mark_reconfigure (this->sinkpad); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_video360_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec) +{ + GstVideo360 *this = GST_VIDEO360 (object); + + switch (prop_id) { + case PROP_STEREO: + g_value_set_enum (value, this->stereo_mode); + break; + case PROP_YAW: + g_value_set_int (value, this->pose_yaw_radians * 180.0 / M_PI); + break; + case PROP_PITCH: + g_value_set_int (value, this->pose_pitch_radians * 180.0 / M_PI); + break; + case PROP_ROLL: + g_value_set_int (value, this->pose_roll_radians * 180.0 / M_PI); + break; + case PROP_PROJECTION: + g_value_set_enum (value, this->projection_type); + break; + case PROP_TOP: + g_value_set_uint (value, this->projection_bounds_top); + break; + case PROP_BOTTOM: + g_value_set_uint (value, this->projection_bounds_bottom); + break; + case PROP_LEFT: + g_value_set_uint (value, this->projection_bounds_left); + break; + case PROP_RIGHT: + g_value_set_uint (value, this->projection_bounds_right); + break; + case PROP_HFOV: + g_value_set_uint (value, this->horizontal_fov_degree); + break; + case PROP_VFOV: + g_value_set_uint (value, this->vertical_fov_degree); + break; + case PROP_ZOOM: + g_value_set_float (value, this->zoom); + break; + case PROP_PASSTHROUGH: + g_value_set_boolean (value, this->passthrough); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static GstStateChangeReturn +gst_video360_change_state (GstElement * element, GstStateChange transition) +{ + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + + /* Resources allocation depends on negotiated capabilities and thus + * is called from sink pad events handler + */ + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + if (transition == GST_STATE_CHANGE_READY_TO_NULL) { + deallocate_local_resources (GST_VIDEO360 (element)); + } + + return ret; +} + +/* GstElement vmethod implementations */ + +/* this function handles sink events */ +static gboolean +gst_video360_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + GstVideo360 *this = GST_VIDEO360 (parent); + gboolean ret = TRUE; + GstCaps *caps; + GValue value = G_VALUE_INIT; + GstStructure *structure; + const char *input_frame_format_srt; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_CAPS: + { + /* we should handle the format here */ + gst_event_parse_caps (event, &caps); + if (!(this->passthrough = this->requested_passthrough)) { + structure = gst_caps_get_structure (caps, 0); + + ret = gst_structure_get_int (structure, "width", + (gint *) & this->input_frame_width); + + ret = ret && gst_structure_get_int (structure, "height", + (gint *) & this->input_frame_height); + + /* NOTE: below pointer remains valid until the next call to a + * gst_structure_*() function with the given structure + */ + ret = ret && + (input_frame_format_srt = gst_structure_get_string (structure, + "format")) != NULL; + + if (G_UNLIKELY (!ret)) { + GST_ERROR ("CAPS negotiation error: Wrong CAPS format"); + } else { + this->input_frame_memory_object = 0; +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + this->output_frame_format = GST_VIDEO_FORMAT_SR32; +#else + this->output_frame_format = GST_VIDEO_FORMAT_BGRA; +#endif + if (!strcmp (input_frame_format_srt, "BGRA")) { + this->input_frame_format = GST_VIDEO_FORMAT_BGRA; + this->renderer = gst_video360_standard_formats_renderer; + } else if (!strcmp (input_frame_format_srt, "NV12")) { + this->input_frame_format = GST_VIDEO_FORMAT_NV12; + this->renderer = gst_video360_standard_formats_renderer; +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + } else if (!strcmp (input_frame_format_srt, "SN12")) { + this->input_frame_format = GST_VIDEO_FORMAT_SN12; + this->renderer = gst_video360_native_formats_renderer; + this->input_frame_memory_object = 1; +#endif + } else if (!strcmp (input_frame_format_srt, "I420")) { + this->input_frame_format = GST_VIDEO_FORMAT_I420; + this->renderer = gst_video360_standard_formats_renderer; + } else { + /* TODO(a.martynets): add support for more formats + * (e.g. S420) + */ + this->output_frame_format = this->input_frame_format = + GST_VIDEO_FORMAT_UNKNOWN; + } + + this->panorama_height = this->input_frame_height + + this->projection_bounds_bottom + this->projection_bounds_top; + this->panorama_width = this->input_frame_width + + this->projection_bounds_left + this->projection_bounds_right; + + this->horizontal_fov_degree = this->requested_horizontal_fov_degree; + this->vertical_fov_degree = this->requested_vertical_fov_degree; + + /* Select FOV frame size in pixels based on equator length and given + * horizontal/vertical FOV in degrees. + */ + /* Align width rounding up to 16 which is required for the + * waylandsink. Both RGB and NV12 formats have requirement for width + * to be aligned by 4 which is satisfied automatically. This also + * allows us to use the width as the stride. + */ + /* Mali-400 driver (drm?) aligns internal buffer stride by 32 pixels. + * To simplify TBM surface based images upload/download we need to + * apply the same alignment to output image width. + * */ + this->output_frame_width = + GST_ROUND_UP_32 (this->panorama_width * + this->horizontal_fov_degree / 360); + /* Normally height alignment is by 2. But we might want to rotate + * screen picture by 90 degrees and height will became width for + * wayland. Thus we align height rounding it up to 16 to be on the + * safe side. + * */ + this->output_frame_height = + GST_ROUND_UP_16 (this->output_frame_width * + this->vertical_fov_degree / this->horizontal_fov_degree); + /* Output frame stride is equal to its width as it is already + * alighned. + * */ + this->output_frame_buffer_size = this->output_frame_height * + this->output_frame_width * RGB_BYTES_PER_PIXEL; + + /* Calculate format specific values */ + switch (this->input_frame_format) { + case GST_VIDEO_FORMAT_BGRA: + this->input_frame_planes[0].stride = + GST_ROUND_UP_4 (this->input_frame_width * + RGB_BYTES_PER_PIXEL); + this->input_frame_planes[0].size = + this->input_frame_planes[0].stride * this->input_frame_height; + break; +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + case GST_VIDEO_FORMAT_SN12: +#endif + case GST_VIDEO_FORMAT_NV12: + this->input_frame_planes[0].stride = + this->input_frame_planes[1].stride = + GST_ROUND_UP_4 (this->input_frame_width); + + this->input_frame_planes[0].size = + this->input_frame_planes[0].stride * + GST_ROUND_UP_2 (this->input_frame_height); + this->input_frame_planes[1].size = + this->input_frame_planes[0].size >> 1; + break; + case GST_VIDEO_FORMAT_I420: + this->input_frame_planes[0].stride = + GST_ROUND_UP_4 (this->input_frame_width); + this->input_frame_planes[1].stride = + this->input_frame_planes[2].stride = + GST_ROUND_UP_4 (GST_ROUND_UP_2 (this-> + input_frame_width) >> 1); + + this->input_frame_planes[0].size = + this->input_frame_planes[0].stride * + GST_ROUND_UP_2 (this->input_frame_height); + this->input_frame_planes[1].size = + this->input_frame_planes[2].size = + this->input_frame_planes[1].stride * + GST_ROUND_UP_2 (this->input_frame_height) >> 1; + break; + /* TODO(a.martynets): add support for more formats + * (e.g. S420) + * */ + default: + /* Reject unsupported CAPS */ + return FALSE; + } + + /* Here we save incoming CAPS which might be needed for subsequent + * negotiations. Normally they are present on the PAD and its peer as + * sticky CAPS events and can be obtained by gst_pad_get_current_caps + * call. Unfortunately some elements (e.g. OMX decoder) seems to unref + * these events. + * */ + if (this->sinkpad_caps) + gst_caps_unref (this->sinkpad_caps); + this->sinkpad_caps = gst_caps_ref (caps); + + /* Once sink capabilities are negotiated translate them to source pad. + * Here we do a kind of transform negotiation as we setup fixed CAPS + * on the src PAD. + * */ + /* Use fixed CAPS from sink PAD to preserve all fields set up by the + * uplink. + * NOTE: some elements (e.g. videoscale and waylandsink) are sensitive + * to presence of unknown or absence of some format specific fields. + * This may lead to the pipe doesn't negotiate. + * */ + caps = gst_caps_make_writable (caps); + structure = gst_caps_get_structure (caps, 0); + g_value_init (&value, G_TYPE_INT); + g_value_set_int (&value, (int) this->output_frame_width); + gst_structure_set_value (structure, "width", &value); + g_value_set_int (&value, (int) this->output_frame_height); + gst_structure_set_value (structure, "height", &value); + g_value_unset (&value); + g_value_init (&value, G_TYPE_STRING); +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + g_value_set_static_string (&value, "SR32"); +#else + g_value_set_static_string (&value, "BGRA"); +#endif + gst_structure_set_value (structure, "format", &value); + g_value_unset (&value); + } + + /* Sanity call to deallocate resources in case of re-negotiation */ + deallocate_local_resources (this); + + ret = ret && allocate_local_resources (this); + } + + /* Set capabilities for the source pad */ + if (G_UNLIKELY (ret && !gst_pad_set_caps (this->srcpad, caps))) { + GST_ERROR ("CAPS negotiation error: Can't set CAPS for source pad"); + ret = FALSE; + } + + if (ret) + gst_pad_check_reconfigure (pad); + + break; + } + default: + ret = gst_pad_event_default (pad, parent, event); + break; + } + return ret; +} + +static gboolean +gst_video360_src_event (GstPad * pad, GstObject * parent, GstEvent * event) +{ + GstVideo360 *this = GST_VIDEO360 (parent); + const GstStructure *structure; + const gchar *type; + gdouble x, y; + gdouble yaw, pitch, roll; + gboolean dov_set = FALSE; + int tmp; + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_NAVIGATION: + structure = gst_event_get_structure (event); + type = gst_structure_get_string (structure, "event"); + if (!strcmp (type, "mouse-button-press")) { + gst_structure_get_int (structure, "button", + &this->pressed_mouse_button); + gst_structure_get_double (structure, "pointer_x", &x); + gst_structure_get_double (structure, "pointer_y", &y); + this->last_x = x; + this->last_y = y; + } else if (!strcmp (type, "mouse-move")) { + if (gst_structure_get_double (structure, "yaw", &yaw) && + gst_structure_get_double (structure, "pitch", &pitch) && + gst_structure_get_double (structure, "roll", &roll)) { + this->pose_yaw_radians = yaw; + this->pose_pitch_radians = pitch; + this->pose_roll_radians = roll; + dov_set = TRUE; + } else { + gst_structure_get_double (structure, "pointer_x", &x); + gst_structure_get_double (structure, "pointer_y", &y); + + if (this->pressed_mouse_button == 1) { + /* Here we handle navigation events from a videosink if any. + * It is expected navigation events to bring image coordinates + * otherwise angles will be calculated incorrectly. + * */ + /* tmp variable is introduces here just to get rid of SVACE's error + * reports. + * */ + tmp = this->horizontal_fov_degree * + ((int) x - this->last_x) / (int) this->output_frame_width; + this->pose_yaw_radians -= (float) tmp *M_PI / 180.0; + tmp = 2 * this->vertical_fov_degree * + ((int) y - this->last_y) / (int) this->output_frame_height; + this->pose_pitch_radians += (float) tmp *M_PI / 180.0; + if (this->pose_yaw_radians <= -M_PI) + this->pose_yaw_radians += 2 * M_PI; + else if (this->pose_yaw_radians > M_PI) + this->pose_yaw_radians -= 2 * M_PI; + if (this->pose_pitch_radians < -M_PI_2) + this->pose_pitch_radians = -M_PI_2; + else if (this->pose_pitch_radians > M_PI_2) + this->pose_pitch_radians = M_PI_2; + dov_set = TRUE; + } + this->last_x = x; + this->last_y = y; + } + if (dov_set) + gst_video360_set_dov_gl (this); + } else if (!strcmp (type, "mouse-button-release")) { + this->pressed_mouse_button = 0; + } + break; + default: + break; + } + return gst_pad_event_default (pad, parent, event); +} + +#ifdef GST_TIZEN_USE_NATIVE_FORMATS +/* The callback function which releases MMVideoBuffer with attached TBM BO. + * It is used for outgoing frame buffers of SR32 format. + * */ +static void +mm_vbuffer_free (void * mm_vbuffer) +{ + if (((MMVideoBuffer *) mm_vbuffer)->type == MM_VIDEO_BUFFER_TYPE_TBM_BO && + ((MMVideoBuffer *) mm_vbuffer)->handle.bo[0]) { + tbm_bo_unref (((MMVideoBuffer *) mm_vbuffer)->handle.bo[0]); + } + + g_free (mm_vbuffer); +} +#endif + +/* chain function + * this function does the actual processing + */ +static GstFlowReturn +gst_video360_chain (GstPad * pad, GstObject * parent, GstBuffer * in_buf) +{ + GstVideo360 *this = GST_VIDEO360 (parent); + GstBuffer *out_buf; + GstMapInfo in_info, out_info; +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + MMVideoBuffer *mm_vbuffer; +#else + GstMemory *out_mem; +#endif + GstMemory *in_mem; + int ret; + + if (gst_pad_check_reconfigure (pad)) { + if (!gst_video360_sink_event (pad, parent, + gst_event_new_caps (this->sinkpad_caps))) + return GST_FLOW_NOT_NEGOTIATED; + } + + if (this->passthrough) + return gst_pad_push (this->srcpad, in_buf); + +#ifdef GST_TIZEN_USE_TIMING + struct timespec start_time, stop_time; + + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start_time); +#endif + +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + if ((out_buf = gst_buffer_new_wrapped ( + g_malloc (GST_TIZEN_NATIVE_FORMATS_FIRST_MEMORY_SIZE), + GST_TIZEN_NATIVE_FORMATS_FIRST_MEMORY_SIZE)) && + (mm_vbuffer = g_malloc0 (sizeof (MMVideoBuffer)))) { + + mm_vbuffer->type = MM_VIDEO_BUFFER_TYPE_TBM_BO; + mm_vbuffer->format = MM_PIXEL_FORMAT_RGBA; + mm_vbuffer->plane_num = 1; + mm_vbuffer->width[0] = this->output_frame_width; + mm_vbuffer->height[0] = this->output_frame_height; + mm_vbuffer->stride_width[0] = this->output_frame_width * RGB_BYTES_PER_PIXEL; + mm_vbuffer->stride_height[0] = this->output_frame_height; + mm_vbuffer->size[0] = this->output_frame_buffer_size; + mm_vbuffer->handle_num = 1; + mm_vbuffer->handle_size[0] = this->output_frame_buffer_size; + + gst_buffer_append_memory (out_buf, + gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, mm_vbuffer, + sizeof (MMVideoBuffer), 0, sizeof (MMVideoBuffer), mm_vbuffer, + mm_vbuffer_free)); +#else + if ((out_buf = gst_buffer_new_allocate (NULL, + this->output_frame_buffer_size, NULL))) { +#endif + + GST_BUFFER_PTS (out_buf) = GST_BUFFER_PTS (in_buf); + GST_BUFFER_DTS (out_buf) = GST_BUFFER_DTS (in_buf); + GST_BUFFER_DURATION (out_buf) = GST_BUFFER_DURATION (in_buf); + GST_BUFFER_OFFSET (out_buf) = GST_BUFFER_OFFSET (in_buf); + GST_BUFFER_OFFSET_END (out_buf) = GST_BUFFER_OFFSET_END (in_buf); + + ret = FALSE; + in_info.data = out_info.data = NULL; + + in_mem = gst_buffer_peek_memory (in_buf, this->input_frame_memory_object); + gst_memory_map (in_mem, &in_info, GST_MAP_READ); +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + out_info.data = (void *) mm_vbuffer; +#else + out_mem = gst_buffer_peek_memory (out_buf, 0); + gst_memory_map (out_mem, &out_info, GST_MAP_WRITE); +#endif + + if (in_info.data && out_info.data) { + /* Here we do the rendering */ + pthread_mutex_lock (&this->gl_mutex); + ret = (*this->renderer) (this, in_info.data, out_info.data); + pthread_mutex_unlock (&this->gl_mutex); + } + + if (in_info.data) + gst_memory_unmap (in_mem, &in_info); +#ifndef GST_TIZEN_USE_NATIVE_FORMATS + if (out_info.data) + gst_memory_unmap (out_mem, &out_info); +#endif + + if (ret) { + gst_buffer_unref (in_buf); + +#ifdef GST_TIZEN_USE_TIMING + clock_gettime (CLOCK_THREAD_CPUTIME_ID, &stop_time); + this->frames_processed++; + this->frames_nanoseconds += (stop_time.tv_sec - start_time.tv_sec) * + 1000000000; + this->frames_nanoseconds += stop_time.tv_nsec - start_time.tv_nsec; +#endif + + return gst_pad_push (this->srcpad, out_buf); + } + } + + GST_ERROR ("Frame rendering error: " + "Memory allocation / write permission request failed"); + + return GST_FLOW_ERROR; +} + +static int +allocate_local_resources (GstVideo360 * this) +{ + /* On failure sets the video360_error_message string and returns FALSE */ + if (!gst_video360_init_gl (this)) { + deallocate_local_resources (this); + GST_ERROR ("Video360 initialization failed: OpenGL initialization failed"); + return FALSE; + } + + return TRUE; +} + +static void +deallocate_local_resources (GstVideo360 * this) +{ + gst_video360_deinit_gl (this); + +#ifdef GST_TIZEN_USE_TIMING + if (this->frames_processed) { + g_message + ("\n===================== Video360 =============================\n" + "Frames processed: %ld. Average time: %9lld ns per frame.\n" + "\tUploads average time:\t%9lld ns per frame.\n" + "\tDownloads average time:\t%9lld ns per frame.\n" + "\tRendering average time:\t%9lld ns per frame.\n" + "============================================================\n", + this->frames_processed, + this->frames_nanoseconds / this->frames_processed, + this->uploads_nanoseconds / this->frames_processed, + this->downloads_nanoseconds / this->frames_processed, + this->rendering_nanoseconds / this->frames_processed); + + this->frames_processed = this->frames_nanoseconds = + this->uploads_nanoseconds = this->downloads_nanoseconds = + this->rendering_nanoseconds = 0; + } +#endif + + return; +} + + +/* entry point to initialize the plug-in + * initialize the plug-in itself + * register the element factories and other features + */ +static gboolean +video360_init (GstPlugin * video360) +{ + + /* Debug category initialization. + * It can be used next to filter log messages with GST_DEBUG environmental + * variable set like: + * GST_DEBUG=video360:4 + * */ + GST_DEBUG_CATEGORY_INIT (video360_debug_category, "video360", + 0, "Spatial Video GStreamer plugin"); + + return gst_element_register (video360, "video360", GST_RANK_NONE, + GST_TYPE_VIDEO360); +} + +/* PACKAGE: this is usually set by autotools depending on some _INIT macro + * in configure.ac and then written into and defined in config.h, but we can + * just set it ourselves here in case someone doesn't use autotools to + * compile this code. GST_PLUGIN_DEFINE needs PACKAGE to be defined. + */ +#ifndef PACKAGE +#define PACKAGE "video360-package" +#endif + +/* gstreamer looks for this structure to register video360s + * + * exchange the string 'Template video360' with your video360 description + */ +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + video360, + "Spatial Video GStreamer plugin", + video360_init, VERSION, "LGPL", "GStreamer", "http://gstreamer.net/") diff --git a/video360/src/gstvideo360.h b/video360/src/gstvideo360.h new file mode 100644 index 0000000..143468c --- /dev/null +++ b/video360/src/gstvideo360.h @@ -0,0 +1,359 @@ +/* + * Video360 GStreamer plug-in + * Copyright (C) 2017 Samsung R&D Institute Ukraine + * All rights reserved. + * + * @author: Andriy Martynets + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#ifndef __GST_VIDEO360_H__ +#define __GST_VIDEO360_H__ + +#define _GNU_SOURCE + +/* Compilation macroses */ + +/* Define one of below macroses to choose OpenGL API: + * #define GST_TIZEN_GL_API_GLES2 + * #define GST_TIZEN_GL_API_OPENGL (Not supported yet) + * */ +#define GST_TIZEN_GL_PLATFORM_EGL +#define GST_TIZEN_GL_WINDOW_WAYLAND +#define GST_TIZEN_USE_EGLIMAGE +/* Define below macros to enable multisample antialiasing + * #define GST_TIZEN_USE_MSAA + * */ + +/* Define below macros to have per frame timings calculated and summary output: + * #define GST_TIZEN_USE_TIMING + * */ + +/* Define below macros to build with Tizen native formats support: + * #define GST_TIZEN_USE_NATIVE_FORMATS + * */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifdef GST_TIZEN_GL_API_GLES2 +#include +#include + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +#include +#include + +#ifdef GST_TIZEN_GL_WINDOW_WAYLAND +#include +#include +#else /* Not GL_WINDOW_WAYLAND */ +#error "Wayland based EGL is the only supported platform" +#endif /* GL_WINDOW_WAYLAND */ + +#else /* Not GL_PLATFORM_EGL */ +#error "GLES API supported on EGL platform only" +#endif /* GL_PLATFORM_EGL */ + +#else /* Not GL_API_GLES2 */ +#error "OpenGL ES2 is the only supported API" +#include +#include +#endif /* GL_API_GLES2 */ + +#include +#include +#include + +#include "video360.h" + +#ifdef GST_TIZEN_USE_TIMING +#include +#endif + +#if defined (GST_TIZEN_USE_NATIVE_FORMATS) || defined (GST_TIZEN_USE_EGLIMAGE) +#include +#include +#include +#include +#endif + +#if (G_BYTE_ORDER == G_BIG_ENDIAN) +#error "This code was tested for Little Endian architectures only!" +#endif + +#if (GST_VERSION_MAJOR != 1) +#error "This code designed for GStreamer version 1.0" +#endif + +#ifdef GST_TIZEN_USE_NATIVE_FORMATS +#define GST_TIZEN_NATIVE_FORMATS_FIRST_MEMORY_SIZE 16 +#endif + +/* RGB format specific constants */ +#define RGB_BYTES_PER_PIXEL 4 + +/* Cropped area fill color (buffer clear color) */ +#define GAP_FILL_COLOUR_RED 0.605f +#define GAP_FILL_COLOUR_GREEN 0.652f +#define GAP_FILL_COLOUR_BLUE 0.652f + +/* Default aspect ratio for output image */ +#define OUTPUT_RATIO_H 16 +#define OUTPUT_RATIO_V 9 + +/* Default field of view for output image. + * Human eye horizontal stereoscopic FOV is 120 degrees. + * */ +#define HORIZONTAL_FOV_DEGREE 120 +#define VERTICAL_FOV_DEGREE (HORIZONTAL_FOV_DEGREE * OUTPUT_RATIO_V / OUTPUT_RATIO_H) + +G_BEGIN_DECLS + +/* #defines don't like whitespacey bits */ +#define GST_TYPE_VIDEO360 \ + (gst_video360_get_type()) +#define GST_VIDEO360(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_VIDEO360,GstVideo360)) +#define GST_VIDEO360_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_VIDEO360,GstVideo360Class)) +#define GST_IS_VIDEO360(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_VIDEO360)) +#define GST_IS_VIDEO360_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_VIDEO360)) +#define GST_VIDEO360_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_VIDEO360,GstVideo360Class)) + +/* Debug category declaration */ +GST_DEBUG_CATEGORY_EXTERN (video360_debug_category); +#define GST_CAT_DEFAULT video360_debug_category + +typedef struct _GstVideo360 GstVideo360; +typedef struct _GstVideo360Class GstVideo360Class; + +struct _GstVideo360 +{ + GstElement element; + + GstPad *sinkpad, *srcpad; + GstCaps *sinkpad_caps; + + /***************************************************************************** + * OpenGL ES related variables + * **************************************************************************/ +#ifdef GST_TIZEN_GL_WINDOW_WAYLAND + struct wl_display *wl_display; +#endif +#ifdef GST_TIZEN_GL_PLATFORM_EGL + EGLDisplay egl_display; + EGLConfig egl_config; + EGLSurface egl_surface; + EGLContext egl_context; + +#ifdef GST_TIZEN_USE_EGLIMAGE + /* EGL extension functions */ + PFNEGLCREATEIMAGEKHRPROC eglCreateImage; + PFNEGLDESTROYIMAGEKHRPROC eglDestroyImage; + PFNGLEGLIMAGETARGETTEXTURE2DOESPROC glEGLImageTargetTexture2D; + + EGLImage input_egl_image; + EGLImage output_egl_image; + tbm_surface_h input_tbm_surface; + tbm_surface_h output_tbm_surface; + void *input_image_ptr [TBM_SURF_PLANE_MAX]; + void *output_image_ptr; + tbm_surface_info_s input_surf_info; +#endif + +#endif + /* GL extension functions */ + PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisample; + + GLuint tex_ids [2]; + GLuint fbo_id; + GLuint bo_ids [2]; + GLuint prog_id; + GLint fov_uni; + GLint dov_uni; + GLint crops_uni; + GLint zoom_uni; + + pthread_mutex_t gl_mutex; + + /***************************************************************************** + * Element's properties + * **************************************************************************/ + /* Currently monoscopic equirectangular projection is the only supported */ + ProjectionType projection_type; + StereoMode stereo_mode; + + unsigned int projection_bounds_top; + unsigned int projection_bounds_bottom; + unsigned int projection_bounds_left; + unsigned int projection_bounds_right; + + /* counter-clockwise rotation in radians around the up vector +/- PI + * (+/-180.0 degrees) + */ + float pose_yaw_radians; + /* counter-clockwise rotation in radians around the right vector +/- PI/2 + * (+/-90.0 degrees) post yaw transform + */ + float pose_pitch_radians; + /* clockwise rotation in radians around the forward vector +/- PI + * (+/-180.0 degrees) post yaw and pitch transform + */ + float pose_roll_radians; + + unsigned int horizontal_fov_degree; + unsigned int vertical_fov_degree; + gboolean passthrough; + float zoom; + + /* Below fields contain requested values (set via properties) until they are + * applied at CAPS negotiation. + * */ + unsigned int requested_horizontal_fov_degree; + unsigned int requested_vertical_fov_degree; + gboolean requested_passthrough; + + /***************************************************************************** + * Element's internal variables + * **************************************************************************/ + GstVideoFormat input_frame_format; + GstVideoFormat output_frame_format; + + /* Full input panorama sizes in pixels (input frame sizes + cropped areas) */ + unsigned int panorama_width, panorama_height; + + /* Number of the memory block in gst buffer which contains actual data */ + unsigned int input_frame_memory_object; + + /* Input frame dimentions in pixels, rows stride and buffer size in bytes */ + unsigned int input_frame_width, input_frame_height; + struct { + unsigned int stride; + unsigned int size; + } input_frame_planes [TBM_SURF_PLANE_MAX]; + + /* Output frame sizes in pixels. Rows stride in bytes is equal to width as it + * is always aligned + * */ + unsigned int output_frame_width, output_frame_height; + unsigned int output_frame_buffer_size; + + /* Navigation events related stuff. It is used to handle navigation events + * from a videosink if any. It is expected navigation events to bring image + * coordinates otherwise angles will be calculated incorrectly. + * */ + int last_x, last_y, pressed_mouse_button; + + /* Pointer to frame renderer for current frame format */ + gboolean (*renderer) (GstVideo360 * this, void * in_data, void * out_data); + +#ifdef GST_TIZEN_USE_TIMING + unsigned long frames_processed; + unsigned long long frames_nanoseconds; + unsigned long long uploads_nanoseconds; + unsigned long long downloads_nanoseconds; + unsigned long long rendering_nanoseconds; +#endif +}; + +struct _GstVideo360Class +{ + GstElementClass parent_class; +}; + +GType gst_video360_get_type (void); + +G_END_DECLS + +/* Shader sources for equirectangular projection */ +extern const char * equirectangular_vertex_source; +extern const char * equirectangular_fragment_source; +extern const char * direct_colors_fragment_source; +extern const char * reverse_colors_fragment_source; +/* Sets VBOs. Returns TRUE on success and FALSE otherwise. */ +gboolean _equirectangular_bind_vertex_buffers (GstVideo360 * this); +/* Sets attributes and uniforms. Returns TRUE on success and FALSE otherwise. */ +gboolean _equirectangular_program_attribs (GstVideo360 * this); + +/* GL stuff initialization. Returns TRUE on success and FALSE otherwise. */ +gboolean gst_video360_init_gl (GstVideo360 * this); +/* GL stuff deinitialization. */ +void gst_video360_deinit_gl (GstVideo360 * this); +/* GL errors checking function. Returns TRUE if there were errors. */ +gboolean _check_gl_error(const char *file, int line); +#define GL_ERROR _check_gl_error(__FILE__,__LINE__) + +#ifdef GST_TIZEN_GL_PLATFORM_EGL +/* Below function returns TRUE on errors and FALSE otherwise */ +gboolean _check_egl_error (const char *file, int line); +#define EGL_ERROR _check_egl_error(__FILE__,__LINE__) +#else + /* Space for alternate platform code */ +#endif + + +/* Frame renderers for supported frame formats. + * All these functions return TRUE on success and FALSE otherwise. + */ +gboolean gst_video360_standard_formats_renderer (GstVideo360 * this, + void * in_data, void * out_data); +#ifdef GST_TIZEN_USE_NATIVE_FORMATS +gboolean gst_video360_native_formats_renderer (GstVideo360 * this, + void * in_data, void * out_data); +#endif + +/* Renderers helper function - performs GL calls. */ +gboolean gst_video360_draw_gl (GstVideo360 * this); +/* GL uniforms setters */ +void gst_video360_set_fov_gl (GstVideo360 * this); +void gst_video360_set_dov_gl (GstVideo360 * this); +void gst_video360_set_crops_gl (GstVideo360 * this); +void gst_video360_set_zoom_gl (GstVideo360 * this); + +#endif /* __GST_VIDEO360_H__ */ diff --git a/video360/src/video360.h b/video360/src/video360.h new file mode 100644 index 0000000..37aed57 --- /dev/null +++ b/video360/src/video360.h @@ -0,0 +1,72 @@ +/* + * Video360 GStreamer plug-in + * Copyright (C) 2017 Samsung R&D Institute Ukraine + * All rights reserved. + * + * @author: Andriy Martynets + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + * Alternatively, the contents of this file may be used under the + * GNU Lesser General Public License Version 2.1 (the "LGPL"), in + * which case the following provisions apply instead of the ones + * mentioned above: + * + * 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., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* TODO(a.martynets): export this file to be used by target application */ + +#ifndef __VIDEO360_H__ +#define __VIDEO360_H__ + +/* Minimum-maximum ranges for properties set using below values */ +typedef enum +{ + MODE_UNKNOWN = -1, + MODE_MONOSCOPIC = 0, + MODE_STEREOSCOPIC_TOP_BOTTOM = 1, + MODE_STEREOSCOPIC_LEFT_RIGHT = 2, + MODE_STEREOSCOPIC_STEREO_MESH = 3, + MODE_LAST_ITEM +} StereoMode; + +typedef enum +{ + PROJECTION_TYPE_UNKNOWN = -1, + PROJECTION_TYPE_EQUIRECTANGULAR = 0, + PROJECTION_TYPE_CUBEMAP = 1, + PROJECTION_TYPE_MESH = 2, + PROJECTION_TYPE_LAST_ITEM +} ProjectionType; + +#endif /* __VIDEO360_H__ */ -- 2.7.4 From e8753f173aecf00db64ad921d14b0ce9a55491bb Mon Sep 17 00:00:00 2001 From: SeokHoon Lee Date: Thu, 2 Nov 2017 11:00:39 +0900 Subject: [PATCH 03/16] Change retry count to 20 - Retry count is too big so change standard rtsp retry count. Signed-off-by: SeokHoon Lee Change-Id: I31c6e007236f40ed7826a1cdc553668506e3e051 --- packaging/gst-plugins-tizen.spec | 2 +- wfdmanager/wfdbase/gstwfdbasesrc.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 386e1aa..b9ed39d 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -9,7 +9,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 48 +Release: 49 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ diff --git a/wfdmanager/wfdbase/gstwfdbasesrc.c b/wfdmanager/wfdbase/gstwfdbasesrc.c index 9de2017..dbfe9b1 100644 --- a/wfdmanager/wfdbase/gstwfdbasesrc.c +++ b/wfdmanager/wfdbase/gstwfdbasesrc.c @@ -127,7 +127,7 @@ enum /* properties default values */ #define DEFAULT_LOCATION NULL #define DEFAULT_DUMP_RTSP_MESSAGE FALSE -#define DEFAULT_RETRY 50 +#define DEFAULT_RETRY 20 #define DEFAULT_TCP_TIMEOUT 20000000 #define DEFAULT_PROXY NULL #define DEFAULT_RTP_BLOCKSIZE 0 -- 2.7.4 From 0552099ec0ed40834a2e5b39d02305bdc99d4063 Mon Sep 17 00:00:00 2001 From: Hyunil Date: Thu, 9 Nov 2017 14:51:36 +0900 Subject: [PATCH 04/16] tizenwlsink: get source from gst-plugins-bad/ext/wayland and create new tizen wayland video sink Change-Id: Id60188662450ac0c142b19ebff59df08fd4b9423 Signed-off-by: Hyunil --- Makefile.am | 8 + configure.ac | 20 + packaging/gst-plugins-tizen.spec | 5 +- tizenwlsink/Makefile.am | 1 + tizenwlsink/src/.gitignore | 2 + tizenwlsink/src/Makefile.am | 48 + tizenwlsink/src/gstwaylandsink.c | 2713 +++++++++++++++++++++++++++++++++ tizenwlsink/src/gstwaylandsink.h | 130 ++ tizenwlsink/src/scaler.xml | 210 +++ tizenwlsink/src/tizen-wlvideoformat.c | 115 ++ tizenwlsink/src/tizen-wlvideoformat.h | 41 + tizenwlsink/src/wlbuffer.c | 327 ++++ tizenwlsink/src/wlbuffer.h | 69 + tizenwlsink/src/wldisplay.c | 468 ++++++ tizenwlsink/src/wldisplay.h | 141 ++ tizenwlsink/src/wlshmallocator.c | 545 +++++++ tizenwlsink/src/wlshmallocator.h | 79 + tizenwlsink/src/wlvideoformat.c | 113 ++ tizenwlsink/src/wlvideoformat.h | 37 + tizenwlsink/src/wlwindow.c | 1103 ++++++++++++++ tizenwlsink/src/wlwindow.h | 167 ++ 21 files changed, 6339 insertions(+), 3 deletions(-) mode change 100755 => 100644 configure.ac create mode 100644 tizenwlsink/Makefile.am create mode 100644 tizenwlsink/src/.gitignore create mode 100644 tizenwlsink/src/Makefile.am create mode 100755 tizenwlsink/src/gstwaylandsink.c create mode 100644 tizenwlsink/src/gstwaylandsink.h create mode 100644 tizenwlsink/src/scaler.xml create mode 100644 tizenwlsink/src/tizen-wlvideoformat.c create mode 100755 tizenwlsink/src/tizen-wlvideoformat.h create mode 100644 tizenwlsink/src/wlbuffer.c create mode 100644 tizenwlsink/src/wlbuffer.h create mode 100644 tizenwlsink/src/wldisplay.c create mode 100644 tizenwlsink/src/wldisplay.h create mode 100644 tizenwlsink/src/wlshmallocator.c create mode 100644 tizenwlsink/src/wlshmallocator.h create mode 100644 tizenwlsink/src/wlvideoformat.c create mode 100644 tizenwlsink/src/wlvideoformat.h create mode 100644 tizenwlsink/src/wlwindow.c create mode 100644 tizenwlsink/src/wlwindow.h diff --git a/Makefile.am b/Makefile.am index ffad5e7..7dfb351 100755 --- a/Makefile.am +++ b/Makefile.am @@ -61,6 +61,10 @@ if GST_TIZEN_USE_VIDEO360 SUBDIRS += video360 endif +if GST_TIZEN_USE_WAYLANDSINK +SUBDIRS += tizenwlsink +endif + DIST_SUBDIRS = common if GST_TIZEN_USE_ENCODEBIN @@ -104,6 +108,10 @@ if GST_TIZEN_USE_VIDEO360 DIST_SUBDIRS += video360 endif +if GST_TIZEN_USE_WAYLANDSINK +DIST_SUBDIRS += tizenwlsink +endif + EXTRA_DIST = \ gstreamer.spec gstreamer.spec.in \ configure.ac autogen.sh depcomp \ diff --git a/configure.ac b/configure.ac old mode 100755 new mode 100644 index 2f59780..a385065 --- a/configure.ac +++ b/configure.ac @@ -386,6 +386,24 @@ AS_IF([test "x$with_gles2" = "xyes"], [ CFLAGS="$CFLAGS -DGST_TIZEN_GL_API_GLES2" ]) +dnl use waylandsink -------------------------------------------------------------------------- +AC_ARG_ENABLE(waylandsink, AC_HELP_STRING([--enable-waylandsink], [using waylandsink]), +[ + case "${enableval}" in + yes) GST_TIZEN_USE_WAYLANDSINK=yes ;; + no) GST_TIZEN_USE_WAYLANDSINK=no ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-waylandsink) ;; + esac + ], + [GST_TIZEN_USE_WAYLANDSINK=yes]) +AM_CONDITIONAL([GST_TIZEN_USE_WAYLANDSINK], [test "x$GST_TIZEN_USE_WAYLANDSINK" = "xyes"]) +if test "x$GST_TIZEN_USE_WAYLANDSINK" = "xyes"; then +PKG_CHECK_MODULES(WAYLAND, wayland-client >= 1.4.0 wayland-tbm-client tizen-extension-client wayland-scanner) +AC_PATH_PROG([wayland_scanner], [wayland-scanner]) +AC_SUBST(WAYLAND_CFLAGS) +AC_SUBST(WAYLAND_LIBS) +fi + AC_OUTPUT( Makefile common/Makefile @@ -415,4 +433,6 @@ wfdtizenmanager/Makefile alfec/Makefile video360/Makefile video360/src/Makefile +tizenwlsink/Makefile +tizenwlsink/src/Makefile ) diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index b9ed39d..30bd6c5 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -9,7 +9,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 49 +Release: 50 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ @@ -42,7 +42,6 @@ BuildRequires: pkgconfig(gles20) BuildRequires: pkgconfig(wayland-client) >= 1.0.0 BuildRequires: pkgconfig(wayland-tbm-client) BuildRequires: pkgconfig(tizen-extension-client) -BuildRequires: pkgconfig(gstreamer-wayland-1.0) %endif %description @@ -67,7 +66,7 @@ GStreamer tizen plugins Extension for mobile TM1 %build -export CFLAGS+=" -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" " +export CFLAGS+=" -DTIZEN_FEATURE_WLSINK_ENHANCEMENT -DEXPORT_API=\"__attribute__((visibility(\\\"default\\\")))\" " export CFLAGS_DEFAULT="$CFLAGS" %ifarch %{arm} diff --git a/tizenwlsink/Makefile.am b/tizenwlsink/Makefile.am new file mode 100644 index 0000000..af437a6 --- /dev/null +++ b/tizenwlsink/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = src diff --git a/tizenwlsink/src/.gitignore b/tizenwlsink/src/.gitignore new file mode 100644 index 0000000..44cd427 --- /dev/null +++ b/tizenwlsink/src/.gitignore @@ -0,0 +1,2 @@ +*-protocol.c +*-client-protocol.h diff --git a/tizenwlsink/src/Makefile.am b/tizenwlsink/src/Makefile.am new file mode 100644 index 0000000..998787f --- /dev/null +++ b/tizenwlsink/src/Makefile.am @@ -0,0 +1,48 @@ +plugin_LTLIBRARIES = libgsttizenwlsink.la + +libgsttizenwlsink_la_SOURCES = \ + gstwaylandsink.c \ + wlshmallocator.c \ + wlbuffer.c \ + wldisplay.c \ + wlwindow.c \ + scaler-protocol.c \ + wlvideoformat.c \ + tizen-wlvideoformat.c + +libgsttizenwlsink_la_CFLAGS = $(GST_CFLAGS) $(GST_BASE_CFLAGS)$ $(GST_PLUGINS_BASE_CFLAGS) $(GST_VIDEO_CFLAGS) \ + $(WAYLAND_CFLAGS) $(DRM_CFLAGS) $(TBM_CFLAGS) $(MMCOMMON_CFLAGS) +libgsttizenwlsink_la_LIBADD = \ + $(GST_LIBS) $(GST_BASE_LIBS) $(GST_PLUGINS_BASE_LIBS) $(GST_VIDEO_LIBS)\ + $(WAYLAND_LIBS) $(DRM_LIBS) $(TBM_LIBS) $(MMCOMMON_LIBS) +libgsttizenwlsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +libgsttizenwlsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) + +noinst_HEADERS = \ + gstwaylandsink.h \ + wlshmallocator.h \ + wlbuffer.h \ + wldisplay.h \ + wlwindow.h \ + scaler-client-protocol.h \ + wlvideoformat.h \ + tizen-wlvideoformat.h + +EXTRA_DIST = scaler.xml +CLEANFILES = scaler-protocol.c scaler-client-protocol.h + +%-protocol.c : %.xml + $(wayland_scanner) code < $< > $@ + +%-client-protocol.h : %.xml + $(wayland_scanner) client-header < $< > $@ + +gstwaylandsink.c: scaler-client-protocol.h + +wlshmallocator.c: scaler-client-protocol.h + +wlbuffer.c: scaler-client-protocol.h + +wldisplay.c: scaler-client-protocol.h + +wlwindow.c: scaler-client-protocol.h diff --git a/tizenwlsink/src/gstwaylandsink.c b/tizenwlsink/src/gstwaylandsink.c new file mode 100755 index 0000000..4a33e8c --- /dev/null +++ b/tizenwlsink/src/gstwaylandsink.c @@ -0,0 +1,2713 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Sreerenj Balachandran + * Copyright (C) 2012 Wim Taymans + * 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 + * Wayland home page. + * The current implementaion is based on weston compositor. + * + * + * Example pipelines + * |[ + * gst-launch -v videotestsrc ! waylandsink + * ]| test the video rendering in wayland + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "gstwaylandsink.h" +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +#include +#include "tizen-wlvideoformat.h" +#endif +#include "wlvideoformat.h" +#include "wlbuffer.h" +#include "wlshmallocator.h" + +#include + + +#include +#include +#include + +#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 , " + "Sreerenj Balachandran , " + "George Kiagiadakis "); + + gstelement_class->change_state = + GST_DEBUG_FUNCPTR (gst_wayland_sink_change_state); +#if 0 + gstelement_class->set_context = + GST_DEBUG_FUNCPTR (gst_wayland_sink_set_context); +#endif + gstbasesink_class->get_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_get_caps); + gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_wayland_sink_set_caps); + gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_wayland_sink_preroll); + gstbasesink_class->propose_allocation = + GST_DEBUG_FUNCPTR (gst_wayland_sink_propose_allocation); + gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_wayland_sink_render); +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_wayland_sink_event); + gstbasesink_class->get_times = GST_DEBUG_FUNCPTR (gst_wayland_sink_get_times); +#endif + + g_object_class_install_property (gobject_class, PROP_DISPLAY, + g_param_spec_string ("display", "Wayland Display name", "Wayland " + "display name to connect to, if not supplied via the GstContext", + NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + g_object_class_install_property (gobject_class, PROP_DUMP_VIDEO, + g_param_spec_boolean ("dump-video", "dump raw video buffer", + "Dump raw video buffer", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DUMP_COUNT, + g_param_spec_uint ("dump-video-count", "dump video count", + "Dump video count", 1, G_MAXUINT, DEFAULT_DUMP_COUNT, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DISABLE_OVERLAY, + g_param_spec_boolean ("disable-overlay", "disable overlay", + "Stop using overlay by destroying wl_window and wl_display, " + "Use gst_video_overlay_set_wl_window_wl_surface_id before setting FALSE " + "to use overlay", FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_KEEP_CAMERA_PREVIEW, + g_param_spec_boolean ("keep-camera-preview", "use flush buffer mechanism", + "Last tbm buffer is copied and returned to camerasrc immediately " + "when state change(PAUSED_TO_READY)", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_USE_TBM, + g_param_spec_boolean ("use-tbm", "use tbm buffer", + "Use Tizen Buffer Memory insted of Shared memory, " + "Memory is alloced by TBM insted of SHM when enabled", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_ROTATE_ANGLE, + g_param_spec_enum ("rotate", "Rotate angle", + "Rotate angle of display output", + GST_TYPE_WAYLANDSINK_ROTATE_ANGLE, DEGREE_0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_DISPLAY_GEOMETRY_METHOD, + g_param_spec_enum ("display-geometry-method", "Display geometry method", + "Geometrical method for display", + GST_TYPE_WAYLANDSINK_DISPLAY_GEOMETRY_METHOD, + DEF_DISPLAY_GEOMETRY_METHOD, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_FLIP, + g_param_spec_enum ("flip", "Display flip", + "Flip for display", + GST_TYPE_WAYLANDSINK_FLIP, DEF_DISPLAY_FLIP, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_VISIBLE, + g_param_spec_boolean ("visible", "Visible", + "Draws screen or blacks out, true means visible, false blacks out", + TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + +#ifdef ENABLE_FUNCTION + g_object_class_install_property (gobject_class, PROP_SCALE_WIDTH, + g_param_spec_double ("scale-w", "ratio width", + "scale width for rendering video," + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0.0, + G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_SCALE_HEIGHT, + g_param_spec_double ("scale-h", "scale height", + "scale width for rendering video, " + "Function is not support in DISP_GEO_METHOD_CUSTOM_ROI. ", 0.0, + G_MAXDOUBLE, 1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_FOLLOW_PARENT_TRANSFORM, + g_param_spec_boolean ("follow-parent-transform", + "follow parent transform", + "Video is rotated automatically without setting rotate property by rotating Display" + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", TRUE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_CROP_X, + g_param_spec_uint ("crop-x", "crop x", + "x-coordinate for cropping video. " + "Please set crop-x, crop-y, crop-w and crop-h togethrer. " + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0, + G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_CROP_Y, + g_param_spec_uint ("crop-y", "crop y", + "y-coordinate for cropping video. " + "Please set crop-x, crop-y, crop-w and crop-h togethrer. " + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0, + G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_CROP_WIDTH, + g_param_spec_uint ("crop-w", "crop width", + "width for cropping video. " + "If value is not set or is set 0, Width is set to video width after set_caps. " + "Please set crop-x, crop-y, crop-w and crop-h togethrer. " + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0, + G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_CROP_HEIGHT, + g_param_spec_uint ("crop-h", "crop height", + "height for cropping video. " + "If value is not set or is set 0, Hight is set to video height after set_caps. " + "Please set crop-x, crop-y, crop-w and crop-h togethrer. " + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0, + G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_RATIO_WIDTH, + g_param_spec_double ("ratio-w", "ratio width", + "ratio width for rendering video," + "If value is set, Original video ratio is ignored. to restore original size, set to -1" + "Please set ratio-w and ratio-h togethrer. " + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", -1.0, + G_MAXDOUBLE, -1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_RATIO_HEIGHT, + g_param_spec_double ("ratio-h", "ratio height", + "ratio width for rendering video, " + "If value is set, Original video ratio is ignored. to restore original size, set to -1" + "Please set ratio-w and ratio-h togethrer. " + "Function is not support in DISP_GEO_METHOD_CUSTOM_ROI. ", -1.0, + G_MAXDOUBLE, -1.0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_OFFSET_X, + g_param_spec_uint ("offset-x", "offset x", + "x offset for moving x-coordinate of video pixel, " + "Please set x, y, w and h offset togethrer" + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0, + G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_OFFSET_Y, + g_param_spec_uint ("offset-y", "offset y", + "y offset for moving y-coordinate of video pixel, " + "Please set x, y, w and h offset togethrer" + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0, + G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_OFFSET_WIDTH, + g_param_spec_uint ("offset-w", "offset width", + "width offset for adjusting width of of video pixel, " + "Please set x, y, w and h offset togethrer" + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0, + G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_OFFSET_HEIGHT, + g_param_spec_uint ("offset-h", "offset height", + "height offset for adjusting height of of video pixel" + "Please set x, y, w and h offset togethrer" + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0, + G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_ALIGN_WIDTH, + g_param_spec_double ("align-w", "align width", + "Align with, Left: 0.0, Middle: 0.5, Right: 1.0, " + "Please set align-w and align-h togethrer" + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0.0, + 1.0, 0.5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property (gobject_class, PROP_ALIGN_HEIGHT, + g_param_spec_double ("align-h", "align height", + "Align height, Left: 0.0, Middle: 0.5, Right: 1.0, " + "Please set align-w and align-h togethrer" + "Function is not supported in DISP_GEO_METHOD_CUSTOM_ROI. ", 0.0, + 1.0, 0.5, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +#endif + + /* fakesink function for stream callback of MSL with browser */ + g_object_class_install_property (gobject_class, PROP_SIGNAL_HANDOFFS, + g_param_spec_boolean ("signal-handoffs", "Signal handoffs", + "Send a signal before unreffing the buffer", FALSE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + gst_waylandsink_signals[SIGNAL_HANDOFF] = + g_signal_new ("handoff", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GstWaylandSinkClass, handoff), NULL, NULL, + g_cclosure_marshal_generic, G_TYPE_NONE, 2, + GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD); + + gst_waylandsink_signals[SIGNAL_PREROLL_HANDOFF] = + g_signal_new ("preroll-handoff", G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstWaylandSinkClass, preroll_handoff), + NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, + GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD); + +#endif +} + +static void +gst_wayland_sink_dump_raw_video (GstWaylandSink * sink, GstBuffer * buffer, + guint dump_count, guint dump_total) +{ + GstMemory *mem; + GstMapInfo mem_info = GST_MAP_INFO_INIT; + gpointer data; + gint ret, size; + gchar file_name[128]; + + g_return_if_fail (sink != NULL); + g_return_if_fail (buffer != NULL); + + if (dump_count > dump_total) { + sink->dump_video = FALSE; + return; + } + + size = GST_VIDEO_INFO_SIZE (&sink->video_info); + mem = gst_buffer_peek_memory (buffer, 0); + gst_memory_map (mem, &mem_info, GST_MAP_READ); + + data = mem_info.data; + snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump", + dump_count); + ret = gst_wl_fwrite_data (file_name, data, size); + if (ret) { + GST_ERROR ("_write_rawdata() failed"); + } + + GST_LOG ("DUMP IMAGE %d, size (%d)", dump_count, size); + gst_memory_unmap (mem, &mem_info); +} + +static void +gst_wayland_sink_init (GstWaylandSink * sink) +{ + FUNCTION; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + sink->dump_video = FALSE; + sink->total_dump = DEFAULT_DUMP_COUNT; + sink->disable_overlay = FALSE; + sink->signal_handoffs = FALSE; + sink->request_camera_flush_buf = FALSE; + sink->keep_camera_preview = FALSE; + sink->got_costum_event = FALSE; + sink->USE_TBM = TRUE; + sink->is_native_format = FALSE; + sink->display_geometry_method = DEF_DISPLAY_GEOMETRY_METHOD; + sink->flip = DEF_DISPLAY_FLIP; + sink->rotate_angle = DEGREE_0; + sink->visible = TRUE; + sink->crop_x = sink->crop_y = sink->crop_w = sink->crop_h = 0; +#ifdef ENABLE_FUNCTION + sink->follow_parent_transform = FALSE; + sink->ratio_w = sink->ratio_h = -1.0; //need to set -1.0 for original video ratio + sink->align_w = sink->align_h = 0.5; + sink->scale_w = sink->scale_h = 1.0; + sink->offset_x = sink->offset_y = sink->offset_w = sink->offset_h = 0; +#endif +#endif + g_mutex_init (&sink->display_lock); + g_mutex_init (&sink->render_lock); +} + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +static void +gst_wayland_sink_recover_display_window_info (GstWaylandSink * sink) +{ + GstWlShmAllocator *self = NULL; + FUNCTION; + g_return_if_fail (sink != NULL); + g_return_if_fail (sink->display != NULL); + g_return_if_fail (sink->window != NULL); + + sink->display->USE_TBM = sink->USE_TBM; + sink->display->is_native_format = sink->is_native_format; + self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ()); + self->display = sink->display; + + gst_wayland_sink_update_window_geometry (sink); + sink->video_info_changed = TRUE; +} + +static gboolean +gst_wayland_sink_is_disabled_overlay (GstWaylandSink * sink) +{ + g_return_val_if_fail (sink != NULL, FALSE); + //Ensure display is null and the display info has been copied by unsetting disable_overlay + //If using the toplevel window, window is null + if (!sink->disable_overlay && sink->display) { + return FALSE; + } + sink->redraw_pending = FALSE; + return TRUE; +} + +static void +gst_wayland_sink_stop_video (GstWaylandSink * sink) +{ + FUNCTION; + g_return_if_fail (sink != NULL); + gst_wl_window_render (sink->window, NULL, NULL); +} + +static int +gst_wayland_sink_is_gapless (GstWaylandSink * sink) +{ + g_return_val_if_fail (sink != NULL, FALSE); + g_return_val_if_fail (sink->display != NULL, FALSE); + + if (sink->got_costum_event && sink->USE_TBM + && sink->display->is_native_format) + return TRUE; + + return FALSE; +} + +static int +gst_wayland_sink_need_flush_buffer (GstWaylandSink * sink) +{ + g_return_val_if_fail (sink != NULL, FALSE); + g_return_val_if_fail (sink->display != NULL, FALSE); + + if ((gst_wayland_sink_is_gapless (sink)) + || sink->request_camera_flush_buf || sink->display->flush_request == 1) { + sink->display->flush_request = TRUE; + return TRUE; + } + return FALSE; +} + +static void +gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink) +{ + GstWlBuffer *wlbuffer; + gboolean no_render_buffer = FALSE; + FUNCTION; + g_return_if_fail (sink != NULL); + g_return_if_fail (sink->last_buffer != NULL); + wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer); + + g_return_if_fail (wlbuffer != NULL); + + if (wlbuffer->used_by_compositor) { + /* used last buffer by compositor don't receive buffer-release-event when attach */ + wlbuffer->used_by_compositor = FALSE; + } else { + /* unused last buffer by compositor will receive buffer release event when attach */ + no_render_buffer = TRUE; + } + + GST_LOG ("gstbuffer(%p) ref_count(%d)", sink->last_buffer, + GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer)); + + if (sink->visible) { + /* need to render last buffer, reuse current GstWlBuffer */ + render_last_buffer (sink); + + /* ref count is incresed in gst_wl_buffer_attach() of render_last_buffer(), + to call gst_wl_buffer_finalize(), we need to decrease buffer ref count. + wayland server can not release buffer if we attach same buffer and + videosink can not receive buffer-release-event. if we use no visible, + we need to attach null buffer and videosink can receive buffer-release-event */ + + /* need to decrease buffer ref_count, if no_render_buffer is TRUE, + buffer is attached firstly so, videosink can receive buffer-release-event */ + if (no_render_buffer) { + GST_LOG ("skip unref.. will get buffer-release-event"); + } else { + gst_buffer_unref (wlbuffer->gstbuffer); + } + + } else { + GST_LOG ("skip rendering"); + } + + GST_LOG ("gstbuffer(%p) ref_count(%d)", sink->last_buffer, + GST_OBJECT_REFCOUNT_VALUE (sink->last_buffer)); + +} + +#ifdef USE_WL_FLUSH_BUFFER +static int +gst_wayland_sink_make_flush_buffer (GstWlDisplay * display, + MMVideoBuffer * mm_video_buf) +{ + GstWlFlushBuffer *flush_buffer = NULL; + tbm_bo bo = NULL; + int bo_size = 0; + int i; + FUNCTION; + + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (mm_video_buf != NULL, FALSE); + + flush_buffer = (GstWlFlushBuffer *) malloc (sizeof (GstWlFlushBuffer)); + if (G_UNLIKELY (!flush_buffer)) { + GST_ERROR ("GstWlFlushBuffer alloc faile"); + return FALSE; + } + memset (flush_buffer, 0x0, sizeof (GstWlFlushBuffer)); + + display->flush_tbm_bufmgr = + wayland_tbm_client_get_bufmgr (display->tbm_client); + g_return_val_if_fail (display->flush_tbm_bufmgr != NULL, FALSE); + + for (i = 0; i < display->tbm_bo_num; i++) { + if (mm_video_buf->handle.bo[i] != NULL) { + tbm_bo_handle src; + tbm_bo_handle dst; + gchar err_str[256]; + + /* get bo size */ + bo_size = tbm_bo_size (mm_video_buf->handle.bo[i]); + GST_LOG ("tbm bo size: %d", bo_size); + /* alloc bo */ + bo = tbm_bo_alloc (display->flush_tbm_bufmgr, bo_size, TBM_DEVICE_CPU); + if (G_UNLIKELY (!bo)) { + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR ("alloc tbm bo(size:%d) failed: %s(%d)", bo_size, err_str, + errno); + return FALSE; + } + GST_LOG ("flush buffer tbm_bo =(%p)", bo); + flush_buffer->bo[i] = bo; + /* get virtual address */ + src.ptr = dst.ptr = NULL; + /* bo map, we can use tbm_bo_map too. */ + src = + tbm_bo_map (mm_video_buf->handle.bo[i], TBM_DEVICE_CPU, + TBM_OPTION_READ); + dst = tbm_bo_map (bo, TBM_DEVICE_CPU, TBM_OPTION_READ | TBM_OPTION_WRITE); + if (G_UNLIKELY ((!src.ptr || !dst.ptr))) { + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR ("get tbm bo handle failed src(%p) dst(%p): %s(%d)", src.ptr, + dst.ptr, err_str, errno); + if (src.ptr) + tbm_bo_unmap (mm_video_buf->handle.bo[i]); + if (dst.ptr) + tbm_bo_unmap (bo); + return FALSE; + } + /* copy */ + memcpy (dst.ptr, src.ptr, bo_size); + /* bo unmap */ + tbm_bo_unmap (mm_video_buf->handle.bo[i]); + tbm_bo_unmap (bo); + } + } + display->flush_buffer = flush_buffer; + return TRUE; +} + +static int +gst_wayland_sink_copy_mm_video_buf_info_to_flush_buffer (GstWlDisplay * display, + MMVideoBuffer * mm_video_buf) +{ + int ret = FALSE; + g_return_val_if_fail (display != NULL, FALSE); + g_return_val_if_fail (mm_video_buf != NULL, FALSE); + FUNCTION; + + display->plane_num = mm_video_buf->plane_num; + display->tbm_bo_num = mm_video_buf->handle_num; + ret = gst_wayland_sink_make_flush_buffer (display, mm_video_buf); + if (ret) { + int i; + for (i = 0; i < display->plane_num; i++) { + if (display->flush_buffer->bo[i] != NULL) { + display->bo[i] = display->flush_buffer->bo[i]; + GST_LOG ("bo %p", display->bo[i]); + } else { + display->bo[i] = 0; + } + display->plane_size[i] = mm_video_buf->size[i]; + display->width[i] = mm_video_buf->width[i]; + display->height[i] = mm_video_buf->height[i]; + display->stride_width[i] = mm_video_buf->stride_width[i]; + display->stride_height[i] = mm_video_buf->stride_height[i]; + display->native_video_size += display->plane_size[i]; + GST_LOG ("TBM bo[%d]:%p", i, display->bo[i]); + GST_LOG ("width[%d]:%d, height[%d]:%d", i, display->width[i], i, + display->height[i]); + GST_LOG ("stride_width[%d]:%d, stride_height[%d]:%d", i, + display->stride_width[i], i, display->stride_height[i]); + GST_LOG ("plane size[%d]:%d", i, display->plane_size[i]); + } + memset (mm_video_buf, 0, sizeof (MMVideoBuffer)); + } + return ret; +} +#endif + +static void +gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display, + MMVideoBuffer * mm_video_buf) +{ + int i; + g_return_if_fail (display != NULL); + g_return_if_fail (mm_video_buf != NULL); + FUNCTION; + + display->plane_num = mm_video_buf->plane_num; + display->tbm_bo_num = mm_video_buf->handle_num; + for (i = 0; i < display->plane_num; i++) { + if (mm_video_buf->handle.bo[i] != NULL) { + display->bo[i] = mm_video_buf->handle.bo[i]; + } else { + display->bo[i] = 0; + } + display->plane_size[i] = mm_video_buf->size[i]; + display->width[i] = mm_video_buf->width[i]; + display->height[i] = mm_video_buf->height[i]; + display->stride_width[i] = mm_video_buf->stride_width[i]; + display->stride_height[i] = mm_video_buf->stride_height[i]; + display->native_video_size += display->plane_size[i]; + GST_LOG ("TBM bo[%d]:%p", i, display->bo[i]); + GST_LOG ("width[%d]:%d, height[%d]:%d", i, display->width[i], i, + display->height[i]); + GST_LOG ("stride_width[%d]:%d, stride_height[%d]:%d", i, + display->stride_width[i], i, display->stride_height[i]); + GST_LOG ("plane size[%d]:%d", i, display->plane_size[i]); + } +} + +static MMVideoBuffer * +gst_wayland_sink_get_mm_video_buf (GstBuffer * buffer) +{ + GstMemory *mem; + GstMapInfo mem_info = GST_MAP_INFO_INIT; + MMVideoBuffer *mm_video_buf = NULL; + + g_return_val_if_fail (buffer != NULL, NULL); + FUNCTION; + + mem = gst_buffer_peek_memory (buffer, 1); + gst_memory_map (mem, &mem_info, GST_MAP_READ); + mm_video_buf = (MMVideoBuffer *) mem_info.data; + gst_memory_unmap (mem, &mem_info); + + if (mm_video_buf == NULL) { + GST_WARNING ("mm_video_buf of gstbuffer(@%p) is NULL.", buffer); + return NULL; + } + + if (mm_video_buf->type != MM_VIDEO_BUFFER_TYPE_TBM_BO) { + GST_ERROR ("Buffer type is not TBM"); + return NULL; + } + GST_DEBUG ("TBM bo: handle.bo[0]:%p, handle.bo[1]:%p, handle.bo[2]:%p", + mm_video_buf->handle.bo[0], mm_video_buf->handle.bo[1], + mm_video_buf->handle.bo[2]); + GST_DEBUG ("Number of TBM bo is %d", mm_video_buf->handle_num); + GST_DEBUG ("Number of plane is %d", mm_video_buf->plane_num); + return mm_video_buf; +} + +static int +gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink, + GstBuffer * buffer) +{ + GstWlDisplay *display; + MMVideoBuffer *mm_video_buf = NULL; + + g_return_val_if_fail (sink != NULL, FALSE); + g_return_val_if_fail (buffer != NULL, FALSE); + + FUNCTION; + display = sink->display; + g_return_val_if_fail (sink->display != NULL, FALSE); + + /* get MMVideoBuffer from buffer */ + mm_video_buf = gst_wayland_sink_get_mm_video_buf (buffer); + g_return_val_if_fail (mm_video_buf != NULL, FALSE); + + /* assign mm_video_buf info */ + display->native_video_size = 0; + display->flush_request = 0; + display->flush_request = mm_video_buf->flush_request; + GST_DEBUG ("flush_request value is %d", display->flush_request); +#ifdef USE_WL_FLUSH_BUFFER + if (gst_wayland_sink_need_flush_buffer (sink)) { + /* Sometimes there isn't video data in MMVideoBuffer from buffer + when flush_request is true */ + if (mm_video_buf->flush_request && !mm_video_buf->size[0] + && sink->last_buffer) { + /* replace MMVideoBuffer from last buffer */ + mm_video_buf = gst_wayland_sink_get_mm_video_buf (sink->last_buffer); + g_return_val_if_fail (mm_video_buf != NULL, FALSE); + } + if (!gst_wayland_sink_copy_mm_video_buf_info_to_flush_buffer (display, + mm_video_buf)) { + GST_ERROR ("cat not copy mm_video_buf info to flush"); + return FALSE; + } + } else +#endif + /* normal routine */ + gst_wayland_sink_add_mm_video_buf_info (display, mm_video_buf); + + return TRUE; +} + +static void +gst_wayland_sink_render_flush_buffer (GstBaseSink * bsink) +{ + GstWaylandSink *sink; + sink = GST_WAYLAND_SINK (bsink); + FUNCTION; + g_return_if_fail (sink != NULL); + g_return_if_fail (sink->last_buffer != NULL); + + gst_wayland_sink_render (bsink, sink->last_buffer); +} + +static void +gst_wayland_sink_render_last_sample (GstWaylandSink * sink) +{ + GstSample *last_sample = NULL; + GstBuffer *last_buffer = NULL; + FUNCTION; + g_return_if_fail (sink != NULL); + + g_object_get (G_OBJECT (sink), "last-sample", &last_sample, NULL); + if (last_sample) { + last_buffer = gst_sample_get_buffer (last_sample); + if (last_buffer) { + GST_LOG ("PAUSED state : last buffer %p", last_buffer); + gst_buffer_ref (last_buffer); + gst_wayland_sink_render (GST_BASE_SINK (sink), last_buffer); + gst_buffer_unref (last_buffer); + last_buffer = NULL; + } + gst_sample_unref (last_sample); + last_sample = NULL; + } +} + +#endif + +static void +gst_wayland_sink_get_property (GObject * object, + guint prop_id, GValue * value, GParamSpec * pspec) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (object); + FUNCTION; + + switch (prop_id) { + case PROP_DISPLAY: + GST_OBJECT_LOCK (sink); + g_value_set_string (value, sink->display_name); + GST_OBJECT_UNLOCK (sink); + break; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + case PROP_DUMP_VIDEO: + g_value_set_boolean (value, sink->dump_video); + break; + case PROP_DUMP_COUNT: + g_value_set_uint (value, sink->total_dump); + break; + case PROP_DISABLE_OVERLAY: + g_value_set_boolean (value, sink->disable_overlay); + break; + case PROP_KEEP_CAMERA_PREVIEW: + g_value_set_boolean (value, sink->keep_camera_preview); + break; + case PROP_SIGNAL_HANDOFFS: + g_value_set_boolean (value, sink->signal_handoffs); + break; + case PROP_USE_TBM: + g_value_set_boolean (value, sink->USE_TBM); + break; + case PROP_ROTATE_ANGLE: + g_value_set_enum (value, sink->rotate_angle); + break; + case PROP_DISPLAY_GEOMETRY_METHOD: + g_value_set_enum (value, sink->display_geometry_method); + break; + case PROP_FLIP: + g_value_set_enum (value, sink->flip); + break; + case PROP_VISIBLE: + g_value_set_boolean (value, sink->visible); + break; +#ifdef ENABLE_FUNCTION + case PROP_SCALE_WIDTH: + g_value_set_double (value, sink->scale_w); + break; + case PROP_SCALE_HEIGHT: + g_value_set_double (value, sink->scale_h); + break; + case PROP_FOLLOW_PARENT_TRANSFORM: + g_value_set_boolean (value, sink->follow_parent_transform); + break; + case PROP_CROP_X: + g_value_set_uint (value, sink->crop_x); + break; + case PROP_CROP_Y: + g_value_set_uint (value, sink->crop_y); + break; + case PROP_CROP_WIDTH: + g_value_set_uint (value, sink->crop_w); + break; + case PROP_CROP_HEIGHT: + g_value_set_uint (value, sink->crop_h); + break; + case PROP_RATIO_WIDTH: + g_value_set_double (value, sink->ratio_w); + break; + case PROP_RATIO_HEIGHT: + g_value_set_double (value, sink->ratio_h); + break; + case PROP_OFFSET_X: + g_value_set_uint (value, sink->offset_x); + break; + case PROP_OFFSET_Y: + g_value_set_uint (value, sink->offset_y); + break; + case PROP_OFFSET_WIDTH: + g_value_set_uint (value, sink->offset_w); + break; + case PROP_OFFSET_HEIGHT: + g_value_set_uint (value, sink->offset_h); + break; + case PROP_ALIGN_WIDTH: + g_value_set_double (value, sink->align_w); + break; + case PROP_ALIGN_HEIGHT: + g_value_set_double (value, sink->align_h); + break; +#endif +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gst_wayland_sink_set_property (GObject * object, + guint prop_id, const GValue * value, GParamSpec * pspec) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (object); + FUNCTION; + g_mutex_lock (&sink->render_lock); + + switch (prop_id) { + case PROP_DISPLAY: + GST_OBJECT_LOCK (sink); + sink->display_name = g_value_dup_string (value); + GST_OBJECT_UNLOCK (sink); + break; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + case PROP_DUMP_VIDEO: + sink->dump_video = g_value_get_boolean (value); + if (sink->display) { + sink->display->dump_video = sink->dump_video; + GST_LOG ("Dump video set (%d):", sink->dump_video); + } + break; + case PROP_DUMP_COUNT: + sink->total_dump = g_value_get_uint (value); + if (sink->display) + sink->display->total_dump = sink->total_dump; + break; + case PROP_DISABLE_OVERLAY: + sink->disable_overlay = g_value_get_boolean (value); + if (sink->window && sink->display) { + if (sink->disable_overlay) { + g_clear_object (&sink->window); + g_clear_object (&sink->display); + } else + gst_wayland_sink_recover_display_window_info (sink); + } + break; + case PROP_SIGNAL_HANDOFFS: + sink->signal_handoffs = g_value_get_boolean (value); + GST_LOG ("set signal_handoffs(%d)", sink->signal_handoffs); + if (sink->window) { + if (sink->signal_handoffs) { + /* overlay -> hand-off */ + if (GST_STATE (sink) == GST_STATE_PAUSED) { + /* check if the prerolled buffer has been rendered in GST_STATE_PAUSED */ + if (sink->last_buffer) { + GST_LOG ("g_signal_emit: preroll-handoff"); + g_signal_emit (sink, + gst_waylandsink_signals[SIGNAL_PREROLL_HANDOFF], 0, + sink->last_buffer, GST_BASE_SINK (object)->sinkpad); + } + } + gst_wayland_sink_stop_video (sink); + } else { + if (GST_STATE (sink) == GST_STATE_PAUSED) { + g_mutex_unlock (&sink->render_lock); + /* scenario: inline video mode->paused->fullscreen mode->signal_handoffs(0) + we need to update preroll buffer on wayland surface */ + gst_wayland_sink_render_last_sample (sink); + g_mutex_lock (&sink->render_lock); + } + } + } + break; + case PROP_KEEP_CAMERA_PREVIEW: + sink->keep_camera_preview = g_value_get_boolean (value); + GST_LOG ("keep_camera_preview (%d)", sink->keep_camera_preview); + break; + case PROP_USE_TBM: + sink->USE_TBM = g_value_get_boolean (value); + GST_LOG ("1:USE TBM 0: USE SHM set(%d)", sink->USE_TBM); + break; + case PROP_ROTATE_ANGLE: + if (sink->rotate_angle == g_value_get_enum (value)) + break; + sink->rotate_angle = g_value_get_enum (value); + GST_WARNING_OBJECT (sink, "Rotate angle is set (%d)", sink->rotate_angle); + sink->video_info_changed = TRUE; + if (sink->window) { + gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle); + } + break; + case PROP_DISPLAY_GEOMETRY_METHOD: + if (sink->display_geometry_method == g_value_get_enum (value)) + break; + sink->display_geometry_method = g_value_get_enum (value); + GST_WARNING_OBJECT (sink, "Display geometry method is set (%d)", + sink->display_geometry_method); + sink->video_info_changed = TRUE; + if (sink->window) { + gst_wl_window_set_destination_mode (sink->window, + sink->display_geometry_method); + } + break; + case PROP_FLIP: + if (sink->flip == g_value_get_enum (value)) + break; + sink->flip = g_value_get_enum (value); + GST_WARNING_OBJECT (sink, "flip is set (%d)", sink->flip); + sink->video_info_changed = TRUE; + if (sink->window) { + gst_wl_window_set_flip (sink->window, sink->flip); + } + break; + case PROP_VISIBLE: + if (sink->visible == g_value_get_boolean (value)) + break; + sink->visible = g_value_get_boolean (value); + GST_WARNING_OBJECT (sink, "visible is set (%d)", sink->visible); + if (sink->visible && GST_STATE (sink) == GST_STATE_PAUSED) { + /* need to attatch last buffer */ + sink->video_info_changed = TRUE; + } else if (!sink->visible && GST_STATE (sink) >= GST_STATE_PAUSED) { + /* video stop */ + if (sink->window) { + gst_wayland_sink_stop_video (sink); + } + } + break; +#ifdef ENABLE_FUNCTION + case PROP_SCALE_WIDTH: + if (sink->scale_w == g_value_get_double (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->scale_w = g_value_get_double (value); + GST_WARNING_OBJECT (sink, "scale-w is set (%f)", sink->scale_w); + sink->video_info_changed = TRUE; + if (sink->window) + gst_wl_window_set_destination_mode_scale (sink->window, sink->scale_w, + sink->scale_h); + break; + case PROP_SCALE_HEIGHT: + if (sink->scale_h == g_value_get_double (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->scale_h = g_value_get_double (value); + GST_WARNING_OBJECT (sink, "scale-h is set (%f)", sink->scale_h); + sink->video_info_changed = TRUE; + if (sink->window) + gst_wl_window_set_destination_mode_scale (sink->window, sink->scale_w, + sink->scale_h); + break; + case PROP_FOLLOW_PARENT_TRANSFORM: + if (sink->follow_parent_transform == g_value_get_boolean (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->follow_parent_transform = g_value_get_boolean (value); + GST_WARNING_OBJECT (sink, "follow parent transform is set (%d)", + sink->follow_parent_transform); + sink->video_info_changed = TRUE; + if (sink->window) { + gst_wl_window_set_destination_mode_follow_parent_transform + (sink->window, sink->follow_parent_transform); + } + break; + case PROP_CROP_X: + if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->crop_x = g_value_get_uint (value); + GST_WARNING_OBJECT (sink, "crop-x is set (%d)", sink->crop_x); + break; + case PROP_CROP_Y: + if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->crop_y = g_value_get_uint (value); + GST_WARNING_OBJECT (sink, "crop-y is set (%d)", sink->crop_y); + break; + case PROP_CROP_WIDTH: + if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->crop_w = g_value_get_uint (value); + GST_WARNING_OBJECT (sink, "crop_w is set (%d)", sink->crop_w); + /* crop-w is unset by 0, set to video width size */ + if (sink->crop_w == 0 && sink->video_info.width > 0) { + sink->crop_w = + gst_util_uint64_scale_int_round (sink->video_info.width, + sink->video_info.par_n, sink->video_info.par_d); + GST_LOG ("crop-w is unset by 0, set to video width size(%d)", + sink->crop_w); + } + break; + case PROP_CROP_HEIGHT: + if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->crop_h = g_value_get_uint (value); + GST_WARNING_OBJECT (sink, "crop-h is set (%d)", sink->crop_h); + /* crop-h unset by 0, set to video height size */ + if (sink->crop_h == 0 && sink->video_info.height > 0) { + sink->crop_h = sink->video_info.height; + GST_LOG ("crop-h is unset by 0, set to video height size(%d)", + sink->crop_h); + } + sink->video_info_changed = TRUE; + if (sink->window && sink->crop_w > 0 && sink->crop_h > 0) { + gst_wl_window_set_destination_mode_crop_wl_buffer (sink->window, + sink->crop_x, sink->crop_y, sink->crop_w, sink->crop_h); + } + break; + case PROP_RATIO_WIDTH: + if (sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->ratio_w = g_value_get_double (value); + GST_WARNING_OBJECT (sink, "ratio-w is set (%f)", sink->ratio_w); + break; + case PROP_RATIO_HEIGHT: + if (sink->scale_w == g_value_get_double (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->ratio_h = g_value_get_double (value); + GST_WARNING_OBJECT (sink, "ratio-h is set (%f)", sink->ratio_h); + sink->video_info_changed = TRUE; + if (sink->window) + gst_wl_window_set_destination_mode_ratio (sink->window, sink->ratio_w, + sink->ratio_h); + break; + case PROP_OFFSET_X: + if (sink->offset_x == g_value_get_uint (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->offset_x = g_value_get_uint (value); + GST_WARNING_OBJECT (sink, "offset-x is set (%d)", sink->offset_x); + break; + case PROP_OFFSET_Y: + if (sink->offset_y == g_value_get_uint (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->offset_y = g_value_get_uint (value); + GST_WARNING_OBJECT (sink, "offset-y is set (%d)", sink->offset_y); + break; + case PROP_OFFSET_WIDTH: + if (sink->offset_w == g_value_get_uint (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->offset_w = g_value_get_uint (value); + GST_WARNING_OBJECT (sink, "offset-w is set (%d)", sink->offset_w); + break; + case PROP_OFFSET_HEIGHT: + if (sink->offset_h == g_value_get_uint (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->offset_h = g_value_get_uint (value); + GST_WARNING_OBJECT (sink, "offset-h is set (%d)", sink->offset_h); + sink->video_info_changed = TRUE; + if (sink->window) + gst_wl_window_set_destination_mode_offset (sink->window, sink->offset_x, + sink->offset_y, sink->offset_w, sink->offset_h); + break; + case PROP_ALIGN_WIDTH: + if (sink->align_w == g_value_get_double (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->align_w = g_value_get_double (value); + GST_WARNING_OBJECT (sink, "align_w is set (%f)", sink->align_w); + break; + case PROP_ALIGN_HEIGHT: + if (sink->align_h == g_value_get_double (value) + || sink->display_geometry_method == DISP_GEO_METHOD_CUSTOM_ROI) + break; + sink->align_h = g_value_get_double (value); + GST_WARNING_OBJECT (sink, "align_h is set (%f)", sink->align_h); + sink->video_info_changed = TRUE; + if (sink->window) + gst_wl_window_set_destination_mode_align (sink->window, sink->align_w, + sink->align_h); + break; +#endif +#endif + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (sink->video_info_changed && sink->window) { + gst_wl_window_set_video_info_change (sink->window, TRUE); + if (GST_STATE (sink) == GST_STATE_PAUSED) + gst_wayland_sink_update_last_buffer_geometry (sink); + } +#endif + g_mutex_unlock (&sink->render_lock); + +} + +static void +gst_wayland_sink_finalize (GObject * object) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (object); + FUNCTION; + GST_DEBUG_OBJECT (sink, "Finalizing the sink.."); + + if (sink->last_buffer) + gst_buffer_unref (sink->last_buffer); + if (sink->display) + g_object_unref (sink->display); + if (sink->window) + g_object_unref (sink->window); + if (sink->pool) + gst_object_unref (sink->pool); + + if (sink->display_name) + g_free (sink->display_name); + + g_mutex_clear (&sink->display_lock); + g_mutex_clear (&sink->render_lock); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +static gboolean +gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event) +{ + GstWaylandSink *sink; + const GstStructure *s; + + sink = GST_WAYLAND_SINK (bsink); + + switch (GST_EVENT_TYPE (event)) { + case GST_EVENT_EOS: + GST_LOG ("get GST_EVENT_EOS event..state is %d", GST_STATE (sink)); + break; + case GST_EVENT_CUSTOM_DOWNSTREAM: + s = gst_event_get_structure (event); + if (s == NULL + || !gst_structure_has_name (s, GST_APP_EVENT_FLUSH_BUFFER_NAME)) + break; + + GST_LOG ("get GST_EVENT_CUSTOM_DOWNSTREAM EVENT: %s..state is %d", + gst_structure_get_name (s), GST_STATE (sink)); + + sink->got_costum_event = TRUE; + if (gst_wayland_sink_is_gapless (sink)) { + gst_wayland_sink_render_flush_buffer (bsink); + sink->got_costum_event = FALSE; + } + sink->got_costum_event = FALSE; + break; + default: + break; + } + return GST_BASE_SINK_CLASS (parent_class)->event (bsink, event); +} + +static void +gst_wayland_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, + GstClockTime * start, GstClockTime * end) +{ + /* If basesink need to drop buffer, basesink ask waylandsink to start and end */ + GstWaylandSink *sink; + + sink = GST_WAYLAND_SINK (bsink); + + if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { + *start = GST_BUFFER_TIMESTAMP (buf); + if (GST_BUFFER_DURATION_IS_VALID (buf)) { + *end = *start + GST_BUFFER_DURATION (buf); + } else { + if (sink->fps_n > 0) { + *end = + *start + gst_util_uint64_scale_int (GST_SECOND, sink->fps_d, + sink->fps_n); + } + } + } +} +#endif + +#if 0 +/* must be called with the display_lock */ +static void +gst_wayland_sink_set_display_from_context (GstWaylandSink * sink, + GstContext * context) +{ + struct wl_display *display; + GError *error = NULL; + FUNCTION; + + display = gst_wayland_display_handle_context_get_handle (context); + sink->display = gst_wl_display_new_existing (display, FALSE, &error); + + if (error) { + GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE, + ("Could not set display handle"), + ("Failed to use the external wayland display: '%s'", error->message)); + g_error_free (error); + } +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + sink->display->USE_TBM = sink->USE_TBM; +#endif +} +#endif +static gboolean +gst_wayland_sink_find_display (GstWaylandSink * sink) +{ +// GstQuery *query; +// GstMessage *msg; +// GstContext *context = NULL; + GError *error = NULL; + gboolean ret = TRUE; + FUNCTION; + + g_mutex_lock (&sink->display_lock); + + if (!sink->display) { +#if 0 + /* first query upstream for the needed display handle */ + query = gst_query_new_context (GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE); + if (gst_pad_peer_query (GST_VIDEO_SINK_PAD (sink), query)) { + gst_query_parse_context (query, &context); + gst_wayland_sink_set_display_from_context (sink, context); + } + gst_query_unref (query); +#endif + if (G_LIKELY (!sink->display)) { +#if 0 + /* now ask the application to set the display handle */ + msg = gst_message_new_need_context (GST_OBJECT_CAST (sink), + GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE); + + g_mutex_unlock (&sink->display_lock); + gst_element_post_message (GST_ELEMENT_CAST (sink), msg); + /* at this point we expect gst_wayland_sink_set_context + * to get called and fill sink->display */ + g_mutex_lock (&sink->display_lock); +#endif + if (!sink->display) { + /* if the application didn't set a display, let's create it ourselves */ + GST_OBJECT_LOCK (sink); + sink->display = gst_wl_display_new (sink->display_name, &error); + GST_OBJECT_UNLOCK (sink); + + if (error) { + GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE, + ("Could not initialise Wayland output"), + ("Failed to create GstWlDisplay: '%s'", error->message)); + g_error_free (error); + ret = FALSE; + } +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (G_LIKELY (sink->display)) + sink->display->USE_TBM = sink->USE_TBM; +#endif + } + } + } + + g_mutex_unlock (&sink->display_lock); + + return ret; +} + +static GstStateChangeReturn +gst_wayland_sink_change_state (GstElement * element, GstStateChange transition) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (element); + GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; + FUNCTION; + + switch (transition) { + case GST_STATE_CHANGE_NULL_TO_READY: + GST_LOG ("WAYLANDSINK TRANSITION: NULL_TO_READY"); + if (!gst_wayland_sink_find_display (sink)) + return GST_STATE_CHANGE_FAILURE; + break; + case GST_STATE_CHANGE_READY_TO_PAUSED: + GST_LOG ("WAYLANDSINK TRANSITION: READY_TO_PAUSED"); + break; + case GST_STATE_CHANGE_PAUSED_TO_PLAYING: + GST_LOG ("WAYLANDSINK TRANSITION: PAUSED_TO_PLAYING"); + break; + default: + break; + } + + ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); + if (ret == GST_STATE_CHANGE_FAILURE) + return ret; + + switch (transition) { + case GST_STATE_CHANGE_PLAYING_TO_PAUSED: + GST_LOG ("WAYLANDSINK TRANSITION: PLAYING_TO_PAUSED"); + break; + case GST_STATE_CHANGE_PAUSED_TO_READY: + GST_LOG ("WAYLANDSINK TRANSITION: PAUSED_TO_READY"); +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (sink->keep_camera_preview) { + if (sink->window) { + if (!gst_wl_window_is_toplevel (sink->window)) { + GstBaseSink *bsink = GST_BASE_SINK (element); + if (sink->USE_TBM && sink->display->is_native_format + && !sink->display->flush_buffer) { + /* To avoid duplicate request by App, check flush_buffer by flush_request of MMVideoBuffer */ + sink->request_camera_flush_buf = TRUE; + gst_wayland_sink_render_flush_buffer (bsink); + sink->request_camera_flush_buf = FALSE; + } + break; + } + } + } +#endif + gst_buffer_replace (&sink->last_buffer, NULL); + if (sink->window) { + if (gst_wl_window_is_toplevel (sink->window)) { + GST_DEBUG ("internal window"); + g_clear_object (&sink->window); + } else { + /* remove buffer from surface, show nothing */ + GST_DEBUG ("external window"); + gst_wl_window_render (sink->window, NULL, NULL); + } + } + break; + case GST_STATE_CHANGE_READY_TO_NULL: + GST_LOG ("WAYLANDSINK TRANSITION: READY_TO_NULL"); + g_mutex_lock (&sink->display_lock); + /* If we had a toplevel window, we most likely have our own connection + * to the display too, and it is a good idea to disconnect and allow + * potentially the application to embed us with GstVideoOverlay + * (which requires to re-use the same display connection as the parent + * surface). If we didn't have a toplevel window, then the display + * connection that we have is definitely shared with the application + * and it's better to keep it around (together with the window handle) + * to avoid requesting them again from the application if/when we are + * restarted (GstVideoOverlay behaves like that in other sinks) + */ + if (sink->display && !sink->window) { /* -> the window was toplevel */ + g_clear_object (&sink->display); + } + g_mutex_unlock (&sink->display_lock); + g_clear_object (&sink->pool); + break; + default: + break; + } + + return ret; +} +#if 0 +static void +gst_wayland_sink_set_context (GstElement * element, GstContext * context) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (element); + FUNCTION; + + if (gst_context_has_context_type (context, + GST_WAYLAND_DISPLAY_HANDLE_CONTEXT_TYPE)) { + g_mutex_lock (&sink->display_lock); + if (G_LIKELY (!sink->display)) + gst_wayland_sink_set_display_from_context (sink, context); + else { + GST_WARNING_OBJECT (element, "changing display handle is not supported"); +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + g_mutex_unlock (&sink->display_lock); + return; +#endif + } + g_mutex_unlock (&sink->display_lock); + } + + if (GST_ELEMENT_CLASS (parent_class)->set_context) + GST_ELEMENT_CLASS (parent_class)->set_context (element, context); +} +#endif +static GstCaps * +gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) +{ + GstWaylandSink *sink; + GstCaps *caps; + FUNCTION; + + sink = GST_WAYLAND_SINK (bsink); + + caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink)); +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + /* To Do : When caps negotiation is newly needed by such as gapless, + waylandsink may have to make display when disable-overlay is TRUE in here */ +#endif + g_mutex_lock (&sink->display_lock); + + if (sink->display) { + GValue list = G_VALUE_INIT; + GValue value = G_VALUE_INIT; + GArray *formats; + gint i; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + uint32_t tbm_fmt; +#endif + enum wl_shm_format fmt; + + g_value_init (&list, GST_TYPE_LIST); + g_value_init (&value, G_TYPE_STRING); +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (sink->USE_TBM) + formats = sink->display->tbm_formats; + else /* SHM */ +#endif + formats = sink->display->formats; + + for (i = 0; i < formats->len; i++) { +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (sink->USE_TBM) { + tbm_fmt = g_array_index (formats, uint32_t, i); + g_value_set_string (&value, gst_wl_tbm_format_to_string (tbm_fmt)); + gst_value_list_append_value (&list, &value); + + /* TBM doesn't support Native formats(SN12, ST12, SN21, SR32 and S420), + So we add Native formats manually as supported format. */ + if (tbm_fmt == TBM_FORMAT_NV12) { + g_value_set_string (&value, + gst_video_format_to_string (GST_VIDEO_FORMAT_SN12)); + gst_value_list_append_value (&list, &value); + } else if (tbm_fmt == TBM_FORMAT_NV12MT) { + g_value_set_string (&value, + gst_video_format_to_string (GST_VIDEO_FORMAT_ST12)); + gst_value_list_append_value (&list, &value); + } else if (tbm_fmt == TBM_FORMAT_NV21) { + g_value_set_string (&value, + gst_video_format_to_string (GST_VIDEO_FORMAT_SN21)); + gst_value_list_append_value (&list, &value); + } else if (tbm_fmt == TBM_FORMAT_ARGB8888) { + g_value_set_string (&value, + gst_video_format_to_string (GST_VIDEO_FORMAT_SR32)); + gst_value_list_append_value (&list, &value); + } else if (tbm_fmt == TBM_FORMAT_YUV420) { + g_value_set_string (&value, + gst_video_format_to_string (GST_VIDEO_FORMAT_S420)); + gst_value_list_append_value (&list, &value); + } + } else { /* USE SHM */ + fmt = g_array_index (formats, uint32_t, i); + g_value_set_string (&value, gst_wl_shm_format_to_string (fmt)); + gst_value_list_append_value (&list, &value); + } +#else /* open source */ + fmt = g_array_index (formats, uint32_t, i); + g_value_set_string (&value, gst_wl_shm_format_to_string (fmt)); + gst_value_list_append_value (&list, &value); +#endif + } + + caps = gst_caps_make_writable (caps); + gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list); + + GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps); + g_value_unset (&value); + g_value_unset (&list); + + } + + g_mutex_unlock (&sink->display_lock); + + if (filter) { + GstCaps *intersection; + + intersection = + gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST); + gst_caps_unref (caps); + caps = intersection; + } + + return caps; +} + +static gboolean +gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) +{ + GstWaylandSink *sink; + GstBufferPool *newpool; + GstVideoInfo info; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + uint32_t tbm_format = -1; +#endif + enum wl_shm_format format = -1; + + GArray *formats; + gint i; + GstStructure *structure; + GstWlShmAllocator *self = NULL; + + FUNCTION; + + sink = GST_WAYLAND_SINK (bsink); + + GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps); + + /* extract info from caps */ + if (!gst_video_info_from_caps (&info, caps)) + goto invalid_format; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (sink->USE_TBM) { + tbm_format = + gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (&info)); + if ((gint) tbm_format == -1) + goto invalid_format; + } else { + format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info)); + if ((gint) format == -1) + goto invalid_format; + } +#else /* open source */ + format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info)); + + if ((gint) format == -1) + goto invalid_format; +#endif + + /* verify we support the requested format */ +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (sink->USE_TBM) { + GST_LOG ("USE TBM FORMAT"); + formats = sink->display->tbm_formats; + for (i = 0; i < formats->len; i++) { + if (g_array_index (formats, uint32_t, i) == tbm_format) + break; + } + } else { /* USE SHM */ + GST_LOG ("USE SHM FORMAT"); + formats = sink->display->formats; + for (i = 0; i < formats->len; i++) { + if (g_array_index (formats, uint32_t, i) == format) + break; + } + } +#else /* open source */ + formats = sink->display->formats; + for (i = 0; i < formats->len; i++) { + if (g_array_index (formats, uint32_t, i) == format) + break; + } +#endif + if (i >= formats->len) + goto unsupported_format; + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + /* init frame rate for baseink */ + sink->fps_n = info.fps_n; + sink->fps_d = info.fps_d; + + /* init value for set source */ + sink->crop_x = sink->crop_y = sink->crop_w = sink->crop_h = 0; + + if (sink->USE_TBM) { + if (GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN12 || + GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_ST12 || + GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SN21 || + GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_SR32 || + GST_VIDEO_INFO_FORMAT (&info) == GST_VIDEO_FORMAT_S420) { + sink->display->is_native_format = TRUE; + + /* store the video info */ + sink->video_info = info; + sink->video_info_changed = TRUE; + } else { + sink->display->is_native_format = FALSE; + self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ()); + self->display = sink->display; + /* create a new pool for the new configuration */ + newpool = gst_video_buffer_pool_new (); + if (!newpool) + goto pool_failed; + + structure = gst_buffer_pool_get_config (newpool); + gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0); + gst_buffer_pool_config_set_allocator (structure, + gst_wl_shm_allocator_get (), NULL); + if (!gst_buffer_pool_set_config (newpool, structure)) + goto config_failed; + + /* store the video info */ + sink->video_info = info; + sink->video_info_changed = TRUE; + + gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool); + gst_object_unref (newpool); + } + } else { /* USE SHM */ + + self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ()); + self->display = sink->display; + + /* create a new pool for the new configuration */ + newpool = gst_video_buffer_pool_new (); + if (!newpool) + goto pool_failed; + + structure = gst_buffer_pool_get_config (newpool); + gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0); + gst_buffer_pool_config_set_allocator (structure, + gst_wl_shm_allocator_get (), NULL); + if (!gst_buffer_pool_set_config (newpool, structure)) + goto config_failed; + + /* store the video info */ + sink->video_info = info; + sink->video_info_changed = TRUE; + + gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool); + gst_object_unref (newpool); + } + + sink->is_native_format = sink->display->is_native_format; + + if (sink->window) + gst_wayland_sink_update_window_geometry (sink); + + +#else /*open source */ + /* create a new pool for the new configuration */ + newpool = gst_video_buffer_pool_new (); + if (!newpool) + goto pool_failed; + + structure = gst_buffer_pool_get_config (newpool); + gst_buffer_pool_config_set_params (structure, caps, info.size, 6, 0); + gst_buffer_pool_config_set_allocator (structure, + gst_wl_shm_allocator_get (), NULL); + if (!gst_buffer_pool_set_config (newpool, structure)) + goto config_failed; + + /* store the video info */ + sink->video_info = info; + sink->video_info_changed = TRUE; + + gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool); + gst_object_unref (newpool); +#endif + + return TRUE; + +invalid_format: + { + GST_DEBUG_OBJECT (sink, + "Could not locate image format from caps %" GST_PTR_FORMAT, caps); + return FALSE; + } +unsupported_format: + { +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (sink->USE_TBM) + GST_DEBUG_OBJECT (sink, "Format %s is not available on the display", + gst_wl_tbm_format_to_string (tbm_format)); + else /*USE SHM */ + GST_DEBUG_OBJECT (sink, "Format %s is not available on the display", + gst_wl_shm_format_to_string (format)); +#else /*open source */ + GST_DEBUG_OBJECT (sink, "Format %s is not available on the display", + gst_wl_shm_format_to_string (format)); +#endif + return FALSE; + } +pool_failed: + { + GST_DEBUG_OBJECT (sink, "Failed to create new pool"); + return FALSE; + } +config_failed: + { + GST_DEBUG_OBJECT (bsink, "failed setting config"); + gst_object_unref (newpool); + return FALSE; + } +} + +static gboolean +gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstStructure *config; + guint size, min_bufs, max_bufs; + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + gboolean need_pool; + GstCaps *caps; + FUNCTION; + + if (sink->USE_TBM) { + if (sink->display->is_native_format == TRUE) + return FALSE; + + gst_query_parse_allocation (query, &caps, &need_pool); + + if (caps == NULL) { + GST_DEBUG_OBJECT (bsink, "no caps specified"); + return FALSE; + } + } +#endif + config = gst_buffer_pool_get_config (sink->pool); + gst_buffer_pool_config_get_params (config, NULL, &size, &min_bufs, &max_bufs); + + /* we do have a pool for sure (created in set_caps), + * so let's propose it anyway, but also propose the allocator on its own */ + gst_query_add_allocation_pool (query, sink->pool, size, min_bufs, max_bufs); + gst_query_add_allocation_param (query, gst_wl_shm_allocator_get (), NULL); + + gst_structure_free (config); + + return TRUE; +} + +static GstFlowReturn +gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer) +{ +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + FUNCTION; + + GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer); + + if (sink->signal_handoffs) { + GST_LOG ("g_signal_emit: preroll-handoff"); + g_signal_emit (sink, + gst_waylandsink_signals[SIGNAL_PREROLL_HANDOFF], 0, buffer, + bsink->sinkpad); + + return GST_FLOW_OK; + } +#endif + return gst_wayland_sink_render (bsink, buffer); +} + +static void +frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time) +{ + GstWaylandSink *sink = data; + FUNCTION; + + GST_LOG ("frame_redraw_cb"); + + g_atomic_int_set (&sink->redraw_pending, FALSE); + GST_INFO ("wl_callback_destroy (wl_callback@%p)", callback); + wl_callback_destroy (callback); +} + +static const struct wl_callback_listener frame_callback_listener = { + frame_redraw_callback +}; + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +static void +gst_wayland_sink_update_window_geometry (GstWaylandSink * sink) +{ + FUNCTION; + g_return_if_fail (sink != NULL); + g_return_if_fail (sink->window != NULL); + + gst_wl_window_set_rotate_angle (sink->window, sink->rotate_angle); + gst_wl_window_set_destination_mode (sink->window, + sink->display_geometry_method); + gst_wl_window_set_flip (sink->window, sink->flip); + if (sink->crop_w == 0 && sink->crop_h == 0) { + sink->crop_w = + gst_util_uint64_scale_int_round (sink->video_info.width, + sink->video_info.par_n, sink->video_info.par_d); + sink->crop_h = sink->video_info.height; + } + gst_wl_window_set_destination_mode_crop_wl_buffer (sink->window, sink->crop_x, + sink->crop_y, sink->crop_w, sink->crop_h); +#ifdef ENABLE_FUNCTION + gst_wl_window_set_destination_mode_follow_parent_transform (sink->window, + sink->follow_parent_transform); + gst_wl_window_set_destination_mode_ratio (sink->window, sink->ratio_w, + sink->ratio_h); + gst_wl_window_set_destination_mode_scale (sink->window, sink->scale_w, + sink->scale_h); + gst_wl_window_set_destination_mode_offset (sink->window, sink->offset_x, + sink->offset_y, sink->offset_w, sink->offset_h); + gst_wl_window_set_destination_mode_align (sink->window, sink->align_w, + sink->align_h); +#endif +} +#endif +/* must be called with the render lock */ +static void +render_last_buffer (GstWaylandSink * sink) +{ + GstWlBuffer *wlbuffer; + const GstVideoInfo *info = NULL; + struct wl_surface *surface; + struct wl_callback *callback; + FUNCTION; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + g_return_if_fail (sink->last_buffer != NULL); + g_return_if_fail (sink->window != NULL); +#endif + + wlbuffer = gst_buffer_get_wl_buffer (sink->last_buffer); + surface = gst_wl_window_get_wl_surface (sink->window); + + g_atomic_int_set (&sink->redraw_pending, TRUE); + callback = wl_surface_frame (surface); + GST_INFO ("wl_callback@%p = wl_surface_frame (video_surface@%p)", callback, + surface); + + /* frame_callback_listener is called when wayland-client finish rendering the wl_buffer */ + GST_INFO + ("wl_callback_add_listener (wl_callback@%p, wl_callback_listener@%p, GstWaylandSink@%p)", + callback, &frame_callback_listener, sink); + wl_callback_add_listener (callback, &frame_callback_listener, sink); + + if (G_UNLIKELY (sink->video_info_changed)) { +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + gst_wl_window_set_video_info_change (sink->window, TRUE); +#endif + info = &sink->video_info; + sink->video_info_changed = FALSE; + } + gst_wl_window_render (sink->window, wlbuffer, info); +} + + +static gboolean +gst_wayland_sink_has_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) +{ + GstWlBuffer *gstwlbuffer; + FUNCTION; + g_return_val_if_fail (sink != NULL, FALSE); + g_return_val_if_fail (buffer != NULL, FALSE); + + gstwlbuffer = gst_buffer_get_wl_buffer (buffer); + if (gstwlbuffer && gstwlbuffer->display == sink->display + && !gst_wayland_sink_is_gapless (sink) + && !sink->request_camera_flush_buf) { + /* gstbuffer has wlbuffer */ + /* e.g) last_buffer, buffer is created by previous plugin or waylandsink with BufferPool */ + GST_LOG ("buffer(%p) has GstWlBuffer(%p):wlbuffer(%p)", buffer, gstwlbuffer, + gstwlbuffer->wlbuffer); + return TRUE; + } + GST_LOG ("buffer(%p) has not wlbuffer", buffer); + return FALSE; +} + +static GstFlowReturn +gst_wayland_sink_no_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) +{ + GstMemory *mem; + MMVideoBuffer *mm_video_buf = NULL; + GstFlowReturn ret = GST_FLOW_OK; + FUNCTION; + g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); + + /* the last_buffer for flushing has wlbuffer or + buffer is created by previous plugins or waylandsink has wlbuffer */ + mem = gst_buffer_peek_memory (buffer, 0); + if (gst_is_wl_memory (mem)) { + GST_LOG ("buffer(%p) is created by waylandsink has a wl_buffer, " + "writing directly", buffer); + } else { + GST_LOG + ("buffer(%p) is created by previous plugins with BufferPool has a wl_buffer, " + "writing directly", buffer); + GST_LOG ("previous plugins must manage buffer index well"); + /* check MMVideoBuffer */ + mm_video_buf = gst_wayland_sink_get_mm_video_buf (buffer); + if (mm_video_buf != NULL) { + GST_LOG ("GstBuffer(%p) has MMVideoBuffer(%p)", buffer, mm_video_buf); + } else { + GST_ERROR ("GstBuffer(%p) has not MMVideoBuffer(%p)", buffer, + mm_video_buf); + return GST_FLOW_ERROR; + } + } + + sink->to_render = buffer; + + if (sink->dump_video && !sink->display->is_native_format) + gst_wayland_sink_dump_raw_video (sink, sink->to_render, + sink->display->dump_count++, sink->total_dump); + + return ret; +} + +static void +gst_wayland_sink_create_wlbuffer_with_wl_mem (GstWaylandSink * sink, + GstBuffer * buffer) +{ + GstMemory *mem; + struct wl_buffer *wbuf = NULL; + FUNCTION; + g_return_if_fail (sink != NULL); + g_return_if_fail (buffer != NULL); + + GST_LOG ("gstbuffer(%p) is created by wayland has not wlbuffer", buffer); + mem = gst_buffer_peek_memory (buffer, 0); + wbuf = + gst_wl_shm_memory_construct_wl_buffer (mem, sink->display, + &sink->video_info); + if (wbuf) { + gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); + sink->to_render = buffer; + } +} + +static GstFlowReturn +gst_wayland_sink_create_wlbuffer_with_previous_plugin_tbm (GstWaylandSink * + sink, GstBuffer * buffer) +{ + GstMemory *mem; + GstWlBuffer *wlbuffer; + struct wl_buffer *wbuf = NULL; + GstFlowReturn ret = GST_FLOW_OK; + FUNCTION; + g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); + sink->flush_gstbuf = NULL; + + GST_LOG + ("buffer(%p) is created by previous plugin with no BufferPool does not have a wl_buffer", + buffer); + GST_LOG ("Use native format with previous plugins TBM"); + /* in case of native format (SN12, ST12, SN21, SR32 and S420) */ + if (!gst_wayland_sink_get_mm_video_buf_info (sink, buffer)) { + return GST_FLOW_ERROR; + } + + wlbuffer = gst_buffer_get_wl_buffer (buffer); + /* last_buffer from gaplasee have wlbuffer */ + if (G_UNLIKELY (!wlbuffer) || sink->display->flush_request) { + mem = gst_buffer_peek_memory (buffer, 0); + wbuf = + gst_wl_shm_memory_construct_wl_buffer (mem, sink->display, + &sink->video_info); + if (G_UNLIKELY (!wbuf)) { + GST_ERROR ("could not create wl_buffer"); + return GST_FLOW_ERROR; + } + if (sink->display->flush_request) { + sink->flush_gstbuf = gst_buffer_new (); + GST_LOG ("To flush, new gstBuffer(%p)", sink->flush_gstbuf); + gst_buffer_add_wl_buffer (sink->flush_gstbuf, wbuf, sink->display); + } else { + gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); + } + } + return ret; +} + +static GstFlowReturn + gst_wayland_sink_copy_input_gstbuffer_to_wl_gstbuffer_with_wl_mem + (GstWaylandSink * sink, GstBuffer * buffer) +{ + GstWlBuffer *wlbuffer; + GstMemory *mem; + GstWlShmMemory *shm_mem; + GstMapInfo src; + struct wl_buffer *wbuf = NULL; + GstFlowReturn ret = GST_FLOW_OK; + FUNCTION; + g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); + + GST_LOG ("Use normal format with wayland TBM or SHM"); + /* sink->pool always exists (created in set_caps), but it may not + * be active if upstream is not using it */ + if (!gst_buffer_pool_is_active (sink->pool) && + !gst_buffer_pool_set_active (sink->pool, TRUE)) { + GST_ERROR ("failed to activate bufferpool."); + return GST_FLOW_ERROR; + } + + ret = gst_buffer_pool_acquire_buffer (sink->pool, &sink->to_render, NULL); + if (ret != GST_FLOW_OK) { + GST_WARNING ("could not create buffer"); + return ret; + } + /* the first time we acquire a buffer, + * we need to attach a wl_buffer on it */ + wlbuffer = gst_buffer_get_wl_buffer (buffer); + if (G_UNLIKELY (!wlbuffer)) { + mem = gst_buffer_peek_memory (sink->to_render, 0); + shm_mem = (GstWlShmMemory *) mem; + GST_LOG ("to_render(%p), shm_mem->fd(%d)", sink->to_render, shm_mem->fd); + wbuf = + gst_wl_shm_memory_construct_wl_buffer (mem, sink->display, + &sink->video_info); + if (G_UNLIKELY (!wbuf)) { + GST_ERROR ("could not create wl_buffer out of wl memory"); + return GST_FLOW_ERROR; + } + wlbuffer = gst_buffer_add_wl_buffer (sink->to_render, wbuf, sink->display); + } + + gst_buffer_map (buffer, &src, GST_MAP_READ); + gst_buffer_fill (sink->to_render, 0, src.data, src.size); + gst_buffer_unmap (buffer, &src); + + return ret; +} + +static GstFlowReturn +gst_wayland_sink_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) +{ + GstMemory *mem; + GstFlowReturn ret = GST_FLOW_OK; + FUNCTION; + g_return_val_if_fail (sink != NULL, GST_FLOW_ERROR); + g_return_val_if_fail (buffer != NULL, GST_FLOW_ERROR); + + sink->to_render = NULL; + + if (gst_wayland_sink_has_wlbuffer (sink, buffer)) { + ret = gst_wayland_sink_no_create_wlbuffer (sink, buffer); + } else { + mem = gst_buffer_peek_memory (buffer, 0); + if (gst_is_wl_memory (mem)) { + /* SHM or TBM */ + gst_wayland_sink_create_wlbuffer_with_wl_mem (sink, buffer); + } else { + /* gstbuffer is not wl memory */ + if (sink->USE_TBM && sink->display->is_native_format) { + /* Use tbm of buffer directly */ + ret = + gst_wayland_sink_create_wlbuffer_with_previous_plugin_tbm (sink, + buffer); + } else { + /* Copy virtual addr to wayland SHM or TBM */ + ret = + gst_wayland_sink_copy_input_gstbuffer_to_wl_gstbuffer_with_wl_mem + (sink, buffer); + } + } + } + return ret; +} + +static void +gst_wayland_sink_buffer_replace (GstWaylandSink * sink, GstBuffer * buffer) +{ + FUNCTION; + g_return_if_fail (sink != NULL); + + if (sink->USE_TBM && sink->display->is_native_format) { + if (sink->flush_gstbuf && sink->display->flush_request) { + GST_LOG_OBJECT (sink, "replace last_buffer:(%p)->(%p)", sink->last_buffer, + sink->flush_gstbuf); + /* increase ref count of sink->fflush_gstbuf, decrease ref count of sink->last_buffer */ + gst_buffer_replace (&sink->last_buffer, sink->flush_gstbuf); + GST_LOG_OBJECT (sink, "after gst_buffer_replace buffer %p, ref_count(%d)", + sink->flush_gstbuf, GST_OBJECT_REFCOUNT_VALUE (sink->flush_gstbuf)); + /* decrease ref count of flush_buffer */ + gst_buffer_unref (sink->flush_gstbuf); + } else { + /* normal case */ + GST_LOG_OBJECT (sink, "replace last_buffer:(%p)->(%p)", sink->last_buffer, + buffer); + /* increase ref count of buffer decrease ref count of sink->last_buffer */ + gst_buffer_replace (&sink->last_buffer, buffer); + GST_LOG_OBJECT (sink, "after gst_buffer_replace buffer %p, ref_count(%d)", + buffer, GST_OBJECT_REFCOUNT_VALUE (buffer)); + } + } else { + gst_buffer_replace (&sink->last_buffer, sink->to_render); + GST_LOG_OBJECT (sink, "after gst_buffer_replace buffer %p, ref_count(%d)", + sink->to_render, GST_OBJECT_REFCOUNT_VALUE (sink->to_render)); + } +} + +static void +gst_wayland_sink_get_window (GstWaylandSink * sink) +{ + g_return_if_fail (sink != NULL); + FUNCTION; + + /* ask for window handle. Unlock render_lock while doing that because + * set_window_handle & friends will lock it in this context */ + g_mutex_unlock (&sink->render_lock); + gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink)); + g_mutex_lock (&sink->render_lock); + + if (!sink->window) { + /* if we were not provided a window, create one ourselves */ + sink->window = + gst_wl_window_new_toplevel (sink->display, &sink->video_info); + } + gst_wayland_sink_update_window_geometry (sink); +} + +static GstFlowReturn +gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) +{ +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + + GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstFlowReturn ret = GST_FLOW_OK; + FUNCTION; + + g_mutex_lock (&sink->render_lock); + + GST_LOG_OBJECT (sink, "input gstbuffer %p, ref_count(%d)", buffer, + GST_OBJECT_REFCOUNT_VALUE (buffer)); + + /* check overlay */ + if (gst_wayland_sink_is_disabled_overlay (sink)) { + GST_LOG ("set disable_overlay, so skip"); + goto done; + } + + /* check window */ + if (G_UNLIKELY (!sink->window)) { + gst_wayland_sink_get_window (sink); + } + + /* fakesink function for media stream callback case */ + if (sink->signal_handoffs) { + GST_LOG ("g_signal_emit: hand-off "); + g_signal_emit (sink, gst_waylandsink_signals[SIGNAL_HANDOFF], 0, buffer, + bsink->sinkpad); + goto done; + } + + /* drop buffers until we get a frame callback */ + if (g_atomic_int_get (&sink->redraw_pending) == TRUE + && !gst_wayland_sink_is_gapless (sink)) + goto done; + + /* create wl_buffer */ + ret = gst_wayland_sink_create_wlbuffer (sink, buffer); + if (ret != GST_FLOW_OK) + goto done; + + /* drop double rendering */ + if ((G_UNLIKELY (buffer == sink->last_buffer) + && !(sink->display->flush_request))) { + GST_LOG_OBJECT (sink, "Buffer already being rendered"); + goto done; + } + + /* replace last_buffer */ + gst_wayland_sink_buffer_replace (sink, buffer); + + /* rendering */ + if (sink->visible) { + render_last_buffer (sink); + } else { + GST_LOG ("skip rendering"); + } + + if (sink->to_render) { + if (buffer != sink->to_render) + gst_buffer_unref (sink->to_render); + } + + goto done; + +#else /* open source */ + + GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstBuffer *to_render = NULL; + GstFlowReturn ret = GST_FLOW_OK; + + g_mutex_lock (&sink->render_lock); + + if (G_UNLIKELY (!sink->window)) { + /* ask for window handle. Unlock render_lock while doing that because + * set_window_handle & friends will lock it in this context */ + g_mutex_unlock (&sink->render_lock); + gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink)); + g_mutex_lock (&sink->render_lock); + + if (!sink->window) { + /* if we were not provided a window, create one ourselves */ + sink->window = + gst_wl_window_new_toplevel (sink->display, &sink->video_info); + } + } + + /* drop buffers until we get a frame callback */ + if (g_atomic_int_get (&sink->redraw_pending) == TRUE + && !gst_wayland_sink_is_gapless (sink)) + goto done; + + /* make sure that the application has called set_render_rectangle() */ + if (G_UNLIKELY (sink->window->render_rectangle.w == 0)) + goto no_window_size; + + wlbuffer = gst_buffer_get_wl_buffer (buffer); + + if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) { + GST_LOG_OBJECT (sink, + "buffer %p has a wl_buffer from our display, " "writing directly", + buffer); + GST_LOG ("wl_buffer (%p)", wlbuffer->wlbuffer); + to_render = buffer; + + } else { + GstMemory *mem; + struct wl_buffer *wbuf = NULL; + + GST_LOG_OBJECT (sink, + "buffer %p does not have a wl_buffer from our " "display, creating it", + buffer); + mem = gst_buffer_peek_memory (buffer, 0); + if (gst_is_wl_shm_memory (mem)) { /* is wayland memory */ + FUNCTION; + wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display, + &sink->video_info); + } + if (wbuf) { + gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); + to_render = buffer; + + } else { + GstMapInfo src; + /* we don't know how to create a wl_buffer directly from the provided + * memory, so we have to copy the data to a memory that we know how + * to handle... */ + + GST_LOG_OBJECT (sink, "buffer %p is not from our pool", buffer); + GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, " "copying", + buffer); + /* sink->pool always exists (created in set_caps), but it may not + * be active if upstream is not using it */ + if (!gst_buffer_pool_is_active (sink->pool) && + !gst_buffer_pool_set_active (sink->pool, TRUE)) + goto activate_failed; + + ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL); + if (ret != GST_FLOW_OK) + goto no_buffer; + + /* the first time we acquire a buffer, + * we need to attach a wl_buffer on it */ + wlbuffer = gst_buffer_get_wl_buffer (buffer); + if (G_UNLIKELY (!wlbuffer)) { + mem = gst_buffer_peek_memory (to_render, 0); + wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display, + &sink->video_info); + if (G_UNLIKELY (!wbuf)) + goto no_wl_buffer; + + gst_buffer_add_wl_buffer (to_render, wbuf, sink->display); + } + + gst_buffer_map (buffer, &src, GST_MAP_READ); + gst_buffer_fill (to_render, 0, src.data, src.size); + gst_buffer_unmap (buffer, &src); + } + } + /* drop double rendering */ + if (G_UNLIKELY (buffer == sink->last_buffer)) { + GST_LOG_OBJECT (sink, "Buffer already being rendered"); + goto done; + } + + gst_buffer_replace (&sink->last_buffer, to_render); + render_last_buffer (sink); + + if (buffer != to_render) + gst_buffer_unref (to_render); + + goto done; + +#endif /* TIZEN_FEATURE_WLSINK_ENHANCEMENT */ + +#ifndef TIZEN_FEATURE_WLSINK_ENHANCEMENT +no_window_size: + { + GST_ELEMENT_ERROR (sink, RESOURCE, WRITE, + ("Window has no size set"), + ("Make sure you set the size after calling set_window_handle")); + ret = GST_FLOW_ERROR; + goto done; + } +no_buffer: + { + GST_WARNING_OBJECT (sink, "could not create buffer"); + goto done; + } +no_wl_buffer: + { + GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory"); + ret = GST_FLOW_ERROR; + goto done; + } +activate_failed: + { + GST_ERROR_OBJECT (sink, "failed to activate bufferpool."); + ret = GST_FLOW_ERROR; + goto done; + } +#endif +done: + { + g_mutex_unlock (&sink->render_lock); + return ret; + } +} + +static void +gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface) +{ + iface->set_window_handle = gst_wayland_sink_set_window_handle; + iface->set_render_rectangle = gst_wayland_sink_set_render_rectangle; + iface->expose = gst_wayland_sink_expose; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT /* use unique_id */ + iface->set_wl_window_wl_surface_id = + gst_wayland_sink_set_wl_window_wl_surface_id; +#endif +} + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +/* use unique_id */ +static void +gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay, + guintptr wl_surface_id) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + FUNCTION; + g_return_if_fail (sink != NULL); + + if (sink->window != NULL) { + GST_WARNING_OBJECT (sink, "changing window handle is not supported"); + return; + } + g_mutex_lock (&sink->render_lock); + g_clear_object (&sink->window); + + GST_LOG ("wl_surface_id %d %x", (int) wl_surface_id, + (guintptr) wl_surface_id); + + if (wl_surface_id) { + if (G_LIKELY (gst_wayland_sink_find_display (sink))) { + /* we can use our own display with an external window handle */ + if (G_LIKELY (sink->display->own_display)) { + sink->display->wl_surface_id = (int) wl_surface_id; + sink->window = gst_wl_window_new_in_surface (sink->display, NULL); + } + } else { + GST_ERROR_OBJECT (sink, "Failed to find display handle, " + "ignoring window handle"); + } + } + g_mutex_unlock (&sink->render_lock); + +} +#endif + +static void +gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + struct wl_surface *surface = (struct wl_surface *) handle; + FUNCTION; + + g_return_if_fail (sink != NULL); + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT /* use unique_id */ + if (sink->window != NULL) { + GST_WARNING_OBJECT (sink, "changing window handle is not supported"); + return; + } +#endif + g_mutex_lock (&sink->render_lock); + + GST_DEBUG_OBJECT (sink, "Setting window handle %" GST_PTR_FORMAT, + (void *) handle); + + g_clear_object (&sink->window); + + if (handle) { + if (G_LIKELY (gst_wayland_sink_find_display (sink))) { + /* we cannot use our own display with an external window handle */ + if (G_UNLIKELY (sink->display->own_display)) { + GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE, + ("Application did not provide a wayland display handle"), + ("Now waylandsink use internal display handle " + "which is created ourselves. Consider providing a " + "display handle from your application with GstContext")); + sink->window = gst_wl_window_new_in_surface (sink->display, surface); + } else { + sink->window = gst_wl_window_new_in_surface (sink->display, surface); + } + } else { + GST_ERROR_OBJECT (sink, "Failed to find display handle, " + "ignoring window handle"); + } + } + g_mutex_unlock (&sink->render_lock); +} + +static void +gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay, + gint x, gint y, gint w, gint h) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + FUNCTION; + + g_return_if_fail (sink != NULL); + + g_mutex_lock (&sink->render_lock); + if (!sink->window) { + g_mutex_unlock (&sink->render_lock); + GST_WARNING_OBJECT (sink, + "set_render_rectangle called without window, ignoring"); + return; + } + + GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d", + x, y, w, h); + if (gst_wl_window_set_render_rectangle (sink->window, x, y, w, h)) { + sink->video_info_changed = TRUE; + if (sink->window && GST_STATE (sink) == GST_STATE_PAUSED) + gst_wayland_sink_update_last_buffer_geometry (sink); + } + g_mutex_unlock (&sink->render_lock); +} + +static void +gst_wayland_sink_expose (GstVideoOverlay * overlay) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + FUNCTION; + + g_return_if_fail (sink != NULL); + + GST_DEBUG_OBJECT (sink, "expose"); + + g_mutex_lock (&sink->render_lock); + if (sink->last_buffer && g_atomic_int_get (&sink->redraw_pending) == FALSE) { + GST_DEBUG_OBJECT (sink, "redrawing last buffer"); + render_last_buffer (sink); + } + g_mutex_unlock (&sink->render_lock); +} +#if 0 +static void +gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface) +{ + iface->begin_geometry_change = gst_wayland_sink_begin_geometry_change; + iface->end_geometry_change = gst_wayland_sink_end_geometry_change; +} + +static void +gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (video); + FUNCTION; + g_return_if_fail (sink != NULL); + + g_mutex_lock (&sink->render_lock); + if (!sink->window || !sink->window->area_subsurface) { + g_mutex_unlock (&sink->render_lock); + GST_INFO_OBJECT (sink, + "begin_geometry_change called without window, ignoring"); + return; + } + + wl_subsurface_set_sync (sink->window->area_subsurface); + g_mutex_unlock (&sink->render_lock); +} + +static void +gst_wayland_sink_end_geometry_change (GstWaylandVideo * video) +{ + GstWaylandSink *sink = GST_WAYLAND_SINK (video); + FUNCTION; + g_return_if_fail (sink != NULL); + + g_mutex_lock (&sink->render_lock); + if (!sink->window || !sink->window->area_subsurface) { + g_mutex_unlock (&sink->render_lock); + GST_INFO_OBJECT (sink, + "end_geometry_change called without window, ignoring"); + return; + } + + wl_subsurface_set_desync (sink->window->area_subsurface); + g_mutex_unlock (&sink->render_lock); +} +#endif + +static gboolean +plugin_init (GstPlugin * plugin) +{ + GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "tizenwlsink", 0, + " tizen wayland video sink"); + + gst_wl_shm_allocator_register (); + + return gst_element_register (plugin, "tizenwlsink", GST_RANK_MARGINAL, + GST_TYPE_WAYLAND_SINK); +} + +GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, + GST_VERSION_MINOR, + tizenwlsink, + "Tizen Wayland Video Sink", plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, + GST_PACKAGE_ORIGIN) diff --git a/tizenwlsink/src/gstwaylandsink.h b/tizenwlsink/src/gstwaylandsink.h new file mode 100644 index 0000000..58c1e11 --- /dev/null +++ b/tizenwlsink/src/gstwaylandsink.h @@ -0,0 +1,130 @@ +/* + * GStreamer Wayland video sink + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Sreerenj Balachandran + * + * 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 +#include + +#include + +#include "wldisplay.h" +#include "wlwindow.h" + +G_BEGIN_DECLS +#define GST_TYPE_WAYLAND_SINK \ + (gst_wayland_sink_get_type()) +#define GST_WAYLAND_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_WAYLAND_SINK,GstWaylandSink)) +#define GST_WAYLAND_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_WAYLAND_SINK,GstWaylandSinkClass)) +#define GST_IS_WAYLAND_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_WAYLAND_SINK)) +#define GST_IS_WAYLAND_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_WAYLAND_SINK)) +#define GST_WAYLAND_SINK_GET_CLASS(inst) \ + (G_TYPE_INSTANCE_GET_CLASS ((inst), GST_TYPE_WAYLAND_SINK, GstWaylandSinkClass)) +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +enum +{ + DISP_GEO_METHOD_LETTER_BOX = 0, + DISP_GEO_METHOD_ORIGIN_SIZE, + DISP_GEO_METHOD_FULL_SCREEN, + DISP_GEO_METHOD_CROPPED_FULL_SCREEN, + DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX, + DISP_GEO_METHOD_CUSTOM_ROI, + DISP_GEO_METHOD_NUM, +}; + +#define DEF_DISPLAY_FLIP FLIP_NONE +#define DEF_DISPLAY_GEOMETRY_METHOD DISP_GEO_METHOD_LETTER_BOX +#define DEFAULT_DUMP_COUNT 10 +#endif + +typedef struct _GstWaylandSink GstWaylandSink; +typedef struct _GstWaylandSinkClass GstWaylandSinkClass; + +struct _GstWaylandSink +{ + GstVideoSink parent; + + GMutex display_lock; + GstWlDisplay *display; + GstWlWindow *window; + GstBufferPool *pool; + + gboolean video_info_changed; + GstVideoInfo video_info; + + gchar *display_name; + + gboolean redraw_pending; + GMutex render_lock; + GstBuffer *last_buffer; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + GstBuffer *to_render; + GstBuffer *flush_gstbuf; + /* Framerate numerator and denominator */ + gint fps_n; + gint fps_d; + + gboolean dump_video; + gboolean signal_handoffs; + gboolean request_camera_flush_buf; + gboolean keep_camera_preview; + gboolean got_costum_event; + gboolean visible; + gboolean follow_parent_transform; + gboolean USE_TBM; + gboolean is_native_format; + gboolean flush_request; + gboolean disable_overlay; + guint total_dump; + guint rotate_angle; + guint display_geometry_method; + guint flip; + guint crop_x, crop_y, crop_w, crop_h; +#ifdef ENABLE_FUNCTION + guint offset_x, offset_y, offset_w, offset_h; + gdouble ratio_w, ratio_h; + gdouble scale_w, scale_h; + gdouble align_w, align_h; +#endif +#endif +}; + +struct _GstWaylandSinkClass +{ + GstVideoSinkClass parent; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + /* signals */ + void (*handoff) (GstElement *element, GstBuffer *buf, GstPad *pad); + void (*preroll_handoff) (GstElement *element, GstBuffer *buf, GstPad *pad); +#endif +}; + +GType +gst_wayland_sink_get_type (void) + G_GNUC_CONST; + +G_END_DECLS +#endif /* __GST_WAYLAND_VIDEO_SINK_H__ */ diff --git a/tizenwlsink/src/scaler.xml b/tizenwlsink/src/scaler.xml new file mode 100644 index 0000000..e21ae5b --- /dev/null +++ b/tizenwlsink/src/scaler.xml @@ -0,0 +1,210 @@ + + + + + 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. + + + + + 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. + + + + + 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. + + + + + + + + + + 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. + + + + + + + + + + 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. + + + + + The associated wl_surface's crop and scale state is removed. + The change is applied on the next wl_surface.commit. + + + + + + + + + + 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. + + + + + + + + + + + + + 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. + + + + + + + + + + + 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. + + + + + + + diff --git a/tizenwlsink/src/tizen-wlvideoformat.c b/tizenwlsink/src/tizen-wlvideoformat.c new file mode 100644 index 0000000..8ebf505 --- /dev/null +++ b/tizenwlsink/src/tizen-wlvideoformat.c @@ -0,0 +1,115 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Sreerenj Balachandran + * Copyright (C) 2012 Wim Taymans + * 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 +#endif +#include "tizen-wlvideoformat.h" +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + +GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); +#define GST_CAT_DEFAULT gstwayland_debug + +typedef struct +{ + uint32_t wl_format; + GstVideoFormat gst_format; +} wl_TbmVideoFormat; + +static const wl_TbmVideoFormat tbm_formats[] = { +#if G_BYTE_ORDER == G_BIG_ENDIAN + {TBM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_xRGB}, + {TBM_FORMAT_XBGR8888, GST_VIDEO_FORMAT_xBGR}, + {TBM_FORMAT_RGBX8888, GST_VIDEO_FORMAT_RGBx}, + {TBM_FORMAT_BGRX8888, GST_VIDEO_FORMAT_BGRx}, + {TBM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_ARGB}, + {TBM_FORMAT_ABGR8888, GST_VIDEO_FORMAT_RGBA}, + {TBM_FORMAT_RGBA8888, GST_VIDEO_FORMAT_RGBA}, + {TBM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_BGRA}, + {TBM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_SR32}, +#else + {TBM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_BGRx}, + {TBM_FORMAT_XBGR8888, GST_VIDEO_FORMAT_RGBx}, + {TBM_FORMAT_RGBX8888, GST_VIDEO_FORMAT_xBGR}, + {TBM_FORMAT_BGRX8888, GST_VIDEO_FORMAT_xRGB}, + {TBM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_BGRA}, + {TBM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_SR32}, + {TBM_FORMAT_ABGR8888, GST_VIDEO_FORMAT_RGBA}, + {TBM_FORMAT_RGBA8888, GST_VIDEO_FORMAT_ABGR}, + {TBM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_ARGB}, +#endif + {TBM_FORMAT_RGB565, GST_VIDEO_FORMAT_RGB16}, + {TBM_FORMAT_BGR565, GST_VIDEO_FORMAT_BGR16}, + {TBM_FORMAT_RGB888, GST_VIDEO_FORMAT_RGB}, + {TBM_FORMAT_BGR888, GST_VIDEO_FORMAT_BGR}, + {TBM_FORMAT_YUYV, GST_VIDEO_FORMAT_YUY2}, + {TBM_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU}, + {TBM_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY}, + {TBM_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV}, + {TBM_FORMAT_NV12, GST_VIDEO_FORMAT_NV12}, + {TBM_FORMAT_NV21, GST_VIDEO_FORMAT_NV21}, + {TBM_FORMAT_NV16, GST_VIDEO_FORMAT_NV16}, + {TBM_FORMAT_YUV410, GST_VIDEO_FORMAT_YUV9}, + {TBM_FORMAT_YVU410, GST_VIDEO_FORMAT_YVU9}, + {TBM_FORMAT_YUV411, GST_VIDEO_FORMAT_Y41B}, + {TBM_FORMAT_YUV420, GST_VIDEO_FORMAT_I420}, + {TBM_FORMAT_YVU420, GST_VIDEO_FORMAT_YV12}, + {TBM_FORMAT_YUV422, GST_VIDEO_FORMAT_Y42B}, + {TBM_FORMAT_YUV444, GST_VIDEO_FORMAT_v308}, + {TBM_FORMAT_NV12MT, GST_VIDEO_FORMAT_ST12}, + {TBM_FORMAT_NV12, GST_VIDEO_FORMAT_SN12}, + {TBM_FORMAT_NV21, GST_VIDEO_FORMAT_SN21}, + {TBM_FORMAT_YUV420, GST_VIDEO_FORMAT_S420} +}; + +uint32_t +gst_video_format_to_wl_tbm_format (GstVideoFormat format) +{ + guint i; + for (i = 0; i < G_N_ELEMENTS (tbm_formats); i++) + if (tbm_formats[i].gst_format == format) + return tbm_formats[i].wl_format; + GST_WARNING ("wayland tbm video format not found"); + return -1; +} + +GstVideoFormat +gst_wl_tbm_format_to_video_format (uint32_t wl_format) +{ + guint i; + + for (i = 0; i < G_N_ELEMENTS (tbm_formats); i++) + if (tbm_formats[i].wl_format == wl_format) + return tbm_formats[i].gst_format; + + GST_WARNING ("gst video format not found"); + return GST_VIDEO_FORMAT_UNKNOWN; +} + +const gchar * +gst_wl_tbm_format_to_string (uint32_t wl_format) +{ + return gst_video_format_to_string + (gst_wl_tbm_format_to_video_format (wl_format)); +} +#endif diff --git a/tizenwlsink/src/tizen-wlvideoformat.h b/tizenwlsink/src/tizen-wlvideoformat.h new file mode 100755 index 0000000..711c154 --- /dev/null +++ b/tizenwlsink/src/tizen-wlvideoformat.h @@ -0,0 +1,41 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Sreerenj Balachandran + * Copyright (C) 2012 Wim Taymans + * 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 +#include + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +#include + +G_BEGIN_DECLS + uint32_t gst_video_format_to_wl_tbm_format (GstVideoFormat format); +GstVideoFormat gst_wl_tbm_format_to_video_format (uint32_t wl_format); + +const gchar *gst_wl_tbm_format_to_string (uint32_t wl_format); + +G_END_DECLS +#endif +#endif diff --git a/tizenwlsink/src/wlbuffer.c b/tizenwlsink/src/wlbuffer.c new file mode 100644 index 0000000..c37e61e --- /dev/null +++ b/tizenwlsink/src/wlbuffer.c @@ -0,0 +1,327 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +/* GstWlBuffer wraps wl_buffer and provides a mechanism for preventing + * buffers from being re-used while the compositor is using them. This + * is achieved by adding a reference to the GstBuffer as soon as its + * associated wl_buffer is sent to the compositor and by removing this + * reference as soon as the compositor sends a wl_buffer::release message. + * + * This mechanism is a bit complicated, though, because it adds cyclic + * references that can be dangerous. The reference cycles looks like: + * + * ---------------- + * | GstWlDisplay | ----------------------------> + * ---------------- | + * | + * V + * ----------------- ------------- --------------- + * | GstBufferPool | --> | GstBuffer | ==> | GstWlBuffer | + * | | <-- | | <-- | | + * ----------------- ------------- --------------- + * + * A GstBufferPool normally holds references to its GstBuffers and each buffer + * holds a reference to a GstWlBuffer (saved in the GstMiniObject qdata). + * When a GstBuffer is in use, it holds a reference back to the pool and the + * pool doesn't hold a reference to the GstBuffer. When the GstBuffer is unrefed + * externally, it returns back to the pool and the pool holds again a reference + * to the buffer. + * + * Now when the compositor is using a buffer, the GstWlBuffer also holds a ref + * to the GstBuffer, which prevents it from returning to the pool. When the + * last GstWlBuffer receives a release event and unrefs the last GstBuffer, + * the GstBufferPool will be able to stop and if no-one is holding a strong + * ref to it, it will be destroyed. This will destroy the pool's GstBuffers and + * also the GstWlBuffers. This will all happen in the same context of the last + * gst_buffer_unref, which will be called from the buffer_release() callback. + * + * The problem here lies in the fact that buffer_release() will be called + * from the event loop thread of GstWlDisplay, so it's as if the display + * holds a reference to the GstWlBuffer, but without having an actual reference. + * When we kill the display, there is no way for the GstWlBuffer, the associated + * GstBuffer and the GstBufferPool to get destroyed, so we are going to leak a + * fair ammount of memory. + * + * Normally, this rarely happens, because the compositor releases buffers + * almost immediately and when waylandsink stops, they are already released. + * + * However, we want to be absolutely certain, so a solution is introduced + * by registering all the GstWlBuffers with the display and explicitly + * releasing all the buffer references as soon as the display is destroyed. + * + * When the GstWlDisplay is finalized, it takes a reference to all the + * registered GstWlBuffers and then calls gst_wl_buffer_force_release_and_unref, + * which releases the potential reference to the GstBuffer, destroys the + * underlying wl_buffer and removes the reference that GstWlDisplay is holding. + * At that point, either the GstBuffer is alive somewhere and still holds a ref + * to the GstWlBuffer, which it will release when it gets destroyed, or the + * GstBuffer was destroyed in the meantime and the GstWlBuffer gets destroyed + * as soon as we remove the reference that GstWlDisplay holds. + */ + +#include "wlbuffer.h" + +GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); +#define GST_CAT_DEFAULT gstwayland_debug + +G_DEFINE_TYPE (GstWlBuffer, gst_wl_buffer, G_TYPE_OBJECT); + +static G_DEFINE_QUARK (GstWlBufferQDataQuark, gst_wl_buffer_qdata); + +static void +gst_wl_buffer_dispose (GObject * gobject) +{ + GstWlBuffer *self = GST_WL_BUFFER (gobject); + FUNCTION; + GST_LOG ("GstWlBuffer:%p", self); + GST_TRACE_OBJECT (self, "dispose"); + + /* if the display is shutting down and we are trying to dipose + * the GstWlBuffer from another thread, unregister_buffer() will + * block and in the end the display will increase the refcount + * of this GstWlBuffer, so it will not be finalized */ + if (self->display) + gst_wl_display_unregister_buffer (self->display, self); + + G_OBJECT_CLASS (gst_wl_buffer_parent_class)->dispose (gobject); +} + +static void +gst_wl_buffer_finalize (GObject * gobject) +{ + GstWlBuffer *self = GST_WL_BUFFER (gobject); + int i; + + FUNCTION; + + GST_TRACE_OBJECT (self, "finalize"); +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (self->tsurface) { + GST_LOG ("tbm_surface_destroy (tbm_surface_h@%p)", self->tsurface); + tbm_surface_destroy (self->tsurface); + } +#endif + if (self->wlbuffer) { + GST_INFO ("wl_buffer_destroy (wl_buffer@%p)", self->wlbuffer); + wl_buffer_destroy (self->wlbuffer); + } +#ifdef USE_WL_FLUSH_BUFFER + if (self->display) { + if (self->is_flush_request) { + self->display->flush_tbm_bufmgr = NULL; + if (self->display->flush_buffer) { + for (i = 0; i < self->display->tbm_bo_num; i++) { + if (self->display->flush_buffer->bo[i]) { + GST_LOG ("flush buffer: tbm_bo_unref (bo@%p)", + self->display->flush_buffer->bo[i]); + tbm_bo_unref (self->display->flush_buffer->bo[i]); + self->display->flush_buffer->bo[i] = NULL; + } + } + g_free (self->display->flush_buffer); + self->display->flush_buffer = NULL; + } + } + } +#endif + + G_OBJECT_CLASS (gst_wl_buffer_parent_class)->finalize (gobject); +} + +static void +gst_wl_buffer_class_init (GstWlBufferClass * klass) +{ + GObjectClass *object_class = (GObjectClass *) klass; + FUNCTION; + object_class->dispose = gst_wl_buffer_dispose; + object_class->finalize = gst_wl_buffer_finalize; +} + +static void +gst_wl_buffer_init (GstWlBuffer * self) +{ +} + +static void +buffer_release (void *data, struct wl_buffer *wl_buffer) +{ + GstWlBuffer *self = data; + FUNCTION; + g_return_if_fail (self != NULL); + + GST_INFO_OBJECT (self, + "get event : wl_buffer@%p ::release GstBuffer@%p:: tsurface@%p", + wl_buffer, self->gstbuffer, self->tsurface); + + self->used_by_compositor = FALSE; + +#ifdef USE_WL_FLUSH_BUFFER + /* unref should be last, because it may end up destroying the GstWlBuffer */ + if (!self->is_flush_request) { + /*in case of is_flush_request, gstbuffer ref-count has already decreased. */ + GST_LOG_OBJECT (self, "gstbuffer(%p), ref_count(%d)", self->gstbuffer, + GST_OBJECT_REFCOUNT_VALUE (self->gstbuffer)); + gst_buffer_unref (self->gstbuffer); + if (self->gstbuffer) { + GST_LOG_OBJECT (self, + "buffer is our pool..so is kept by bufferpool :: gstbuffer(%p), ref_count(%d)", + self->gstbuffer, GST_OBJECT_REFCOUNT_VALUE (self->gstbuffer)); + } + } else { + /*we blocked below code at gstbuffer_disposed() */ + /* unref(GstWlBuffer), now gst_wl_buffer_dispose() will be called by below code */ + g_object_unref (self); + } +#else + gst_buffer_unref (self->gstbuffer); +#endif +} + +static const struct wl_buffer_listener buffer_listener = { + buffer_release +}; + +static void +gstbuffer_disposed (GstWlBuffer * self) +{ + FUNCTION; + g_assert (!self->used_by_compositor); + GST_INFO ("GstBuffer: %p", self->gstbuffer); + self->gstbuffer = NULL; + + GST_TRACE_OBJECT (self, "owning GstBuffer was finalized"); + + /* this will normally destroy the GstWlBuffer, unless the display is + * finalizing and it has taken an additional reference to it */ +#ifdef USE_WL_FLUSH_BUFFER + /* in case of normal routine, gstbuffer_disposed() is called by buffer_release() + but in case of is_flush_request, this func() is called when basesink unref gstbuffer. + buffer_release() is not called if we do 'g_object_unref (self)' */ + if (!self->is_flush_request) +#endif + g_object_unref (self); +} + +GstWlBuffer * +gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, struct wl_buffer *wlbuffer, + GstWlDisplay * display) +{ + GstWlBuffer *self; + FUNCTION; + + self = g_object_new (GST_TYPE_WL_BUFFER, NULL); + self->gstbuffer = gstbuffer; + self->wlbuffer = wlbuffer; + self->display = display; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (display->tsurface) + self->tsurface = display->tsurface; + else + self->tsurface = NULL; + GST_LOG ("self->tsurface(%p)", self->tsurface); +#endif +#ifdef USE_WL_FLUSH_BUFFER + self->is_flush_request = FALSE; + if (display->flush_request) + self->is_flush_request = TRUE; +#endif + + gst_wl_display_register_buffer (self->display, self); //register GstWlBuffer + + GST_INFO + ("wl_buffer_add_listener (wl_buffer@%p, wl_buffer_listener@%p, GstWlBuffer@%p)", + self->wlbuffer, &buffer_listener, self); + wl_buffer_add_listener (self->wlbuffer, &buffer_listener, self); +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT //need to contribute to upstream !! + wl_proxy_set_queue ((struct wl_proxy *) self->wlbuffer, self->display->queue); +#endif + /* called gstbuffer_disposed when the gstbuffer is disposed, + or the same gstbuffer is being overwritten by below api */ + gst_mini_object_set_qdata ((GstMiniObject *) gstbuffer, + gst_wl_buffer_qdata_quark (), self, (GDestroyNotify) gstbuffer_disposed); + GST_LOG ("GstWlBuffer (%p)", self); + return self; +} + +GstWlBuffer * +gst_buffer_get_wl_buffer (GstBuffer * gstbuffer) +{ + FUNCTION; + return gst_mini_object_get_qdata ((GstMiniObject *) gstbuffer, + gst_wl_buffer_qdata_quark ()); +} + +void +gst_wl_buffer_force_release_and_unref (GstWlBuffer * self) +{ + FUNCTION; + /* Force a buffer release. + * At this point, the GstWlDisplay has killed its event loop, + * so we don't need to worry about buffer_release() being called + * at the same time from the event loop thread */ + if (self->used_by_compositor) { + GST_DEBUG_OBJECT (self, "forcing wl_buffer::release (GstBuffer: %p)", + self->gstbuffer); + self->used_by_compositor = FALSE; + gst_buffer_unref (self->gstbuffer); + } + + /* Finalize this GstWlBuffer early. + * This method has been called as a result of the display shutting down, + * so we need to stop using any wayland resources and disconnect from + * the display. The GstWlBuffer stays alive, though, to avoid race + * conditions with the GstBuffer being destroyed from another thread. + * The last reference is either owned by the GstBuffer or by us and + * it will be released at the end of this function. */ + GST_TRACE_OBJECT (self, "finalizing early"); + wl_buffer_destroy (self->wlbuffer); + self->wlbuffer = NULL; + self->display = NULL; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + GST_LOG ("self->tsurface(%p)", self->tsurface); + if (self->tsurface) + tbm_surface_destroy (self->tsurface); +#endif + /* remove the reference that the caller (GstWlDisplay) owns */ + g_object_unref (self); +} + +void +gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface) +{ + FUNCTION; + g_return_if_fail (self->used_by_compositor == FALSE); + GST_INFO ("wl_surface_attach (video_surface@%p, wl_buffer@%p, 0, 0)", surface, + self->wlbuffer); + wl_surface_attach (surface, self->wlbuffer, 0, 0); + + /* Add a reference to the buffer. This represents the fact that + * the compositor is using the buffer and it should not return + * back to the pool and be re-used until the compositor releases it. */ +#ifdef USE_WL_FLUSH_BUFFER + /* in case of is_flush_request, we need to copy info and unref gstbuffer + so, we need not to increase ref count. */ + if (!self->is_flush_request) +#endif + gst_buffer_ref (self->gstbuffer); + GST_LOG_OBJECT (self, "gstbuffer(%p), ref_count(%d)", self->gstbuffer, + GST_OBJECT_REFCOUNT_VALUE (self->gstbuffer)); + self->used_by_compositor = TRUE; +} diff --git a/tizenwlsink/src/wlbuffer.h b/tizenwlsink/src/wlbuffer.h new file mode 100644 index 0000000..d9713eb --- /dev/null +++ b/tizenwlsink/src/wlbuffer.h @@ -0,0 +1,69 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __GST_WL_BUFFER_H__ +#define __GST_WL_BUFFER_H__ + +#include "wldisplay.h" + +G_BEGIN_DECLS +#define GST_TYPE_WL_BUFFER (gst_wl_buffer_get_type ()) +#define GST_WL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_BUFFER, GstWlBuffer)) +#define GST_IS_WL_BUFFER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_BUFFER)) +#define GST_WL_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_BUFFER, GstWlBufferClass)) +#define GST_IS_WL_BUFFER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_BUFFER)) +#define GST_WL_BUFFER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_BUFFER, GstWlBufferClass)) +typedef struct _GstWlBuffer GstWlBuffer; +typedef struct _GstWlBufferClass GstWlBufferClass; + +struct _GstWlBuffer +{ + GObject parent_instance; + + struct wl_buffer *wlbuffer; + GstBuffer *gstbuffer; + + GstWlDisplay *display; + + gboolean used_by_compositor; + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + gboolean is_flush_request; + tbm_surface_h tsurface; +#endif +}; + +struct _GstWlBufferClass +{ + GObjectClass parent_class; +}; + +GType gst_wl_buffer_get_type (void); + +GstWlBuffer *gst_buffer_add_wl_buffer (GstBuffer * gstbuffer, + struct wl_buffer *wlbuffer, GstWlDisplay * display); +GstWlBuffer *gst_buffer_get_wl_buffer (GstBuffer * gstbuffer); + +void gst_wl_buffer_force_release_and_unref (GstWlBuffer * self); + +void gst_wl_buffer_attach (GstWlBuffer * self, struct wl_surface *surface); + +G_END_DECLS +#endif /* __GST_WL_BUFFER_H__ */ diff --git a/tizenwlsink/src/wldisplay.c b/tizenwlsink/src/wldisplay.c new file mode 100644 index 0000000..7e9e39e --- /dev/null +++ b/tizenwlsink/src/wldisplay.c @@ -0,0 +1,468 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "wldisplay.h" +#include "wlbuffer.h" + +#include +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +#include +#include +#include +#include +#include + +#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); +} diff --git a/tizenwlsink/src/wldisplay.h b/tizenwlsink/src/wldisplay.h new file mode 100644 index 0000000..c3e4481 --- /dev/null +++ b/tizenwlsink/src/wldisplay.h @@ -0,0 +1,141 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __GST_WL_DISPLAY_H__ +#define __GST_WL_DISPLAY_H__ + +#include +#include +#include "scaler-client-protocol.h" +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +#include +#include +#include +#include +#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 ("") + +#ifdef USE_WL_FLUSH_BUFFER +typedef struct +{ + void *bo[GST_VIDEO_MAX_PLANES]; +} GstWlFlushBuffer; +#endif + +#define TBM_BO_NUM 20 + +struct _GstWlDisplay +{ + GObject parent_instance; + + /* public objects */ + struct wl_display *display; + struct wl_event_queue *queue; + + /* globals */ + struct wl_registry *registry; + struct wl_compositor *compositor; + struct wl_subcompositor *subcompositor; + struct wl_shell *shell; + struct wl_shm *shm; + struct wl_scaler *scaler; + GArray *formats; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + GArray *tbm_formats; +#endif + /* private */ + gboolean own_display; + GThread *thread; + GstPoll *wl_fd_poll; + + GMutex buffers_mutex; + GHashTable *buffers; + gboolean shutting_down; + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + /*video output layer */ + struct tizen_policy *tizen_policy; + struct tizen_video *tizen_video; + + struct wayland_tbm_client *tbm_client; + tbm_bufmgr tbm_bufmgr; + tbm_bo tbm_bo[TBM_BO_NUM]; + gint tbm_bo_idx; + tbm_surface_h tsurface; + gboolean USE_TBM; + +#ifdef USE_WL_FLUSH_BUFFER + GstWlFlushBuffer *flush_buffer; + tbm_bufmgr flush_tbm_bufmgr; + gint flush_request; +#endif + gboolean dump_video; + guint total_dump; + guint dump_count; + + gboolean is_native_format; /*SN12, ST12, SR32, S420 */ + gpointer bo[GST_VIDEO_MAX_PLANES]; + gint plane_size[GST_VIDEO_MAX_PLANES]; + gint stride_width[GST_VIDEO_MAX_PLANES]; + gint stride_height[GST_VIDEO_MAX_PLANES]; + gint width[GST_VIDEO_MAX_PLANES]; + gint height[GST_VIDEO_MAX_PLANES]; + gint native_video_size; + guint wl_surface_id; + gint buffer_width, buffer_height; + gint plane_num; + gint tbm_bo_num; +#endif + +#if 1 + gboolean need_shell_surface; + gboolean use_parent_wl_surface; +#endif +}; + +struct _GstWlDisplayClass +{ + GObjectClass parent_class; +}; + +typedef struct _GstWlDisplay GstWlDisplay; +typedef struct _GstWlDisplayClass GstWlDisplayClass; + +GType gst_wl_display_get_type (void); + +GstWlDisplay *gst_wl_display_new (const gchar * name, GError ** error); +GstWlDisplay *gst_wl_display_new_existing (struct wl_display *display, + gboolean take_ownership, GError ** error); + +/* see wlbuffer.c for explanation */ +void gst_wl_display_register_buffer (GstWlDisplay * self, gpointer buf); +void gst_wl_display_unregister_buffer (GstWlDisplay * self, gpointer buf); + +G_END_DECLS +#endif /* __GST_WL_DISPLAY_H__ */ diff --git a/tizenwlsink/src/wlshmallocator.c b/tizenwlsink/src/wlshmallocator.c new file mode 100644 index 0000000..81e2cfd --- /dev/null +++ b/tizenwlsink/src/wlshmallocator.c @@ -0,0 +1,545 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2012 Intel Corporation + * Copyright (C) 2012 Sreerenj Balachandran + * 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 +#endif +#include +#include +#include +#include +#include +#include +#include + +GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); +#define GST_CAT_DEFAULT gstwayland_debug + +G_DEFINE_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST_TYPE_ALLOCATOR); + +gint +gst_wl_fwrite_data (gchar * file, gpointer data, guint size) +{ + FILE *fp; + + fp = fopen (file, "wb"); + if (fp == NULL) + return -1; + + fwrite ((gchar *) data, sizeof (gchar), size, fp); + fclose (fp); + + return 0; +} + +static void +gst_wl_tbm_dump_normal_raw_video (gpointer bo, guint size, guint dump_count, + guint dump_total) +{ + tbm_bo_handle virtual_addr; + gint ret; + gchar file_name[128]; + gchar err_str[256]; + g_return_if_fail (bo != NULL); + + virtual_addr = tbm_bo_get_handle (bo, TBM_DEVICE_CPU); + if (!virtual_addr.ptr) { + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno); + return; + } + + snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump", + dump_count); + ret = gst_wl_fwrite_data (file_name, virtual_addr.ptr, size); + if (ret) { + GST_ERROR ("_write_rawdata() failed"); + } + +} + +static void +gst_wl_tbm_dump_native_raw_video (GstWlDisplay * display, guint dump_count) +{ + gchar file_name[128]; + gchar err_str[256]; + FILE *fp; + tbm_bo_handle virtual_addr; + gchar *data; + int i; + g_return_if_fail (display != NULL); + + if (dump_count > display->total_dump) { + display->dump_video = FALSE; + return; + } + /* get virtual addr with bo and TBM_DEVICD_CPU */ + virtual_addr = tbm_bo_get_handle (display->bo[0], TBM_DEVICE_CPU); + if (!virtual_addr.ptr) { + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno); + return; + } + + snprintf (file_name, sizeof (file_name), "/tmp/WLSINK_OUT_DUMP_%2.2d.dump", + dump_count); + + fp = fopen (file_name, "wb"); + if (fp == NULL) + return; + data = (gchar *) virtual_addr.ptr; + + /* Y */ + for (i = 0; i < display->height[0]; i++) { + fwrite (data, display->width[0], 1, fp); + data += display->stride_width[0]; + } + + if (display->bo[1] == NULL) { + /* sprd */ + data = (gchar *) virtual_addr.ptr + + (display->stride_width[0] * display->stride_height[0]); + GST_LOG ("UV: virtual_addr.ptr(%p)", data); + } else { + /* omx */ + virtual_addr = tbm_bo_get_handle (display->bo[1], TBM_DEVICE_CPU); + if (!virtual_addr.ptr) { + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR ("get tbm bo handle failed: %s(%d)", err_str, errno); + fclose (fp); + return; + } + data = (gchar *) virtual_addr.ptr; + } + + /* UV */ + for (i = 0; i < display->height[1]; i++) { + fwrite (data, display->width[1], 1, fp); + data += display->stride_width[1]; + } + + fclose (fp); +} + +static GstMemory * +gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, + GstAllocationParams * params) +{ + GstWlShmAllocator *self = GST_WL_SHM_ALLOCATOR (allocator); + char filename[1024]; + static int init = 0; + int fd; + int idx; + gpointer data; + GstWlShmMemory *mem; + gchar err_str[256]; + FUNCTION; + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (self->display->USE_TBM) { + tbm_bo_handle virtual_addr; + + idx = self->display->tbm_bo_idx++; + + self->display->tbm_bufmgr = + wayland_tbm_client_get_bufmgr (self->display->tbm_client); + g_return_val_if_fail (self->display->tbm_bufmgr != NULL, NULL); + + self->display->tbm_bo[idx] = + tbm_bo_alloc (self->display->tbm_bufmgr, size, TBM_BO_DEFAULT); + if (G_UNLIKELY (!self->display->tbm_bo[idx])) { + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR_OBJECT (self, "alloc tbm bo(size:%d) failed: %s(%d)", size, + err_str, errno); + return FALSE; + } + GST_LOG ("display->tbm_bo[%d]=(%p)", idx, self->display->tbm_bo[idx]); + virtual_addr.ptr = NULL; + virtual_addr = + tbm_bo_get_handle (self->display->tbm_bo[idx], TBM_DEVICE_CPU); + if (G_UNLIKELY (!virtual_addr.ptr)) { + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR_OBJECT (self, "get tbm bo handle failed: %s(%d)", err_str, + errno); + tbm_bo_unref (self->display->tbm_bo[idx]); + self->display->tbm_bo[idx] = NULL; + self->display->tbm_bo_idx--; + return FALSE; + } + + mem = g_slice_new0 (GstWlShmMemory); + gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, + NULL, size, 0, 0, size); + mem->data = virtual_addr.ptr; + mem->tbm_bo_ptr = self->display->tbm_bo[idx]; + GST_LOG ("mem(%p) mem->data(%p) virtual_addr.ptr(%p) size(%d)", mem, + mem->data, virtual_addr.ptr, size); + + return (GstMemory *) mem; + + } else { /* USE SHM */ + /* TODO: make use of the allocation params, if necessary */ + + /* allocate shm pool */ + snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (), + "wayland-shm", init++, "XXXXXX"); + GST_LOG ("opening temp file %s", filename); + + fd = g_mkstemp (filename); + if (fd < 0) { + GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename, + strerror (errno)); + return NULL; + } + if (ftruncate (fd, size) < 0) { + GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno)); + close (fd); + return NULL; + } + + data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + GST_ERROR_OBJECT (self, "mmap failed: %s", strerror (errno)); + close (fd); + return NULL; + } + + unlink (filename); + + mem = g_slice_new0 (GstWlShmMemory); + gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, + NULL, size, 0, 0, size); + mem->data = data; + mem->fd = fd; + + return (GstMemory *) mem; + } + +#else /* open source */ + /* TODO: make use of the allocation params, if necessary */ + + /* allocate shm pool */ + snprintf (filename, 1024, "%s/%s-%d-%s", g_get_user_runtime_dir (), + "wayland-shm", init++, "XXXXXX"); + + fd = g_mkstemp (filename); + if (fd < 0) { + GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename, + strerror (errno)); + return NULL; + } + if (ftruncate (fd, size) < 0) { + GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno)); + close (fd); + return NULL; + } + + data = mmap (NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) { + GST_ERROR_OBJECT (self, "mmap failed: %s", strerror (errno)); + close (fd); + return NULL; + } + + unlink (filename); + + mem = g_slice_new0 (GstWlShmMemory); + gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL, + size, 0, 0, size); + mem->data = data; + mem->fd = fd; + + return (GstMemory *) mem; +#endif +} + +static void +gst_wl_shm_allocator_free (GstAllocator * allocator, GstMemory * memory) +{ + GstWlShmMemory *shm_mem = (GstWlShmMemory *) memory; + FUNCTION; + GST_LOG ("shm_mem->fd(%d)", shm_mem->fd); + if (shm_mem->fd != -1) + close (shm_mem->fd); + munmap (shm_mem->data, memory->maxsize); + + g_slice_free (GstWlShmMemory, shm_mem); +} + +static gpointer +gst_wl_shm_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) +{ + FUNCTION; + return ((GstWlShmMemory *) mem)->data; +} + +static void +gst_wl_shm_mem_unmap (GstMemory * mem) +{ +} + +static void +gst_wl_shm_allocator_class_init (GstWlShmAllocatorClass * klass) +{ + GstAllocatorClass *alloc_class = (GstAllocatorClass *) klass; + FUNCTION; + + alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_alloc); + alloc_class->free = GST_DEBUG_FUNCPTR (gst_wl_shm_allocator_free); +} + +static void +gst_wl_shm_allocator_init (GstWlShmAllocator * self) +{ + FUNCTION; + self->parent_instance.mem_type = GST_ALLOCATOR_WL_SHM; + self->parent_instance.mem_map = gst_wl_shm_mem_map; + self->parent_instance.mem_unmap = gst_wl_shm_mem_unmap; + + GST_OBJECT_FLAG_SET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); +} + +void +gst_wl_shm_allocator_register (void) +{ + FUNCTION; + gst_allocator_register (GST_ALLOCATOR_WL_SHM, + g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL)); +} + +GstAllocator * +gst_wl_shm_allocator_get (void) +{ + FUNCTION; + return gst_allocator_find (GST_ALLOCATOR_WL_SHM); +} + +gboolean +gst_is_wl_shm_memory (GstMemory * mem) +{ + FUNCTION; + return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM); +} + +gboolean +gst_is_wl_memory (GstMemory * mem) +{ + FUNCTION; + return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM); +} + +struct wl_buffer * +gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, + const GstVideoInfo * info) +{ + GstWlShmMemory *shm_mem = (GstWlShmMemory *) mem; + gint width, height, stride; + gsize size; + gint plane_size[GST_VIDEO_MAX_PLANES], n_planes, i; + enum wl_shm_format format; + struct wl_shm_pool *wl_pool; + struct wl_buffer *wbuffer; + FUNCTION; + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (display->USE_TBM) { + tbm_surface_info_s ts_info; + int offset[GST_VIDEO_MAX_PLANES]; + + if (display->is_native_format == TRUE) { + /* In case of native format, use MMVideoBuffer data instead of GstVideoInfo */ + if (display->dump_video) + gst_wl_tbm_dump_native_raw_video (display, display->dump_count++); + + width = display->width[0]; + height = display->height[0]; + format = gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (info)); + ts_info.width = width; + ts_info.height = height; + ts_info.format = format; + ts_info.bpp = tbm_surface_internal_get_bpp (ts_info.format); + ts_info.num_planes = tbm_surface_internal_get_num_planes (ts_info.format); + + for (i = 0; i < display->plane_num; i++) { + ts_info.planes[i].size = display->plane_size[i]; + ts_info.planes[i].stride = display->stride_width[i]; + offset[i] = display->stride_width[i] * display->stride_height[i]; + } + + if (display->tbm_bo_num == 1) { + ts_info.planes[0].offset = 0; + ts_info.planes[1].offset = offset[0]; + if (display->plane_num == 3) + ts_info.planes[2].offset = offset[0] + offset[1]; + } else if (display->tbm_bo_num == 2) { + ts_info.planes[0].offset = 0; + ts_info.planes[1].offset = 0; + if (display->plane_num == 3) + ts_info.planes[2].offset = offset[1]; + } else if (display->tbm_bo_num == 3) { + ts_info.planes[0].offset = 0; + ts_info.planes[1].offset = 0; + ts_info.planes[2].offset = 0; + } + + GST_LOG + ("set tbm_surface_info_s: width(%d) height(%d) format(%s) bpp(%d) num_planes(%d)", + ts_info.width, ts_info.height, gst_wl_tbm_format_to_string (format), + ts_info.bpp, ts_info.num_planes); + GST_LOG + ("set tbm_surface_info_s: planse[0].stride(%d) planes[1].stride(%d) planes[2].stride(%d) planes[0].offset(%d) planes[1].offset(%d) planes[2].offset(%d)", + ts_info.planes[0].stride, ts_info.planes[1].stride, + ts_info.planes[2].stride, ts_info.planes[0].offset, + ts_info.planes[1].offset, ts_info.planes[2].offset); + + display->tsurface = + tbm_surface_internal_create_with_bos (&ts_info, + (tbm_bo *) display->bo, display->tbm_bo_num); + GST_LOG ("create tbm surface(%p)", display->tsurface); + wbuffer = + wayland_tbm_client_create_buffer (display->tbm_client, + display->tsurface); + } else { + + width = GST_VIDEO_INFO_WIDTH (info); + height = GST_VIDEO_INFO_HEIGHT (info); + stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0); + size = GST_VIDEO_INFO_SIZE (info); + + format = gst_video_format_to_wl_tbm_format (GST_VIDEO_INFO_FORMAT (info)); + g_return_val_if_fail (gst_is_wl_memory (mem), NULL); + g_return_val_if_fail (size <= mem->size, NULL); + g_return_val_if_fail (shm_mem->fd != -1, NULL); + + GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %" + G_GSSIZE_FORMAT " (%d x %d, stride %d)", size, width, height, stride); + + if (display->dump_video) { + gst_wl_tbm_dump_normal_raw_video (shm_mem->tbm_bo_ptr, size, + display->dump_count++, display->total_dump); + if (display->dump_count > display->total_dump) + display->dump_video = FALSE; + } + + n_planes = GST_VIDEO_INFO_N_PLANES (info); + switch (n_planes) { + case 1: + plane_size[0] = info->size; + break; + case 2: + plane_size[0] = GST_VIDEO_INFO_PLANE_OFFSET (info, 1); + plane_size[1] = info->size - plane_size[0]; + break; + case 3: + plane_size[0] = GST_VIDEO_INFO_PLANE_OFFSET (info, 1); + plane_size[1] = GST_VIDEO_INFO_PLANE_OFFSET (info, 2) - plane_size[0]; + plane_size[2] = info->size - GST_VIDEO_INFO_PLANE_OFFSET (info, 2); + break; + case 4: + plane_size[0] = GST_VIDEO_INFO_PLANE_OFFSET (info, 1); + plane_size[1] = GST_VIDEO_INFO_PLANE_OFFSET (info, 2) - plane_size[0]; + plane_size[2] = GST_VIDEO_INFO_PLANE_OFFSET (info, 3) + - GST_VIDEO_INFO_PLANE_OFFSET (info, 2); + plane_size[3] = info->size - GST_VIDEO_INFO_PLANE_OFFSET (info, 3); + break; + + default: + break; + } + + ts_info.width = width; + ts_info.height = height; + ts_info.format = format; + ts_info.bpp = tbm_surface_internal_get_bpp (ts_info.format); + ts_info.num_planes = tbm_surface_internal_get_num_planes (ts_info.format); + + for (i = 0; i < n_planes; i++) { + ts_info.planes[i].stride = GST_VIDEO_INFO_PLANE_STRIDE (info, i); + ts_info.planes[i].offset = GST_VIDEO_INFO_PLANE_OFFSET (info, i); + ts_info.planes[i].size = plane_size[i]; + } + + GST_LOG ("tbm_bo (%p)", shm_mem->tbm_bo_ptr); + + display->tsurface = + tbm_surface_internal_create_with_bos (&ts_info, + (tbm_bo *) & shm_mem->tbm_bo_ptr, 1); + wbuffer = + wayland_tbm_client_create_buffer (display->tbm_client, + display->tsurface); + } + GST_LOG ("create wbuffer(%p)", wbuffer); + + } else { /* USE SHM */ + width = GST_VIDEO_INFO_WIDTH (info); + height = GST_VIDEO_INFO_HEIGHT (info); + stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0); + size = GST_VIDEO_INFO_SIZE (info); + format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info)); + g_return_val_if_fail (gst_is_wl_memory (mem), NULL); + g_return_val_if_fail (size <= mem->size, NULL); + g_return_val_if_fail (shm_mem->fd != -1, NULL); + + GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %" + G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height, + stride, gst_wl_shm_format_to_string (format)); + + wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size); + wbuffer = + wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride, format); + + wl_shm_pool_destroy (wl_pool); + } + display->buffer_width = width; + display->buffer_height = height; + GST_LOG ("buffer_width(%d) buffer_height(%d)", display->buffer_width, + display->buffer_height); + return wbuffer; + +#else /* open source */ + width = GST_VIDEO_INFO_WIDTH (info); + height = GST_VIDEO_INFO_HEIGHT (info); + stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0); + size = GST_VIDEO_INFO_SIZE (info); + format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info)); + g_return_val_if_fail (gst_is_wl_shm_memory (mem), NULL); + g_return_val_if_fail (size <= mem->size, NULL); + g_return_val_if_fail (shm_mem->fd != -1, NULL); + + GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %" + G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height, + stride, gst_wl_shm_format_to_string (format)); + + wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size); + wbuffer = wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride, + format); + + close (shm_mem->fd); + shm_mem->fd = -1; + wl_shm_pool_destroy (wl_pool); + + return wbuffer; +#endif +} diff --git a/tizenwlsink/src/wlshmallocator.h b/tizenwlsink/src/wlshmallocator.h new file mode 100644 index 0000000..9f111d3 --- /dev/null +++ b/tizenwlsink/src/wlshmallocator.h @@ -0,0 +1,79 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2012 Intel Corporation + * Copyright (C) 2012 Sreerenj Balachandran + * 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 +#include "wldisplay.h" + +G_BEGIN_DECLS +#define GST_TYPE_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get_type ()) +#define GST_WL_SHM_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocator)) +#define GST_IS_WL_SHM_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_SHM_ALLOCATOR)) +#define GST_WL_SHM_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass)) +#define GST_IS_WL_SHM_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_SHM_ALLOCATOR)) +#define GST_WL_SHM_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass)) +#define GST_ALLOCATOR_WL_SHM "wl_shm" +typedef struct _GstWlShmMemory GstWlShmMemory; +typedef struct _GstWlShmAllocator GstWlShmAllocator; +typedef struct _GstWlShmAllocatorClass GstWlShmAllocatorClass; + +struct _GstWlShmMemory +{ + GstMemory parent; + + gpointer data; + gint fd; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + gpointer tbm_bo_ptr; +#endif +}; + +struct _GstWlShmAllocator +{ + GstAllocator parent_instance; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + GstWlDisplay *display; +#endif +}; + +struct _GstWlShmAllocatorClass +{ + GstAllocatorClass parent_class; +}; + +GType gst_wl_shm_allocator_get_type (void); + +void gst_wl_shm_allocator_register (void); +GstAllocator *gst_wl_shm_allocator_get (void); + +gboolean gst_is_wl_shm_memory (GstMemory * mem); +struct wl_buffer *gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, + GstWlDisplay * display, const GstVideoInfo * info); + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +gint gst_wl_fwrite_data (gchar * file, gpointer data, guint size); +gboolean gst_is_wl_memory (GstMemory * mem); +#endif +G_END_DECLS +#endif /* __GST_WL_SHM_ALLOCATOR_H__ */ diff --git a/tizenwlsink/src/wlvideoformat.c b/tizenwlsink/src/wlvideoformat.c new file mode 100644 index 0000000..59e9c95 --- /dev/null +++ b/tizenwlsink/src/wlvideoformat.c @@ -0,0 +1,113 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Sreerenj Balachandran + * Copyright (C) 2012 Wim Taymans + * 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 +#endif + +#include "wlvideoformat.h" + +GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); +#define GST_CAT_DEFAULT gstwayland_debug +#define FUNCTION GST_LOG ("") +typedef struct +{ + enum wl_shm_format wl_format; + GstVideoFormat gst_format; +} wl_VideoFormat; + +static const wl_VideoFormat formats[] = { +#if G_BYTE_ORDER == G_BIG_ENDIAN + {WL_SHM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_xRGB}, + {WL_SHM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_ARGB}, + {WL_SHM_FORMAT_XBGR8888, GST_VIDEO_FORMAT_xBGR}, + {WL_SHM_FORMAT_RGBX8888, GST_VIDEO_FORMAT_RGBx}, + {WL_SHM_FORMAT_BGRX8888, GST_VIDEO_FORMAT_BGRx}, + {WL_SHM_FORMAT_ABGR8888, GST_VIDEO_FORMAT_ABGR}, + {WL_SHM_FORMAT_RGBA8888, GST_VIDEO_FORMAT_RGBA}, + {WL_SHM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_BGRA}, +#else + {WL_SHM_FORMAT_XRGB8888, GST_VIDEO_FORMAT_BGRx}, + {WL_SHM_FORMAT_ARGB8888, GST_VIDEO_FORMAT_BGRA}, + {WL_SHM_FORMAT_XBGR8888, GST_VIDEO_FORMAT_RGBx}, + {WL_SHM_FORMAT_RGBX8888, GST_VIDEO_FORMAT_xBGR}, + {WL_SHM_FORMAT_BGRX8888, GST_VIDEO_FORMAT_xRGB}, + {WL_SHM_FORMAT_ABGR8888, GST_VIDEO_FORMAT_RGBA}, + {WL_SHM_FORMAT_RGBA8888, GST_VIDEO_FORMAT_ABGR}, + {WL_SHM_FORMAT_BGRA8888, GST_VIDEO_FORMAT_ARGB}, +#endif + {WL_SHM_FORMAT_RGB888, GST_VIDEO_FORMAT_RGB}, + {WL_SHM_FORMAT_BGR888, GST_VIDEO_FORMAT_BGR}, + {WL_SHM_FORMAT_RGB565, GST_VIDEO_FORMAT_RGB16}, + {WL_SHM_FORMAT_BGR565, GST_VIDEO_FORMAT_BGR16}, + + {WL_SHM_FORMAT_YUYV, GST_VIDEO_FORMAT_YUY2}, + {WL_SHM_FORMAT_YVYU, GST_VIDEO_FORMAT_YVYU}, + {WL_SHM_FORMAT_UYVY, GST_VIDEO_FORMAT_UYVY}, + {WL_SHM_FORMAT_AYUV, GST_VIDEO_FORMAT_AYUV}, + {WL_SHM_FORMAT_NV12, GST_VIDEO_FORMAT_NV12}, + {WL_SHM_FORMAT_NV21, GST_VIDEO_FORMAT_NV21}, + {WL_SHM_FORMAT_NV16, GST_VIDEO_FORMAT_NV16}, + {WL_SHM_FORMAT_YUV410, GST_VIDEO_FORMAT_YUV9}, + {WL_SHM_FORMAT_YVU410, GST_VIDEO_FORMAT_YVU9}, + {WL_SHM_FORMAT_YUV411, GST_VIDEO_FORMAT_Y41B}, + {WL_SHM_FORMAT_YUV420, GST_VIDEO_FORMAT_I420}, + {WL_SHM_FORMAT_YVU420, GST_VIDEO_FORMAT_YV12}, + {WL_SHM_FORMAT_YUV422, GST_VIDEO_FORMAT_Y42B}, + {WL_SHM_FORMAT_YUV444, GST_VIDEO_FORMAT_v308}, +}; + +enum wl_shm_format +gst_video_format_to_wl_shm_format (GstVideoFormat format) +{ + guint i; + FUNCTION; + + for (i = 0; i < G_N_ELEMENTS (formats); i++) + if (formats[i].gst_format == format) + return formats[i].wl_format; + + GST_WARNING ("wayland shm video format not found"); + return -1; +} + +GstVideoFormat +gst_wl_shm_format_to_video_format (enum wl_shm_format wl_format) +{ + guint i; + FUNCTION; + + for (i = 0; i < G_N_ELEMENTS (formats); i++) + if (formats[i].wl_format == wl_format) + return formats[i].gst_format; + + GST_WARNING ("gst video format not found"); + return GST_VIDEO_FORMAT_UNKNOWN; +} + +const gchar * +gst_wl_shm_format_to_string (enum wl_shm_format wl_format) +{ + FUNCTION; + return gst_video_format_to_string + (gst_wl_shm_format_to_video_format (wl_format)); +} diff --git a/tizenwlsink/src/wlvideoformat.h b/tizenwlsink/src/wlvideoformat.h new file mode 100644 index 0000000..7377cd1 --- /dev/null +++ b/tizenwlsink/src/wlvideoformat.h @@ -0,0 +1,37 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Sreerenj Balachandran + * Copyright (C) 2012 Wim Taymans + * 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 +#include + +G_BEGIN_DECLS + enum wl_shm_format gst_video_format_to_wl_shm_format (GstVideoFormat + format); +GstVideoFormat gst_wl_shm_format_to_video_format (enum wl_shm_format wl_format); + +const gchar *gst_wl_shm_format_to_string (enum wl_shm_format wl_format); + +G_END_DECLS +#endif diff --git a/tizenwlsink/src/wlwindow.c b/tizenwlsink/src/wlwindow.c new file mode 100644 index 0000000..c8d8366 --- /dev/null +++ b/tizenwlsink/src/wlwindow.c @@ -0,0 +1,1103 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2011 Intel Corporation + * Copyright (C) 2011 Sreerenj Balachandran + * 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 +#endif +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +#include "gstwaylandsink.h" +#else +#include "wlwindow.h" +#endif +#include "wlshmallocator.h" +#include "wlbuffer.h" + +GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); +#define GST_CAT_DEFAULT gstwayland_debug + +G_DEFINE_TYPE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT); + +static void gst_wl_window_finalize (GObject * gobject); + +static void +handle_ping (void *data, struct wl_shell_surface *shell_surface, + uint32_t serial) +{ + wl_shell_surface_pong (shell_surface, serial); +} + +static void +handle_configure (void *data, struct wl_shell_surface *shell_surface, + uint32_t edges, int32_t width, int32_t height) +{ +} + +static void +handle_popup_done (void *data, struct wl_shell_surface *shell_surface) +{ +} + +static const struct wl_shell_surface_listener shell_surface_listener = { + handle_ping, + handle_configure, + handle_popup_done +}; + +static void +gst_wl_window_class_init (GstWlWindowClass * klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + FUNCTION; + gobject_class->finalize = gst_wl_window_finalize; +} + +static void +gst_wl_window_init (GstWlWindow * self) +{ + g_return_if_fail (self != NULL); + self->buffer_width = self->buffer_height = 0; + self->buffer_x = self->buffer_y = 0; + self->roi.x = self->roi.y = self->roi.w = self->roi.h = 0; + self->flip.changed = FALSE; +} + +static void +gst_wl_window_finalize (GObject * gobject) +{ + GstWlWindow *self = GST_WL_WINDOW (gobject); + FUNCTION; + + if (self->shell_surface) { + wl_shell_surface_destroy (self->shell_surface); + } +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (self->video_object) + tizen_video_object_destroy (self->video_object); + if (self->tizen_area_viewport) + tizen_viewport_destroy (self->tizen_area_viewport); + if (self->tizen_video_viewport) + tizen_viewport_destroy (self->tizen_video_viewport); + if (self->tizen_video_dest_mode) + tizen_destination_mode_destroy (self->tizen_video_dest_mode); + if (self->tizen_area_dest_mode) + tizen_destination_mode_destroy (self->tizen_area_dest_mode); +#else + wl_viewport_destroy (self->video_viewport); + wl_viewport_destroy (self->area_viewport); +#endif + wl_subsurface_destroy (self->video_subsurface); + wl_surface_destroy (self->video_surface); + + if (self->area_subsurface) { + wl_subsurface_destroy (self->area_subsurface); + } + + wl_surface_destroy (self->area_surface); + g_clear_object (&self->display); + + G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject); +} + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +static void +gst_wl_window_map_sub_surface (GstWlDisplay * display, GstWlWindow * window, + GstVideoInfo * info) +{ + /* A sub-surface becomes mapped, when a non-NULL wl_buffer is applied + * and the parent surface is mapped */ + GstBuffer *buf; + GstMapInfo mapinfo; + struct wl_buffer *wlbuf; + GstWlBuffer *gwlbuf; + GstWlShmAllocator *self = NULL; + FUNCTION; + + g_return_if_fail (display != NULL); + g_return_if_fail (window != NULL); + g_return_if_fail (info != NULL); + + self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ()); + self->display = display; + + buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info->size, NULL); + gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE); + *((guint32 *) mapinfo.data) = 0; /* paint it black */ + gst_buffer_unmap (buf, &mapinfo); + wlbuf = + gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0), + display, info); + + gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, display); + gst_wl_buffer_attach (gwlbuf, window->area_surface); + + /* for tizen view port + When change area_surface, we don't need to commit anymore if we do below code. + such as gst_wl_window_set_render_rectangle() and */ + GST_INFO + ("wl_surface_damage_buffer (area_surface(wl_surface)@%p, x@%d, y@%d, w@%d, h@%d)", + window->area_surface, 0, 0, info->width, info->height); + wl_surface_damage_buffer (window->area_surface, 0, 0, info->width, + info->height); + GST_INFO ("wl_surface_commit (area_surface(wl_surface)@%p)", + window->area_surface); + wl_surface_commit (window->area_surface); + + /* at this point, the GstWlBuffer keeps the buffer + * alive and will free it on wl_buffer::release */ + gst_buffer_unref (buf); +} +#endif + +static GstWlWindow * +#if 1 +/* for enlightment, we need to get parent to create area_subsurface */ +gst_wl_window_new_internal (GstWlDisplay * display, struct wl_surface *parent) +#else +gst_wl_window_new_internal (GstWlDisplay * display) +#endif +{ + GstWlWindow *window; + GstVideoInfo info; +#ifndef TIZEN_FEATURE_WLSINK_ENHANCEMENT + GstBuffer *buf; + GstMapInfo mapinfo; + struct wl_buffer *wlbuf; + GstWlBuffer *gwlbuf; +#endif + struct wl_region *region; + FUNCTION; + + window = g_object_new (GST_TYPE_WL_WINDOW, NULL); + window->display = g_object_ref (display); + + window->area_surface = wl_compositor_create_surface (display->compositor); + GST_INFO + ("area_surface(wl_surface)@%p = wl_compositor_create_surface(wl_compositor@%p)", + window->area_surface, display->compositor); + window->video_surface = wl_compositor_create_surface (display->compositor); + GST_INFO + ("video_surface(wl_surface)@%p = wl_compositor_create_surface(wl_compositor@%p)", + window->video_surface, display->compositor); + + GST_INFO ("wl_proxy_set_queue (area_surface@%p, wl_event_queue@%p)", + window->area_surface, display->queue); + wl_proxy_set_queue ((struct wl_proxy *) window->area_surface, display->queue); + GST_INFO ("wl_proxy_set_queue (video_surface@%p, wl_event_queue@%p)", + window->video_surface, display->queue); + wl_proxy_set_queue ((struct wl_proxy *) window->video_surface, + display->queue); + +#if 1 /* create shell_surface here for enlightenment */ + /* go toplevel */ + if (display->need_shell_surface) { + /* for internal window */ + GST_INFO + ("wl_shell_surface@%p = wl_shell_get_shell_surface (wl_shell@%p, area_subsurface(wl_surface)@%p)", + window->shell_surface, display->shell, window->area_surface); + window->shell_surface = + wl_shell_get_shell_surface (display->shell, window->area_surface); + } else if (display->use_parent_wl_surface) { +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (display->wl_surface_id && parent == NULL) { + window->area_subsurface = + tizen_policy_get_subsurface (display->tizen_policy, + window->area_surface, display->wl_surface_id); + GST_INFO + ("area_subsurface(wl_subsurface)@%p = tizen_policy_get_subsurface(tizen_policy@%p, area_surface(wl_surface)@%p, wl_surface_id@%d)", + window->area_subsurface, display->tizen_policy, window->area_surface, + display->wl_surface_id); + GST_INFO ("wl_subsurface_set_desync (area_subsurface(wl_subsurface)@%p)", + window->area_subsurface); + wl_subsurface_set_desync (window->area_subsurface); + GST_INFO ("wl_surface_commit (%p)", window->area_surface); + wl_surface_commit (window->area_surface); + } else { + GST_INFO (" wl_surface parent %p", parent); + window->area_subsurface = + wl_subcompositor_get_subsurface (display->subcompositor, + window->area_surface, parent); + GST_INFO + ("area_subsurface(wl_subsurface)@%p = wl_subcompositor_get_subsurface(wl_subcompositor@%p, area_surface(wl_surface)@%p, parent@%p)", + window->area_subsurface, display->subcompositor, window->area_surface, + parent); + GST_INFO ("wl_subsurface_set_desync (area_subsurface(wl_subsurface)@%p)", + window->area_subsurface); + wl_subsurface_set_desync (window->area_subsurface); + } +#else + /*for enlightment , below code is moved */ + window->area_subsurface = + wl_subcompositor_get_subsurface (display->subcompositor, + window->area_surface, parent); + wl_subsurface_set_desync (window->area_subsurface); +#endif + } +#endif + + /* embed video_surface in area_surface */ + window->video_subsurface = + wl_subcompositor_get_subsurface (display->subcompositor, + window->video_surface, window->area_surface); + GST_INFO + ("video_subsurface(wl_subsurface)@%p = wl_subcompositor_get_subsurface(wl_subcompositor@%p, video_surface(wl_surface)@%p, area_surface(wl_surface)@%p)", + window->video_subsurface, display->subcompositor, window->video_surface, + window->area_surface); + + GST_INFO ("wl_subsurface_set_desync (video_subsurface(wl_subsurface)@%p)", + window->video_subsurface); + wl_subsurface_set_desync (window->video_subsurface); + GST_INFO ("wl_surface_commit (%p)", window->video_surface); + wl_surface_commit (window->video_surface); + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + window->tizen_area_viewport = + tizen_video_get_viewport (display->tizen_video, window->area_surface); + GST_INFO + ("tizen_area_viewport(tizen_viewport)@%p = tizen_video_get_viewport(tizen_video@%p, area_surface(wl_surface)@%p)", + window->tizen_area_viewport, display->tizen_video, window->area_surface); + window->tizen_video_viewport = + tizen_video_get_viewport (display->tizen_video, window->video_surface); + GST_INFO + ("tizen_video_viewport(tizen_viewport)@%p = tizen_video_get_viewport(tizen_video@%p, video_surface(wl_surface)@%p)", + window->tizen_video_viewport, display->tizen_video, + window->video_surface); + window->tizen_video_dest_mode = + tizen_viewport_get_destination_mode (window->tizen_video_viewport); + GST_INFO + ("tizen_video_dest_mode(tizen_destination_mode)@%p = tizen_viewport_get_destination_mode (tizen_video_viewport@%p)", + window->tizen_video_dest_mode, window->tizen_video_viewport); + /* video surface always follow area surface by below code. */ + GST_INFO ("tizen_viewport_follow_parent_transform(tizen_video_viewport@%p)", + window->tizen_video_viewport); + tizen_viewport_follow_parent_transform (window->tizen_video_viewport); + +#else + window->area_viewport = wl_scaler_get_viewport (display->scaler, + window->area_surface); + window->video_viewport = wl_scaler_get_viewport (display->scaler, + window->video_surface); +#endif + /* draw the area_subsurface */ + gst_video_info_set_format (&info, + /* we want WL_SHM_FORMAT_XRGB8888 */ +#if G_BYTE_ORDER == G_BIG_ENDIAN + GST_VIDEO_FORMAT_xRGB, +#else + GST_VIDEO_FORMAT_BGRx, +#endif + 1, 1); + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (window->display->USE_TBM) { + /* Inform enlightenment of surface which render video */ + /* tizen_video(tbm) render on video_surface */ + window->video_object = + tizen_video_get_object (display->tizen_video, window->video_surface); + + /* to use shm memory for mapping sub-surface, set FALSE to USE_TBM */ + window->display->USE_TBM = FALSE; + gst_wl_window_map_sub_surface (display, window, &info); + /*restore USE_TBM */ + window->display->USE_TBM = TRUE; + } else { + gst_wl_window_map_sub_surface (display, window, &info); + } +#else /* open source */ + buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info.size, NULL); + gst_buffer_map (buf, &mapinfo, GST_MAP_WRITE); + *((guint32 *) mapinfo.data) = 0; /* paint it black */ + gst_buffer_unmap (buf, &mapinfo); + wlbuf = + gst_wl_shm_memory_construct_wl_buffer (gst_buffer_peek_memory (buf, 0), + display, &info); + gwlbuf = gst_buffer_add_wl_buffer (buf, wlbuf, display); + gst_wl_buffer_attach (gwlbuf, window->area_surface); + + /* at this point, the GstWlBuffer keeps the buffer + * alive and will free it on wl_buffer::release */ + gst_buffer_unref (buf); +#endif + + /* do not accept input */ + region = wl_compositor_create_region (display->compositor); + GST_INFO ("wl_region@%p = wl_compositor_create_region (wl_compositor@%p)", + region, display->compositor); + GST_INFO ("wl_surface_set_input_region (area_surface@%p, wl_region@%p)", + window->area_surface, region); + wl_surface_set_input_region (window->area_surface, region); + GST_INFO ("wl_region_destroy (wl_region@%p)", region); + wl_region_destroy (region); + + region = wl_compositor_create_region (display->compositor); + GST_INFO ("wl_region@%p = wl_compositor_create_region (wl_compositor@%p)", + region, display->compositor); + GST_INFO ("wl_surface_set_input_region (video_surface@%p, wl_region@%p)", + window->video_surface, region); + wl_surface_set_input_region (window->video_surface, region); + GST_INFO ("wl_region_destroy (wl_region@%p)", region); + wl_region_destroy (region); + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + /* set area surface size by full mode(full size of parent window) , toplevel is set to fullmode too for convenient test */ + if (window->tizen_area_viewport) { + int tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_FULL; + + window->tizen_area_dest_mode = + tizen_viewport_get_destination_mode (window->tizen_area_viewport); + GST_INFO + ("tizen_area_dest_mode(tizen_destination_mode)@%p = tizen_viewport_get_destination_mode (tizen_area_viewport@%p)", + window->tizen_area_dest_mode, window->tizen_area_viewport); + if (window->tizen_area_dest_mode) { + GST_INFO + ("tizen_destination_mode_set (tizen_destination_mode@%p, @%d, 3 is FULL)", + window->tizen_area_dest_mode, tizen_disp_mode); + tizen_destination_mode_set (window->tizen_area_dest_mode, + tizen_disp_mode); + } + GST_INFO ("wl_surface_commit (area_surface@%p)", window->area_surface); + wl_surface_commit (window->area_surface); + } +#endif + return window; +} + +GstWlWindow * +gst_wl_window_new_toplevel (GstWlDisplay * display, const GstVideoInfo * info) +{ +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + GstWlWindow *window; + FUNCTION; + +/* not create shell_surface here for enlightenment */ + display->need_shell_surface = TRUE; + window = gst_wl_window_new_internal (display, NULL); + + /* for tizen enlightenment */ +#if 0 + /* go toplevel */ + window->shell_surface = wl_shell_get_shell_surface (display->shell, + window->area_surface); +#endif + if (window->shell_surface) { + GST_INFO + ("wl_shell_surface_add_listener (shell_surface@%p, wl_shell_surface_listener@%p, GstWlWindow@%p", + window->shell_surface, &shell_surface_listener, window); + wl_shell_surface_add_listener (window->shell_surface, + &shell_surface_listener, window); + GST_INFO ("wl_shell_surface_set_toplevel (shell_surface@%p", + window->shell_surface); + wl_shell_surface_set_toplevel (window->shell_surface); + } else { + GST_ERROR ("Unable to get wl_shell_surface"); + + g_object_unref (window); + return NULL; + } + + /* toplevel is set to fullmode for convenient test in tizen_viewport enviroment, don't use below code */ +#if 0 + /* set the initial size to be the same as the reported video size */ + width = + gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); + gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height); +#endif + return window; + +#else /* open source */ + GstWlWindow *window; + gint width; + + window = gst_wl_window_new_internal (display); + + /* go toplevel */ + window->shell_surface = wl_shell_get_shell_surface (display->shell, + window->area_surface); + + if (window->shell_surface) { + wl_shell_surface_add_listener (window->shell_surface, + &shell_surface_listener, window); + wl_shell_surface_set_toplevel (window->shell_surface); + } else { + GST_ERROR ("Unable to get wl_shell_surface"); + + g_object_unref (window); + return NULL; + } + + /* set the initial size to be the same as the reported video size */ + width = + gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); + gst_wl_window_set_render_rectangle (window, 0, 0, width, info->height); + + return window; +#endif +} + + +GstWlWindow * +gst_wl_window_new_in_surface (GstWlDisplay * display, + struct wl_surface * parent) +{ +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + /* use App window */ + GstWlWindow *window; + FUNCTION; + + display->use_parent_wl_surface = TRUE; + if (parent) { + /*use wl_surface */ + window = gst_wl_window_new_internal (display, parent); + } else { + /* use wl_surface id */ + window = gst_wl_window_new_internal (display, NULL); + } + + /*Area surface from App need to be under parent surface */ + if (display->tizen_policy) { + GST_INFO + ("tizen_policy_place_subsurface_below_parent (tizen_policy@%p, area_subsurface@%p)", + display->tizen_policy, window->area_subsurface); + tizen_policy_place_subsurface_below_parent (display->tizen_policy, + window->area_subsurface); + GST_INFO + ("tizen_policy_place_subsurface_below_parent (tizen_policy@%p, video_subsurface@%p)", + display->tizen_policy, window->video_subsurface); + tizen_policy_place_subsurface_below_parent (display->tizen_policy, + window->video_subsurface); + } + return window; + +#else /* open source */ + + GstWlWindow *window; + window = gst_wl_window_new_internal (display, parent); //add parent for enlightment + + /*for enlightment , move to gst_wl_window_new_internal() */ +#if 0 + /* embed in parent */ + window->area_subsurface = + wl_subcompositor_get_subsurface (display->subcompositor, + window->area_surface, parent); + wl_subsurface_set_desync (window->area_subsurface); +#endif + + return window; + +#endif +} + +GstWlDisplay * +gst_wl_window_get_display (GstWlWindow * window) +{ + FUNCTION; + g_return_val_if_fail (window != NULL, NULL); + + return g_object_ref (window->display); +} + +struct wl_surface * +gst_wl_window_get_wl_surface (GstWlWindow * window) +{ + FUNCTION; + g_return_val_if_fail (window != NULL, NULL); + + return window->video_surface; +} + +gboolean +gst_wl_window_is_toplevel (GstWlWindow * window) +{ + FUNCTION; + g_return_val_if_fail (window != NULL, FALSE); + + return (window->shell_surface != NULL); +} + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +static gint +gst_wl_window_find_rotate_transform (guint rotate_angle) +{ + gint transform = WL_OUTPUT_TRANSFORM_NORMAL; + FUNCTION; + + GST_DEBUG ("rotate (%d)", rotate_angle); + switch (rotate_angle) { + case DEGREE_0: + transform = WL_OUTPUT_TRANSFORM_NORMAL; + break; + case DEGREE_90: + transform = WL_OUTPUT_TRANSFORM_90; + break; + case DEGREE_180: + transform = WL_OUTPUT_TRANSFORM_180; + break; + case DEGREE_270: + transform = WL_OUTPUT_TRANSFORM_270; + break; + } + return transform; +} + +static gint +gst_wl_window_find_flip_transform (guint flip) +{ + gint transform = WL_OUTPUT_TRANSFORM_NORMAL; + FUNCTION; + + GST_DEBUG ("flip (%d)", flip); + switch (flip) { + case FLIP_NONE: + transform = WL_OUTPUT_TRANSFORM_NORMAL; + break; + case FLIP_HORIZONTAL: + transform = WL_OUTPUT_TRANSFORM_FLIPPED; + break; + case FLIP_VERTICAL: + transform = WL_OUTPUT_TRANSFORM_FLIPPED_180; + break; + case FLIP_BOTH: + transform = WL_OUTPUT_TRANSFORM_180; + break; + } + return transform; + +} + +#endif +#if TIZEN_FEATURE_WLSINK_ENHANCEMENT +static void +gst_wl_window_resize_tizen_video_viewport (GstWlWindow * window, + gboolean commit) +{ + gint transform = WL_OUTPUT_TRANSFORM_NORMAL; + + FUNCTION; + g_return_if_fail (window->tizen_video_viewport != NULL); + g_return_if_fail (window->tizen_video_dest_mode != NULL); + + /* Set source, wayland need to set "tizen_viewport_set_source" always when change video info, + aligned video issue=> ex) 854 x 480 video : aligned buffer size 864 x 480, so we need to set original video size by set source */ + if (window->mode_crop.changed) { + /* we have known issue about mobile team kernel, when set orign green line can be shown with tbm */ + GST_INFO + ("tizen_viewport_set_source (tizen_video_viewport@%p, x@%d, y@%d, w@%d, h@%d)", + window->tizen_video_viewport, window->mode_crop.x, window->mode_crop.y, + window->mode_crop.w, window->mode_crop.h); + tizen_viewport_set_source (window->tizen_video_viewport, + window->mode_crop.x, window->mode_crop.y, window->mode_crop.w, + window->mode_crop.h); + window->mode_crop.changed = FALSE; + } + + /*set tizen destination mode */ + if (window->disp_geo_method.changed || window->roi_area_changed) { + int tizen_disp_mode = -1; + switch (window->disp_geo_method.value) { + + case DISP_GEO_METHOD_LETTER_BOX: + GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_LETTER_BOX"); + tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_LETTER_BOX; + break; + case DISP_GEO_METHOD_ORIGIN_SIZE: + GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_ORIGIN"); + tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_ORIGIN; + break; + case DISP_GEO_METHOD_FULL_SCREEN: + GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_FULL"); + tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_FULL; + break; + case DISP_GEO_METHOD_CROPPED_FULL_SCREEN: + GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_CROPPED_FULL"); + tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_CROPPED_FULL; + break; + case DISP_GEO_METHOD_ORIGIN_SIZE_OR_LETTER_BOX: + GST_LOG ("TIZEN_DESTINATION_MODE_TYPE_ORIGIN_OR_LETTER"); + tizen_disp_mode = TIZEN_DESTINATION_MODE_TYPE_ORIGIN_OR_LETTER; + break; + case DISP_GEO_METHOD_CUSTOM_ROI: + GST_LOG ("DISP_GEO_METHOD_CUSTOM_ROI..need to set destination ROI"); + tizen_disp_mode = -1; + break; + default: + break; + } + if (tizen_disp_mode > -1) { + GST_INFO + ("tizen_destination_mode_set (tizen_destination_mode@%p, tizen_disp_mode@%d)", + window->tizen_video_dest_mode, tizen_disp_mode); + tizen_destination_mode_set (window->tizen_video_dest_mode, + tizen_disp_mode); + } + if (window->disp_geo_method.value == DISP_GEO_METHOD_CUSTOM_ROI) { + /* set ROI destination */ + GST_INFO + ("tizen_viewport_set_destination (tizen_video_viewport(tizen_viewport)@%p, x@%d, y@%d, w@%d, h@%d)", + window->tizen_video_viewport, window->roi.x, window->roi.y, + window->roi.w, window->roi.h); + tizen_viewport_set_destination (window->tizen_video_viewport, + window->roi.x, window->roi.y, window->roi.w, window->roi.h); + window->roi_area_changed = FALSE; + } + window->disp_geo_method.changed = FALSE; + } + + + goto done; + + /* Even though area_viewport is set to ROI mode, we can set below functions too if video_viewport is set to tizen_destination_mode_set. */ +#ifdef ENABLE_FUNCTION + /* set or unset follow parent transform */ + if (window->follow_parent_transform.changed + && !gst_wl_window_is_toplevel (window)) { + if (window->follow_parent_transform.value) { + GST_INFO + ("tizen_destination_mode_follow_parent_transform (tizen_destination_mode@%p)", + window->tizen_area_dest_mode); + tizen_destination_mode_follow_parent_transform + (window->tizen_area_dest_mode); + GST_INFO + ("tizen_destination_mode_follow_parent_transform (tizen_destination_mode@%p)", + window->tizen_video_dest_mode); + tizen_destination_mode_follow_parent_transform + (window->tizen_video_dest_mode); + + } else { + GST_INFO + ("tizen_destination_mode_unfollow_parent_transform (tizen_destination_mode@%p)", + window->tizen_area_dest_mode); + tizen_destination_mode_unfollow_parent_transform + (window->tizen_area_dest_mode); + GST_INFO + ("tizen_destination_mode_unfollow_parent_transform (tizen_destination_mode@%p)", + window->tizen_video_dest_mode); + tizen_destination_mode_unfollow_parent_transform + (window->tizen_video_dest_mode); + } + window->follow_parent_transform.changed = FALSE; + } + + /* set ratio */ + if (window->mode_ratio.changed) { + wl_fixed_t f_width, f_height; + f_width = wl_fixed_from_double (window->mode_ratio.w); + f_height = wl_fixed_from_double (window->mode_ratio.h); + + GST_INFO + ("tizen_destination_mode_set_ratio (tizen_destination_mode@%p, wl_fixed width@%f, wl_fixed height@%f)", + window->tizen_video_dest_mode, window->mode_ratio.w, + window->mode_ratio.h); + tizen_destination_mode_set_ratio (window->tizen_video_dest_mode, f_width, + f_height); + window->mode_ratio.changed = FALSE; + } + + /* set offset */ + if (window->mode_offset.changed) { + GST_INFO + ("tizen_destination_mode_set_offset (tizen_destination_mode@%p, x@%d, y@%d, w@%d, h@%d)", + window->tizen_video_dest_mode, window->mode_offset.x, + window->mode_offset.y, window->mode_offset.w, window->mode_offset.h); + tizen_destination_mode_set_offset (window->tizen_video_dest_mode, + window->mode_offset.x, window->mode_offset.y, window->mode_offset.w, + window->mode_offset.h); + window->mode_offset.changed = FALSE; + } + + /* set scale */ + if (window->mode_scale.changed) { + wl_fixed_t f_width, f_height; + f_width = wl_fixed_from_double (window->mode_scale.w); + f_height = wl_fixed_from_double (window->mode_scale.h); + + GST_INFO + ("tizen_destination_mode_set_scale (tizen_destination_mode@%p, wl_fixed width@%f, wl_fixed height@%f)", + window->tizen_video_dest_mode, window->mode_scale.w, + window->mode_scale.h); + tizen_destination_mode_set_scale (window->tizen_video_dest_mode, f_width, + f_height); + window->mode_scale.changed = FALSE; + } + + /* set align */ + if (window->mode_align.changed) { + wl_fixed_t f_width, f_height; + f_width = wl_fixed_from_double (window->mode_align.w); + f_height = wl_fixed_from_double (window->mode_align.h); + GST_INFO + ("tizen_destination_mode_set_align (tizen_destination_mode@%p, wl_fixed_width@%f, wl_fixed_height@%f)", + window->tizen_video_dest_mode, window->mode_align.w, + window->mode_align.h); + tizen_destination_mode_set_align (window->tizen_video_dest_mode, f_width, + f_height); + window->mode_align.changed = FALSE; + } +#endif + +done: + /* set rotate */ + if (window->rotate_angle.changed) { + GST_LOG ("set rotate_angle(%d)", window->rotate_angle.value); + transform = + gst_wl_window_find_rotate_transform (window->rotate_angle.value); + GST_INFO + ("tizen_viewport_set_transform(tizen_area_viewport@%p, transform@%d)", + window->tizen_area_viewport, transform); + tizen_viewport_set_transform (window->tizen_area_viewport, transform); + window->rotate_angle.changed = FALSE; + } + /* set flip */ + if (window->flip.changed) { + GST_LOG ("set flip(%d)", window->flip.value); + + transform = gst_wl_window_find_flip_transform (window->flip.value); + GST_INFO + ("tizen_viewport_set_transform(tizen_video_viewport@%p, transform@%d)", + window->tizen_video_viewport, transform); + tizen_viewport_set_transform (window->tizen_video_viewport, transform); + window->flip.changed = FALSE; + } + + if (commit) { + GST_LOG ("need to commit"); + GST_INFO + ("wl_surface_damage_buffer (video_surface@%p, buffer_@x%d, buffer_y@%d, buffer_w@%d, buffer_h@%d)", + window->video_surface, window->buffer_x, window->buffer_y, + window->buffer_width, window->buffer_height); + wl_surface_damage_buffer (window->video_surface, window->buffer_x, + window->buffer_y, window->buffer_width, window->buffer_height); + GST_INFO ("wl_surface_commit (video_surface@%p)", window->video_surface); + wl_surface_commit (window->video_surface); + } +} +#else +static void +gst_wl_window_resize_video_surface (GstWlWindow * window, gboolean commit) +{ + GstVideoRectangle src = { 0, }; + GstVideoRectangle dst = { 0, }; + GstVideoRectangle res; + + /* center the video_subsurface inside area_subsurface */ + src.w = window->video_width; + src.h = window->video_height; + dst.w = window->render_rectangle.w; + dst.h = window->render_rectangle.h; + gst_video_sink_center_rect (src, dst, &res, TRUE); + + wl_subsurface_set_position (window->video_subsurface, res.x, res.y); + wl_viewport_set_destination (window->video_viewport, res.w, res.h); + + if (commit) { + wl_surface_damage (window->video_surface, 0, 0, res.w, res.h); + wl_surface_commit (window->video_surface); + } + + if (gst_wl_window_is_toplevel (window)) { + struct wl_region *region; + + region = wl_compositor_create_region (window->display->compositor); + wl_region_add (region, 0, 0, window->render_rectangle.w, + window->render_rectangle.h); + wl_surface_set_input_region (window->area_surface, region); + wl_region_destroy (region); + } + + /* this is saved for use in wl_surface_damage */ + window->surface_width = res.w; + window->surface_height = res.h; +} +#endif +void +gst_wl_window_render (GstWlWindow * window, GstWlBuffer * buffer, + const GstVideoInfo * info) +{ +#if TIZEN_FEATURE_WLSINK_ENHANCEMENT + FUNCTION; + /* check video buffer size for wl_surface_damage_buffer */ + if (window->buffer_width != window->display->buffer_width + || window->buffer_height != window->display->buffer_height) { + window->buffer_width = window->display->buffer_width; + window->buffer_height = window->display->buffer_height; + GST_LOG ("buffer_width(%d) buffer_height(%d)", + window->display->buffer_width, window->display->buffer_height); + } + GST_LOG ("buffer_width(%d) buffer_height(%d)", window->display->buffer_width, + window->display->buffer_height); + + if (G_UNLIKELY (info)) { + window->video_width = + gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); + window->video_height = info->height; + + wl_subsurface_set_sync (window->video_subsurface); + GST_INFO ("wl_subsurface_set_sync (video_subsurface@%p)", + window->video_subsurface); + /* check video_info_changed to remove repetitive IPC */ + if (window->video_info_changed) { + gst_wl_window_resize_tizen_video_viewport (window, FALSE); + window->video_info_changed = FALSE; + } + } + + GST_LOG ("GstWlBuffer(%p)", buffer); + if (G_LIKELY (buffer)) + gst_wl_buffer_attach (buffer, window->video_surface); + else { + GST_INFO ("wl_surface_attach (video_surface@%p, NULL, 0, 0)", + window->video_surface); + wl_surface_attach (window->video_surface, NULL, 0, 0); + } + /* use tizen view port */ + GST_INFO + ("wl_surface_damage_buffer (video_surface@%p, buffer_x@%d, buffer_y@%d, buffer_w@%d, buffer_h@%d)", + window->video_surface, window->buffer_x, window->buffer_y, + window->buffer_width, window->buffer_height); + wl_surface_damage_buffer (window->video_surface, window->buffer_x, + window->buffer_y, window->buffer_width, window->buffer_height); + /* wl_surface_commit change surface state, if wl_buffer is not attached newly, then surface is not changed */ + GST_INFO ("wl_surface_commit (video_surface@%p)", window->video_surface); + wl_surface_commit (window->video_surface); + + if (G_UNLIKELY (info)) { + GST_INFO ("wl_surface_commit (area_surface@%p)", window->area_surface); + wl_surface_commit (window->area_surface); + GST_INFO ("wl_subsurface_set_desync (video_subsurface@%p)", + window->video_subsurface); + wl_subsurface_set_desync (window->video_subsurface); + } + + wl_display_flush (window->display->display); + +#else /* open source */ + + if (G_UNLIKELY (info)) { + window->video_width = + gst_util_uint64_scale_int_round (info->width, info->par_n, info->par_d); + window->video_height = info->height; + + wl_subsurface_set_sync (window->video_subsurface); + gst_wl_window_resize_video_surface (window, FALSE); + } + + GST_LOG ("GstWlBuffer(%p)", buffer); + if (G_LIKELY (buffer)) + gst_wl_buffer_attach (buffer, window->video_surface); + else + wl_surface_attach (window->video_surface, NULL, 0, 0); + + wl_surface_damage (window->video_surface, 0, 0, window->surface_width, + window->surface_height); + wl_surface_commit (window->video_surface); + + if (G_UNLIKELY (info)) { + /* commit also the parent (area_surface) in order to change + * the position of the video_subsurface */ + wl_surface_damage (window->area_surface, 0, 0, window->render_rectangle.w, + window->render_rectangle.h); + wl_surface_commit (window->area_surface); + wl_subsurface_set_desync (window->video_subsurface); + } + + wl_display_flush (window->display->display); +#endif +} + +#if TIZEN_FEATURE_WLSINK_ENHANCEMENT +gboolean +gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y, + gint w, gint h) +{ + FUNCTION; + g_return_val_if_fail (window != NULL, FALSE); + + if (window->disp_geo_method.value != DISP_GEO_METHOD_CUSTOM_ROI) { + GST_ERROR + ("must be set display-geometry-method to DISP_GEO_METHOD_CUSTOM_ROI before setting render rectangle()"); + return FALSE; + } + + if (w < 0 || h < 0) { + GST_ERROR ("Error : wrong roi size w(%d), h(%d)", w, h); + return FALSE; + } + + window->roi.x = x; + window->roi.y = y; + window->roi.w = w; + window->roi.h = h; + GST_LOG ("set roi x(%d), y(%d), w(%d), h(%d)", x, y, w, h); + window->roi_area_changed = TRUE; + + return TRUE; +} +#else /* open source */ +void +gst_wl_window_set_render_rectangle (GstWlWindow * window, gint x, gint y, + gint w, gint h) +{ + + g_return_if_fail (window != NULL); + + window->render_rectangle.x = x; + window->render_rectangle.y = y; + window->render_rectangle.w = w; + window->render_rectangle.h = h; + + /* position the area inside the parent - needs a parent commit to apply */ + if (window->area_subsurface) + wl_subsurface_set_position (window->area_subsurface, x, y); + + /* change the size of the area */ + wl_viewport_set_destination (window->area_viewport, w, h); + + if (window->video_width != 0) { + wl_subsurface_set_sync (window->video_subsurface); + gst_wl_window_resize_video_surface (window, TRUE); + } + + wl_surface_damage (window->area_surface, 0, 0, w, h); + wl_surface_commit (window->area_surface); + + if (window->video_width != 0) + wl_subsurface_set_desync (window->video_subsurface); + +} +#endif + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +void +gst_wl_window_set_rotate_angle (GstWlWindow * window, guint rotate_angle) +{ + FUNCTION; + g_return_if_fail (window != NULL); + window->rotate_angle.value = rotate_angle; + GST_LOG ("rotate_angle value is (%d)", window->rotate_angle.value); + window->rotate_angle.changed = TRUE; +} + +void +gst_wl_window_set_destination_mode (GstWlWindow * window, guint disp_geo_method) +{ + FUNCTION; + g_return_if_fail (window != NULL); + window->disp_geo_method.value = disp_geo_method; + GST_LOG ("disp_geo_method value is (%d)", window->disp_geo_method.value); + window->disp_geo_method.changed = TRUE; +} + +void +gst_wl_window_set_flip (GstWlWindow * window, guint flip) +{ + FUNCTION; + g_return_if_fail (window != NULL); + window->flip.value = flip; + GST_LOG ("flip value is (%d)", window->flip.value); + window->flip.changed = TRUE; +} + +void +gst_wl_window_set_destination_mode_crop_wl_buffer (GstWlWindow * window, + guint x, guint y, guint w, guint h) +{ + FUNCTION; + g_return_if_fail (window != NULL); + GST_LOG ("set crop x@%d, y@%d, w@%d, h@%d", x, y, w, h); + window->mode_crop.x = x; + window->mode_crop.y = y; + window->mode_crop.w = w; + window->mode_crop.h = h; + window->mode_crop.changed = TRUE; +} + +#ifdef ENABLE_FUNCTION +void +gst_wl_window_set_destination_mode_follow_parent_transform (GstWlWindow * + window, gboolean follow_parent_transform) +{ + FUNCTION; + g_return_if_fail (window != NULL); + window->follow_parent_transform.value = follow_parent_transform; + GST_LOG ("follow_parent_transform value is (%d)", + window->follow_parent_transform.value); + window->follow_parent_transform.changed = TRUE; +} + + +void +gst_wl_window_set_destination_mode_offset (GstWlWindow * window, guint x, + guint y, guint w, guint h) +{ + FUNCTION; + g_return_if_fail (window != NULL); + GST_LOG ("set offset x@%d, y@%d", x, y); + window->mode_offset.x = x; + window->mode_offset.y = y; + window->mode_offset.w = w; + window->mode_offset.h = h; + window->mode_offset.changed = TRUE; +} + +void +gst_wl_window_set_destination_mode_ratio (GstWlWindow * window, gdouble w, + gdouble h) +{ + FUNCTION; + g_return_if_fail (window != NULL); + GST_LOG ("set ratio w@%f, h@%f", w, h); + window->mode_ratio.w = w; + window->mode_ratio.h = h; + window->mode_ratio.changed = TRUE; +} + +void +gst_wl_window_set_destination_mode_scale (GstWlWindow * window, gdouble w, + gdouble h) +{ + FUNCTION; + g_return_if_fail (window != NULL); + GST_LOG ("set scale w@%f, h@%f", w, h); + window->mode_scale.w = w; + window->mode_scale.h = h; + window->mode_scale.changed = TRUE; +} + +void +gst_wl_window_set_destination_mode_align (GstWlWindow * window, gdouble w, + gdouble h) +{ + FUNCTION; + g_return_if_fail (window != NULL); + GST_LOG ("set align w@%f, h@%f", w, h); + window->mode_align.w = w; + window->mode_align.h = h; + window->mode_align.changed = TRUE; +} +#endif +void +gst_wl_window_set_video_info_change (GstWlWindow * window, guint changed) +{ + FUNCTION; + g_return_if_fail (window != NULL); + window->video_info_changed = changed; + GST_LOG ("video_info_changed value is (%d)", window->video_info_changed); +} +#endif diff --git a/tizenwlsink/src/wlwindow.h b/tizenwlsink/src/wlwindow.h new file mode 100644 index 0000000..6f5397d --- /dev/null +++ b/tizenwlsink/src/wlwindow.h @@ -0,0 +1,167 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2014 Collabora Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free + * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + */ + +#ifndef __GST_WL_WINDOW_H__ +#define __GST_WL_WINDOW_H__ + +#include "wldisplay.h" +#include "wlbuffer.h" +#include + +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__ */ -- 2.7.4 From 5d509b9eac9162a2b41d3f4f781507f7d58aeab9 Mon Sep 17 00:00:00 2001 From: Hyunil Date: Tue, 14 Nov 2017 18:11:03 +0900 Subject: [PATCH 05/16] tizenwlsink : change type and function name Change-Id: Id275fec91a931e1a490f48392c722660de292f81 Signed-off-by: Hyunil --- tizenwlsink/src/Makefile.am | 12 +- .../src/{gstwaylandsink.c => gsttizenwlsink.c} | 451 +++++++++++---------- .../src/{gstwaylandsink.h => gsttizenwlsink.h} | 40 +- .../{wlshmallocator.c => tizen-wlshmallocator.c} | 88 ++-- tizenwlsink/src/tizen-wlshmallocator.h | 80 ++++ tizenwlsink/src/tizen-wlvideoformat.c | 4 +- tizenwlsink/src/tizen-wlvideoformat.h | 0 tizenwlsink/src/wlbuffer.c | 4 +- tizenwlsink/src/wldisplay.c | 4 +- tizenwlsink/src/wlshmallocator.h | 79 ---- tizenwlsink/src/wlvideoformat.c | 4 +- tizenwlsink/src/wlwindow.c | 28 +- 12 files changed, 404 insertions(+), 390 deletions(-) rename tizenwlsink/src/{gstwaylandsink.c => gsttizenwlsink.c} (86%) mode change 100755 => 100644 rename tizenwlsink/src/{gstwaylandsink.h => gsttizenwlsink.h} (74%) rename tizenwlsink/src/{wlshmallocator.c => tizen-wlshmallocator.c} (85%) create mode 100644 tizenwlsink/src/tizen-wlshmallocator.h mode change 100755 => 100644 tizenwlsink/src/tizen-wlvideoformat.h delete mode 100644 tizenwlsink/src/wlshmallocator.h diff --git a/tizenwlsink/src/Makefile.am b/tizenwlsink/src/Makefile.am index 998787f..a90af52 100644 --- a/tizenwlsink/src/Makefile.am +++ b/tizenwlsink/src/Makefile.am @@ -1,8 +1,8 @@ plugin_LTLIBRARIES = libgsttizenwlsink.la libgsttizenwlsink_la_SOURCES = \ - gstwaylandsink.c \ - wlshmallocator.c \ + gsttizenwlsink.c \ + tizen-wlshmallocator.c \ wlbuffer.c \ wldisplay.c \ wlwindow.c \ @@ -19,8 +19,8 @@ libgsttizenwlsink_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgsttizenwlsink_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) noinst_HEADERS = \ - gstwaylandsink.h \ - wlshmallocator.h \ + gsttizenwlsink.h \ + tizen-wlshmallocator.h \ wlbuffer.h \ wldisplay.h \ wlwindow.h \ @@ -37,9 +37,9 @@ CLEANFILES = scaler-protocol.c scaler-client-protocol.h %-client-protocol.h : %.xml $(wayland_scanner) client-header < $< > $@ -gstwaylandsink.c: scaler-client-protocol.h +gsttizenwlsink.c: scaler-client-protocol.h -wlshmallocator.c: scaler-client-protocol.h +tizen-wlshmallocator.c: scaler-client-protocol.h wlbuffer.c: scaler-client-protocol.h diff --git a/tizenwlsink/src/gstwaylandsink.c b/tizenwlsink/src/gsttizenwlsink.c old mode 100755 new mode 100644 similarity index 86% rename from tizenwlsink/src/gstwaylandsink.c rename to tizenwlsink/src/gsttizenwlsink.c index 4a33e8c..b693718 --- a/tizenwlsink/src/gstwaylandsink.c +++ b/tizenwlsink/src/gsttizenwlsink.c @@ -41,14 +41,14 @@ #include #endif -#include "gstwaylandsink.h" +#include "gsttizenwlsink.h" #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT #include #include "tizen-wlvideoformat.h" #endif #include "wlvideoformat.h" #include "wlbuffer.h" -#include "wlshmallocator.h" +#include "tizen-wlshmallocator.h" #include @@ -60,14 +60,14 @@ #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()) +#define GST_TYPE_TIZEN_WL_SINK_DISPLAY_GEOMETRY_METHOD (gst_tizen_wl_sink_display_geometry_method_get_type()) +#define GST_TYPE_TIZEN_WL_SINK_ROTATE_ANGLE (gst_tizen_wl_sink_rotate_angle_get_type()) +#define GST_TYPE_TIZEN_WL_SINK_FLIP (gst_tizen_wl_sink_flip_get_type()) static GType -gst_waylandsink_rotate_angle_get_type (void) +gst_tizen_wl_sink_rotate_angle_get_type (void) { - static GType waylandsink_rotate_angle_type = 0; + static GType tizen_wl_sink_rotate_angle_type = 0; static const GEnumValue rotate_angle_type[] = { {0, "No rotate", "DEGREE_0"}, {1, "Rotate 90 degree", "DEGREE_90"}, @@ -76,20 +76,20 @@ gst_waylandsink_rotate_angle_get_type (void) {4, NULL, NULL}, }; - if (!waylandsink_rotate_angle_type) { - waylandsink_rotate_angle_type = - g_enum_register_static ("GstWaylandSinkRotateAngleType", + if (!tizen_wl_sink_rotate_angle_type) { + tizen_wl_sink_rotate_angle_type = + g_enum_register_static ("GstTizenWlSinkRotateAngleType", rotate_angle_type); } - return waylandsink_rotate_angle_type; + return tizen_wl_sink_rotate_angle_type; } static GType -gst_waylandsink_display_geometry_method_get_type (void) +gst_tizen_wl_sink_display_geometry_method_get_type (void) { - static GType waylandsink_display_geometry_method_type = 0; + static GType tizen_wl_sink_display_geometry_method_type = 0; static const GEnumValue display_geometry_method_type[] = { {0, "Letter box", "LETTER_BOX"}, {1, "Origin size", "ORIGIN_SIZE"}, @@ -100,18 +100,18 @@ gst_waylandsink_display_geometry_method_get_type (void) {6, NULL, NULL}, }; - if (!waylandsink_display_geometry_method_type) { - waylandsink_display_geometry_method_type = - g_enum_register_static ("GstWaylandSinkDisplayGeometryMethodType", + if (!tizen_wl_sink_display_geometry_method_type) { + tizen_wl_sink_display_geometry_method_type = + g_enum_register_static ("GstTizenWlSinkDisplayGeometryMethodType", display_geometry_method_type); } - return waylandsink_display_geometry_method_type; + return tizen_wl_sink_display_geometry_method_type; } static GType -gst_waylandsink_flip_get_type (void) +gst_tizen_wl_sink_flip_get_type (void) { - static GType waylandsink_flip_type = 0; + static GType tizen_wl_sink_flip_type = 0; static const GEnumValue flip_type[] = { {FLIP_NONE, "Flip NONE", "FLIP_NONE"}, {FLIP_HORIZONTAL, "Flip HORIZONTAL", "FLIP_HORIZONTAL"}, @@ -120,12 +120,12 @@ gst_waylandsink_flip_get_type (void) {FLIP_NUM, NULL, NULL}, }; - if (!waylandsink_flip_type) { - waylandsink_flip_type = - g_enum_register_static ("GstWaylandSinkFlipType", flip_type); + if (!tizen_wl_sink_flip_type) { + tizen_wl_sink_flip_type = + g_enum_register_static ("GstTizenWlSinkFlipType", flip_type); } - return waylandsink_flip_type; + return tizen_wl_sink_flip_type; } #endif @@ -176,8 +176,8 @@ enum #endif }; -GST_DEBUG_CATEGORY (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +GST_DEBUG_CATEGORY (gst_tizen_wl_debug); +#define GST_CAT_DEFAULT gst_tizen_wl_debug static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", GST_PAD_SINK, @@ -192,67 +192,68 @@ static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink", "YUV9, YVU9, Y41B, I420, YV12, Y42B, v308 }"))); #endif -static void gst_wayland_sink_get_property (GObject * object, +static void gst_tizen_wl_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec); -static void gst_wayland_sink_set_property (GObject * object, +static void gst_tizen_wl_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_wayland_sink_finalize (GObject * object); +static void gst_tizen_wl_sink_finalize (GObject * object); -static GstStateChangeReturn gst_wayland_sink_change_state (GstElement * element, - GstStateChange transition); -static GstCaps *gst_wayland_sink_get_caps (GstBaseSink * bsink, +static GstStateChangeReturn gst_tizen_wl_sink_change_state (GstElement * + element, GstStateChange transition); +static GstCaps *gst_tizen_wl_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, +static gboolean gst_tizen_wl_sink_set_caps (GstBaseSink * bsink, + GstCaps * caps); +static gboolean gst_tizen_wl_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, +static gboolean gst_tizen_wl_sink_propose_allocation (GstBaseSink * bsink, + GstQuery * query); +static gboolean gst_tizen_wl_sink_render (GstBaseSink * bsink, GstBuffer * buffer); /* VideoOverlay interface */ -static void gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * +static void gst_tizen_wl_sink_videooverlay_init (GstVideoOverlayInterface * iface); -static void gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, +static void gst_tizen_wl_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle); static void -gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay, +gst_tizen_wl_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay, guintptr wl_surface_id); -static void gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay, +static void gst_tizen_wl_sink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y, gint w, gint h); -static void gst_wayland_sink_expose (GstVideoOverlay * overlay); +static void gst_tizen_wl_sink_expose (GstVideoOverlay * overlay); /* WaylandVideo interface */ #if 0 -static void gst_wayland_sink_set_context (GstElement * element, +static void gst_tizen_wl_sink_set_context (GstElement * element, GstContext * context); -static void gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * +static void gst_tizen_wl_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); +static void gst_tizen_wl_sink_begin_geometry_change (GstWaylandVideo * video); +static void gst_tizen_wl_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, +static gboolean gst_tizen_wl_sink_event (GstBaseSink * bsink, GstEvent * event); +static void gst_tizen_wl_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 void gst_tizen_wl_sink_update_window_geometry (GstTizenWlSink * sink); +static void render_last_buffer (GstTizenWlSink * 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, +#define gst_tizen_wl_sink_parent_class parent_class +G_DEFINE_TYPE_WITH_CODE (GstTizenWlSink, gst_tizen_wl_sink, GST_TYPE_VIDEO_SINK, G_IMPLEMENT_INTERFACE (GST_TYPE_VIDEO_OVERLAY, - gst_wayland_sink_videooverlay_init) + gst_tizen_wl_sink_videooverlay_init) #if 0 G_IMPLEMENT_INTERFACE (GST_TYPE_WAYLAND_VIDEO, - gst_wayland_sink_waylandvideo_init) + gst_tizen_wl_sink_waylandvideo_init) #endif -); + ); static void -gst_wayland_sink_class_init (GstWaylandSinkClass * klass) +gst_tizen_wl_sink_class_init (GstTizenWlSinkClass * klass) { GObjectClass *gobject_class; GstElementClass *gstelement_class; @@ -263,9 +264,9 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * 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); + gobject_class->set_property = gst_tizen_wl_sink_set_property; + gobject_class->get_property = gst_tizen_wl_sink_get_property; + gobject_class->finalize = GST_DEBUG_FUNCPTR (gst_tizen_wl_sink_finalize); gst_element_class_add_pad_template (gstelement_class, gst_static_pad_template_get (&sink_template)); @@ -278,20 +279,21 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) "George Kiagiadakis "); gstelement_class->change_state = - GST_DEBUG_FUNCPTR (gst_wayland_sink_change_state); + GST_DEBUG_FUNCPTR (gst_tizen_wl_sink_change_state); #if 0 gstelement_class->set_context = - GST_DEBUG_FUNCPTR (gst_wayland_sink_set_context); + GST_DEBUG_FUNCPTR (gst_tizen_wl_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->get_caps = GST_DEBUG_FUNCPTR (gst_tizen_wl_sink_get_caps); + gstbasesink_class->set_caps = GST_DEBUG_FUNCPTR (gst_tizen_wl_sink_set_caps); + gstbasesink_class->preroll = GST_DEBUG_FUNCPTR (gst_tizen_wl_sink_preroll); gstbasesink_class->propose_allocation = - GST_DEBUG_FUNCPTR (gst_wayland_sink_propose_allocation); - gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_wayland_sink_render); + GST_DEBUG_FUNCPTR (gst_tizen_wl_sink_propose_allocation); + gstbasesink_class->render = GST_DEBUG_FUNCPTR (gst_tizen_wl_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); + gstbasesink_class->event = GST_DEBUG_FUNCPTR (gst_tizen_wl_sink_event); + gstbasesink_class->get_times = + GST_DEBUG_FUNCPTR (gst_tizen_wl_sink_get_times); #endif g_object_class_install_property (gobject_class, PROP_DISPLAY, @@ -331,20 +333,20 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) 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, + GST_TYPE_TIZEN_WL_SINK_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, + GST_TYPE_TIZEN_WL_SINK_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, + GST_TYPE_TIZEN_WL_SINK_FLIP, DEF_DISPLAY_FLIP, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); g_object_class_install_property (gobject_class, PROP_VISIBLE, @@ -469,13 +471,13 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) 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_STRUCT_OFFSET (GstTizenWlSinkClass, 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), + G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstTizenWlSinkClass, preroll_handoff), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD); @@ -483,7 +485,7 @@ gst_wayland_sink_class_init (GstWaylandSinkClass * klass) } static void -gst_wayland_sink_dump_raw_video (GstWaylandSink * sink, GstBuffer * buffer, +gst_tizen_wl_sink_dump_raw_video (GstTizenWlSink * sink, GstBuffer * buffer, guint dump_count, guint dump_total) { GstMemory *mem; @@ -507,7 +509,7 @@ gst_wayland_sink_dump_raw_video (GstWaylandSink * sink, GstBuffer * buffer, 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); + ret = gst_tizen_wl_fwrite_data (file_name, data, size); if (ret) { GST_ERROR ("_write_rawdata() failed"); } @@ -517,7 +519,7 @@ gst_wayland_sink_dump_raw_video (GstWaylandSink * sink, GstBuffer * buffer, } static void -gst_wayland_sink_init (GstWaylandSink * sink) +gst_tizen_wl_sink_init (GstTizenWlSink * sink) { FUNCTION; #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT @@ -549,9 +551,9 @@ gst_wayland_sink_init (GstWaylandSink * sink) #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT static void -gst_wayland_sink_recover_display_window_info (GstWaylandSink * sink) +gst_tizen_wl_sink_recover_display_window_info (GstTizenWlSink * sink) { - GstWlShmAllocator *self = NULL; + GstTizenWlShmAllocator *self = NULL; FUNCTION; g_return_if_fail (sink != NULL); g_return_if_fail (sink->display != NULL); @@ -559,15 +561,15 @@ gst_wayland_sink_recover_display_window_info (GstWaylandSink * sink) 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 = GST_TIZEN_WL_SHM_ALLOCATOR (gst_tizen_wl_shm_allocator_get ()); self->display = sink->display; - gst_wayland_sink_update_window_geometry (sink); + gst_tizen_wl_sink_update_window_geometry (sink); sink->video_info_changed = TRUE; } static gboolean -gst_wayland_sink_is_disabled_overlay (GstWaylandSink * sink) +gst_tizen_wl_sink_is_disabled_overlay (GstTizenWlSink * sink) { g_return_val_if_fail (sink != NULL, FALSE); //Ensure display is null and the display info has been copied by unsetting disable_overlay @@ -580,7 +582,7 @@ gst_wayland_sink_is_disabled_overlay (GstWaylandSink * sink) } static void -gst_wayland_sink_stop_video (GstWaylandSink * sink) +gst_tizen_wl_sink_stop_video (GstTizenWlSink * sink) { FUNCTION; g_return_if_fail (sink != NULL); @@ -588,7 +590,7 @@ gst_wayland_sink_stop_video (GstWaylandSink * sink) } static int -gst_wayland_sink_is_gapless (GstWaylandSink * sink) +gst_tizen_wl_sink_is_gapless (GstTizenWlSink * sink) { g_return_val_if_fail (sink != NULL, FALSE); g_return_val_if_fail (sink->display != NULL, FALSE); @@ -601,12 +603,12 @@ gst_wayland_sink_is_gapless (GstWaylandSink * sink) } static int -gst_wayland_sink_need_flush_buffer (GstWaylandSink * sink) +gst_tizen_wl_sink_need_flush_buffer (GstTizenWlSink * 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)) + if ((gst_tizen_wl_sink_is_gapless (sink)) || sink->request_camera_flush_buf || sink->display->flush_request == 1) { sink->display->flush_request = TRUE; return TRUE; @@ -615,7 +617,7 @@ gst_wayland_sink_need_flush_buffer (GstWaylandSink * sink) } static void -gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink) +gst_tizen_wl_sink_update_last_buffer_geometry (GstTizenWlSink * sink) { GstWlBuffer *wlbuffer; gboolean no_render_buffer = FALSE; @@ -666,7 +668,7 @@ gst_wayland_sink_update_last_buffer_geometry (GstWaylandSink * sink) #ifdef USE_WL_FLUSH_BUFFER static int -gst_wayland_sink_make_flush_buffer (GstWlDisplay * display, +gst_tizen_wl_sink_make_flush_buffer (GstWlDisplay * display, MMVideoBuffer * mm_video_buf) { GstWlFlushBuffer *flush_buffer = NULL; @@ -737,8 +739,8 @@ gst_wayland_sink_make_flush_buffer (GstWlDisplay * display, } static int -gst_wayland_sink_copy_mm_video_buf_info_to_flush_buffer (GstWlDisplay * display, - MMVideoBuffer * mm_video_buf) +gst_tizen_wl_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); @@ -747,7 +749,7 @@ gst_wayland_sink_copy_mm_video_buf_info_to_flush_buffer (GstWlDisplay * display, 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); + ret = gst_tizen_wl_sink_make_flush_buffer (display, mm_video_buf); if (ret) { int i; for (i = 0; i < display->plane_num; i++) { @@ -777,7 +779,7 @@ gst_wayland_sink_copy_mm_video_buf_info_to_flush_buffer (GstWlDisplay * display, #endif static void -gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display, +gst_tizen_wl_sink_add_mm_video_buf_info (GstWlDisplay * display, MMVideoBuffer * mm_video_buf) { int i; @@ -809,7 +811,7 @@ gst_wayland_sink_add_mm_video_buf_info (GstWlDisplay * display, } static MMVideoBuffer * -gst_wayland_sink_get_mm_video_buf (GstBuffer * buffer) +gst_tizen_wl_sink_get_mm_video_buf (GstBuffer * buffer) { GstMemory *mem; GstMapInfo mem_info = GST_MAP_INFO_INIT; @@ -841,7 +843,7 @@ gst_wayland_sink_get_mm_video_buf (GstBuffer * buffer) } static int -gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink, +gst_tizen_wl_sink_get_mm_video_buf_info (GstTizenWlSink * sink, GstBuffer * buffer) { GstWlDisplay *display; @@ -855,7 +857,7 @@ gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink, g_return_val_if_fail (sink->display != NULL, FALSE); /* get MMVideoBuffer from buffer */ - mm_video_buf = gst_wayland_sink_get_mm_video_buf (buffer); + mm_video_buf = gst_tizen_wl_sink_get_mm_video_buf (buffer); g_return_val_if_fail (mm_video_buf != NULL, FALSE); /* assign mm_video_buf info */ @@ -864,16 +866,16 @@ gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink, 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)) { + if (gst_tizen_wl_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); + mm_video_buf = gst_tizen_wl_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, + if (!gst_tizen_wl_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; @@ -881,25 +883,25 @@ gst_wayland_sink_get_mm_video_buf_info (GstWaylandSink * sink, } else #endif /* normal routine */ - gst_wayland_sink_add_mm_video_buf_info (display, mm_video_buf); + gst_tizen_wl_sink_add_mm_video_buf_info (display, mm_video_buf); return TRUE; } static void -gst_wayland_sink_render_flush_buffer (GstBaseSink * bsink) +gst_tizen_wl_sink_render_flush_buffer (GstBaseSink * bsink) { - GstWaylandSink *sink; - sink = GST_WAYLAND_SINK (bsink); + GstTizenWlSink *sink; + sink = GST_TIZEN_WL_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); + gst_tizen_wl_sink_render (bsink, sink->last_buffer); } static void -gst_wayland_sink_render_last_sample (GstWaylandSink * sink) +gst_tizen_wl_sink_render_last_sample (GstTizenWlSink * sink) { GstSample *last_sample = NULL; GstBuffer *last_buffer = NULL; @@ -912,7 +914,7 @@ gst_wayland_sink_render_last_sample (GstWaylandSink * sink) 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_tizen_wl_sink_render (GST_BASE_SINK (sink), last_buffer); gst_buffer_unref (last_buffer); last_buffer = NULL; } @@ -924,10 +926,10 @@ gst_wayland_sink_render_last_sample (GstWaylandSink * sink) #endif static void -gst_wayland_sink_get_property (GObject * object, +gst_tizen_wl_sink_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { - GstWaylandSink *sink = GST_WAYLAND_SINK (object); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (object); FUNCTION; switch (prop_id) { @@ -1022,10 +1024,10 @@ gst_wayland_sink_get_property (GObject * object, } static void -gst_wayland_sink_set_property (GObject * object, +gst_tizen_wl_sink_set_property (GObject * object, guint prop_id, const GValue * value, GParamSpec * pspec) { - GstWaylandSink *sink = GST_WAYLAND_SINK (object); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (object); FUNCTION; g_mutex_lock (&sink->render_lock); @@ -1055,7 +1057,7 @@ gst_wayland_sink_set_property (GObject * object, g_clear_object (&sink->window); g_clear_object (&sink->display); } else - gst_wayland_sink_recover_display_window_info (sink); + gst_tizen_wl_sink_recover_display_window_info (sink); } break; case PROP_SIGNAL_HANDOFFS: @@ -1073,13 +1075,13 @@ gst_wayland_sink_set_property (GObject * object, sink->last_buffer, GST_BASE_SINK (object)->sinkpad); } } - gst_wayland_sink_stop_video (sink); + gst_tizen_wl_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); + gst_tizen_wl_sink_render_last_sample (sink); g_mutex_lock (&sink->render_lock); } } @@ -1136,7 +1138,7 @@ gst_wayland_sink_set_property (GObject * object, } else if (!sink->visible && GST_STATE (sink) >= GST_STATE_PAUSED) { /* video stop */ if (sink->window) { - gst_wayland_sink_stop_video (sink); + gst_tizen_wl_sink_stop_video (sink); } } break; @@ -1296,7 +1298,7 @@ gst_wayland_sink_set_property (GObject * object, 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); + gst_tizen_wl_sink_update_last_buffer_geometry (sink); } #endif g_mutex_unlock (&sink->render_lock); @@ -1304,9 +1306,9 @@ gst_wayland_sink_set_property (GObject * object, } static void -gst_wayland_sink_finalize (GObject * object) +gst_tizen_wl_sink_finalize (GObject * object) { - GstWaylandSink *sink = GST_WAYLAND_SINK (object); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (object); FUNCTION; GST_DEBUG_OBJECT (sink, "Finalizing the sink.."); @@ -1330,12 +1332,12 @@ gst_wayland_sink_finalize (GObject * object) #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT static gboolean -gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event) +gst_tizen_wl_sink_event (GstBaseSink * bsink, GstEvent * event) { - GstWaylandSink *sink; + GstTizenWlSink *sink; const GstStructure *s; - sink = GST_WAYLAND_SINK (bsink); + sink = GST_TIZEN_WL_SINK (bsink); switch (GST_EVENT_TYPE (event)) { case GST_EVENT_EOS: @@ -1351,8 +1353,8 @@ gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event) 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); + if (gst_tizen_wl_sink_is_gapless (sink)) { + gst_tizen_wl_sink_render_flush_buffer (bsink); sink->got_costum_event = FALSE; } sink->got_costum_event = FALSE; @@ -1364,13 +1366,13 @@ gst_wayland_sink_event (GstBaseSink * bsink, GstEvent * event) } static void -gst_wayland_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, +gst_tizen_wl_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; + GstTizenWlSink *sink; - sink = GST_WAYLAND_SINK (bsink); + sink = GST_TIZEN_WL_SINK (bsink); if (GST_BUFFER_TIMESTAMP_IS_VALID (buf)) { *start = GST_BUFFER_TIMESTAMP (buf); @@ -1390,7 +1392,7 @@ gst_wayland_sink_get_times (GstBaseSink * bsink, GstBuffer * buf, #if 0 /* must be called with the display_lock */ static void -gst_wayland_sink_set_display_from_context (GstWaylandSink * sink, +gst_tizen_wl_sink_set_display_from_context (GstTizenWlSink * sink, GstContext * context) { struct wl_display *display; @@ -1412,11 +1414,13 @@ gst_wayland_sink_set_display_from_context (GstWaylandSink * sink, } #endif static gboolean -gst_wayland_sink_find_display (GstWaylandSink * sink) +gst_tizen_wl_sink_find_display (GstTizenWlSink * sink) { -// GstQuery *query; -// GstMessage *msg; -// GstContext *context = NULL; +#if 0 + GstQuery *query; + GstMessage *msg; + GstContext *context = NULL; +#endif GError *error = NULL; gboolean ret = TRUE; FUNCTION; @@ -1429,7 +1433,7 @@ gst_wayland_sink_find_display (GstWaylandSink * sink) 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_tizen_wl_sink_set_display_from_context (sink, context); } gst_query_unref (query); #endif @@ -1441,7 +1445,7 @@ gst_wayland_sink_find_display (GstWaylandSink * sink) 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 + /* at this point we expect gst_tizen_wl_sink_set_context * to get called and fill sink->display */ g_mutex_lock (&sink->display_lock); #endif @@ -1472,16 +1476,16 @@ gst_wayland_sink_find_display (GstWaylandSink * sink) } static GstStateChangeReturn -gst_wayland_sink_change_state (GstElement * element, GstStateChange transition) +gst_tizen_wl_sink_change_state (GstElement * element, GstStateChange transition) { - GstWaylandSink *sink = GST_WAYLAND_SINK (element); + GstTizenWlSink *sink = GST_TIZEN_WL_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)) + if (!gst_tizen_wl_sink_find_display (sink)) return GST_STATE_CHANGE_FAILURE; break; case GST_STATE_CHANGE_READY_TO_PAUSED: @@ -1513,7 +1517,7 @@ gst_wayland_sink_change_state (GstElement * element, GstStateChange transition) && !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); + gst_tizen_wl_sink_render_flush_buffer (bsink); sink->request_camera_flush_buf = FALSE; } break; @@ -1558,18 +1562,19 @@ gst_wayland_sink_change_state (GstElement * element, GstStateChange transition) return ret; } + #if 0 static void -gst_wayland_sink_set_context (GstElement * element, GstContext * context) +gst_tizen_wl_sink_set_context (GstElement * element, GstContext * context) { - GstWaylandSink *sink = GST_WAYLAND_SINK (element); + GstTizenWlSink *sink = GST_TIZEN_WL_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); + gst_tizen_wl_sink_set_display_from_context (sink, context); else { GST_WARNING_OBJECT (element, "changing display handle is not supported"); #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT @@ -1585,13 +1590,13 @@ gst_wayland_sink_set_context (GstElement * element, GstContext * context) } #endif static GstCaps * -gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) +gst_tizen_wl_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) { - GstWaylandSink *sink; + GstTizenWlSink *sink; GstCaps *caps; FUNCTION; - sink = GST_WAYLAND_SINK (bsink); + sink = GST_TIZEN_WL_SINK (bsink); caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink)); #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT @@ -1685,9 +1690,9 @@ gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter) } static gboolean -gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) +gst_tizen_wl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) { - GstWaylandSink *sink; + GstTizenWlSink *sink; GstBufferPool *newpool; GstVideoInfo info; #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT @@ -1698,11 +1703,11 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) GArray *formats; gint i; GstStructure *structure; - GstWlShmAllocator *self = NULL; + GstTizenWlShmAllocator *self = NULL; FUNCTION; - sink = GST_WAYLAND_SINK (bsink); + sink = GST_TIZEN_WL_SINK (bsink); GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps); @@ -1775,7 +1780,7 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) sink->video_info_changed = TRUE; } else { sink->display->is_native_format = FALSE; - self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ()); + self = GST_TIZEN_WL_SHM_ALLOCATOR (gst_tizen_wl_shm_allocator_get ()); self->display = sink->display; /* create a new pool for the new configuration */ newpool = gst_video_buffer_pool_new (); @@ -1785,7 +1790,7 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) 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); + gst_tizen_wl_shm_allocator_get (), NULL); if (!gst_buffer_pool_set_config (newpool, structure)) goto config_failed; @@ -1798,7 +1803,7 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) } } else { /* USE SHM */ - self = GST_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get ()); + self = GST_TIZEN_WL_SHM_ALLOCATOR (gst_tizen_wl_shm_allocator_get ()); self->display = sink->display; /* create a new pool for the new configuration */ @@ -1809,7 +1814,7 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) 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); + gst_tizen_wl_shm_allocator_get (), NULL); if (!gst_buffer_pool_set_config (newpool, structure)) goto config_failed; @@ -1824,7 +1829,7 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) sink->is_native_format = sink->display->is_native_format; if (sink->window) - gst_wayland_sink_update_window_geometry (sink); + gst_tizen_wl_sink_update_window_geometry (sink); #else /*open source */ @@ -1836,7 +1841,7 @@ gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) 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); + gst_tizen_wl_shm_allocator_get (), NULL); if (!gst_buffer_pool_set_config (newpool, structure)) goto config_failed; @@ -1885,9 +1890,9 @@ config_failed: } static gboolean -gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) +gst_tizen_wl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) { - GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (bsink); GstStructure *config; guint size, min_bufs, max_bufs; @@ -1914,7 +1919,8 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) /* 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_query_add_allocation_param (query, gst_tizen_wl_shm_allocator_get (), + NULL); gst_structure_free (config); @@ -1922,10 +1928,10 @@ gst_wayland_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) } static GstFlowReturn -gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer) +gst_tizen_wl_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer) { #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT - GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (bsink); FUNCTION; GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer); @@ -1939,13 +1945,13 @@ gst_wayland_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer) return GST_FLOW_OK; } #endif - return gst_wayland_sink_render (bsink, buffer); + return gst_tizen_wl_sink_render (bsink, buffer); } static void frame_redraw_callback (void *data, struct wl_callback *callback, uint32_t time) { - GstWaylandSink *sink = data; + GstTizenWlSink *sink = data; FUNCTION; GST_LOG ("frame_redraw_cb"); @@ -1961,7 +1967,7 @@ static const struct wl_callback_listener frame_callback_listener = { #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT static void -gst_wayland_sink_update_window_geometry (GstWaylandSink * sink) +gst_tizen_wl_sink_update_window_geometry (GstTizenWlSink * sink) { FUNCTION; g_return_if_fail (sink != NULL); @@ -1995,7 +2001,7 @@ gst_wayland_sink_update_window_geometry (GstWaylandSink * sink) #endif /* must be called with the render lock */ static void -render_last_buffer (GstWaylandSink * sink) +render_last_buffer (GstTizenWlSink * sink) { GstWlBuffer *wlbuffer; const GstVideoInfo *info = NULL; @@ -2017,7 +2023,7 @@ render_last_buffer (GstWaylandSink * sink) /* 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)", + ("wl_callback_add_listener (wl_callback@%p, wl_callback_listener@%p, GstTizenWlSink@%p)", callback, &frame_callback_listener, sink); wl_callback_add_listener (callback, &frame_callback_listener, sink); @@ -2033,7 +2039,7 @@ render_last_buffer (GstWaylandSink * sink) static gboolean -gst_wayland_sink_has_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) +gst_tizen_wl_sink_has_wlbuffer (GstTizenWlSink * sink, GstBuffer * buffer) { GstWlBuffer *gstwlbuffer; FUNCTION; @@ -2042,7 +2048,7 @@ gst_wayland_sink_has_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) gstwlbuffer = gst_buffer_get_wl_buffer (buffer); if (gstwlbuffer && gstwlbuffer->display == sink->display - && !gst_wayland_sink_is_gapless (sink) + && !gst_tizen_wl_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 */ @@ -2055,7 +2061,7 @@ gst_wayland_sink_has_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) } static GstFlowReturn -gst_wayland_sink_no_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) +gst_tizen_wl_sink_no_create_wlbuffer (GstTizenWlSink * sink, GstBuffer * buffer) { GstMemory *mem; MMVideoBuffer *mm_video_buf = NULL; @@ -2067,7 +2073,7 @@ gst_wayland_sink_no_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) /* 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)) { + if (gst_is_tizen_wl_memory (mem)) { GST_LOG ("buffer(%p) is created by waylandsink has a wl_buffer, " "writing directly", buffer); } else { @@ -2076,7 +2082,7 @@ gst_wayland_sink_no_create_wlbuffer (GstWaylandSink * sink, GstBuffer * 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); + mm_video_buf = gst_tizen_wl_sink_get_mm_video_buf (buffer); if (mm_video_buf != NULL) { GST_LOG ("GstBuffer(%p) has MMVideoBuffer(%p)", buffer, mm_video_buf); } else { @@ -2089,14 +2095,14 @@ gst_wayland_sink_no_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) sink->to_render = buffer; if (sink->dump_video && !sink->display->is_native_format) - gst_wayland_sink_dump_raw_video (sink, sink->to_render, + gst_tizen_wl_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, +gst_tizen_wl_sink_create_wlbuffer_with_wl_mem (GstTizenWlSink * sink, GstBuffer * buffer) { GstMemory *mem; @@ -2108,7 +2114,7 @@ gst_wayland_sink_create_wlbuffer_with_wl_mem (GstWaylandSink * sink, 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, + gst_tizen_wl_shm_memory_construct_wl_buffer (mem, sink->display, &sink->video_info); if (wbuf) { gst_buffer_add_wl_buffer (buffer, wbuf, sink->display); @@ -2117,7 +2123,7 @@ gst_wayland_sink_create_wlbuffer_with_wl_mem (GstWaylandSink * sink, } static GstFlowReturn -gst_wayland_sink_create_wlbuffer_with_previous_plugin_tbm (GstWaylandSink * +gst_tizen_wl_sink_create_wlbuffer_with_previous_plugin_tbm (GstTizenWlSink * sink, GstBuffer * buffer) { GstMemory *mem; @@ -2134,7 +2140,7 @@ gst_wayland_sink_create_wlbuffer_with_previous_plugin_tbm (GstWaylandSink * 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)) { + if (!gst_tizen_wl_sink_get_mm_video_buf_info (sink, buffer)) { return GST_FLOW_ERROR; } @@ -2143,7 +2149,7 @@ gst_wayland_sink_create_wlbuffer_with_previous_plugin_tbm (GstWaylandSink * 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, + gst_tizen_wl_shm_memory_construct_wl_buffer (mem, sink->display, &sink->video_info); if (G_UNLIKELY (!wbuf)) { GST_ERROR ("could not create wl_buffer"); @@ -2161,12 +2167,12 @@ gst_wayland_sink_create_wlbuffer_with_previous_plugin_tbm (GstWaylandSink * } static GstFlowReturn - gst_wayland_sink_copy_input_gstbuffer_to_wl_gstbuffer_with_wl_mem - (GstWaylandSink * sink, GstBuffer * buffer) + gst_tizen_wl_sink_copy_input_gstbuffer_to_wl_gstbuffer_with_wl_mem + (GstTizenWlSink * sink, GstBuffer * buffer) { GstWlBuffer *wlbuffer; GstMemory *mem; - GstWlShmMemory *shm_mem; + GstTizenWlShmMemory *shm_mem; GstMapInfo src; struct wl_buffer *wbuf = NULL; GstFlowReturn ret = GST_FLOW_OK; @@ -2193,10 +2199,10 @@ static GstFlowReturn wlbuffer = gst_buffer_get_wl_buffer (buffer); if (G_UNLIKELY (!wlbuffer)) { mem = gst_buffer_peek_memory (sink->to_render, 0); - shm_mem = (GstWlShmMemory *) mem; + shm_mem = (GstTizenWlShmMemory *) 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, + gst_tizen_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"); @@ -2213,7 +2219,7 @@ static GstFlowReturn } static GstFlowReturn -gst_wayland_sink_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) +gst_tizen_wl_sink_create_wlbuffer (GstTizenWlSink * sink, GstBuffer * buffer) { GstMemory *mem; GstFlowReturn ret = GST_FLOW_OK; @@ -2223,24 +2229,24 @@ gst_wayland_sink_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) sink->to_render = NULL; - if (gst_wayland_sink_has_wlbuffer (sink, buffer)) { - ret = gst_wayland_sink_no_create_wlbuffer (sink, buffer); + if (gst_tizen_wl_sink_has_wlbuffer (sink, buffer)) { + ret = gst_tizen_wl_sink_no_create_wlbuffer (sink, buffer); } else { mem = gst_buffer_peek_memory (buffer, 0); - if (gst_is_wl_memory (mem)) { + if (gst_is_tizen_wl_memory (mem)) { /* SHM or TBM */ - gst_wayland_sink_create_wlbuffer_with_wl_mem (sink, buffer); + gst_tizen_wl_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, + gst_tizen_wl_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 + gst_tizen_wl_sink_copy_input_gstbuffer_to_wl_gstbuffer_with_wl_mem (sink, buffer); } } @@ -2249,7 +2255,7 @@ gst_wayland_sink_create_wlbuffer (GstWaylandSink * sink, GstBuffer * buffer) } static void -gst_wayland_sink_buffer_replace (GstWaylandSink * sink, GstBuffer * buffer) +gst_tizen_wl_sink_buffer_replace (GstTizenWlSink * sink, GstBuffer * buffer) { FUNCTION; g_return_if_fail (sink != NULL); @@ -2281,7 +2287,7 @@ gst_wayland_sink_buffer_replace (GstWaylandSink * sink, GstBuffer * buffer) } static void -gst_wayland_sink_get_window (GstWaylandSink * sink) +gst_tizen_wl_sink_get_window (GstTizenWlSink * sink) { g_return_if_fail (sink != NULL); FUNCTION; @@ -2297,15 +2303,15 @@ gst_wayland_sink_get_window (GstWaylandSink * sink) sink->window = gst_wl_window_new_toplevel (sink->display, &sink->video_info); } - gst_wayland_sink_update_window_geometry (sink); + gst_tizen_wl_sink_update_window_geometry (sink); } static GstFlowReturn -gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) +gst_tizen_wl_sink_render (GstBaseSink * bsink, GstBuffer * buffer) { #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT - GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (bsink); GstFlowReturn ret = GST_FLOW_OK; FUNCTION; @@ -2315,14 +2321,14 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) GST_OBJECT_REFCOUNT_VALUE (buffer)); /* check overlay */ - if (gst_wayland_sink_is_disabled_overlay (sink)) { + if (gst_tizen_wl_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); + gst_tizen_wl_sink_get_window (sink); } /* fakesink function for media stream callback case */ @@ -2335,11 +2341,11 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) /* drop buffers until we get a frame callback */ if (g_atomic_int_get (&sink->redraw_pending) == TRUE - && !gst_wayland_sink_is_gapless (sink)) + && !gst_tizen_wl_sink_is_gapless (sink)) goto done; /* create wl_buffer */ - ret = gst_wayland_sink_create_wlbuffer (sink, buffer); + ret = gst_tizen_wl_sink_create_wlbuffer (sink, buffer); if (ret != GST_FLOW_OK) goto done; @@ -2351,7 +2357,7 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) } /* replace last_buffer */ - gst_wayland_sink_buffer_replace (sink, buffer); + gst_tizen_wl_sink_buffer_replace (sink, buffer); /* rendering */ if (sink->visible) { @@ -2369,7 +2375,7 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) #else /* open source */ - GstWaylandSink *sink = GST_WAYLAND_SINK (bsink); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (bsink); GstBuffer *to_render = NULL; GstFlowReturn ret = GST_FLOW_OK; @@ -2391,7 +2397,7 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) /* drop buffers until we get a frame callback */ if (g_atomic_int_get (&sink->redraw_pending) == TRUE - && !gst_wayland_sink_is_gapless (sink)) + && !gst_tizen_wl_sink_is_gapless (sink)) goto done; /* make sure that the application has called set_render_rectangle() */ @@ -2417,7 +2423,7 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * 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, + wbuf = gst_tizen_wl_shm_memory_construct_wl_buffer (mem, sink->display, &sink->video_info); } if (wbuf) { @@ -2448,7 +2454,7 @@ gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer) 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, + wbuf = gst_tizen_wl_shm_memory_construct_wl_buffer (mem, sink->display, &sink->video_info); if (G_UNLIKELY (!wbuf)) goto no_wl_buffer; @@ -2512,24 +2518,24 @@ done: } static void -gst_wayland_sink_videooverlay_init (GstVideoOverlayInterface * iface) +gst_tizen_wl_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; + iface->set_window_handle = gst_tizen_wl_sink_set_window_handle; + iface->set_render_rectangle = gst_tizen_wl_sink_set_render_rectangle; + iface->expose = gst_tizen_wl_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; + gst_tizen_wl_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, +gst_tizen_wl_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay, guintptr wl_surface_id) { - GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (overlay); FUNCTION; g_return_if_fail (sink != NULL); @@ -2544,7 +2550,7 @@ gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay, (guintptr) wl_surface_id); if (wl_surface_id) { - if (G_LIKELY (gst_wayland_sink_find_display (sink))) { + if (G_LIKELY (gst_tizen_wl_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; @@ -2561,9 +2567,9 @@ gst_wayland_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay, #endif static void -gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) +gst_tizen_wl_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) { - GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (overlay); struct wl_surface *surface = (struct wl_surface *) handle; FUNCTION; @@ -2583,7 +2589,7 @@ gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) g_clear_object (&sink->window); if (handle) { - if (G_LIKELY (gst_wayland_sink_find_display (sink))) { + if (G_LIKELY (gst_tizen_wl_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, @@ -2604,10 +2610,10 @@ gst_wayland_sink_set_window_handle (GstVideoOverlay * overlay, guintptr handle) } static void -gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay, +gst_tizen_wl_sink_set_render_rectangle (GstVideoOverlay * overlay, gint x, gint y, gint w, gint h) { - GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (overlay); FUNCTION; g_return_if_fail (sink != NULL); @@ -2625,15 +2631,15 @@ gst_wayland_sink_set_render_rectangle (GstVideoOverlay * overlay, 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); + gst_tizen_wl_sink_update_last_buffer_geometry (sink); } g_mutex_unlock (&sink->render_lock); } static void -gst_wayland_sink_expose (GstVideoOverlay * overlay) +gst_tizen_wl_sink_expose (GstVideoOverlay * overlay) { - GstWaylandSink *sink = GST_WAYLAND_SINK (overlay); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (overlay); FUNCTION; g_return_if_fail (sink != NULL); @@ -2647,18 +2653,19 @@ gst_wayland_sink_expose (GstVideoOverlay * overlay) } g_mutex_unlock (&sink->render_lock); } + #if 0 static void -gst_wayland_sink_waylandvideo_init (GstWaylandVideoInterface * iface) +gst_tizen_wl_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; + iface->begin_geometry_change = gst_tizen_wl_sink_begin_geometry_change; + iface->end_geometry_change = gst_tizen_wl_sink_end_geometry_change; } static void -gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video) +gst_tizen_wl_sink_begin_geometry_change (GstWaylandVideo * video) { - GstWaylandSink *sink = GST_WAYLAND_SINK (video); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (video); FUNCTION; g_return_if_fail (sink != NULL); @@ -2675,9 +2682,9 @@ gst_wayland_sink_begin_geometry_change (GstWaylandVideo * video) } static void -gst_wayland_sink_end_geometry_change (GstWaylandVideo * video) +gst_tizen_wl_sink_end_geometry_change (GstWaylandVideo * video) { - GstWaylandSink *sink = GST_WAYLAND_SINK (video); + GstTizenWlSink *sink = GST_TIZEN_WL_SINK (video); FUNCTION; g_return_if_fail (sink != NULL); @@ -2697,13 +2704,13 @@ gst_wayland_sink_end_geometry_change (GstWaylandVideo * video) static gboolean plugin_init (GstPlugin * plugin) { - GST_DEBUG_CATEGORY_INIT (gstwayland_debug, "tizenwlsink", 0, + GST_DEBUG_CATEGORY_INIT (gst_tizen_wl_debug, "tizenwlsink", 0, " tizen wayland video sink"); - gst_wl_shm_allocator_register (); + gst_tizen_wl_shm_allocator_register (); return gst_element_register (plugin, "tizenwlsink", GST_RANK_MARGINAL, - GST_TYPE_WAYLAND_SINK); + GST_TYPE_TIZEN_WL_SINK); } GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, diff --git a/tizenwlsink/src/gstwaylandsink.h b/tizenwlsink/src/gsttizenwlsink.h similarity index 74% rename from tizenwlsink/src/gstwaylandsink.h rename to tizenwlsink/src/gsttizenwlsink.h index 58c1e11..215bbb4 100644 --- a/tizenwlsink/src/gstwaylandsink.h +++ b/tizenwlsink/src/gsttizenwlsink.h @@ -19,8 +19,8 @@ * Boston, MA 02110-1301 USA. */ -#ifndef __GST_WAYLAND_VIDEO_SINK_H__ -#define __GST_WAYLAND_VIDEO_SINK_H__ +#ifndef __GST_TIZEN_WL_VIDEO_SINK_H__ +#define __GST_TIZEN_WL_VIDEO_SINK_H__ #include #include @@ -31,18 +31,18 @@ #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)) +#define GST_TYPE_TIZEN_WL_SINK \ + (gst_tizen_wl_sink_get_type()) +#define GST_TIZEN_WL_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_TIZEN_WL_SINK,GstTizenWlSink)) +#define GST_TIZEN_WL_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_TIZEN_WL_SINK,GstTizenWlSinkClass)) +#define GST_IS_TIZEN_WL_SINK(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_TIZEN_WL_SINK)) +#define GST_IS_TIZEN_WL_SINK_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_TIZEN_WL_SINK)) +#define GST_TIZEN_WL_SINK_GET_CLASS(inst) \ + (G_TYPE_INSTANCE_GET_CLASS ((inst), GST_TYPE_TIZEN_WL_SINK, GstTizenWlSinkClass)) #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT enum { @@ -60,10 +60,10 @@ enum #define DEFAULT_DUMP_COUNT 10 #endif -typedef struct _GstWaylandSink GstWaylandSink; -typedef struct _GstWaylandSinkClass GstWaylandSinkClass; +typedef struct _GstTizenWlSink GstTizenWlSink; +typedef struct _GstTizenWlSinkClass GstTizenWlSinkClass; -struct _GstWaylandSink +struct _GstTizenWlSink { GstVideoSink parent; @@ -112,7 +112,7 @@ struct _GstWaylandSink #endif }; -struct _GstWaylandSinkClass +struct _GstTizenWlSinkClass { GstVideoSinkClass parent; #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT @@ -123,8 +123,8 @@ struct _GstWaylandSinkClass }; GType -gst_wayland_sink_get_type (void) +gst_tizen_wl_sink_get_type (void) G_GNUC_CONST; G_END_DECLS -#endif /* __GST_WAYLAND_VIDEO_SINK_H__ */ +#endif /* __GST_TIZEN_WL_VIDEO_SINK_H__ */ diff --git a/tizenwlsink/src/wlshmallocator.c b/tizenwlsink/src/tizen-wlshmallocator.c similarity index 85% rename from tizenwlsink/src/wlshmallocator.c rename to tizenwlsink/src/tizen-wlshmallocator.c index 81e2cfd..b6495d2 100644 --- a/tizenwlsink/src/wlshmallocator.c +++ b/tizenwlsink/src/tizen-wlshmallocator.c @@ -20,7 +20,7 @@ * Boston, MA 02110-1301, USA. */ -#include "wlshmallocator.h" +#include "tizen-wlshmallocator.h" #include "wlvideoformat.h" #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT #include "tizen-wlvideoformat.h" @@ -34,13 +34,14 @@ #include #include -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +GST_DEBUG_CATEGORY_EXTERN (gst_tizen_wl_debug); +#define GST_CAT_DEFAULT gst_tizen_wl_debug -G_DEFINE_TYPE (GstWlShmAllocator, gst_wl_shm_allocator, GST_TYPE_ALLOCATOR); +G_DEFINE_TYPE (GstTizenWlShmAllocator, gst_tizen_wl_shm_allocator, + GST_TYPE_ALLOCATOR); gint -gst_wl_fwrite_data (gchar * file, gpointer data, guint size) +gst_tizen_wl_fwrite_data (gchar * file, gpointer data, guint size) { FILE *fp; @@ -55,8 +56,8 @@ gst_wl_fwrite_data (gchar * file, gpointer data, guint size) } static void -gst_wl_tbm_dump_normal_raw_video (gpointer bo, guint size, guint dump_count, - guint dump_total) +gst_tizen_wl_tbm_dump_normal_raw_video (gpointer bo, guint size, + guint dump_count, guint dump_total) { tbm_bo_handle virtual_addr; gint ret; @@ -73,7 +74,7 @@ gst_wl_tbm_dump_normal_raw_video (gpointer bo, guint size, guint dump_count, 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); + ret = gst_tizen_wl_fwrite_data (file_name, virtual_addr.ptr, size); if (ret) { GST_ERROR ("_write_rawdata() failed"); } @@ -81,7 +82,8 @@ gst_wl_tbm_dump_normal_raw_video (gpointer bo, guint size, guint dump_count, } static void -gst_wl_tbm_dump_native_raw_video (GstWlDisplay * display, guint dump_count) +gst_tizen_wl_tbm_dump_native_raw_video (GstWlDisplay * display, + guint dump_count) { gchar file_name[128]; gchar err_str[256]; @@ -144,16 +146,16 @@ gst_wl_tbm_dump_native_raw_video (GstWlDisplay * display, guint dump_count) } static GstMemory * -gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, +gst_tizen_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, GstAllocationParams * params) { - GstWlShmAllocator *self = GST_WL_SHM_ALLOCATOR (allocator); + GstTizenWlShmAllocator *self = GST_TIZEN_WL_SHM_ALLOCATOR (allocator); char filename[1024]; static int init = 0; int fd; int idx; gpointer data; - GstWlShmMemory *mem; + GstTizenWlShmMemory *mem; gchar err_str[256]; FUNCTION; @@ -189,7 +191,7 @@ gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, return FALSE; } - mem = g_slice_new0 (GstWlShmMemory); + mem = g_slice_new0 (GstTizenWlShmMemory); gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL, size, 0, 0, size); mem->data = virtual_addr.ptr; @@ -228,7 +230,7 @@ gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, unlink (filename); - mem = g_slice_new0 (GstWlShmMemory); + mem = g_slice_new0 (GstTizenWlShmMemory); gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL, size, 0, 0, size); mem->data = data; @@ -265,7 +267,7 @@ gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, unlink (filename); - mem = g_slice_new0 (GstWlShmMemory); + mem = g_slice_new0 (GstTizenWlShmMemory); gst_memory_init ((GstMemory *) mem, GST_MEMORY_FLAG_NO_SHARE, allocator, NULL, size, 0, 0, size); mem->data = data; @@ -276,85 +278,85 @@ gst_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, } static void -gst_wl_shm_allocator_free (GstAllocator * allocator, GstMemory * memory) +gst_tizen_wl_shm_allocator_free (GstAllocator * allocator, GstMemory * memory) { - GstWlShmMemory *shm_mem = (GstWlShmMemory *) memory; + GstTizenWlShmMemory *shm_mem = (GstTizenWlShmMemory *) 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); + g_slice_free (GstTizenWlShmMemory, shm_mem); } static gpointer -gst_wl_shm_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) +gst_tizen_wl_shm_mem_map (GstMemory * mem, gsize maxsize, GstMapFlags flags) { FUNCTION; - return ((GstWlShmMemory *) mem)->data; + return ((GstTizenWlShmMemory *) mem)->data; } static void -gst_wl_shm_mem_unmap (GstMemory * mem) +gst_tizen_wl_shm_mem_unmap (GstMemory * mem) { } static void -gst_wl_shm_allocator_class_init (GstWlShmAllocatorClass * klass) +gst_tizen_wl_shm_allocator_class_init (GstTizenWlShmAllocatorClass * 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); + alloc_class->alloc = GST_DEBUG_FUNCPTR (gst_tizen_wl_shm_allocator_alloc); + alloc_class->free = GST_DEBUG_FUNCPTR (gst_tizen_wl_shm_allocator_free); } static void -gst_wl_shm_allocator_init (GstWlShmAllocator * self) +gst_tizen_wl_shm_allocator_init (GstTizenWlShmAllocator * 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; + self->parent_instance.mem_type = GST_ALLOCATOR_TIZEN_WL_SHM; + self->parent_instance.mem_map = gst_tizen_wl_shm_mem_map; + self->parent_instance.mem_unmap = gst_tizen_wl_shm_mem_unmap; GST_OBJECT_FLAG_SET (self, GST_ALLOCATOR_FLAG_CUSTOM_ALLOC); } void -gst_wl_shm_allocator_register (void) +gst_tizen_wl_shm_allocator_register (void) { FUNCTION; - gst_allocator_register (GST_ALLOCATOR_WL_SHM, - g_object_new (GST_TYPE_WL_SHM_ALLOCATOR, NULL)); + gst_allocator_register (GST_ALLOCATOR_TIZEN_WL_SHM, + g_object_new (GST_TYPE_TIZEN_WL_SHM_ALLOCATOR, NULL)); } GstAllocator * -gst_wl_shm_allocator_get (void) +gst_tizen_wl_shm_allocator_get (void) { FUNCTION; - return gst_allocator_find (GST_ALLOCATOR_WL_SHM); + return gst_allocator_find (GST_ALLOCATOR_TIZEN_WL_SHM); } gboolean gst_is_wl_shm_memory (GstMemory * mem) { FUNCTION; - return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM); + return gst_memory_is_type (mem, GST_ALLOCATOR_TIZEN_WL_SHM); } gboolean -gst_is_wl_memory (GstMemory * mem) +gst_is_tizen_wl_memory (GstMemory * mem) { FUNCTION; - return gst_memory_is_type (mem, GST_ALLOCATOR_WL_SHM); + return gst_memory_is_type (mem, GST_ALLOCATOR_TIZEN_WL_SHM); } struct wl_buffer * -gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, - const GstVideoInfo * info) +gst_tizen_wl_shm_memory_construct_wl_buffer (GstMemory * mem, + GstWlDisplay * display, const GstVideoInfo * info) { - GstWlShmMemory *shm_mem = (GstWlShmMemory *) mem; + GstTizenWlShmMemory *shm_mem = (GstTizenWlShmMemory *) mem; gint width, height, stride; gsize size; gint plane_size[GST_VIDEO_MAX_PLANES], n_planes, i; @@ -371,7 +373,7 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, 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++); + gst_tizen_wl_tbm_dump_native_raw_video (display, display->dump_count++); width = display->width[0]; height = display->height[0]; @@ -429,7 +431,7 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, 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 (gst_is_tizen_wl_memory (mem), NULL); g_return_val_if_fail (size <= mem->size, NULL); g_return_val_if_fail (shm_mem->fd != -1, NULL); @@ -437,7 +439,7 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, 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, + gst_tizen_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; @@ -498,7 +500,7 @@ gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display, 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 (gst_is_tizen_wl_memory (mem), NULL); g_return_val_if_fail (size <= mem->size, NULL); g_return_val_if_fail (shm_mem->fd != -1, NULL); diff --git a/tizenwlsink/src/tizen-wlshmallocator.h b/tizenwlsink/src/tizen-wlshmallocator.h new file mode 100644 index 0000000..3acbcc8 --- /dev/null +++ b/tizenwlsink/src/tizen-wlshmallocator.h @@ -0,0 +1,80 @@ +/* GStreamer Wayland video sink + * + * Copyright (C) 2012 Intel Corporation + * Copyright (C) 2012 Sreerenj Balachandran + * 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_TIZEN_WL_SHM_ALLOCATOR_H__ +#define __GST_TIZEN_WL_SHM_ALLOCATOR_H__ + +#include +#include "wldisplay.h" + +G_BEGIN_DECLS +#define GST_TYPE_TIZEN_WL_SHM_ALLOCATOR (gst_tizen_wl_shm_allocator_get_type ()) +#define GST_TIZEN_WL_SHM_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_TIZEN_WL_SHM_ALLOCATOR, GstTizenWlShmAllocator)) +#define GST_IS_TIZEN_WL_SHM_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_TIZEN_WL_SHM_ALLOCATOR)) +#define GST_TIZEN_WL_SHM_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_TIZEN_WL_SHM_ALLOCATOR, GstTizenWlShmAllocatorClass)) +#define GST_IS_TIZEN_WL_SHM_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_TIZEN_WL_SHM_ALLOCATOR)) +#define GST_TIZEN_WL_SHM_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_TIZEN_WL_SHM_ALLOCATOR, GstTizenWlShmAllocatorClass)) +#define GST_ALLOCATOR_TIZEN_WL_SHM "tizen_wl_shm" + +typedef struct _GstTizenWlShmMemory GstTizenWlShmMemory; +typedef struct _GstTizenWlShmAllocator GstTizenWlShmAllocator; +typedef struct _GstTizenWlShmAllocatorClass GstTizenWlShmAllocatorClass; + +struct _GstTizenWlShmMemory +{ + GstMemory parent; + + gpointer data; + gint fd; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + gpointer tbm_bo_ptr; +#endif +}; + +struct _GstTizenWlShmAllocator +{ + GstAllocator parent_instance; +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + GstWlDisplay *display; +#endif +}; + +struct _GstTizenWlShmAllocatorClass +{ + GstAllocatorClass parent_class; +}; + +GType gst_tizen_wl_shm_allocator_get_type (void); + +void gst_tizen_wl_shm_allocator_register (void); +GstAllocator *gst_tizen_wl_shm_allocator_get (void); + +gboolean gst_is_tizen_wl_shm_memory (GstMemory * mem); +struct wl_buffer *gst_tizen_wl_shm_memory_construct_wl_buffer (GstMemory * mem, + GstWlDisplay * display, const GstVideoInfo * info); + +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT +gint gst_tizen_wl_fwrite_data (gchar * file, gpointer data, guint size); +gboolean gst_is_tizen_wl_memory (GstMemory * mem); +#endif +G_END_DECLS +#endif /* __GST_TIZEN_WL_SHM_ALLOCATOR_H__ */ diff --git a/tizenwlsink/src/tizen-wlvideoformat.c b/tizenwlsink/src/tizen-wlvideoformat.c index 8ebf505..e4d8a81 100644 --- a/tizenwlsink/src/tizen-wlvideoformat.c +++ b/tizenwlsink/src/tizen-wlvideoformat.c @@ -27,8 +27,8 @@ #include "tizen-wlvideoformat.h" #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +GST_DEBUG_CATEGORY_EXTERN (gst_tizen_wl_debug); +#define GST_CAT_DEFAULT gst_tizen_wl_debug typedef struct { diff --git a/tizenwlsink/src/tizen-wlvideoformat.h b/tizenwlsink/src/tizen-wlvideoformat.h old mode 100755 new mode 100644 diff --git a/tizenwlsink/src/wlbuffer.c b/tizenwlsink/src/wlbuffer.c index c37e61e..55b7162 100644 --- a/tizenwlsink/src/wlbuffer.c +++ b/tizenwlsink/src/wlbuffer.c @@ -78,8 +78,8 @@ #include "wlbuffer.h" -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +GST_DEBUG_CATEGORY_EXTERN (gst_tizen_wl_debug); +#define GST_CAT_DEFAULT gst_tizen_wl_debug G_DEFINE_TYPE (GstWlBuffer, gst_wl_buffer, G_TYPE_OBJECT); diff --git a/tizenwlsink/src/wldisplay.c b/tizenwlsink/src/wldisplay.c index 7e9e39e..ac058c2 100644 --- a/tizenwlsink/src/wldisplay.c +++ b/tizenwlsink/src/wldisplay.c @@ -53,8 +53,8 @@ static const struct tizen_video_listener tizen_video_listener = { }; #endif -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +GST_DEBUG_CATEGORY_EXTERN (gst_tizen_wl_debug); +#define GST_CAT_DEFAULT gst_tizen_wl_debug G_DEFINE_TYPE (GstWlDisplay, gst_wl_display, G_TYPE_OBJECT); diff --git a/tizenwlsink/src/wlshmallocator.h b/tizenwlsink/src/wlshmallocator.h deleted file mode 100644 index 9f111d3..0000000 --- a/tizenwlsink/src/wlshmallocator.h +++ /dev/null @@ -1,79 +0,0 @@ -/* GStreamer Wayland video sink - * - * Copyright (C) 2012 Intel Corporation - * Copyright (C) 2012 Sreerenj Balachandran - * 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 -#include "wldisplay.h" - -G_BEGIN_DECLS -#define GST_TYPE_WL_SHM_ALLOCATOR (gst_wl_shm_allocator_get_type ()) -#define GST_WL_SHM_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocator)) -#define GST_IS_WL_SHM_ALLOCATOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GST_TYPE_WL_SHM_ALLOCATOR)) -#define GST_WL_SHM_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass)) -#define GST_IS_WL_SHM_ALLOCATOR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GST_TYPE_WL_SHM_ALLOCATOR)) -#define GST_WL_SHM_ALLOCATOR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GST_TYPE_WL_SHM_ALLOCATOR, GstWlShmAllocatorClass)) -#define GST_ALLOCATOR_WL_SHM "wl_shm" -typedef struct _GstWlShmMemory GstWlShmMemory; -typedef struct _GstWlShmAllocator GstWlShmAllocator; -typedef struct _GstWlShmAllocatorClass GstWlShmAllocatorClass; - -struct _GstWlShmMemory -{ - GstMemory parent; - - gpointer data; - gint fd; -#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT - gpointer tbm_bo_ptr; -#endif -}; - -struct _GstWlShmAllocator -{ - GstAllocator parent_instance; -#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT - GstWlDisplay *display; -#endif -}; - -struct _GstWlShmAllocatorClass -{ - GstAllocatorClass parent_class; -}; - -GType gst_wl_shm_allocator_get_type (void); - -void gst_wl_shm_allocator_register (void); -GstAllocator *gst_wl_shm_allocator_get (void); - -gboolean gst_is_wl_shm_memory (GstMemory * mem); -struct wl_buffer *gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, - GstWlDisplay * display, const GstVideoInfo * info); - -#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT -gint gst_wl_fwrite_data (gchar * file, gpointer data, guint size); -gboolean gst_is_wl_memory (GstMemory * mem); -#endif -G_END_DECLS -#endif /* __GST_WL_SHM_ALLOCATOR_H__ */ diff --git a/tizenwlsink/src/wlvideoformat.c b/tizenwlsink/src/wlvideoformat.c index 59e9c95..a4f57a7 100644 --- a/tizenwlsink/src/wlvideoformat.c +++ b/tizenwlsink/src/wlvideoformat.c @@ -26,8 +26,8 @@ #include "wlvideoformat.h" -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +GST_DEBUG_CATEGORY_EXTERN (gst_tizen_wl_debug); +#define GST_CAT_DEFAULT gst_tizen_wl_debug #define FUNCTION GST_LOG ("") typedef struct { diff --git a/tizenwlsink/src/wlwindow.c b/tizenwlsink/src/wlwindow.c index c8d8366..1a44092 100644 --- a/tizenwlsink/src/wlwindow.c +++ b/tizenwlsink/src/wlwindow.c @@ -24,15 +24,15 @@ #include #endif #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT -#include "gstwaylandsink.h" +#include "gsttizenwlsink.h" #else #include "wlwindow.h" #endif -#include "wlshmallocator.h" +#include "tizen-wlshmallocator.h" #include "wlbuffer.h" -GST_DEBUG_CATEGORY_EXTERN (gstwayland_debug); -#define GST_CAT_DEFAULT gstwayland_debug +GST_DEBUG_CATEGORY_EXTERN (gst_tizen_wl_debug); +#define GST_CAT_DEFAULT gst_tizen_wl_debug G_DEFINE_TYPE (GstWlWindow, gst_wl_window, G_TYPE_OBJECT); @@ -128,23 +128,25 @@ gst_wl_window_map_sub_surface (GstWlDisplay * display, GstWlWindow * window, GstMapInfo mapinfo; struct wl_buffer *wlbuf; GstWlBuffer *gwlbuf; - GstWlShmAllocator *self = NULL; + GstTizenWlShmAllocator *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 = GST_TIZEN_WL_SHM_ALLOCATOR (gst_tizen_wl_shm_allocator_get ()); self->display = display; - buf = gst_buffer_new_allocate (gst_wl_shm_allocator_get (), info->size, NULL); + buf = + gst_buffer_new_allocate (gst_tizen_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); + gst_tizen_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); @@ -322,13 +324,15 @@ gst_wl_window_new_internal (GstWlDisplay * display) 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); + buf = + gst_buffer_new_allocate (gst_tizen_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); + gst_tizen_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); -- 2.7.4 From 0c36c3275a0f7dc8c3d2886c18acf7c8734b6f1a Mon Sep 17 00:00:00 2001 From: Sejun Park Date: Fri, 17 Nov 2017 14:18:11 +0900 Subject: [PATCH 06/16] fixed svace issues Change-Id: If62e7e710f15410eab88735015301c21a418c22b --- video360/src/gstvideo360-gl.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/video360/src/gstvideo360-gl.c b/video360/src/gstvideo360-gl.c index 1b0c26d..123a897 100644 --- a/video360/src/gstvideo360-gl.c +++ b/video360/src/gstvideo360-gl.c @@ -96,7 +96,7 @@ gst_video360_init_gl (GstVideo360 * this) #ifdef GST_TIZEN_GL_PLATFORM_EGL #ifdef GST_TIZEN_USE_EGLIMAGE - if (strstr ((const char *) string, "GL_OES_EGL_image_external")) { + if (string && strstr ((const char *) string, "GL_OES_EGL_image_external")) { /* We need GL_OES_EGL_image_external extension which introduces new texture * target TEXTURE_EXTERNAL_OES. * GL_OES_EGL_image introduces the same call but for TEXTURE_2D target only. @@ -291,7 +291,7 @@ _init_gl_platform (GstVideo360 * this) GST_INFO ("EGL extensions supported: %s", string); #ifdef GST_TIZEN_USE_EGLIMAGE - if (!strstr (string, "EGL_TIZEN_image_native_surface")) { + if (!string || !strstr (string, "EGL_TIZEN_image_native_surface")) { GST_ERROR ("EGL_TIZEN_image_native_surface isn't supported"); return FALSE; } -- 2.7.4 From 08ca6d522cd066d9c8780f8a5f4686862a7d1978 Mon Sep 17 00:00:00 2001 From: Hyunil Date: Tue, 21 Nov 2017 15:26:50 +0900 Subject: [PATCH 07/16] tizenwlsink : restrict use of wayland buffer pool Change-Id: I9924c6322f1feda3b27f296534d43ffee3dac4ee Signed-off-by: Hyunil --- tizenwlsink/src/gsttizenwlsink.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tizenwlsink/src/gsttizenwlsink.c b/tizenwlsink/src/gsttizenwlsink.c index b693718..0dc1473 100644 --- a/tizenwlsink/src/gsttizenwlsink.c +++ b/tizenwlsink/src/gsttizenwlsink.c @@ -1905,6 +1905,9 @@ gst_tizen_wl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) if (sink->display->is_native_format == TRUE) return FALSE; + if (!gst_wl_window_is_toplevel (sink->window)) + return FALSE; + gst_query_parse_allocation (query, &caps, &need_pool); if (caps == NULL) { -- 2.7.4 From 7ec4621a1017b46c8647bc0298a8a4c5da27609d Mon Sep 17 00:00:00 2001 From: Hyunil Date: Thu, 23 Nov 2017 17:17:45 +0900 Subject: [PATCH 08/16] tizenwlsink: fix g_assert issue and modify gstbuffer for flush_buffer destroy process Change-Id: I61ea99db8186c38bd0e1f6b2ff95c3e07e1978d1 Signed-off-by: Hyunil --- tizenwlsink/src/gsttizenwlsink.c | 2 -- tizenwlsink/src/wlbuffer.c | 29 ++++++++--------------------- 2 files changed, 8 insertions(+), 23 deletions(-) diff --git a/tizenwlsink/src/gsttizenwlsink.c b/tizenwlsink/src/gsttizenwlsink.c index 0dc1473..6f9d16e 100644 --- a/tizenwlsink/src/gsttizenwlsink.c +++ b/tizenwlsink/src/gsttizenwlsink.c @@ -2271,8 +2271,6 @@ gst_tizen_wl_sink_buffer_replace (GstTizenWlSink * sink, GstBuffer * 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, diff --git a/tizenwlsink/src/wlbuffer.c b/tizenwlsink/src/wlbuffer.c index 55b7162..af4de87 100644 --- a/tizenwlsink/src/wlbuffer.c +++ b/tizenwlsink/src/wlbuffer.c @@ -174,20 +174,13 @@ buffer_release (void *data, struct wl_buffer *wl_buffer) #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); + 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 from pool..so is kept by bufferpool :: gstbuffer(%p), ref_count(%d)", + self->gstbuffer, GST_OBJECT_REFCOUNT_VALUE (self->gstbuffer)); } #else gst_buffer_unref (self->gstbuffer); @@ -210,13 +203,7 @@ gstbuffer_disposed (GstWlBuffer * self) /* 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); + g_object_unref (self); } GstWlBuffer * -- 2.7.4 From 3e16a545d0f05e8299f7db488591febaf8c2b60e Mon Sep 17 00:00:00 2001 From: Hyunil Date: Tue, 28 Nov 2017 14:39:04 +0900 Subject: [PATCH 09/16] tizenwlsink: fix SVACE issue (strerror) Signed-off-by: Hyunil Change-Id: I59f6a31f6300901766b98e8c0ca5a1b18ac7d07e --- tizenwlsink/src/tizen-wlshmallocator.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/tizenwlsink/src/tizen-wlshmallocator.c b/tizenwlsink/src/tizen-wlshmallocator.c index b6495d2..de5e516 100644 --- a/tizenwlsink/src/tizen-wlshmallocator.c +++ b/tizenwlsink/src/tizen-wlshmallocator.c @@ -211,19 +211,22 @@ gst_tizen_wl_shm_allocator_alloc (GstAllocator * allocator, gsize size, fd = g_mkstemp (filename); if (fd < 0) { - GST_ERROR_OBJECT (self, "opening temp file %s failed: %s", filename, - strerror (errno)); + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR_OBJECT (self, "opening temp file %s failed: %s(%d)", filename, + err_str, errno); return NULL; } if (ftruncate (fd, size) < 0) { - GST_ERROR_OBJECT (self, "ftruncate failed: %s", strerror (errno)); + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR_OBJECT (self, "ftruncate failed: %s(%d)", err_str, 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)); + strerror_r (errno, err_str, sizeof (err_str)); + GST_ERROR_OBJECT (self, "mmap failed: %s(%d)", err_str, errno); close (fd); return NULL; } -- 2.7.4 From 567f1c0f84508bb39509d477a445e0e2fde479a9 Mon Sep 17 00:00:00 2001 From: Hyunsoo Park Date: Mon, 4 Dec 2017 19:03:06 +0900 Subject: [PATCH 10/16] Remove GstNetSim in alfec plugin. GstNetSim plugins goes to gst-plugins-bad. So it is duplicated gst-plugins-tizen and gst-plugins-bad. So i removed GstNetSim in gst-plugins-tizen. Change-Id: I7e9c633bfcdcc84e0562a575b7689f7a530e8164 Signed-off-by: Hyunsoo Park --- alfec/Makefile.am | 6 +- alfec/gstalfec.c | 4 - alfec/gstnetsim.c | 415 --------------------------------------- alfec/gstnetsim.h | 72 ------- packaging/gst-plugins-tizen.spec | 2 +- 5 files changed, 3 insertions(+), 496 deletions(-) delete mode 100755 alfec/gstnetsim.c delete mode 100755 alfec/gstnetsim.h diff --git a/alfec/Makefile.am b/alfec/Makefile.am index f74c1c8..92e53d4 100755 --- a/alfec/Makefile.am +++ b/alfec/Makefile.am @@ -6,8 +6,7 @@ libgstalfec_la_SOURCES = gstalfec.c \ gst_source_blocking_algorithm.c \ gstalfecencaps.c \ gst_source_deblocking_algorithm.c \ - gstalfecdecaps.c \ - gstnetsim.c + gstalfecdecaps.c libgstalfec_la_SOURCES += feccodes/FECCodes.c \ feccodes/FecEncoder.c \ @@ -30,8 +29,7 @@ noinst_HEADERS = gstalfecencoder.h \ gst_source_blocking_algorithm.h \ gstalfecencaps.h \ gst_source_deblocking_algorithm.h \ - gstalfecdecaps.h \ - gstnetsim.h + gstalfecdecaps.h noinst_HEADERS += feccodes/include/FECCodes.h \ feccodes/include/FecEncoder.h \ diff --git a/alfec/gstalfec.c b/alfec/gstalfec.c index e6391da..104831b 100755 --- a/alfec/gstalfec.c +++ b/alfec/gstalfec.c @@ -50,7 +50,6 @@ #include "gstalfecencoder.h" #include "gstalfecdecoder.h" -#include "gstnetsim.h" static gboolean @@ -60,9 +59,6 @@ plugin_init (GstPlugin * plugin) return FALSE; if (!gst_element_register (plugin, "alfecdecoder", GST_RANK_NONE, GST_TYPE_AL_FEC_DECODER)) return FALSE; - if (!gst_element_register (plugin, "netsim", GST_RANK_MARGINAL, GST_TYPE_NET_SIM)) - return FALSE; - return TRUE; } diff --git a/alfec/gstnetsim.c b/alfec/gstnetsim.c deleted file mode 100755 index ca3354b..0000000 --- a/alfec/gstnetsim.c +++ /dev/null @@ -1,415 +0,0 @@ -/* - * Farsight Voice+Video library - * - * Copyright 2006 Collabora Ltd, - * Copyright 2006 Nokia Corporation - * @author: Philippe Kalaf . - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include -#include "gstnetsim.h" - -GST_DEBUG_CATEGORY_STATIC (netsim_debug); -#define GST_CAT_DEFAULT (netsim_debug) - -#define gst_net_sim_parent_class parent_class -/* NetSim signals and args */ -enum -{ - /* FILL ME */ - LAST_SIGNAL -}; - -enum -{ - ARG_0, - ARG_MIN_DELAY, - ARG_MAX_DELAY, - ARG_DELAY_PROBABILITY, - ARG_DROP_PROBABILITY, - ARG_DUPLICATE_PROBABILITY -}; - -struct _GstNetSimPrivate -{ - GstPad *sinkpad, *srcpad; - - GMainLoop *main_loop; - GMainContext *main_context; - GRand *rand_seed; - gint min_delay; - gint max_delay; - gfloat delay_probability; - gfloat drop_probability; - gfloat duplicate_probability; -}; - -typedef struct -{ - GstNetSim *netsim; - GstBuffer *buffer; -} SourceInfo; - -/* these numbers are nothing but wild guesses and dont reflect any reality */ -#define DEFAULT_MIN_DELAY 200 -#define DEFAULT_MAX_DELAY 400 -#define DEFAULT_DELAY_PROBABILITY 0.5 -#define DEFAULT_DROP_PROBABILITY 0.2 -#define DEFAULT_DUPLICATE_PROBABILITY 0.1 - -#define GST_NET_SIM_GET_PRIVATE(o) \ - (G_TYPE_INSTANCE_GET_PRIVATE ((o), GST_TYPE_NET_SIM, \ - GstNetSimPrivate)) - -static GstStaticPadTemplate gst_net_sim_sink_template = -GST_STATIC_PAD_TEMPLATE ("sink", - GST_PAD_SINK, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY -); - -static GstStaticPadTemplate gst_net_sim_src_template = -GST_STATIC_PAD_TEMPLATE ("src", - GST_PAD_SRC, - GST_PAD_ALWAYS, - GST_STATIC_CAPS_ANY -); - -static void gst_net_sim_set_property (GObject *object, - guint prop_id, const GValue * value, GParamSpec * pspec); -static void gst_net_sim_get_property (GObject *object, - guint prop_id, GValue *value, GParamSpec *pspec); -/* static void gst_net_sim_dispose (GObject *object); */ - -static gboolean -gst_net_sim_src_activate_push (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active); - -static GstStateChangeReturn gst_net_sim_change_state ( - GstElement *element, GstStateChange transition); -static GstFlowReturn gst_net_sim_chain (GstPad *pad, - GstObject *parent, GstBuffer *buffer); -static void gst_net_sim_loop (GstNetSim *netsim); - - -G_DEFINE_TYPE_WITH_CODE (GstNetSim, gst_net_sim, GST_TYPE_ELEMENT, NULL); - -static void -gst_net_sim_class_init (GstNetSimClass *klass) -{ - GObjectClass *gobject_class; - GstElementClass *gstelement_class; - - gobject_class = (GObjectClass *) klass; - gstelement_class = (GstElementClass *) klass; - - gobject_class->set_property = gst_net_sim_set_property; - gobject_class->get_property = gst_net_sim_get_property; - - g_object_class_install_property (gobject_class, ARG_MIN_DELAY, - g_param_spec_int ("min_delay", - "Minimum delay (ms)", - "The minimum delay in ms to apply to buffers", - G_MININT, G_MAXINT, DEFAULT_MIN_DELAY, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, ARG_MAX_DELAY, - g_param_spec_int ("max_delay", - "Maximum delay (ms)", - "The maximum delay in ms to apply to buffers", - G_MININT, G_MAXINT, DEFAULT_MAX_DELAY, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - ARG_DELAY_PROBABILITY, g_param_spec_float ("delay_probability", - "Delay Probability", - "The Probability a buffer is delayed", 0.0, 1.0, - DEFAULT_DELAY_PROBABILITY, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - ARG_DROP_PROBABILITY, g_param_spec_float ("drop_probability", - "Drop Probability", - "The Probability a buffer is dropped", 0.0, 1.0, - DEFAULT_DROP_PROBABILITY, G_PARAM_READWRITE)); - - g_object_class_install_property (gobject_class, - ARG_DUPLICATE_PROBABILITY, g_param_spec_float ("duplicate_probability", - "Duplicate Probability", - "The Probability a buffer is duplicated", 0.0, 1.0, - DEFAULT_DUPLICATE_PROBABILITY, G_PARAM_READWRITE)); - - gstelement_class->change_state = gst_net_sim_change_state; - gst_element_class_set_static_metadata (gstelement_class, - "Network Simulator", - "Filter/Network", - "An element that simulates network jitter, packet loss and packet duplication", - "Philippe Kalaf "); - - GST_DEBUG_CATEGORY_INIT - (netsim_debug, "netsim", 0, "Network simulator"); - - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_net_sim_src_template)); - gst_element_class_add_pad_template (gstelement_class, - gst_static_pad_template_get (&gst_net_sim_sink_template)); - - g_type_class_add_private (klass, sizeof (GstNetSimPrivate)); -} - -static void -gst_net_sim_init (GstNetSim *netsim) -{ - GstNetSimPrivate *priv = - GST_NET_SIM_GET_PRIVATE (netsim); - netsim->priv = priv; - - priv->srcpad = - gst_pad_new_from_static_template (&gst_net_sim_src_template, "src"); - priv->sinkpad = - gst_pad_new_from_static_template (&gst_net_sim_sink_template, "sink"); - - gst_element_add_pad (GST_ELEMENT (netsim), priv->srcpad); - gst_element_add_pad (GST_ELEMENT (netsim), priv->sinkpad); - - priv->min_delay = DEFAULT_MIN_DELAY; - priv->max_delay = DEFAULT_MAX_DELAY; - priv->delay_probability = DEFAULT_DELAY_PROBABILITY; - priv->drop_probability = DEFAULT_DROP_PROBABILITY; - priv->duplicate_probability = DEFAULT_DUPLICATE_PROBABILITY; - - priv->rand_seed = g_rand_new (); - - gst_pad_set_chain_function (priv->sinkpad, gst_net_sim_chain); - - gst_pad_set_activatemode_function (priv->srcpad, - GST_DEBUG_FUNCPTR (gst_net_sim_src_activate_push)); -} - -static gboolean -gst_net_sim_src_activate_push (GstPad * pad, GstObject * parent, GstPadMode mode, gboolean active) -{ - gboolean result = TRUE; - GstNetSim *netsim = NULL; - - netsim = GST_NET_SIM (gst_pad_get_parent (pad)); - - if (active) { -#if 0 - /* we do not start the task yet if the pad is not connected */ - if (gst_pad_is_linked (pad)) - result = gst_pad_start_task (pad, (GstTaskFunction) gst_queue_loop, pad); - else { - GST_DEBUG_OBJECT (queue, "not starting task as pad is not linked"); - result = TRUE; - } -#endif - } else { - g_main_loop_quit (netsim->priv->main_loop); - /* NOTE this will hardlock if the state change is called from the src pad - * task thread */ - GST_DEBUG_OBJECT (netsim, "Stopping task on srcpad"); - result = gst_pad_stop_task (pad); - } - - gst_object_unref (netsim); - - return result; -} - -static GstStateChangeReturn -gst_net_sim_change_state (GstElement * element, - GstStateChange transition) -{ - GstNetSim *netsim; - GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; - - netsim = GST_NET_SIM (element); - - switch (transition) { - case GST_STATE_CHANGE_NULL_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_DEBUG_OBJECT (netsim, "Starting task on srcpad"); - gst_pad_start_task (netsim->priv->srcpad, - (GstTaskFunction) gst_net_sim_loop, netsim, NULL); - break; - case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - break; - default: - break; - } - - ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); - - switch (transition) { - case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - break; - case GST_STATE_CHANGE_PAUSED_TO_READY: - break; - case GST_STATE_CHANGE_READY_TO_NULL: - break; - default: - break; - } - - return ret; -} - -static gboolean -push_buffer (SourceInfo *info) -{ - GST_DEBUG_OBJECT (info->netsim, "Pushing buffer now"); - gst_pad_push (info->netsim->priv->srcpad, info->buffer); - g_free (info); - - return FALSE; -} - -static GstFlowReturn -gst_net_sim_delay_buffer (GstNetSim *netsim, GstPad *pad, GstBuffer *buffer) -{ - GstNetSimPrivate *priv = netsim->priv; - GSource *source; - - if (priv->delay_probability > 0) - { - if (g_rand_double_range (priv->rand_seed, 0, 1) < priv->delay_probability) - { - SourceInfo *info = g_new0 (SourceInfo, 1); - gint delay; - info->netsim = netsim; - info->buffer = buffer; - delay = g_rand_int_range (priv->rand_seed, priv->min_delay, - priv->max_delay); - GST_DEBUG_OBJECT (netsim, "Delaying packet by %d", delay); - source = g_timeout_source_new (delay); - g_source_set_callback (source, (GSourceFunc)push_buffer, info, NULL); - g_source_attach (source, priv->main_context); - - return GST_FLOW_OK; - } - } - - return gst_pad_push (pad, buffer); -} - -static GstFlowReturn -gst_net_sim_chain (GstPad *pad, GstObject * parent, GstBuffer *buffer) -{ - GstNetSim *netsim; - GstNetSimPrivate *priv; - - netsim = GST_NET_SIM (gst_pad_get_parent (pad)); - priv = netsim->priv; - - if (priv->drop_probability > 0) - { - if ((gfloat)g_rand_double_range (priv->rand_seed, 0, 1) < - priv->drop_probability) - { - GST_DEBUG_OBJECT (netsim, "Dropping packet"); - gst_buffer_unref (buffer); - return GST_FLOW_OK; - } - } - if (priv->duplicate_probability > 0) - { - if ((gfloat)g_rand_double_range (priv->rand_seed, 0, 1) < - priv->duplicate_probability) - { - GST_DEBUG_OBJECT (netsim, "Duplicating packet"); - gst_buffer_ref (buffer); - gst_net_sim_delay_buffer (netsim, priv->srcpad, buffer); - } - } - - return gst_net_sim_delay_buffer (netsim, priv->srcpad, buffer); -} - - -static void -gst_net_sim_loop (GstNetSim *netsim) -{ - GstNetSimPrivate *priv; - - priv = netsim->priv; - - GST_DEBUG_OBJECT (netsim, "Creating mainloop and context"); - priv->main_context = g_main_context_new (); - priv->main_loop = g_main_loop_new (priv->main_context, FALSE); - - g_main_loop_run (priv->main_loop); -} - -static void -gst_net_sim_set_property (GObject *object, - guint prop_id, const GValue *value, GParamSpec *pspec) -{ - GstNetSim *netsim = GST_NET_SIM (object); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - case ARG_MIN_DELAY: - netsim->priv->min_delay = g_value_get_int (value); - break; - case ARG_MAX_DELAY: - netsim->priv->max_delay = g_value_get_int (value); - break; - case ARG_DELAY_PROBABILITY: - netsim->priv->delay_probability = g_value_get_float (value); - break; - case ARG_DROP_PROBABILITY: - netsim->priv->drop_probability = g_value_get_float (value); - break; - case ARG_DUPLICATE_PROBABILITY: - netsim->priv->duplicate_probability = g_value_get_float (value); - break; - } -} - -static void -gst_net_sim_get_property (GObject *object, - guint prop_id, GValue *value, GParamSpec *pspec) -{ - GstNetSim *netsim = GST_NET_SIM (object); - - switch (prop_id) { - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - case ARG_MIN_DELAY: - g_value_set_int (value, netsim->priv->min_delay); - break; - case ARG_MAX_DELAY: - g_value_set_int (value, netsim->priv->max_delay); - break; - case ARG_DELAY_PROBABILITY: - g_value_set_float (value, netsim->priv->delay_probability); - break; - case ARG_DROP_PROBABILITY: - g_value_set_float (value, netsim->priv->drop_probability); - break; - case ARG_DUPLICATE_PROBABILITY: - g_value_set_float (value, netsim->priv->duplicate_probability); - break; - } -} diff --git a/alfec/gstnetsim.h b/alfec/gstnetsim.h deleted file mode 100755 index 2147321..0000000 --- a/alfec/gstnetsim.h +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Farsight Voice+Video library - * - * Copyright 2006 Collabora Ltd, - * Copyright 2006 Nokia Corporation - * @author: Philippe Kalaf . - * - * 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., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * - */ - -#ifndef __GST_NET_SIM_H__ -#define __GST_NET_SIM_H__ - -#include - -G_BEGIN_DECLS - -/* #define's don't like whitespacey bits */ -#define GST_TYPE_NET_SIM \ - (gst_net_sim_get_type()) -#define GST_NET_SIM(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), \ - GST_TYPE_NET_SIM,GstNetSim)) -#define GST_NET_SIM_CLASS(klass) \ - (G_TYPE_CHECK_CLASS_CAST((klass), \ - GST_TYPE_NET_SIM,GstNetSimClass)) -#define GST_IS_NET_SIM(obj) \ - (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_NET_SIM)) -#define GST_IS_NET_SIM_CLASS(obj) \ - (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_NET_SIM)) - -typedef struct _GstNetSim GstNetSim; -typedef struct _GstNetSimClass GstNetSimClass; -typedef struct _GstNetSimPrivate GstNetSimPrivate; - -struct _GstNetSim -{ - GstElement parent; - - GstNetSimPrivate *priv; - - /*< private > */ - gpointer _gst_reserved[GST_PADDING]; -}; - -struct _GstNetSimClass -{ - GstElementClass parent_class; - - /*< private > */ - gpointer _gst_reserved[GST_PADDING]; -}; - -GType gst_net_sim_get_type (void); - -G_END_DECLS - -#endif /* __GST_NET_SIM_H__ */ diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 30bd6c5..04c045c 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -9,7 +9,7 @@ Name: gst-plugins-tizen Version: 1.0.0 Summary: GStreamer tizen plugins (common) -Release: 50 +Release: 51 Group: Multimedia/Framework Url: http://gstreamer.freedesktop.org/ License: LGPL-2.1+ -- 2.7.4 From daebef5c4b5c4021143e7a26485bf2d02ae25e34 Mon Sep 17 00:00:00 2001 From: Hyunil Date: Thu, 7 Dec 2017 14:24:51 +0900 Subject: [PATCH 11/16] tizenwlsink : change log level for crash analysis Change-Id: Id3d6771756e134ba8330d4b38e6ab7c7b22609c9 Signed-off-by: Hyunil --- tizenwlsink/src/gsttizenwlsink.c | 46 ++++++++++++++++-------------- tizenwlsink/src/wldisplay.c | 23 +++++++-------- tizenwlsink/src/wlwindow.c | 60 +++++++++++++++++++++------------------- 3 files changed, 69 insertions(+), 60 deletions(-) diff --git a/tizenwlsink/src/gsttizenwlsink.c b/tizenwlsink/src/gsttizenwlsink.c index 6f9d16e..a060806 100644 --- a/tizenwlsink/src/gsttizenwlsink.c +++ b/tizenwlsink/src/gsttizenwlsink.c @@ -480,7 +480,6 @@ gst_tizen_wl_sink_class_init (GstTizenWlSinkClass * klass) G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstTizenWlSinkClass, preroll_handoff), NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, GST_TYPE_BUFFER | G_SIGNAL_TYPE_STATIC_SCOPE, GST_TYPE_PAD); - #endif } @@ -838,6 +837,9 @@ gst_tizen_wl_sink_get_mm_video_buf (GstBuffer * buffer) 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); + if (!mm_video_buf->handle_num) { + GST_ERROR ("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; } @@ -1030,6 +1032,7 @@ gst_tizen_wl_sink_set_property (GObject * object, GstTizenWlSink *sink = GST_TIZEN_WL_SINK (object); FUNCTION; g_mutex_lock (&sink->render_lock); + GST_WARNING ("prop_id (%d)", prop_id); switch (prop_id) { case PROP_DISPLAY: @@ -1042,7 +1045,7 @@ gst_tizen_wl_sink_set_property (GObject * object, 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); + GST_WARNING ("Dump video set (%d):", sink->dump_video); } break; case PROP_DUMP_COUNT: @@ -1052,6 +1055,7 @@ gst_tizen_wl_sink_set_property (GObject * object, break; case PROP_DISABLE_OVERLAY: sink->disable_overlay = g_value_get_boolean (value); + GST_WARNING ("disable_overlay (%d)", sink->disable_overlay); if (sink->window && sink->display) { if (sink->disable_overlay) { g_clear_object (&sink->window); @@ -1062,7 +1066,7 @@ gst_tizen_wl_sink_set_property (GObject * object, break; case PROP_SIGNAL_HANDOFFS: sink->signal_handoffs = g_value_get_boolean (value); - GST_LOG ("set signal_handoffs(%d)", sink->signal_handoffs); + GST_WARNING ("set signal_handoffs(%d)", sink->signal_handoffs); if (sink->window) { if (sink->signal_handoffs) { /* overlay -> hand-off */ @@ -1089,11 +1093,11 @@ gst_tizen_wl_sink_set_property (GObject * object, 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); + GST_WARNING ("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); + GST_WARNING ("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)) @@ -1310,7 +1314,7 @@ gst_tizen_wl_sink_finalize (GObject * object) { GstTizenWlSink *sink = GST_TIZEN_WL_SINK (object); FUNCTION; - GST_DEBUG_OBJECT (sink, "Finalizing the sink.."); + GST_WARNING_OBJECT (sink, "Finalizing the sink.."); if (sink->last_buffer) gst_buffer_unref (sink->last_buffer); @@ -1456,7 +1460,7 @@ gst_tizen_wl_sink_find_display (GstTizenWlSink * sink) GST_OBJECT_UNLOCK (sink); if (error) { - GST_ELEMENT_WARNING (sink, RESOURCE, OPEN_READ_WRITE, + GST_ELEMENT_ERROR (sink, RESOURCE, OPEN_READ_WRITE, ("Could not initialise Wayland output"), ("Failed to create GstWlDisplay: '%s'", error->message)); g_error_free (error); @@ -1484,15 +1488,15 @@ gst_tizen_wl_sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: - GST_LOG ("WAYLANDSINK TRANSITION: NULL_TO_READY"); + GST_WARNING ("WAYLANDSINK TRANSITION: NULL_TO_READY"); if (!gst_tizen_wl_sink_find_display (sink)) return GST_STATE_CHANGE_FAILURE; break; case GST_STATE_CHANGE_READY_TO_PAUSED: - GST_LOG ("WAYLANDSINK TRANSITION: READY_TO_PAUSED"); + GST_WARNING ("WAYLANDSINK TRANSITION: READY_TO_PAUSED"); break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: - GST_LOG ("WAYLANDSINK TRANSITION: PAUSED_TO_PLAYING"); + GST_WARNING ("WAYLANDSINK TRANSITION: PAUSED_TO_PLAYING"); break; default: break; @@ -1504,10 +1508,10 @@ gst_tizen_wl_sink_change_state (GstElement * element, GstStateChange transition) switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: - GST_LOG ("WAYLANDSINK TRANSITION: PLAYING_TO_PAUSED"); + GST_WARNING ("WAYLANDSINK TRANSITION: PLAYING_TO_PAUSED"); break; case GST_STATE_CHANGE_PAUSED_TO_READY: - GST_LOG ("WAYLANDSINK TRANSITION: PAUSED_TO_READY"); + GST_WARNING ("WAYLANDSINK TRANSITION: PAUSED_TO_READY"); #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT if (sink->keep_camera_preview) { if (sink->window) { @@ -1528,17 +1532,17 @@ gst_tizen_wl_sink_change_state (GstElement * element, GstStateChange transition) gst_buffer_replace (&sink->last_buffer, NULL); if (sink->window) { if (gst_wl_window_is_toplevel (sink->window)) { - GST_DEBUG ("internal window"); + GST_WARNING ("internal window"); g_clear_object (&sink->window); } else { /* remove buffer from surface, show nothing */ - GST_DEBUG ("external window"); + GST_WARNING ("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"); + GST_WARNING ("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 @@ -1709,7 +1713,7 @@ gst_tizen_wl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) sink = GST_TIZEN_WL_SINK (bsink); - GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps); + GST_WARNING_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps); /* extract info from caps */ if (!gst_video_info_from_caps (&info, caps)) @@ -1735,7 +1739,7 @@ gst_tizen_wl_sink_set_caps (GstBaseSink * bsink, GstCaps * caps) /* verify we support the requested format */ #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT if (sink->USE_TBM) { - GST_LOG ("USE TBM FORMAT"); + GST_WARNING ("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) @@ -1926,7 +1930,7 @@ gst_tizen_wl_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query) NULL); gst_structure_free (config); - + GST_WARNING ("set propose allocation"); return TRUE; } @@ -1937,7 +1941,7 @@ gst_tizen_wl_sink_preroll (GstBaseSink * bsink, GstBuffer * buffer) GstTizenWlSink *sink = GST_TIZEN_WL_SINK (bsink); FUNCTION; - GST_DEBUG_OBJECT (bsink, "preroll buffer %p", buffer); + GST_WARNING_OBJECT (bsink, "preroll buffer %p", buffer); if (sink->signal_handoffs) { GST_LOG ("g_signal_emit: preroll-handoff"); @@ -2547,7 +2551,7 @@ gst_tizen_wl_sink_set_wl_window_wl_surface_id (GstVideoOverlay * overlay, g_mutex_lock (&sink->render_lock); g_clear_object (&sink->window); - GST_LOG ("wl_surface_id %d %x", (int) wl_surface_id, + GST_WARNING ("wl_surface_id %d %x", (int) wl_surface_id, (guintptr) wl_surface_id); if (wl_surface_id) { @@ -2627,7 +2631,7 @@ gst_tizen_wl_sink_set_render_rectangle (GstVideoOverlay * overlay, return; } - GST_DEBUG_OBJECT (sink, "window geometry changed to (%d, %d) %d x %d", + GST_WARNING_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; diff --git a/tizenwlsink/src/wldisplay.c b/tizenwlsink/src/wldisplay.c index ac058c2..cb5b7b3 100644 --- a/tizenwlsink/src/wldisplay.c +++ b/tizenwlsink/src/wldisplay.c @@ -164,6 +164,7 @@ gst_wl_display_finalize (GObject * gobject) wl_display_flush (self->display); wl_display_disconnect (self->display); } + GST_WARNING ("wl_display finalize is done"); G_OBJECT_CLASS (gst_wl_display_parent_class)->finalize (gobject); } @@ -234,27 +235,27 @@ registry_handle_global (void *data, struct wl_registry *registry, if (g_strcmp0 (interface, "wl_compositor") == 0) { self->compositor = wl_registry_bind (registry, id, &wl_compositor_interface, MIN (version, 4)); - GST_INFO + GST_WARNING ("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 + GST_WARNING ("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 + GST_WARNING ("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 + GST_WARNING ("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 + GST_WARNING ("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); @@ -262,25 +263,25 @@ registry_handle_global (void *data, struct wl_registry *registry, } else if (g_strcmp0 (interface, "wl_scaler") == 0) { self->scaler = wl_registry_bind (registry, id, &wl_scaler_interface, 2); - GST_INFO + GST_WARNING ("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 + GST_WARNING ("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 + GST_WARNING ("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 + GST_WARNING ("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); @@ -347,7 +348,7 @@ gst_wl_display_new (const gchar * name, GError ** error) FUNCTION; display = wl_display_connect (name); - GST_INFO ("wl_display@%p = wl_display_connect (name@%p)", display, name); + GST_WARNING ("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'", @@ -414,7 +415,7 @@ gst_wl_display_new_existing (struct wl_display * display, 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)", + GST_WARNING ("tbm_client@%p = wayland_tbm_client_init (wl_display@%p)", self->tbm_client, self->display); if (!self->tbm_client) { diff --git a/tizenwlsink/src/wlwindow.c b/tizenwlsink/src/wlwindow.c index 1a44092..a772bc5 100644 --- a/tizenwlsink/src/wlwindow.c +++ b/tizenwlsink/src/wlwindow.c @@ -114,6 +114,7 @@ gst_wl_window_finalize (GObject * gobject) wl_surface_destroy (self->area_surface); g_clear_object (&self->display); + GST_WARNING ("wl_window finalize is done"); G_OBJECT_CLASS (gst_wl_window_parent_class)->finalize (gobject); } @@ -192,18 +193,18 @@ gst_wl_window_new_internal (GstWlDisplay * display) window->display = g_object_ref (display); window->area_surface = wl_compositor_create_surface (display->compositor); - GST_INFO + GST_WARNING ("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 + GST_WARNING ("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)", + GST_WARNING ("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)", + GST_WARNING ("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); @@ -212,7 +213,7 @@ gst_wl_window_new_internal (GstWlDisplay * display) /* go toplevel */ if (display->need_shell_surface) { /* for internal window */ - GST_INFO + GST_WARNING ("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 = @@ -223,25 +224,27 @@ gst_wl_window_new_internal (GstWlDisplay * display) window->area_subsurface = tizen_policy_get_subsurface (display->tizen_policy, window->area_surface, display->wl_surface_id); - GST_INFO + GST_WARNING ("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)", + GST_WARNING + ("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); + GST_WARNING ("wl_surface_commit (%p)", window->area_surface); wl_surface_commit (window->area_surface); } else { - GST_INFO (" wl_surface parent %p", parent); + GST_WARNING (" wl_surface parent %p", parent); window->area_subsurface = wl_subcompositor_get_subsurface (display->subcompositor, window->area_surface, parent); - GST_INFO + GST_WARNING ("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)", + GST_WARNING + ("wl_subsurface_set_desync (area_subsurface(wl_subsurface)@%p)", window->area_subsurface); wl_subsurface_set_desync (window->area_subsurface); } @@ -259,36 +262,37 @@ gst_wl_window_new_internal (GstWlDisplay * display) window->video_subsurface = wl_subcompositor_get_subsurface (display->subcompositor, window->video_surface, window->area_surface); - GST_INFO + GST_WARNING ("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)", + GST_WARNING ("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); + GST_WARNING ("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 + GST_WARNING ("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 + GST_WARNING ("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 + GST_WARNING ("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)", + GST_WARNING + ("tizen_viewport_follow_parent_transform(tizen_video_viewport@%p)", window->tizen_video_viewport); tizen_viewport_follow_parent_transform (window->tizen_video_viewport); @@ -343,21 +347,21 @@ gst_wl_window_new_internal (GstWlDisplay * display) /* do not accept input */ region = wl_compositor_create_region (display->compositor); - GST_INFO ("wl_region@%p = wl_compositor_create_region (wl_compositor@%p)", + GST_WARNING ("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)", + GST_WARNING ("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); + GST_WARNING ("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)", + GST_WARNING ("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)", + GST_WARNING ("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); + GST_WARNING ("wl_region_destroy (wl_region@%p)", region); wl_region_destroy (region); #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT @@ -367,17 +371,17 @@ gst_wl_window_new_internal (GstWlDisplay * display) window->tizen_area_dest_mode = tizen_viewport_get_destination_mode (window->tizen_area_viewport); - GST_INFO + GST_WARNING ("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 + GST_WARNING ("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); + GST_WARNING ("wl_surface_commit (area_surface@%p)", window->area_surface); wl_surface_commit (window->area_surface); } #endif @@ -1024,7 +1028,7 @@ gst_wl_window_set_destination_mode_crop_wl_buffer (GstWlWindow * window, { FUNCTION; g_return_if_fail (window != NULL); - GST_LOG ("set crop x@%d, y@%d, w@%d, h@%d", x, y, w, h); + GST_WARNING ("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; -- 2.7.4 From de1642d8e6ca631f456bd6e7bfcf375f4fdd24fa Mon Sep 17 00:00:00 2001 From: Hyunil Date: Fri, 8 Dec 2017 10:27:42 +0900 Subject: [PATCH 12/16] tizenwlsink : Add exception handling for flush_buffer Change-Id: I9ab05d493c102214a7e63bcde27e7b932c9aade0 Signed-off-by: Hyunil --- tizenwlsink/src/gsttizenwlsink.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tizenwlsink/src/gsttizenwlsink.c b/tizenwlsink/src/gsttizenwlsink.c index a060806..6d34573 100644 --- a/tizenwlsink/src/gsttizenwlsink.c +++ b/tizenwlsink/src/gsttizenwlsink.c @@ -705,6 +705,7 @@ gst_tizen_wl_sink_make_flush_buffer (GstWlDisplay * display, strerror_r (errno, err_str, sizeof (err_str)); GST_ERROR ("alloc tbm bo(size:%d) failed: %s(%d)", bo_size, err_str, errno); + g_free (flush_buffer); return FALSE; } GST_LOG ("flush buffer tbm_bo =(%p)", bo); @@ -724,7 +725,8 @@ gst_tizen_wl_sink_make_flush_buffer (GstWlDisplay * display, tbm_bo_unmap (mm_video_buf->handle.bo[i]); if (dst.ptr) tbm_bo_unmap (bo); - return FALSE; + g_free (flush_buffer); + return FALSE; } /* copy */ memcpy (dst.ptr, src.ptr, bo_size); -- 2.7.4 From 6a702fb8389cbafaee38d0d9981db41d85327e8e Mon Sep 17 00:00:00 2001 From: Hyunil Date: Mon, 11 Dec 2017 15:01:17 +0900 Subject: [PATCH 13/16] tizenwlsink : Change location of creating flush_buffer Change-Id: I65ac01dd6e70a0e3593f3817144885d0efd0c30f Signed-off-by: Hyunil --- tizenwlsink/src/gsttizenwlsink.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tizenwlsink/src/gsttizenwlsink.c b/tizenwlsink/src/gsttizenwlsink.c index 6d34573..8b5dae2 100644 --- a/tizenwlsink/src/gsttizenwlsink.c +++ b/tizenwlsink/src/gsttizenwlsink.c @@ -678,6 +678,9 @@ gst_tizen_wl_sink_make_flush_buffer (GstWlDisplay * display, g_return_val_if_fail (display != NULL, FALSE); g_return_val_if_fail (mm_video_buf != NULL, FALSE); + display->flush_tbm_bufmgr = + wayland_tbm_client_get_bufmgr (display->tbm_client); + g_return_val_if_fail (display->flush_tbm_bufmgr != NULL, FALSE); flush_buffer = (GstWlFlushBuffer *) malloc (sizeof (GstWlFlushBuffer)); if (G_UNLIKELY (!flush_buffer)) { @@ -686,10 +689,6 @@ gst_tizen_wl_sink_make_flush_buffer (GstWlDisplay * display, } 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; -- 2.7.4 From b4ba4cc0df16265432fbe6fb5779dce68965b74a Mon Sep 17 00:00:00 2001 From: Andriy Martynets Date: Tue, 12 Dec 2017 16:04:33 +0200 Subject: [PATCH 14/16] Engage with TPL to prevent muse-server crash. Fix sink pad caps unref. Change-Id: I8a5c21d44553edcc236e50f20d9000c944accdd2 Signed-off-by: Andriy Martynets --- configure.ac | 38 +++++++++++++++++++++++++-- packaging/gst-plugins-tizen.spec | 11 +++++--- video360/src/Makefile.am | 3 ++- video360/src/gstvideo360-gl.c | 49 +++++++++++++++++++++++++++++++---- video360/src/gstvideo360.c | 38 +++++++++++++-------------- video360/src/gstvideo360.h | 56 ++++++++++++++++++++++++++++------------ 6 files changed, 146 insertions(+), 49 deletions(-) diff --git a/configure.ac b/configure.ac index a385065..a738fab 100644 --- a/configure.ac +++ b/configure.ac @@ -370,12 +370,43 @@ AC_ARG_ENABLE(video360, AC_HELP_STRING([--enable-video360], [using video360]), [GST_TIZEN_USE_VIDEO360=yes]) AM_CONDITIONAL(GST_TIZEN_USE_VIDEO360, test "x$GST_TIZEN_USE_VIDEO360" = "xyes") -dnl video360 related options --------------------------------------------------------------- +dnl video360 related options START -------------------------------------------------------- +AC_ARG_WITH([tizen-platform], AS_HELP_STRING([--with-tizen-platform], + [Build with Tizen Porting Layer(TPL)])) + AC_ARG_WITH([native-formats], AS_HELP_STRING([--with-native-formats], [Build with support for Tizen native video formats])) -AS_IF([test "x$with_native_formats" = "xyes"], [CFLAGS="$CFLAGS -DGST_TIZEN_USE_NATIVE_FORMATS"]) AC_ARG_WITH([gles2], AS_HELP_STRING([--with-gles2], [Build with OpenGL ES 2.0])) + +AS_IF([test "x$with_tizen_platform" = "xyes"], [ + PKG_CHECK_MODULES(TPL, [ + tpl-egl + ], [ + AC_SUBST(TPL_CFLAGS) + AC_SUBST(TPL_LIBS) + ]) + CFLAGS="$CFLAGS -DGST_TIZEN_PLATFORM" +]) + +AS_IF([test "x$with_native_formats" = "xyes" -o "x$with_gles2" = "xyes"], [ + PKG_CHECK_MODULES(MMCOMMON, [ + mm-common + ], [ + AC_SUBST(MMCOMMON_CFLAGS) + ]) + PKG_CHECK_MODULES(TBM, [ + libtbm + ], [ + AC_SUBST(TBM_CFLAGS) + AC_SUBST(TBM_LIBS) + ]) +]) + +AS_IF([test "x$with_native_formats" = "xyes"], [ + CFLAGS="$CFLAGS -DGST_TIZEN_USE_NATIVE_FORMATS" +]) + AS_IF([test "x$with_gles2" = "xyes"], [ PKG_CHECK_MODULES(GLES, [ gles20 @@ -385,6 +416,9 @@ AS_IF([test "x$with_gles2" = "xyes"], [ ]) CFLAGS="$CFLAGS -DGST_TIZEN_GL_API_GLES2" ]) +dnl video360 related options END -------------------------------------------------------- + + dnl use waylandsink -------------------------------------------------------------------------- AC_ARG_ENABLE(waylandsink, AC_HELP_STRING([--enable-waylandsink], [using waylandsink]), diff --git a/packaging/gst-plugins-tizen.spec b/packaging/gst-plugins-tizen.spec index 04c045c..20ee3d2 100644 --- a/packaging/gst-plugins-tizen.spec +++ b/packaging/gst-plugins-tizen.spec @@ -38,6 +38,7 @@ BuildRequires: libdrm-devel BuildRequires: pkgconfig(vconf) BuildRequires: pkgconfig(mm-common) BuildRequires: pkgconfig(gles20) +BuildRequires: pkgconfig(tpl-egl) %if %{with wayland} BuildRequires: pkgconfig(wayland-client) >= 1.0.0 BuildRequires: pkgconfig(wayland-tbm-client) @@ -83,8 +84,9 @@ export CFLAGS="$CFLAGS_DEFAULT -DTIZEN_FEATURE_PRODUCT_TM1" --enable-ext-alfec\ --disable-tizenipc\ --disable-static\ - --with-native-formats\ - --with-gles2 + --with-tizen-platform \ + --with-native-formats \ + --with-gles2 make %{?jobs:-j%jobs} @@ -106,8 +108,9 @@ export CFLAGS="$CFLAGS_DEFAULT" --enable-ext-alfec\ --disable-tizenipc\ --disable-static\ - --with-native-formats\ - --with-gles2 + --with-tizen-platform \ + --with-native-formats \ + --with-gles2 make %{?jobs:-j%jobs} diff --git a/video360/src/Makefile.am b/video360/src/Makefile.am index 802ea26..60c4017 100644 --- a/video360/src/Makefile.am +++ b/video360/src/Makefile.am @@ -8,12 +8,13 @@ libgstvideo360_la_SOURCES = gstvideo360.c\ # compiler and linker flags used to compile this plugin, set in configure.ac libgstvideo360_la_CFLAGS = $(GST_CFLAGS)\ + $(TPL_CFLAGS)\ $(TBM_CFLAGS)\ $(MMCOMMON_CFLAGS)\ $(GLES_CFLAGS)\ -Wdouble-promotion\ -fsingle-precision-constant -libgstvideo360_la_LIBADD = $(GST_LIBS) $(TBM_LIBS) $(GLES_LIBS) +libgstvideo360_la_LIBADD = $(GST_LIBS) $(TPL_LIBS) $(TBM_LIBS) $(GLES_LIBS) libgstvideo360_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) libgstvideo360_la_LIBTOOLFLAGS = --tag=disable-static diff --git a/video360/src/gstvideo360-gl.c b/video360/src/gstvideo360-gl.c index 123a897..622ebb0 100644 --- a/video360/src/gstvideo360-gl.c +++ b/video360/src/gstvideo360-gl.c @@ -215,18 +215,32 @@ gst_video360_deinit_gl (GstVideo360 * this) eglTerminate (this->egl_display); this->egl_display = EGL_NO_DISPLAY; } +#ifdef GST_TIZEN_PLATFORM + if (this->tpl_display) { + /* Destroy TPL display. + * In Tizen environment TPL stealthy catches the native display handler + * (most probably hooking eglInitialize call) and uses it internally. + * To force TPL to release it before we disconnect (and thus prevent + * possible crash) we force TPL display object destruction by the below + * call. + * This is actually the reason we touch TPL at all. + * */ + tpl_object_unreference ((tpl_object_t *) this->tpl_display); + this->tpl_display = NULL; + } +#endif #ifdef GST_TIZEN_GL_WINDOW_WAYLAND if (this->wl_display) { /* Disconnect from the native display */ wl_display_disconnect (this->wl_display); this->wl_display = NULL; } -#else +#else /* Not GST_TIZEN_GL_WINDOW_WAYLAND */ /* Space for alternate windowing system code */ -#endif /* GL_WINDOW_WAYLAND */ +#endif /* GST_TIZEN_GL_WINDOW_WAYLAND */ #else /* Space for alternate platform code */ -#endif /* GL_PLATFORM_EGL */ +#endif /* GST_TIZEN_GL_PLATFORM_EGL */ } static gboolean @@ -269,9 +283,25 @@ _init_gl_platform (GstVideo360 * this) GST_ERROR ("eglGetDisplay failed"); return FALSE; } -#else +#else /* Not GST_TIZEN_GL_WINDOW_WAYLAND */ /* Space for alternate windowing system code */ -#endif /* GL_WINDOW_WAYLAND */ +#endif /* GST_TIZEN_GL_WINDOW_WAYLAND */ + +#ifdef GST_TIZEN_PLATFORM + /* Note: backend type must be TPL_BACKEND_WAYLAND_THREAD + * (not TPL_BACKEND_WAYLAND) otherwise TPL implicitly creates distinct + * instance of TPL display structure for TPL_BACKEND_WAYLAND_THREAD backend + * and thus we will not get means to synchronize display destruction + * process. Without the synchronization Wayland display derived objects + * (proxies, wrappers, queues, etc.) get deleted after wl_display_disconnect + * call causing muse-server to be killed by SIGSEG. + * */ + this->tpl_display = tpl_display_create (TPL_BACKEND_WAYLAND_THREAD, this->wl_display); + if (this->tpl_display == NULL) { + GST_ERROR ("tpl_display_create failed"); + return FALSE; + } +#endif /* GST_TIZEN_PLATFORM */ /* initialize the EGL display connection */ eglInitialize (this->egl_display, &ver_major, &ver_minor); @@ -401,6 +431,15 @@ _prepare_gl_framebuffer (GstVideo360 * this) EGL_NO_CONTEXT, EGL_NATIVE_SURFACE_TIZEN, (EGLClientBuffer) this->output_tbm_surface, NULL); +#ifdef GST_TIZEN_USE_NATIVE_FORMATS + this->output_frame_buffer_size = + tbm_bo_size (tbm_surface_internal_get_bo (this->output_tbm_surface, 0)); + if (GST_ROUND_UP_N (this->output_frame_buffer_size, 4096) != + this->output_frame_buffer_size) { + GST_WARNING ("TBM BO size isn't aligned by 4k"); + } +#endif + if (this->input_egl_image == EGL_NO_IMAGE_KHR || this->output_egl_image == EGL_NO_IMAGE_KHR) { EGL_ERROR; diff --git a/video360/src/gstvideo360.c b/video360/src/gstvideo360.c index 2d1bd84..0edc77f 100644 --- a/video360/src/gstvideo360.c +++ b/video360/src/gstvideo360.c @@ -329,8 +329,6 @@ gst_video360_init (GstVideo360 * this) gst_pad_use_fixed_caps (this->srcpad); gst_element_add_pad (GST_ELEMENT (this), this->srcpad); - this->sinkpad_caps = NULL; - this->stereo_mode = MODE_MONOSCOPIC; this->pose_yaw_radians = 0.0; this->pose_pitch_radians = 0.0; @@ -348,6 +346,9 @@ gst_video360_init (GstVideo360 * this) this->zoom = 1.0; #ifdef GST_TIZEN_GL_PLATFORM_EGL +#ifdef GST_TIZEN_PLATFORM + this->tpl_display = NULL; +#endif #ifdef GST_TIZEN_GL_WINDOW_WAYLAND this->wl_display = NULL; #endif @@ -537,6 +538,9 @@ gst_video360_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) { /* we should handle the format here */ gst_event_parse_caps (event, &caps); + gst_caps_ref (caps); + gst_event_unref (event); + if (!(this->passthrough = this->requested_passthrough)) { structure = gst_caps_get_structure (caps, 0); @@ -669,16 +673,6 @@ gst_video360_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) return FALSE; } - /* Here we save incoming CAPS which might be needed for subsequent - * negotiations. Normally they are present on the PAD and its peer as - * sticky CAPS events and can be obtained by gst_pad_get_current_caps - * call. Unfortunately some elements (e.g. OMX decoder) seems to unref - * these events. - * */ - if (this->sinkpad_caps) - gst_caps_unref (this->sinkpad_caps); - this->sinkpad_caps = gst_caps_ref (caps); - /* Once sink capabilities are negotiated translate them to source pad. * Here we do a kind of transform negotiation as we setup fixed CAPS * on the src PAD. @@ -722,6 +716,7 @@ gst_video360_sink_event (GstPad * pad, GstObject * parent, GstEvent * event) if (ret) gst_pad_check_reconfigure (pad); + gst_caps_unref (caps); break; } default: @@ -830,18 +825,17 @@ gst_video360_chain (GstPad * pad, GstObject * parent, GstBuffer * in_buf) GstBuffer *out_buf; GstMapInfo in_info, out_info; #ifdef GST_TIZEN_USE_NATIVE_FORMATS - MMVideoBuffer *mm_vbuffer; + MMVideoBuffer *mm_vbuffer = NULL; #else GstMemory *out_mem; #endif GstMemory *in_mem; int ret; - if (gst_pad_check_reconfigure (pad)) { + if (gst_pad_check_reconfigure (pad)) if (!gst_video360_sink_event (pad, parent, - gst_event_new_caps (this->sinkpad_caps))) + gst_pad_get_sticky_event (pad, GST_EVENT_CAPS, 0))) return GST_FLOW_NOT_NEGOTIATED; - } if (this->passthrough) return gst_pad_push (this->srcpad, in_buf); @@ -853,11 +847,8 @@ gst_video360_chain (GstPad * pad, GstObject * parent, GstBuffer * in_buf) #endif #ifdef GST_TIZEN_USE_NATIVE_FORMATS - if ((out_buf = gst_buffer_new_wrapped ( - g_malloc (GST_TIZEN_NATIVE_FORMATS_FIRST_MEMORY_SIZE), - GST_TIZEN_NATIVE_FORMATS_FIRST_MEMORY_SIZE)) && + if ((out_buf = gst_buffer_new ()) && (mm_vbuffer = g_malloc0 (sizeof (MMVideoBuffer)))) { - mm_vbuffer->type = MM_VIDEO_BUFFER_TYPE_TBM_BO; mm_vbuffer->format = MM_PIXEL_FORMAT_RGBA; mm_vbuffer->plane_num = 1; @@ -871,6 +862,10 @@ gst_video360_chain (GstPad * pad, GstObject * parent, GstBuffer * in_buf) gst_buffer_append_memory (out_buf, gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, mm_vbuffer, + GST_TIZEN_NATIVE_FORMATS_FIRST_MEMORY_SIZE, 0, + GST_TIZEN_NATIVE_FORMATS_FIRST_MEMORY_SIZE, NULL, NULL)); + gst_buffer_append_memory (out_buf, + gst_memory_new_wrapped (GST_MEMORY_FLAG_READONLY, mm_vbuffer, sizeof (MMVideoBuffer), 0, sizeof (MMVideoBuffer), mm_vbuffer, mm_vbuffer_free)); #else @@ -925,6 +920,9 @@ gst_video360_chain (GstPad * pad, GstObject * parent, GstBuffer * in_buf) } } + if (out_buf) + gst_buffer_unref (out_buf); + GST_ERROR ("Frame rendering error: " "Memory allocation / write permission request failed"); diff --git a/video360/src/gstvideo360.h b/video360/src/gstvideo360.h index 143468c..18333af 100644 --- a/video360/src/gstvideo360.h +++ b/video360/src/gstvideo360.h @@ -55,9 +55,24 @@ * #define GST_TIZEN_GL_API_GLES2 * #define GST_TIZEN_GL_API_OPENGL (Not supported yet) * */ + +/* Define below macros to build for EGL as the OpenGL platform: + * */ #define GST_TIZEN_GL_PLATFORM_EGL + +/* Define below macros to build with Tizen Porting Layer(TPL) support: + * #define GST_TIZEN_PLATFORM + * */ + +/* Define below macros to build for Wayland as native display system: + * */ #define GST_TIZEN_GL_WINDOW_WAYLAND + +/* Define below macros to build using EGL_TIZEN_image_native_surface and + * GL_OES_EGL_image_external extensions: + * */ #define GST_TIZEN_USE_EGLIMAGE + /* Define below macros to enable multisample antialiasing * #define GST_TIZEN_USE_MSAA * */ @@ -74,10 +89,21 @@ #include #endif +#include +#include +#include +#include + +#ifdef GST_TIZEN_USE_TIMING +#include +#endif + #include #include #include +#include "video360.h" + #ifdef GST_TIZEN_GL_API_GLES2 #include #include @@ -86,32 +112,26 @@ #include #include +#ifdef GST_TIZEN_PLATFORM +#include +#endif /* GST_TIZEN_PLATFORM */ + #ifdef GST_TIZEN_GL_WINDOW_WAYLAND #include #include -#else /* Not GL_WINDOW_WAYLAND */ +#else /* Not GST_TIZEN_GL_WINDOW_WAYLAND */ #error "Wayland based EGL is the only supported platform" -#endif /* GL_WINDOW_WAYLAND */ +#endif /* GST_TIZEN_GL_WINDOW_WAYLAND */ -#else /* Not GL_PLATFORM_EGL */ +#else /* Not GST_TIZEN_GL_PLATFORM_EGL */ #error "GLES API supported on EGL platform only" -#endif /* GL_PLATFORM_EGL */ +#endif /* GST_TIZEN_GL_PLATFORM_EGL */ -#else /* Not GL_API_GLES2 */ +#else /* Not GST_TIZEN_GL_API_GLES2 */ #error "OpenGL ES2 is the only supported API" #include #include -#endif /* GL_API_GLES2 */ - -#include -#include -#include - -#include "video360.h" - -#ifdef GST_TIZEN_USE_TIMING -#include -#endif +#endif /* GST_TIZEN_GL_API_GLES2 */ #if defined (GST_TIZEN_USE_NATIVE_FORMATS) || defined (GST_TIZEN_USE_EGLIMAGE) #include @@ -178,11 +198,13 @@ struct _GstVideo360 GstElement element; GstPad *sinkpad, *srcpad; - GstCaps *sinkpad_caps; /***************************************************************************** * OpenGL ES related variables * **************************************************************************/ +#ifdef GST_TIZEN_PLATFORM + tpl_display_t *tpl_display; +#endif #ifdef GST_TIZEN_GL_WINDOW_WAYLAND struct wl_display *wl_display; #endif -- 2.7.4 From 2f6af43a06261ce91b4f769980a4c33e67651c13 Mon Sep 17 00:00:00 2001 From: Hyunil Date: Wed, 20 Dec 2017 09:25:07 +0900 Subject: [PATCH 15/16] tizenwlsink : Check bo numbers in MMVideBuffer to avoid error Change-Id: I9ff2b752532a0d86982f196ff7859a5390afe2bc Signed-off-by: Hyunil --- tizenwlsink/src/gsttizenwlsink.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tizenwlsink/src/gsttizenwlsink.c b/tizenwlsink/src/gsttizenwlsink.c index 8b5dae2..51fad82 100644 --- a/tizenwlsink/src/gsttizenwlsink.c +++ b/tizenwlsink/src/gsttizenwlsink.c @@ -838,8 +838,9 @@ gst_tizen_wl_sink_get_mm_video_buf (GstBuffer * buffer) 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); - if (!mm_video_buf->handle_num) { + if (mm_video_buf->handle_num == 0) { GST_ERROR ("Number of TBM bo is %d", mm_video_buf->handle_num); + return NULL; } GST_DEBUG ("Number of plane is %d", mm_video_buf->plane_num); return mm_video_buf; -- 2.7.4 From 002b616e1bcb9d50619d755c8b9f6cee384675c1 Mon Sep 17 00:00:00 2001 From: Hyunil Date: Mon, 8 Jan 2018 09:48:39 +0900 Subject: [PATCH 16/16] tizenwlsink : Check instance of object_type Change-Id: I4ab2944d8a9432a370279e2bd9fef9ce974fa17e Signed-off-by: Hyunil --- tizenwlsink/src/gsttizenwlsink.c | 8 ++++++-- tizenwlsink/src/wldisplay.c | 6 ++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/tizenwlsink/src/gsttizenwlsink.c b/tizenwlsink/src/gsttizenwlsink.c index 51fad82..594d63a 100644 --- a/tizenwlsink/src/gsttizenwlsink.c +++ b/tizenwlsink/src/gsttizenwlsink.c @@ -725,7 +725,7 @@ gst_tizen_wl_sink_make_flush_buffer (GstWlDisplay * display, if (dst.ptr) tbm_bo_unmap (bo); g_free (flush_buffer); - return FALSE; + return FALSE; } /* copy */ memcpy (dst.ptr, src.ptr, bo_size); @@ -1469,8 +1469,12 @@ gst_tizen_wl_sink_find_display (GstTizenWlSink * sink) ret = FALSE; } #ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT - if (G_LIKELY (sink->display)) + if (G_LIKELY (sink->display)) { sink->display->USE_TBM = sink->USE_TBM; + } else { + GST_ERROR ("Failed to create GstWlDisplay"); + ret = FALSE; + } #endif } } diff --git a/tizenwlsink/src/wldisplay.c b/tizenwlsink/src/wldisplay.c index cb5b7b3..b1c8e27 100644 --- a/tizenwlsink/src/wldisplay.c +++ b/tizenwlsink/src/wldisplay.c @@ -371,6 +371,12 @@ gst_wl_display_new_existing (struct wl_display * display, g_return_val_if_fail (display != NULL, NULL); self = g_object_new (GST_TYPE_WL_DISPLAY, NULL); +#ifdef TIZEN_FEATURE_WLSINK_ENHANCEMENT + if (self == NULL) { + GST_ERROR ("g_object_new return value is null"); + return NULL; + } +#endif self->display = display; self->own_display = take_ownership; -- 2.7.4