diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0001-Support-croping-and-alignment-handling.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0001-Support-croping-and-alignment-handling.patch new file mode 100644 index 000000000..5c341f79c --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0001-Support-croping-and-alignment-handling.patch @@ -0,0 +1,171 @@ +From e5b2bade360bcf12ac389463019162a6ce64d9ef Mon Sep 17 00:00:00 2001 +From: Jian +Date: Thu, 26 Mar 2015 14:22:07 +0800 +Subject: [PATCH] Support croping and alignment handling +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian +--- + ext/gl/gstglimagesink.c | 57 ++++++++++++++++++++++++++++++- + ext/gl/gstglimagesink.h | 3 ++ + gst-libs/gst/gl/gstglvivdirecttexture.c | 22 ++++++------ + 3 files changed, 71 insertions(+), 11 deletions(-) + +diff --git a/ext/gl/gstglimagesink.c b/ext/gl/gstglimagesink.c +index cd3a9ff..1d60e1d 100644 +--- a/ext/gl/gstglimagesink.c ++++ b/ext/gl/gstglimagesink.c +@@ -302,6 +302,8 @@ gst_glimage_sink_init (GstGLImageSink * glimage_sink) + glimage_sink->pool = NULL; + glimage_sink->stored_buffer = NULL; + glimage_sink->redisplay_texture = 0; ++ glimage_sink->cropmeta = NULL; ++ glimage_sink->videometa = NULL; + + g_mutex_init (&glimage_sink->drawing_lock); + } +@@ -602,6 +604,10 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) + gst_object_unref (glimage_sink->display); + glimage_sink->display = NULL; + } ++ ++ glimage_sink->cropmeta = NULL; ++ glimage_sink->videometa = NULL; ++ + break; + } + case GST_STATE_CHANGE_READY_TO_NULL: +@@ -804,6 +810,9 @@ gst_glimage_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) + if (stored_buffer) + gst_buffer_unref (stored_buffer); + ++ glimage_sink->cropmeta = gst_buffer_get_video_crop_meta (buf); ++ glimage_sink->videometa = gst_buffer_get_video_meta (buf); ++ + /* Ask the underlying window to redraw its content */ + if (!gst_glimage_sink_redisplay (glimage_sink)) + goto redisplay_failed; +@@ -1155,7 +1164,7 @@ gst_glimage_sink_on_draw (GstGLImageSink * gl_sink) + #endif + #if GST_GL_HAVE_GLES2 + if (USING_GLES2 (gl_sink->context)) { +- const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f, ++ GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f, + 1.0f, 0.0f, + -1.0f, 1.0f, 0.0f, + 0.0f, 0.0f, +@@ -1165,6 +1174,52 @@ gst_glimage_sink_on_draw (GstGLImageSink * gl_sink) + 1.0f, 1.0f + }; + ++ // recalculate the texcoords based on video crop and alignment ++ { ++ gint bufw, bufh; ++ gint x,y,width,height; ++ ++ if (gl_sink->videometa ++ && (gl_sink->videometa->format == GST_VIDEO_FORMAT_I420 ++ || gl_sink->videometa->format == GST_VIDEO_FORMAT_NV12)) { ++ bufw = gl_sink->videometa->stride[0]; ++ bufh = gl_sink->videometa->offset[1] / bufw; ++ } ++ else { ++ bufw = GST_VIDEO_SINK_WIDTH (gl_sink); ++ bufh = GST_VIDEO_SINK_HEIGHT (gl_sink); ++ } ++ ++ //g_print ("buffer res: %d, %d\n", bufw, bufh); ++ ++ if (gl_sink->cropmeta) { ++ x = gl_sink->cropmeta->x; ++ y = gl_sink->cropmeta->y; ++ width = gl_sink->cropmeta->width; ++ height = gl_sink->cropmeta->height; ++ } ++ else { ++ x = y = 0; ++ width = GST_VIDEO_SINK_WIDTH (gl_sink); ++ height = GST_VIDEO_SINK_HEIGHT (gl_sink); ++ } ++ ++ vVertices[8] = (float)(x) / bufw; ++ vVertices[9] = (float)(y) / bufh; ++ ++ vVertices[3] = (float)(x + width) / bufw; ++ vVertices[4] = vVertices[9]; ++ ++ vVertices[13] = vVertices[8]; ++ vVertices[14] = (float)(y + height) / bufh; ++ ++ vVertices[18] = vVertices[3]; ++ vVertices[19] = vVertices[14]; ++ ++ //g_print ("vVertices, (%f, %f), (%f, %f), (%f, %f), (%f, %f)\n", vVertices[8], vVertices[9], vVertices[3], vVertices[4], ++ // vVertices[13], vVertices[14], vVertices[18], vVertices[19]); ++ } ++ + GLushort indices[] = { 0, 1, 2, 0, 2, 3 }; + + gl->ClearColor (0.0, 0.0, 0.0, 0.0); +diff --git a/ext/gl/gstglimagesink.h b/ext/gl/gstglimagesink.h +index 25e6a13..1805e94 100644 +--- a/ext/gl/gstglimagesink.h ++++ b/ext/gl/gstglimagesink.h +@@ -82,6 +82,9 @@ struct _GstGLImageSink + guint window_width; + guint window_height; + ++ GstVideoCropMeta *cropmeta; ++ GstVideoMeta *videometa; ++ + #if GST_GL_HAVE_GLES2 + GstGLShader *redisplay_shader; + GLint redisplay_attr_position_loc; +diff --git a/gst-libs/gst/gl/gstglvivdirecttexture.c b/gst-libs/gst/gl/gstglvivdirecttexture.c +index 4806335..9131101 100644 +--- a/gst-libs/gst/gl/gstglvivdirecttexture.c ++++ b/gst-libs/gst/gl/gstglvivdirecttexture.c +@@ -89,8 +89,18 @@ gst_gl_viv_direct_bind_gstbuffer (GstGLContext * context, guint tex_id, GstVideo + PhyMemBlock *memblk = &memphy->block; + + GstVideoFormat fmt = GST_VIDEO_INFO_FORMAT (info); +- guint viv_fmt; ++ gint width, height; ++ GstVideoMeta *vmeta = gst_buffer_get_video_meta (buffer); ++ if (vmeta && (fmt == GST_VIDEO_FORMAT_I420 || fmt == GST_VIDEO_FORMAT_NV12)) { ++ width = vmeta->stride[0]; ++ height = vmeta->offset[1] / width; ++ } ++ else { ++ width = GST_VIDEO_INFO_WIDTH (info); ++ height = GST_VIDEO_INFO_HEIGHT (info); ++ } + ++ guint viv_fmt; + switch (fmt) { + case GST_VIDEO_FORMAT_I420: + viv_fmt = GL_VIV_I420; +@@ -107,15 +117,7 @@ gst_gl_viv_direct_bind_gstbuffer (GstGLContext * context, guint tex_id, GstVideo + return FALSE; + } + +- GstVivDirectTexture viv_tex = { +- tex_id, +- GST_VIDEO_INFO_WIDTH (info), +- GST_VIDEO_INFO_HEIGHT (info), +- viv_fmt, +- memblk->vaddr, +- memblk->paddr, +- FALSE}; +- ++ GstVivDirectTexture viv_tex = {tex_id, width, height, viv_fmt, memblk->vaddr, memblk->paddr, FALSE}; + gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _do_viv_direct_tex_bind_mem, &viv_tex); + + return viv_tex.ret; +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0002-mpegtsmux-Need-get-pid-when-create-streams.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0002-mpegtsmux-Need-get-pid-when-create-streams.patch new file mode 100644 index 000000000..a412b276f --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0002-mpegtsmux-Need-get-pid-when-create-streams.patch @@ -0,0 +1,46 @@ +From 315a61197dafe6df4ee6e81b1fff46b3696cc9c6 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Wed, 22 Apr 2015 18:06:35 +0800 +Subject: [PATCH] mpegtsmux: Need get pid when create streams. + +when camerabin use mpegtsmux as muxer, start video recording and then +stop video recording and then start video recording, mpegtsmux get wrong +pid. + +https://bugzilla.gnome.org/show_bug.cgi?id=748288 + +UpStream Status: Pending + +--- + gst/mpegtsmux/mpegtsmux.c | 15 +++++++++++++++ + 1 file changed, 15 insertions(+) + +diff --git a/gst/mpegtsmux/mpegtsmux.c b/gst/mpegtsmux/mpegtsmux.c +index af246a2..c9918a8 100644 +--- a/gst/mpegtsmux/mpegtsmux.c ++++ b/gst/mpegtsmux/mpegtsmux.c +@@ -769,6 +769,21 @@ mpegtsmux_create_streams (MpegTsMux * mux) + } else { + ts_data->prog_id = DEFAULT_PROG_ID; + } ++ ++ if (!ts_data->pid) { ++ gint pid = -1; ++ ++ name = GST_PAD_NAME (c_data->pad); ++ if (name != NULL && sscanf (name, "sink_%d", &pid) == 1) { ++ if (tsmux_find_stream (mux->tsmux, pid)) { ++ GST_WARNING_OBJECT (mux, "Duplicate PID"); ++ } ++ } else { ++ pid = tsmux_get_new_pid (mux->tsmux); ++ } ++ ++ ts_data->pid = pid; ++ } + } + + ts_data->prog = mux->programs[ts_data->prog_id]; +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0003-glimagesink-Add-fps-print-in-glimagesink.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0003-glimagesink-Add-fps-print-in-glimagesink.patch new file mode 100644 index 000000000..e607a1ddf --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0003-glimagesink-Add-fps-print-in-glimagesink.patch @@ -0,0 +1,69 @@ +From 29da042a43dd49e1fb821afd8f6d5d63ad0f9f07 Mon Sep 17 00:00:00 2001 +From: Jian +Date: Mon, 27 Apr 2015 17:42:36 +0800 +Subject: [PATCH 1/3] [glimagesink] Add fps print in glimagesink +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian +--- + ext/gl/gstglimagesink.c | 12 ++++++++++++ + ext/gl/gstglimagesink.h | 2 ++ + 2 files changed, 14 insertions(+) + +diff --git a/ext/gl/gstglimagesink.c b/ext/gl/gstglimagesink.c +index d3cacce..3c0c6b3 100644 +--- a/ext/gl/gstglimagesink.c ++++ b/ext/gl/gstglimagesink.c +@@ -304,6 +304,7 @@ gst_glimage_sink_init (GstGLImageSink * glimage_sink) + glimage_sink->redisplay_texture = 0; + glimage_sink->cropmeta = NULL; + glimage_sink->videometa = NULL; ++ glimage_sink->frame_showed = 0; + + g_mutex_init (&glimage_sink->drawing_lock); + } +@@ -611,6 +612,15 @@ gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) + break; + } + case GST_STATE_CHANGE_READY_TO_NULL: ++ { ++ GstClockTime run_time = gst_element_get_start_time (GST_ELEMENT (glimage_sink)); ++ if (run_time > 0) { ++ g_print ("Total showed frames (%lld), playing for (%"GST_TIME_FORMAT"), fps (%.3f).\n", ++ glimage_sink->frame_showed, GST_TIME_ARGS (run_time), ++ (gfloat)GST_SECOND * glimage_sink->frame_showed / run_time); ++ } ++ } ++ + break; + default: + break; +@@ -827,6 +837,8 @@ gst_glimage_sink_show_frame (GstVideoSink * vsink, GstBuffer * buf) + return GST_FLOW_ERROR; + } + ++ glimage_sink->frame_showed ++; ++ + return GST_FLOW_OK; + + /* ERRORS */ +diff --git a/ext/gl/gstglimagesink.h b/ext/gl/gstglimagesink.h +index 1805e94..5990457 100644 +--- a/ext/gl/gstglimagesink.h ++++ b/ext/gl/gstglimagesink.h +@@ -85,6 +85,8 @@ struct _GstGLImageSink + GstVideoCropMeta *cropmeta; + GstVideoMeta *videometa; + ++ guint64 frame_showed; ++ + #if GST_GL_HAVE_GLES2 + GstGLShader *redisplay_shader; + GLint redisplay_attr_position_loc; +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0004-gl-fb-Support-fb-backend-for-gl-plugins.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0004-gl-fb-Support-fb-backend-for-gl-plugins.patch new file mode 100644 index 000000000..cade26c0d --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0004-gl-fb-Support-fb-backend-for-gl-plugins.patch @@ -0,0 +1,779 @@ +From f70aa04abd040569038136a536d27ba928ad9339 Mon Sep 17 00:00:00 2001 +From: Jian +Date: Mon, 27 Apr 2015 17:41:57 +0800 +Subject: [PATCH 2/3] [gl fb] Support fb backend for gl plugins +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian +--- + configure.ac | 23 ++- + gst-libs/gst/gl/Makefile.am | 6 + + gst-libs/gst/gl/fb/Makefile.am | 25 +++ + gst-libs/gst/gl/fb/gstgldisplay_fb.c | 109 ++++++++++++ + gst-libs/gst/gl/fb/gstgldisplay_fb.h | 66 +++++++ + gst-libs/gst/gl/fb/gstglwindow_fb_egl.c | 283 +++++++++++++++++++++++++++++++ + gst-libs/gst/gl/fb/gstglwindow_fb_egl.h | 68 ++++++++ + gst-libs/gst/gl/gstgldisplay.c | 8 + + gst-libs/gst/gl/gstgldisplay.h | 1 + + gst-libs/gst/gl/gstglwindow.c | 5 + + 10 files changed, 593 insertions(+), 1 deletion(-) + create mode 100644 gst-libs/gst/gl/fb/Makefile.am + create mode 100644 gst-libs/gst/gl/fb/gstgldisplay_fb.c + create mode 100644 gst-libs/gst/gl/fb/gstgldisplay_fb.h + create mode 100644 gst-libs/gst/gl/fb/gstglwindow_fb_egl.c + create mode 100644 gst-libs/gst/gl/fb/gstglwindow_fb_egl.h + +diff --git a/configure.ac b/configure.ac +index b1cfbd8..1dc21f2 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -654,6 +654,7 @@ HAVE_GL=no + HAVE_GLES2=no + HAVE_GLU=no + HAVE_WAYLAND_EGL=no ++HAV_FB_EGL=no + + HAVE_EGL_RPI=no + +@@ -740,6 +741,7 @@ case $host in + CFLAGS=$old_CFLAGS + + PKG_CHECK_MODULES(WAYLAND_EGL, wayland-client >= 1.0 wayland-cursor >= 1.0 wayland-egl >= 1.0, HAVE_WAYLAND_EGL=yes, HAVE_WAYLAND_EGL=no) ++ AC_CHECK_LIB(EGL, fbGetDisplay, HAVE_FB_EGL=yes, HAVE_FB_EGL=no) + ;; + esac + +@@ -958,6 +960,16 @@ case $host in + fi + fi + ++ if test "x$HAVE_FB_EGL" = "xyes"; then ++ if test "x$NEED_EGL" = "xno" -o "x$HAVE_EGL" = "xno"; then ++ AC_MSG_WARN([EGL is required by the fb backend for OpenGL support]) ++ else ++ HAVE_WINDOW_FB=yes ++ GL_LIBS="$GL_LIBS" ++ GL_CFLAGS="$GL_CFLAGS" ++ fi ++ fi ++ + if test "x$HAVE_EGL_RPI" = "xyes"; then + if test "x$NEED_DISPMANX" != "xno"; then + HAVE_WINDOW_DISPMANX=yes +@@ -972,7 +984,7 @@ case $host in + fi + else + if test "x$NEED_EGL" != "xno"; then +- if test "x$HAVE_WINDOW_WAYLAND" = "xyes" -o "x$HAVE_WINDOW_X11" = "xyes" -o "x$HAVE_WINDOW_DISPMANX" = "xyes"; then ++ if test "x$HAVE_WINDOW_WAYLAND" = "xyes" -o "x$HAVE_WINDOW_X11" = "xyes" -o "x$HAVE_WINDOW_DISPMANX" = "xyes" -o "x$HAVE_WINDOW_FB" = "xyes"; then + GL_LIBS="$GL_LIBS -lEGL $EGL_LIBS" + GL_CFLAGS="$GL_CFLAGS $EGL_CFLAGS" + USE_EGL=yes +@@ -1112,6 +1124,7 @@ GST_GL_HAVE_WINDOW_WAYLAND=0 + GST_GL_HAVE_WINDOW_ANDROID=0 + GST_GL_HAVE_WINDOW_DISPMANX=0 + GST_GL_HAVE_WINDOW_EAGL=0 ++GST_GL_HAVE_WINDOW_FB=0 + + if test "x$HAVE_WINDOW_X11" = "xyes"; then + GL_WINDOWS="x11 $GL_WINDOWS" +@@ -1141,6 +1154,10 @@ if test "x$HAVE_WINDOW_EAGL" = "xyes"; then + GL_WINDOWS="eagl $GL_WINDOWS" + GST_GL_HAVE_WINDOW_EAGL=1 + fi ++if test "x$HAVE_WINDOW_FB" = "xyes"; then ++ GL_WINDOWS="fb $GL_WINDOWS" ++ GST_GL_HAVE_WINDOW_FB=1 ++fi + + GL_CONFIG_DEFINES="$GL_CONFIG_DEFINES + #define GST_GL_HAVE_WINDOW_X11 $GST_GL_HAVE_WINDOW_X11 +@@ -1150,6 +1167,7 @@ GL_CONFIG_DEFINES="$GL_CONFIG_DEFINES + #define GST_GL_HAVE_WINDOW_ANDROID $GST_GL_HAVE_WINDOW_ANDROID + #define GST_GL_HAVE_WINDOW_DISPMANX $GST_GL_HAVE_WINDOW_DISPMANX + #define GST_GL_HAVE_WINDOW_EAGL $GST_GL_HAVE_WINDOW_EAGL ++#define GST_GL_HAVE_WINDOW_FB $GST_GL_HAVE_WINDOW_FB + " + + dnl PLATFORM's +@@ -1221,6 +1239,7 @@ if test "x$GL_APIS" = "x" -o "x$GL_PLATFORMS" = "x" -o "x$GL_WINDOWS" = "x"; the + HAVE_WINDOW_ANDROID=no + HAVE_WINDOW_COCOA=no + HAVE_WINDOW_EAGL=no ++ HAVE_WINDOW_FB=no + fi + + AC_SUBST(GL_LIBS) +@@ -1236,6 +1255,7 @@ AM_CONDITIONAL(HAVE_WINDOW_DISPMANX, test "x$HAVE_WINDOW_DISPMANX" = "xyes") + AM_CONDITIONAL(HAVE_WINDOW_WAYLAND, test "x$HAVE_WINDOW_WAYLAND" = "xyes") + AM_CONDITIONAL(HAVE_WINDOW_ANDROID, test "x$HAVE_WINDOW_ANDROID" = "xyes") + AM_CONDITIONAL(HAVE_WINDOW_EAGL, test "x$HAVE_WINDOW_EAGL" = "xyes") ++AM_CONDITIONAL(HAVE_WINDOW_FB, test "x$HAVE_WINDOW_FB" = "xyes") + + AM_CONDITIONAL(USE_OPENGL, test "x$USE_OPENGL" = "xyes") + AM_CONDITIONAL(USE_GLES2, test "x$USE_GLES2" = "xyes") +@@ -3206,6 +3226,7 @@ gst-libs/gst/gl/egl/Makefile + gst-libs/gst/gl/wayland/Makefile + gst-libs/gst/gl/win32/Makefile + gst-libs/gst/gl/x11/Makefile ++gst-libs/gst/gl/fb/Makefile + gst-libs/gst/insertbin/Makefile + gst-libs/gst/interfaces/Makefile + gst-libs/gst/codecparsers/Makefile +diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am +index 86bc439..d5e5baa 100644 +--- a/gst-libs/gst/gl/Makefile.am ++++ b/gst-libs/gst/gl/Makefile.am +@@ -92,11 +92,17 @@ SUBDIRS += eagl + libgstgl_@GST_API_VERSION@_la_LIBADD += eagl/libgstgl-eagl.la + endif + ++if HAVE_WINDOW_FB ++SUBDIRS += fb ++libgstgl_@GST_API_VERSION@_la_LIBADD += fb/libgstgl-fb.la ++endif ++ + if USE_EGL + SUBDIRS += egl + libgstgl_@GST_API_VERSION@_la_LIBADD += egl/libgstgl-egl.la + endif + ++ + nodist_libgstgl_@GST_API_VERSION@include_HEADERS = \ + $(built_header_configure) + +diff --git a/gst-libs/gst/gl/fb/Makefile.am b/gst-libs/gst/gl/fb/Makefile.am +new file mode 100644 +index 0000000..8e4656c +--- /dev/null ++++ b/gst-libs/gst/gl/fb/Makefile.am +@@ -0,0 +1,25 @@ ++## Process this file with automake to produce Makefile.in ++ ++noinst_LTLIBRARIES = libgstgl-fb.la ++ ++libgstgl_fb_la_SOURCES = \ ++ gstgldisplay_fb.c \ ++ gstglwindow_fb_egl.c ++ ++noinst_HEADERS = \ ++ gstgldisplay_fb.h \ ++ gstglwindow_fb_egl.h ++ ++libgstgl_fbincludedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl/fb ++ ++libgstgl_fb_la_CFLAGS = \ ++ -I$(top_srcdir)/gst-libs \ ++ -I$(top_builddir)/gst-libs \ ++ $(GL_CFLAGS) \ ++ $(GST_PLUGINS_BASE_CFLAGS) \ ++ $(GST_BASE_CFLAGS) \ ++ $(GST_CFLAGS) ++ ++libgstgl_fb_la_LDFLAGS = \ ++ $(GST_LIB_LDFLAGS) \ ++ $(GST_ALL_LDFLAGS) +diff --git a/gst-libs/gst/gl/fb/gstgldisplay_fb.c b/gst-libs/gst/gl/fb/gstgldisplay_fb.c +new file mode 100644 +index 0000000..3be9756 +--- /dev/null ++++ b/gst-libs/gst/gl/fb/gstgldisplay_fb.c +@@ -0,0 +1,109 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2014 Matthew Waters ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++ ++GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug); ++#define GST_CAT_DEFAULT gst_gl_display_debug ++ ++G_DEFINE_TYPE (GstGLDisplayFB, gst_gl_display_fb, GST_TYPE_GL_DISPLAY); ++ ++static void gst_gl_display_fb_finalize (GObject * object); ++static guintptr gst_gl_display_fb_get_handle (GstGLDisplay * display); ++ ++static void ++gst_gl_display_fb_class_init (GstGLDisplayFBClass * klass) ++{ ++ GST_GL_DISPLAY_CLASS (klass)->get_handle = ++ GST_DEBUG_FUNCPTR (gst_gl_display_fb_get_handle); ++ ++ G_OBJECT_CLASS (klass)->finalize = gst_gl_display_fb_finalize; ++} ++ ++static void ++gst_gl_display_fb_init (GstGLDisplayFB * display_fb) ++{ ++ GstGLDisplay *display = (GstGLDisplay *) display_fb; ++ ++ display->type = GST_GL_DISPLAY_TYPE_FB; ++ display_fb->name = NULL; ++ display_fb->disp_idx = 0; ++ display_fb->display = NULL; ++} ++ ++static void ++gst_gl_display_fb_finalize (GObject * object) ++{ ++ GstGLDisplayFB *display_fb = GST_GL_DISPLAY_FB (object); ++ ++ if (display_fb->name) ++ g_free (display_fb->name); ++ ++ if (display_fb->display) ++ fbDestroyDisplay (display_fb->display); ++ ++ G_OBJECT_CLASS (gst_gl_display_fb_parent_class)->finalize (object); ++} ++ ++/** ++ * gst_gl_display_fb_new: ++ * @name: (allow-none): a display name ++ * ++ * Create a new #GstGLDisplayFB from the x11 display name. See XOpenDisplay() ++ * for details on what is a valid name. ++ * ++ * Returns: (transfer full): a new #GstGLDisplayFB or %NULL ++ */ ++GstGLDisplayFB * ++gst_gl_display_fb_new (gchar *name) ++{ ++ GstGLDisplayFB *display; ++ const gchar *fb_name = NULL; ++ ++ GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay"); ++ GST_DEBUG ("creating Fb EGL display"); ++ ++ fb_name = name; ++ if (!fb_name) fb_name = "fb0"; ++ ++ display = g_object_new (GST_TYPE_GL_DISPLAY_FB, NULL); ++ display->name = g_strdup (fb_name); ++ sscanf (display->name, "fb%d", &display->disp_idx); ++ display->display = fbGetDisplayByIndex (display->disp_idx); ++ if (!display->display) { ++ GST_ERROR ("Failed to open FB display, \'%s\'", fb_name); ++ return NULL; ++ } ++ ++ GST_DEBUG ("Created fb EGL display %d", display->display); ++ ++ return display; ++} ++ ++static guintptr ++gst_gl_display_fb_get_handle (GstGLDisplay * display) ++{ ++ GST_DEBUG ("Get fb EGL display %d", GST_GL_DISPLAY_FB (display)->display); ++ return (guintptr) GST_GL_DISPLAY_FB (display)->display; ++} +diff --git a/gst-libs/gst/gl/fb/gstgldisplay_fb.h b/gst-libs/gst/gl/fb/gstgldisplay_fb.h +new file mode 100644 +index 0000000..f0a5ce5 +--- /dev/null ++++ b/gst-libs/gst/gl/fb/gstgldisplay_fb.h +@@ -0,0 +1,66 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2014 Matthew Waters ++ * ++ * 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_GL_DISPLAY_FB_H__ ++#define __GST_GL_DISPLAY_FB_H__ ++ ++#include ++#include ++ ++G_BEGIN_DECLS ++ ++GType gst_gl_display_fb_get_type (void); ++ ++#define GST_TYPE_GL_DISPLAY_FB (gst_gl_display_fb_get_type()) ++#define GST_GL_DISPLAY_FB(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DISPLAY_FB,GstGLDisplayFB)) ++#define GST_GL_DISPLAY_FB_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GL_DISPLAY_FB,GstGLDisplayFBClass)) ++#define GST_IS_GL_DISPLAY_FB(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DISPLAY_FB)) ++#define GST_IS_GL_DISPLAY_FB_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GL_DISPLAY_FB)) ++#define GST_GL_DISPLAY_FB_CAST(obj) ((GstGLDisplayFB*)(obj)) ++ ++typedef struct _GstGLDisplayFB GstGLDisplayFB; ++typedef struct _GstGLDisplayFBClass GstGLDisplayFBClass; ++ ++/** ++ * GstGLDisplayFB: ++ * ++ * the contents of a #GstGLDisplayFB are private and should only be accessed ++ * through the provided API ++ */ ++struct _GstGLDisplayFB ++{ ++ GstGLDisplay parent; ++ ++ /* */ ++ gchar *name; ++ gint disp_idx; ++ EGLNativeDisplayType display; ++}; ++ ++struct _GstGLDisplayFBClass ++{ ++ GstGLDisplayClass object_class; ++}; ++ ++GstGLDisplayFB *gst_gl_display_fb_new (gchar *name); ++ ++G_END_DECLS ++ ++#endif /* __GST_GL_DISPLAY_FB_H__ */ +diff --git a/gst-libs/gst/gl/fb/gstglwindow_fb_egl.c b/gst-libs/gst/gl/fb/gstglwindow_fb_egl.c +new file mode 100644 +index 0000000..edb5fb9 +--- /dev/null ++++ b/gst-libs/gst/gl/fb/gstglwindow_fb_egl.c +@@ -0,0 +1,283 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2008 Julien Isorce ++ * Copyright (C) 2012 Matthew Waters ++ * ++ * 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 "../gstgl_fwd.h" ++#include ++ ++#include "gstglwindow_fb_egl.h" ++ ++#define GST_CAT_DEFAULT gst_gl_window_debug ++ ++#define gst_gl_window_fb_egl_parent_class parent_class ++G_DEFINE_TYPE (GstGLWindowFbEGL, gst_gl_window_fb_egl, ++ GST_GL_TYPE_WINDOW); ++ ++static guintptr gst_gl_window_fb_egl_get_window_handle (GstGLWindow * ++ window); ++static void gst_gl_window_fb_egl_set_window_handle (GstGLWindow * window, ++ guintptr handle); ++static void gst_gl_window_fb_egl_draw (GstGLWindow * window, guint width, ++ guint height); ++static void gst_gl_window_fb_egl_run (GstGLWindow * window); ++static void gst_gl_window_fb_egl_quit (GstGLWindow * window); ++static void gst_gl_window_fb_egl_send_message_async (GstGLWindow * window, ++ GstGLWindowCB callback, gpointer data, GDestroyNotify destroy); ++static void gst_gl_window_fb_egl_close (GstGLWindow * window); ++static gboolean gst_gl_window_fb_egl_open (GstGLWindow * window, ++ GError ** error); ++ ++static void ++gst_gl_window_fb_egl_class_init (GstGLWindowFbEGLClass * klass) ++{ ++ GstGLWindowClass *window_class = (GstGLWindowClass *) klass; ++ ++ window_class->get_window_handle = ++ GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_get_window_handle); ++ window_class->set_window_handle = ++ GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_set_window_handle); ++ window_class->draw_unlocked = ++ GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_draw); ++ window_class->draw = GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_draw); ++ window_class->run = GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_run); ++ window_class->quit = GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_quit); ++ window_class->send_message_async = ++ GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_send_message_async); ++ window_class->close = GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_close); ++ window_class->open = GST_DEBUG_FUNCPTR (gst_gl_window_fb_egl_open); ++} ++ ++static void ++gst_gl_window_fb_egl_init (GstGLWindowFbEGL * window) ++{ ++ GstGLWindowFbEGL *window_egl; ++ ++ window_egl = GST_GL_WINDOW_FB_EGL (window); ++ ++ window_egl->width = 0; ++ window_egl->height = 0; ++ window_egl->fullscreen = FALSE; ++ window_egl->display = 0; ++ window_egl->main_context = NULL; ++ window_egl->loop = NULL; ++} ++ ++/* Must be called in the gl thread */ ++GstGLWindowFbEGL * ++gst_gl_window_fb_egl_new (GstGLDisplay * display) ++{ ++ GstGLWindowFbEGL *window; ++ const gchar *fb_name = NULL; ++ ++ if (!display) ++ return NULL; ++ ++ window = g_object_new (GST_GL_TYPE_WINDOW_FB_EGL, NULL); ++ window->display = gst_gl_display_get_handle (display); ++ if (!window->display) { ++ GST_ERROR ("failed to get display for egl window"); ++ return NULL; ++ } ++ ++ return window; ++} ++ ++static void ++gst_gl_window_fb_egl_close (GstGLWindow * window) ++{ ++ GstGLWindowFbEGL *window_egl; ++ ++ window_egl = GST_GL_WINDOW_FB_EGL (window); ++ ++ g_main_loop_unref (window_egl->loop); ++ g_main_context_unref (window_egl->main_context); ++ ++ if (window_egl->win_id) { ++ fbDestroyWindow (window_egl->win_id); ++ } ++} ++ ++static gboolean ++gst_gl_window_fb_egl_open (GstGLWindow * window, GError ** error) ++{ ++ GstGLWindowFbEGL *window_egl; ++ ++ window_egl = GST_GL_WINDOW_FB_EGL (window); ++ ++ if (!window_egl->display) { ++ GST_ERROR ("No display for window_egl."); ++ return FALSE; ++ } ++ ++ window_egl->win_id = fbCreateWindow (window_egl->display, -1, -1, 0, 0); ++ if (!window_egl->win_id) { ++ GST_ERROR ("Failed to create window_egl"); ++ return FALSE; ++ } ++ ++ fbGetDisplayGeometry (window_egl->display, &window_egl->width, &window_egl->height); ++ window_egl->req_width = window_egl->width; ++ window_egl->req_height = window_egl->height; ++ GST_DEBUG ("Open FB display succesfully, resolution is (%dx%d),display %d, window %d.", ++ window_egl->width, window_egl->height, window_egl->display, window_egl->win_id); ++ ++ window_egl->main_context = g_main_context_new (); ++ window_egl->loop = g_main_loop_new (window_egl->main_context, FALSE); ++ ++ return TRUE; ++} ++ ++static void ++gst_gl_window_fb_egl_run (GstGLWindow * window) ++{ ++ GstGLWindowFbEGL *window_egl; ++ ++ window_egl = GST_GL_WINDOW_FB_EGL (window); ++ ++ GST_LOG ("starting main loop"); ++ g_main_loop_run (window_egl->loop); ++ GST_LOG ("exiting main loop"); ++} ++ ++static void ++gst_gl_window_fb_egl_quit (GstGLWindow * window) ++{ ++ GstGLWindowFbEGL *window_egl; ++ ++ window_egl = GST_GL_WINDOW_FB_EGL (window); ++ ++ GST_LOG ("sending quit"); ++ ++ g_main_loop_quit (window_egl->loop); ++ ++ GST_LOG ("quit sent"); ++} ++ ++typedef struct _GstGLMessage ++{ ++ GstGLWindowCB callback; ++ gpointer data; ++ GDestroyNotify destroy; ++} GstGLMessage; ++ ++static gboolean ++_run_message (GstGLMessage * message) ++{ ++ if (message->callback) ++ message->callback (message->data); ++ ++ if (message->destroy) ++ message->destroy (message->data); ++ ++ g_slice_free (GstGLMessage, message); ++ ++ return FALSE; ++} ++ ++static void ++gst_gl_window_fb_egl_send_message_async (GstGLWindow * window, ++ GstGLWindowCB callback, gpointer data, GDestroyNotify destroy) ++{ ++ GstGLWindowFbEGL *window_egl; ++ GstGLMessage *message; ++ ++ window_egl = GST_GL_WINDOW_FB_EGL (window); ++ message = g_slice_new (GstGLMessage); ++ ++ message->callback = callback; ++ message->data = data; ++ message->destroy = destroy; ++ ++ g_main_context_invoke (window_egl->main_context, (GSourceFunc) _run_message, ++ message); ++} ++ ++static guintptr ++gst_gl_window_fb_egl_get_window_handle (GstGLWindow * window) ++{ ++ GST_DEBUG ("fb egl get window: %d", GST_GL_WINDOW_FB_EGL (window)->win_id); ++ return (guintptr) GST_GL_WINDOW_FB_EGL (window)->win_id; ++} ++ ++static void ++gst_gl_window_fb_egl_set_window_handle (GstGLWindow * window, ++ guintptr handle) ++{ ++} ++ ++struct draw ++{ ++ GstGLWindowFbEGL *window; ++ guint width, height; ++}; ++ ++static void ++draw_cb (gpointer data) ++{ ++ struct draw *draw_data = data; ++ GstGLWindowFbEGL *window_egl = draw_data->window; ++ GstGLWindow *window = GST_GL_WINDOW (window_egl); ++ GstGLContext *context = gst_gl_window_get_context (window); ++ GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context); ++ ++#if 0 ++ if (draw_data->width != window_egl->req_width || draw_data->height != window_egl->req_height) { ++ if (draw_data->width == 0) ++ window_egl->req_width = window_egl->width; ++ else ++ window_egl->req_width = draw_data->width; ++ ++ if (draw_data->height == 0) ++ window_egl->req_height = window_egl->height; ++ else ++ window_egl->req_height = draw_data->height; ++ ++ if (window->resize) ++ window->resize (window->resize_data, window_egl->req_width, window_egl->req_height); ++ } ++#endif ++ ++ //FIXME: default full screen currently ++ if (!window_egl->fullscreen && window->resize) { ++ window->resize (window->resize_data, window_egl->width, window_egl->height); ++ window_egl->fullscreen = TRUE; ++ } ++ ++ if (window->draw) ++ window->draw (window->draw_data); ++ ++ GST_DEBUG ("####### draw data"); ++ context_class->swap_buffers (context); ++ ++ gst_object_unref (context); ++} ++ ++static void ++gst_gl_window_fb_egl_draw (GstGLWindow * window, guint width, guint height) ++{ ++ struct draw draw_data; ++ ++ draw_data.window = GST_GL_WINDOW_FB_EGL (window); ++ draw_data.width = width; ++ draw_data.height = height; ++ ++ gst_gl_window_send_message (window, (GstGLWindowCB) draw_cb, &draw_data); ++} ++ +diff --git a/gst-libs/gst/gl/fb/gstglwindow_fb_egl.h b/gst-libs/gst/gl/fb/gstglwindow_fb_egl.h +new file mode 100644 +index 0000000..bcd71ab +--- /dev/null ++++ b/gst-libs/gst/gl/fb/gstglwindow_fb_egl.h +@@ -0,0 +1,68 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2012 Matthew Waters ++ * ++ * 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_GL_WINDOW_FB_EGL_H__ ++#define __GST_GL_WINDOW_FB_EGL_H__ ++ ++#include ++#include "EGL/eglvivante.h" ++ ++G_BEGIN_DECLS ++ ++#define GST_GL_TYPE_WINDOW_FB_EGL (gst_gl_window_fb_egl_get_type()) ++#define GST_GL_WINDOW_FB_EGL(o) (G_TYPE_CHECK_INSTANCE_CAST((o), GST_GL_TYPE_WINDOW_FB_EGL, GstGLWindowFbEGL)) ++#define GST_GL_WINDOW_FB_EGL_CLASS(k) (G_TYPE_CHECK_CLASS((k), GST_GL_TYPE_WINDOW_FB_EGL, GstGLWindowFbEGLClass)) ++#define GST_GL_IS_WINDOW_FB_EGL(o) (G_TYPE_CHECK_INSTANCE_TYPE((o), GST_GL_TYPE_WINDOW_FB_EGL)) ++#define GST_GL_IS_WINDOW_FB_EGL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE((k), GST_GL_TYPE_WINDOW_FB_EGL)) ++#define GST_GL_WINDOW_FB_EGL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS((o), GST_GL_TYPE_WINDOW_FB_EGL, GstGLWindowFbEGL_Class)) ++ ++typedef struct _GstGLWindowFbEGL GstGLWindowFbEGL; ++typedef struct _GstGLWindowFbEGLClass GstGLWindowFbEGLClass; ++ ++struct _GstGLWindowFbEGL { ++ /*< private >*/ ++ GstGLWindow parent; ++ ++ /* */ ++ gint width, req_width; ++ gint height, req_height; ++ gboolean fullscreen; ++ EGLNativeDisplayType display; ++ EGLNativeWindowType win_id; ++ ++ GMainContext *main_context; ++ GMainLoop *loop; ++}; ++ ++struct _GstGLWindowFbEGLClass { ++ /*< private >*/ ++ GstGLWindowClass parent_class; ++ ++ /*< private >*/ ++ gpointer _reserved[GST_PADDING]; ++}; ++ ++GType gst_gl_window_fb_egl_get_type (void); ++ ++GstGLWindowFbEGL * gst_gl_window_fb_egl_new (GstGLDisplay * display); ++ ++G_END_DECLS ++ ++#endif /* __GST_GL_WINDOW_FB_EGL_H__ */ +diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c +index 6b7b835..9de8411 100644 +--- a/gst-libs/gst/gl/gstgldisplay.c ++++ b/gst-libs/gst/gl/gstgldisplay.c +@@ -157,6 +157,14 @@ gst_gl_display_new (void) + if (!display && (!user_choice || g_strstr_len (user_choice, 7, "wayland"))) + display = g_object_new (GST_TYPE_GL_DISPLAY, NULL); + #endif ++#if GST_GL_HAVE_WINDOW_FB ++ if (!display && (!user_choice || g_strstr_len (user_choice, 2, "fb"))) { ++ const gchar *fb_name = NULL; ++ fb_name = g_getenv ("GST_GL_FB"); ++ if (!fb_name) fb_name = "fb0"; ++ display = GST_GL_DISPLAY (gst_gl_display_fb_new (fb_name)); ++ } ++#endif + #if GST_GL_HAVE_PLATFORM_EGL + if (!display && (!platform_choice + || g_strstr_len (platform_choice, 3, "egl"))) +diff --git a/gst-libs/gst/gl/gstgldisplay.h b/gst-libs/gst/gl/gstgldisplay.h +index 09489a6..d4d3db5 100644 +--- a/gst-libs/gst/gl/gstgldisplay.h ++++ b/gst-libs/gst/gl/gstgldisplay.h +@@ -49,6 +49,7 @@ typedef enum + GST_GL_DISPLAY_TYPE_WIN32 = (1 << 3), + GST_GL_DISPLAY_TYPE_DISPMANX = (1 << 4), + GST_GL_DISPLAY_TYPE_EGL = (1 << 5), ++ GST_GL_DISPLAY_TYPE_FB = (1 << 6), + + GST_GL_DISPLAY_TYPE_ANY = G_MAXUINT32 + } GstGLDisplayType; +diff --git a/gst-libs/gst/gl/gstglwindow.c b/gst-libs/gst/gl/gstglwindow.c +index a35ca05..86ebf78 100644 +--- a/gst-libs/gst/gl/gstglwindow.c ++++ b/gst-libs/gst/gl/gstglwindow.c +@@ -187,6 +187,11 @@ gst_gl_window_new (GstGLDisplay * display) + if (!window && (!user_choice || g_strstr_len (user_choice, 4, "eagl"))) + window = GST_GL_WINDOW (gst_gl_window_eagl_new ()); + #endif ++#if GST_GL_HAVE_WINDOW_FB ++ if (!window && (!user_choice || g_strstr_len (user_choice, 2, "fb"))) ++ window = GST_GL_WINDOW (gst_gl_window_fb_egl_new (display)); ++#endif ++ + if (!window) { + /* subclass returned a NULL window */ + GST_WARNING ("Could not create window. user specified %s, creating dummy" +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0005-gl-wayland-Make-it-always-fullscreen-1024x768.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0005-gl-wayland-Make-it-always-fullscreen-1024x768.patch new file mode 100644 index 000000000..6af56b4e6 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0005-gl-wayland-Make-it-always-fullscreen-1024x768.patch @@ -0,0 +1,57 @@ +From 6bdbf69076950eb3024b1b271f3ff205df3937e4 Mon Sep 17 00:00:00 2001 +From: Jian +Date: Mon, 27 Apr 2015 17:43:16 +0800 +Subject: [PATCH 3/3] [gl wayland] Make it always fullscreen (1024x768) +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +gl wayland backend has problem for window resolution, +currently make if always 1024x768. + +Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian +--- + gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c +index d5853b0..5d9b457 100644 +--- a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c ++++ b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c +@@ -195,9 +195,9 @@ create_surface (GstGLWindowWaylandEGL * window_egl) + &shell_surface_listener, window_egl); + + if (window_egl->window.window_width <= 0) +- window_egl->window.window_width = 320; ++ window_egl->window.window_width = 1024; + if (window_egl->window.window_height <= 0) +- window_egl->window.window_height = 240; ++ window_egl->window.window_height = 768; + + window_egl->window.native = + wl_egl_window_create (window_egl->window.surface, +@@ -483,11 +483,19 @@ draw_cb (gpointer data) + GstGLContext *context = gst_gl_window_get_context (window); + GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context); + ++#if 0 + if (window_egl->window.window_width != draw_data->width + || window_egl->window.window_height != draw_data->height) { + GST_DEBUG ("dimensions don't match, attempting resize"); + window_resize (window_egl, draw_data->width, draw_data->height); + } ++#endif ++ ++ // Fix to fullscreen here ++ if (!window_egl->window.fullscreen) { ++ window_resize (window_egl, window_egl->window.window_width, window_egl->window.window_height); ++ window_egl->window.fullscreen = 1; ++ } + + if (window->draw) + window->draw (window->draw_data); +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0006-h263parse_fix_CPFMT_parsing.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0006-h263parse_fix_CPFMT_parsing.patch new file mode 100644 index 000000000..b5009b1d4 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0006-h263parse_fix_CPFMT_parsing.patch @@ -0,0 +1,88 @@ +From: Lyon Wang +Date: Tue May 12 15:47:33 2015 +0800 + + h263parse: fix custom picture format (CPFMT) parsing + + In the H263 spec, CPFMT is present only if the use of a custom + picture format is signalled in PLUSEPTYPE and UFEP is "001", + so we need to check params->format and only if the value is + 6 (custom source format) the CPFMT should be read, otherwise + it's not present and wrong data will be parsed. + + When reading the CPFMT, the width and height were not + calculated correctly (wrong bitmask). + + https://bugzilla.gnome.org//show_bug.cgi?id=749253 + Upstream Status: accepted and has been pushed to the master + +diff --git a/gst/videoparsers/h263parse.c b/gst/videoparsers/h263parse.c +index d794f7a..98a30e7 100644 +--- a/gst/videoparsers/h263parse.c ++++ b/gst/videoparsers/h263parse.c +@@ -271,29 +271,46 @@ gst_h263_parse_get_params (H263Params * params, GstBuffer * buffer, + } + + if (ufep == 1) { +- guint32 cpfmt = 0; ++ if (params->format == 6) { ++ /* A fixed length codeword of 23 bits that is present only if the use of ++ * a custom picture format is signalled in PLUSPTYPE and UFEP is 001 */ ++ guint32 cpfmt = 0; + +- /* 5.1.5 CPFMT : Custom Picture Format (23 bits) */ +- if (!gst_bit_reader_get_bits_uint32 (&br, &cpfmt, 23)) +- goto more; +- if (!(cpfmt & 0x200)) { +- GST_WARNING ("Corrupted CPFMT (0x%x)", cpfmt); +- goto beach; +- } +- temp8 = cpfmt >> 19; +- params->width = (((cpfmt >> 10) & 0x1f) + 1) * 4; +- params->height = ((cpfmt & 0x1f) + 1) * 4; +- +- if (temp8 == 0xf) { +- guint32 epar = 0; +- /* 5.1.6 EPAR : Extended Pixel Aspect Ratio (16bits) */ +- if (!gst_bit_reader_get_bits_uint32 (&br, &epar, 16)) ++ /* 5.1.5 CPFMT : Custom Picture Format (23 bits) */ ++ if (!gst_bit_reader_get_bits_uint32 (&br, &cpfmt, 23)) + goto more; +- params->parnum = epar >> 8; +- params->pardenom = epar & 0xf; ++ if (!(cpfmt & 0x200)) { ++ GST_WARNING ("Corrupted CPFMT (0x%x)", cpfmt); ++ goto beach; ++ } ++ temp8 = cpfmt >> 19; ++ /* Bits 5-13: Picture Width Indication: Range [0, ... , 511]; ++ * Number of pixels per line = (PWI + 1) * 4 */ ++ params->width = (((cpfmt >> 10) & 0x1ff) + 1) * 4; ++ /* Bits 15-23 Picture Height Indication: Range [1, ... , 288]; ++ * Number of lines = PHI * 4 */ ++ params->height = (cpfmt & 0x1ff) * 4; ++ ++ if (temp8 == 0xf) { ++ guint32 epar = 0; ++ /* 5.1.6 EPAR : Extended Pixel Aspect Ratio (16bits) */ ++ if (!gst_bit_reader_get_bits_uint32 (&br, &epar, 16)) ++ goto more; ++ params->parnum = epar >> 8; ++ params->pardenom = epar & 0xf; ++ } else { ++ params->parnum = partable[temp8][0]; ++ params->pardenom = partable[temp8][1]; ++ } + } else { +- params->parnum = partable[temp8][0]; +- params->pardenom = partable[temp8][1]; ++ /* Fill in width/height based on format */ ++ params->width = sizetable[params->format][0]; ++ params->height = sizetable[params->format][1]; ++ GST_DEBUG (" Picture width x height: %d x %d", ++ params->width, params->height); ++ /* Fill in default Pixel aspect ratios */ ++ params->parnum = 12; ++ params->pardenom = 11; + } + + if (params->custompcfpresent) { diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0007-glfilter-Fix-video-is-tearing-after-enab.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0007-glfilter-Fix-video-is-tearing-after-enab.patch new file mode 100644 index 000000000..203166ee4 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0007-glfilter-Fix-video-is-tearing-after-enab.patch @@ -0,0 +1,66 @@ +From b74f9d15cad37abddd9050a14fb12c1dac0a43eb Mon Sep 17 00:00:00 2001 +From: Jian +Date: Thu, 21 May 2015 12:55:15 +0800 +Subject: [PATCH] MMFMWK-6582 [glfilter] Fix video is tearing after enable + graphic effect +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Need to finish current gl draw before send the buffer +to downstream elements + +Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian +--- + gst-libs/gst/gl/gstglfilter.c | 7 +++++++ + gst-libs/gst/gl/gstglfilter.h | 2 ++ + 2 files changed, 9 insertions(+) + +diff --git a/gst-libs/gst/gl/gstglfilter.c b/gst-libs/gst/gl/gstglfilter.c +index d038dcc..feff9de 100644 +--- a/gst-libs/gst/gl/gstglfilter.c ++++ b/gst-libs/gst/gl/gstglfilter.c +@@ -300,6 +300,8 @@ gst_gl_filter_reset (GstGLFilter * filter) + if (filter->context) + gst_object_unref (filter->context); + filter->context = NULL; ++ ++ filter->sync_draw = FALSE; + } + + static gboolean +@@ -1197,6 +1199,7 @@ gst_gl_filter_filter_texture (GstGLFilter * filter, GstBuffer * inbuf, + GST_DEBUG ("Physical continious buffer, attempting viv direct texture binding"); + gst_gl_viv_direct_bind_gstbuffer (filter->context, filter->out_tex_id, &filter->out_info, outbuf); + to_download = FALSE; ++ filter->sync_draw = TRUE; + out_tex = filter->out_tex_id; + } + else { +@@ -1434,4 +1437,8 @@ gst_gl_filter_draw_texture (GstGLFilter * filter, GLuint texture, + gl->DisableVertexAttribArray (filter->draw_attr_texture_loc); + } + #endif ++ ++ if (filter->sync_draw) { ++ gl->Finish (); ++ } + } +diff --git a/gst-libs/gst/gl/gstglfilter.h b/gst-libs/gst/gl/gstglfilter.h +index c786493..1543d61 100644 +--- a/gst-libs/gst/gl/gstglfilter.h ++++ b/gst-libs/gst/gl/gstglfilter.h +@@ -90,6 +90,8 @@ struct _GstGLFilter + GLint draw_attr_position_loc; + GLint draw_attr_texture_loc; + #endif ++ ++ gboolean sync_draw; + }; + + /** +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0008-gl-Fix-glimagesink-loop-playback-failed-in-wayland.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0008-gl-Fix-glimagesink-loop-playback-failed-in-wayland.patch new file mode 100644 index 000000000..3d2df025e --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0008-gl-Fix-glimagesink-loop-playback-failed-in-wayland.patch @@ -0,0 +1,561 @@ +From 060f597eda27c8e4492c265f249e21d4ad5f3cc3 Mon Sep 17 00:00:00 2001 +From: Jian +Date: Mon, 25 May 2015 16:30:53 +0800 +Subject: [PATCH] [gl] Fix glimagesink loop playback failed in wayland +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +gl/wayland: add GstGLDisplayWayland +Simple implementation split from GstGLWindowWayland + +Upstream Status: Back Port + +https://bugzilla.gnome.org/show_bug.cgi?id=749411 + +Signed-off-by: Jian +--- + gst-libs/gst/gl/gstgldisplay.c | 5 +- + gst-libs/gst/gl/wayland/Makefile.am | 2 + + gst-libs/gst/gl/wayland/gstgldisplay_wayland.c | 157 +++++++++++++++++++++ + gst-libs/gst/gl/wayland/gstgldisplay_wayland.h | 74 ++++++++++ + gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c | 129 ++++++----------- + 5 files changed, 280 insertions(+), 87 deletions(-) + create mode 100644 gst-libs/gst/gl/wayland/gstgldisplay_wayland.c + create mode 100644 gst-libs/gst/gl/wayland/gstgldisplay_wayland.h + +diff --git a/gst-libs/gst/gl/gstgldisplay.c b/gst-libs/gst/gl/gstgldisplay.c +index 9de8411..a200c14 100644 +--- a/gst-libs/gst/gl/gstgldisplay.c ++++ b/gst-libs/gst/gl/gstgldisplay.c +@@ -59,6 +59,9 @@ + #if GST_GL_HAVE_WINDOW_X11 + #include + #endif ++#if GST_GL_HAVE_WINDOW_WAYLAND ++#include ++#endif + #if GST_GL_HAVE_PLATFORM_EGL + #include + #include +@@ -155,7 +158,7 @@ gst_gl_display_new (void) + #endif + #if GST_GL_HAVE_WINDOW_WAYLAND + if (!display && (!user_choice || g_strstr_len (user_choice, 7, "wayland"))) +- display = g_object_new (GST_TYPE_GL_DISPLAY, NULL); ++ display = GST_GL_DISPLAY (gst_gl_display_wayland_new (NULL)); + #endif + #if GST_GL_HAVE_WINDOW_FB + if (!display && (!user_choice || g_strstr_len (user_choice, 2, "fb"))) { +diff --git a/gst-libs/gst/gl/wayland/Makefile.am b/gst-libs/gst/gl/wayland/Makefile.am +index 9006e67..1b284fb 100644 +--- a/gst-libs/gst/gl/wayland/Makefile.am ++++ b/gst-libs/gst/gl/wayland/Makefile.am +@@ -3,10 +3,12 @@ + noinst_LTLIBRARIES = libgstgl-wayland.la + + libgstgl_wayland_la_SOURCES = \ ++ gstgldisplay_wayland.c \ + gstglwindow_wayland_egl.c \ + wayland_event_source.c + + noinst_HEADERS = \ ++ gstgldisplay_wayland.h \ + gstglwindow_wayland_egl.h \ + wayland_event_source.h + +diff --git a/gst-libs/gst/gl/wayland/gstgldisplay_wayland.c b/gst-libs/gst/gl/wayland/gstgldisplay_wayland.c +new file mode 100644 +index 0000000..90cf1ea +--- /dev/null ++++ b/gst-libs/gst/gl/wayland/gstgldisplay_wayland.c +@@ -0,0 +1,157 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2013 Matthew Waters ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include ++ ++GST_DEBUG_CATEGORY_STATIC (gst_gl_display_debug); ++#define GST_CAT_DEFAULT gst_gl_display_debug ++ ++G_DEFINE_TYPE (GstGLDisplayWayland, gst_gl_display_wayland, ++ GST_TYPE_GL_DISPLAY); ++ ++static void gst_gl_display_wayland_finalize (GObject * object); ++static guintptr gst_gl_display_wayland_get_handle (GstGLDisplay * display); ++ ++static void ++registry_handle_global (void *data, struct wl_registry *registry, ++ uint32_t name, const char *interface, uint32_t version) ++{ ++ GstGLDisplayWayland *display = data; ++ ++ GST_TRACE_OBJECT (display, "registry_handle_global with registry %p, " ++ "interface %s, version %u", registry, interface, version); ++ ++ if (g_strcmp0 (interface, "wl_compositor") == 0) { ++ display->compositor = ++ wl_registry_bind (registry, name, &wl_compositor_interface, 1); ++ } else if (g_strcmp0 (interface, "wl_shell") == 0) { ++ display->shell = wl_registry_bind (registry, name, &wl_shell_interface, 1); ++ } ++} ++ ++static const struct wl_registry_listener registry_listener = { ++ registry_handle_global ++}; ++ ++static void ++_connect_listeners (GstGLDisplayWayland * display) ++{ ++ display->registry = wl_display_get_registry (display->display); ++ wl_registry_add_listener (display->registry, ®istry_listener, display); ++ ++ wl_display_roundtrip (display->display); ++} ++ ++static void ++gst_gl_display_wayland_class_init (GstGLDisplayWaylandClass * klass) ++{ ++ GST_GL_DISPLAY_CLASS (klass)->get_handle = ++ GST_DEBUG_FUNCPTR (gst_gl_display_wayland_get_handle); ++ ++ G_OBJECT_CLASS (klass)->finalize = gst_gl_display_wayland_finalize; ++} ++ ++static void ++gst_gl_display_wayland_init (GstGLDisplayWayland * display_wayland) ++{ ++ GstGLDisplay *display = (GstGLDisplay *) display_wayland; ++ ++ display->type = GST_GL_DISPLAY_TYPE_WAYLAND; ++ display_wayland->foreign_display = FALSE; ++} ++ ++static void ++gst_gl_display_wayland_finalize (GObject * object) ++{ ++ GstGLDisplayWayland *display_wayland = GST_GL_DISPLAY_WAYLAND (object); ++ ++ if (!display_wayland->foreign_display && display_wayland->display) { ++ wl_display_flush (display_wayland->display); ++ wl_display_disconnect (display_wayland->display); ++ } ++ ++ G_OBJECT_CLASS (gst_gl_display_wayland_parent_class)->finalize (object); ++} ++ ++/** ++ * gst_gl_display_wayland_new: ++ * @name: (allow-none): a display name ++ * ++ * Create a new #GstGLDisplayWayland from the wayland display name. See wl_display_connect() ++ * for details on what is a valid name. ++ * ++ * Returns: (transfer full): a new #GstGLDisplayWayland or %NULL ++ */ ++GstGLDisplayWayland * ++gst_gl_display_wayland_new (const gchar * name) ++{ ++ GstGLDisplayWayland *ret; ++ ++ GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay"); ++ ++ ret = g_object_new (GST_TYPE_GL_DISPLAY_WAYLAND, NULL); ++ ret->display = wl_display_connect (name); ++ ++ if (!ret->display) { ++ GST_ERROR ("Failed to open X11 display connection with name, \'%s\'", name); ++ return NULL; ++ } ++ ++ _connect_listeners (ret); ++ ++ return ret; ++} ++ ++/** ++ * gst_gl_display_wayland_new_with_display: ++ * @display: an existing, wayland display ++ * ++ * Creates a new display connection from a wl_display Display. ++ * ++ * Returns: (transfer full): a new #GstGLDisplayWayland ++ */ ++GstGLDisplayWayland * ++gst_gl_display_wayland_new_with_display (struct wl_display * display) ++{ ++ GstGLDisplayWayland *ret; ++ ++ g_return_val_if_fail (display != NULL, NULL); ++ ++ GST_DEBUG_CATEGORY_GET (gst_gl_display_debug, "gldisplay"); ++ ++ ret = g_object_new (GST_TYPE_GL_DISPLAY_WAYLAND, NULL); ++ ++ ret->display = display; ++ ret->foreign_display = TRUE; ++ ++ _connect_listeners (ret); ++ ++ return ret; ++} ++ ++static guintptr ++gst_gl_display_wayland_get_handle (GstGLDisplay * display) ++{ ++ return (guintptr) GST_GL_DISPLAY_WAYLAND (display)->display; ++} +diff --git a/gst-libs/gst/gl/wayland/gstgldisplay_wayland.h b/gst-libs/gst/gl/wayland/gstgldisplay_wayland.h +new file mode 100644 +index 0000000..67b3883 +--- /dev/null ++++ b/gst-libs/gst/gl/wayland/gstgldisplay_wayland.h +@@ -0,0 +1,74 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2013 Matthew Waters ++ * ++ * 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_GL_DISPLAY_WAYLAND_H__ ++#define __GST_GL_DISPLAY_WAYLAND_H__ ++ ++#include ++ ++#include ++ ++#include ++#include ++ ++G_BEGIN_DECLS ++ ++GType gst_gl_display_wayland_get_type (void); ++ ++#define GST_TYPE_GL_DISPLAY_WAYLAND (gst_gl_display_wayland_get_type()) ++#define GST_GL_DISPLAY_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_DISPLAY_WAYLAND,GstGLDisplayWayland)) ++#define GST_GL_DISPLAY_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), GST_TYPE_GL_DISPLAY_WAYLAND,GstGLDisplayWaylandClass)) ++#define GST_IS_GL_DISPLAY_WAYLAND(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_DISPLAY_WAYLAND)) ++#define GST_IS_GL_DISPLAY_WAYLAND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), GST_TYPE_GL_DISPLAY_WAYLAND)) ++#define GST_GL_DISPLAY_WAYLAND_CAST(obj) ((GstGLDisplayWayland*)(obj)) ++ ++typedef struct _GstGLDisplayWayland GstGLDisplayWayland; ++typedef struct _GstGLDisplayWaylandClass GstGLDisplayWaylandClass; ++ ++/** ++ * GstGLDisplayWayland: ++ * ++ * the contents of a #GstGLDisplayWayland are private and should only be accessed ++ * through the provided API ++ */ ++struct _GstGLDisplayWayland ++{ ++ GstGLDisplay parent; ++ ++ struct wl_display *display; ++ struct wl_registry *registry; ++ struct wl_compositor *compositor; ++ struct wl_shell *shell; ++ ++ /* */ ++ gboolean foreign_display; ++}; ++ ++struct _GstGLDisplayWaylandClass ++{ ++ GstGLDisplayClass object_class; ++}; ++ ++GstGLDisplayWayland *gst_gl_display_wayland_new (const gchar * name); ++GstGLDisplayWayland *gst_gl_display_wayland_new_with_display (struct wl_display *display); ++ ++G_END_DECLS ++ ++#endif /* __GST_GL_DISPLAY_WAYLAND_H__ */ +diff --git a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c +index 5d9b457..f1dd0d0 100644 +--- a/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c ++++ b/gst-libs/gst/gl/wayland/gstglwindow_wayland_egl.c +@@ -32,6 +32,7 @@ + #include "../gstgl_fwd.h" + #include + ++#include "gstgldisplay_wayland.h" + #include "gstglwindow_wayland_egl.h" + + const gchar *WlEGLErrorString (); +@@ -41,13 +42,13 @@ const gchar *WlEGLErrorString (); + #define gst_gl_window_wayland_egl_parent_class parent_class + G_DEFINE_TYPE (GstGLWindowWaylandEGL, gst_gl_window_wayland_egl, + GST_GL_TYPE_WINDOW); ++static void gst_gl_window_wayland_egl_finalize (GObject * object); + + static guintptr gst_gl_window_wayland_egl_get_window_handle (GstGLWindow * + window); + static void gst_gl_window_wayland_egl_set_window_handle (GstGLWindow * window, + guintptr handle); +-static void gst_gl_window_wayland_egl_draw (GstGLWindow * window, guint width, +- guint height); ++static void gst_gl_window_wayland_egl_draw (GstGLWindow * window, guint width, guint height); + static void gst_gl_window_wayland_egl_run (GstGLWindow * window); + static void gst_gl_window_wayland_egl_quit (GstGLWindow * window); + static void gst_gl_window_wayland_egl_send_message_async (GstGLWindow * window, +@@ -57,6 +58,7 @@ static gboolean gst_gl_window_wayland_egl_open (GstGLWindow * window, + GError ** error); + static guintptr gst_gl_window_wayland_egl_get_display (GstGLWindow * window); + ++#if 0 + static void + pointer_handle_enter (void *data, struct wl_pointer *pointer, uint32_t serial, + struct wl_surface *surface, wl_fixed_t sx_w, wl_fixed_t sy_w) +@@ -149,11 +151,15 @@ seat_handle_capabilities (void *data, struct wl_seat *seat, + static const struct wl_seat_listener seat_listener = { + seat_handle_capabilities, + }; +- ++#endif + static void + handle_ping (void *data, struct wl_shell_surface *shell_surface, + uint32_t serial) + { ++ GstGLWindowWaylandEGL *window_egl = data; ++ ++ GST_TRACE_OBJECT (window_egl, "ping received serial %u", serial); ++ + wl_shell_surface_pong (shell_surface, serial); + } + +@@ -166,7 +172,8 @@ handle_configure (void *data, struct wl_shell_surface *shell_surface, + { + GstGLWindowWaylandEGL *window_egl = data; + +- GST_DEBUG ("configure event %ix%i", width, height); ++ GST_DEBUG ("configure event on surface %p, %ix%i", shell_surface, width, ++ height); + + window_resize (window_egl, width, height); + } +@@ -185,11 +192,13 @@ static const struct wl_shell_surface_listener shell_surface_listener = { + static gboolean + create_surface (GstGLWindowWaylandEGL * window_egl) + { ++ GstGLDisplayWayland *display = ++ GST_GL_DISPLAY_WAYLAND (GST_GL_WINDOW (window_egl)->display); ++ + window_egl->window.surface = +- wl_compositor_create_surface (window_egl->display.compositor); ++ wl_compositor_create_surface (display->compositor); + window_egl->window.shell_surface = +- wl_shell_get_shell_surface (window_egl->display.shell, +- window_egl->window.surface); ++ wl_shell_get_shell_surface (display->shell, window_egl->window.surface); + + wl_shell_surface_add_listener (window_egl->window.shell_surface, + &shell_surface_listener, window_egl); +@@ -225,46 +234,13 @@ destroy_surface (GstGLWindowWaylandEGL * window_egl) + + if (window_egl->window.callback) + wl_callback_destroy (window_egl->window.callback); +- +- g_source_destroy (window_egl->wl_source); +- g_source_unref (window_egl->wl_source); +- window_egl->wl_source = NULL; +- g_main_loop_unref (window_egl->loop); +- window_egl->loop = NULL, g_main_context_unref (window_egl->main_context); +- window_egl->main_context = NULL; +-} +- +-static void +-registry_handle_global (void *data, struct wl_registry *registry, +- uint32_t name, const char *interface, uint32_t version) +-{ +- GstGLWindowWaylandEGL *window_egl = data; +- struct display *d = &window_egl->display; +- +- if (g_strcmp0 (interface, "wl_compositor") == 0) { +- d->compositor = +- wl_registry_bind (registry, name, &wl_compositor_interface, 1); +- } else if (g_strcmp0 (interface, "wl_shell") == 0) { +- d->shell = wl_registry_bind (registry, name, &wl_shell_interface, 1); +- } else if (g_strcmp0 (interface, "wl_seat") == 0) { +- d->seat = wl_registry_bind (registry, name, &wl_seat_interface, 1); +- wl_seat_add_listener (d->seat, &seat_listener, window_egl); +- } else if (g_strcmp0 (interface, "wl_shm") == 0) { +- d->shm = wl_registry_bind (registry, name, &wl_shm_interface, 1); +- d->cursor_theme = wl_cursor_theme_load (NULL, 32, d->shm); +- d->default_cursor = +- wl_cursor_theme_get_cursor (d->cursor_theme, "left_ptr"); +- } + } + +-static const struct wl_registry_listener registry_listener = { +- registry_handle_global +-}; +- + static void + gst_gl_window_wayland_egl_class_init (GstGLWindowWaylandEGLClass * klass) + { + GstGLWindowClass *window_class = (GstGLWindowClass *) klass; ++ GObjectClass *gobject_class = (GObjectClass *) klass; + + window_class->get_window_handle = + GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_get_window_handle); +@@ -281,11 +257,26 @@ gst_gl_window_wayland_egl_class_init (GstGLWindowWaylandEGLClass * klass) + window_class->open = GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_open); + window_class->get_display = + GST_DEBUG_FUNCPTR (gst_gl_window_wayland_egl_get_display); ++ ++ gobject_class->finalize = gst_gl_window_wayland_egl_finalize; + } + + static void + gst_gl_window_wayland_egl_init (GstGLWindowWaylandEGL * window) + { ++ window->main_context = g_main_context_new (); ++ window->loop = g_main_loop_new (window->main_context, FALSE); ++} ++ ++static void ++gst_gl_window_wayland_egl_finalize (GObject * object) ++{ ++ GstGLWindowWaylandEGL *window_egl = GST_GL_WINDOW_WAYLAND_EGL (object); ++ ++ g_main_loop_unref (window_egl->loop); ++ g_main_context_unref (window_egl->main_context); ++ ++ G_OBJECT_CLASS (parent_class)->finalize (object); + } + + /* Must be called in the gl thread */ +@@ -310,60 +301,33 @@ gst_gl_window_wayland_egl_close (GstGLWindow * window) + + destroy_surface (window_egl); + +- if (window_egl->display.cursor_surface) +- wl_surface_destroy (window_egl->display.cursor_surface); +- +- if (window_egl->display.cursor_theme) +- wl_cursor_theme_destroy (window_egl->display.cursor_theme); +- +- if (window_egl->display.shell) +- wl_shell_destroy (window_egl->display.shell); +- +- if (window_egl->display.compositor) +- wl_compositor_destroy (window_egl->display.compositor); +- +- if (window_egl->display.display) { +- wl_display_flush (window_egl->display.display); +- wl_display_disconnect (window_egl->display.display); +- } ++ g_source_destroy (window_egl->wl_source); ++ g_source_unref (window_egl->wl_source); ++ window_egl->wl_source = NULL; + } + + static gboolean + gst_gl_window_wayland_egl_open (GstGLWindow * window, GError ** error) + { ++ GstGLDisplayWayland *display = GST_GL_DISPLAY_WAYLAND (window->display); + GstGLWindowWaylandEGL *window_egl = GST_GL_WINDOW_WAYLAND_EGL (window); + +- window_egl->display.display = wl_display_connect (NULL); +- if (!window_egl->display.display) { ++ if (!display->display) { + g_set_error (error, GST_GL_WINDOW_ERROR, + GST_GL_WINDOW_ERROR_RESOURCE_UNAVAILABLE, +- "Failed to connect to Wayland display server"); +- goto error; ++ "Failed to retreive Wayland display"); ++ return FALSE; + } + +- window_egl->display.registry = +- wl_display_get_registry (window_egl->display.display); +- wl_registry_add_listener (window_egl->display.registry, ®istry_listener, +- window_egl); +- +- wl_display_dispatch (window_egl->display.display); ++ wl_display_roundtrip (display->display); + + create_surface (window_egl); + +- window_egl->display.cursor_surface = +- wl_compositor_create_surface (window_egl->display.compositor); +- +- window_egl->wl_source = +- wayland_event_source_new (window_egl->display.display); +- window_egl->main_context = g_main_context_new (); +- window_egl->loop = g_main_loop_new (window_egl->main_context, FALSE); ++ window_egl->wl_source = wayland_event_source_new (display->display); + + g_source_attach (window_egl->wl_source, window_egl->main_context); + + return TRUE; +- +-error: +- return FALSE; + } + + static void +@@ -461,11 +425,6 @@ window_resize (GstGLWindowWaylandEGL * window_egl, guint width, guint height) + + window_egl->window.window_width = width; + window_egl->window.window_height = height; +- +-#if 0 +- wl_shell_surface_resize (window_egl->window.shell_surface, +- window_egl->display.seat, window_egl->display.serial, 0); +-#endif + } + + struct draw +@@ -520,9 +479,7 @@ gst_gl_window_wayland_egl_draw (GstGLWindow * window, guint width, guint height) + static guintptr + gst_gl_window_wayland_egl_get_display (GstGLWindow * window) + { +- GstGLWindowWaylandEGL *window_egl; +- +- window_egl = GST_GL_WINDOW_WAYLAND_EGL (window); ++ GstGLDisplayWayland *display = GST_GL_DISPLAY_WAYLAND (window->display); + +- return (guintptr) window_egl->display.display; ++ return (guintptr) display->display; + } +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0009-mpeg4videoparse-Need-detect-picture-coding-type-when.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0009-mpeg4videoparse-Need-detect-picture-coding-type-when.patch new file mode 100644 index 000000000..183f7d014 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0009-mpeg4videoparse-Need-detect-picture-coding-type-when.patch @@ -0,0 +1,48 @@ +From 6e49c3547f2a99882542c64fdcd4d77c88b44c17 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Wed, 20 May 2015 15:13:20 +0800 +Subject: [PATCH 1/2] mpeg4videoparse: Need detect picture coding type when + drain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +our use case is demuxer only output key frame when backward playback. +every frame is DISCONT and KEY frame. mpeg4videoparse will detect coding +type when detect start code after VOP. our use case will drain after VOP +and can't detect start code after VOP. Add check coding type code when +drain. + +Upstream Status: Waiting for review. + +https://bugzilla.gnome.org/show_bug.cgi?id=749617 +--- + gst/videoparsers/gstmpeg4videoparse.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/gst/videoparsers/gstmpeg4videoparse.c b/gst/videoparsers/gstmpeg4videoparse.c +index 1afaa17..a5a41c7 100644 +--- a/gst/videoparsers/gstmpeg4videoparse.c ++++ b/gst/videoparsers/gstmpeg4videoparse.c +@@ -502,6 +502,18 @@ next: + case (GST_MPEG4_PARSER_ERROR): + /* if draining, take all */ + if (GST_BASE_PARSE_DRAINING (parse)) { ++ /* need decide intra_frame */ ++ if (mp4vparse->vop_offset >= 0) { ++ if (G_LIKELY (size > mp4vparse->vop_offset + 1)) { ++ mp4vparse->intra_frame = ++ ((data[mp4vparse->vop_offset + 1] >> 6 & 0x3) == 0); ++ } else { ++ GST_WARNING_OBJECT (mp4vparse, "no data following VOP startcode"); ++ mp4vparse->intra_frame = FALSE; ++ } ++ GST_LOG_OBJECT (mp4vparse, "is intra %d %d", ++ mp4vparse->intra_frame, mp4vparse->vop_offset); ++ } + framesize = size; + ret = TRUE; + } else { +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0010-mpegvideoparse-Need-detect-picture-coding-type-when-.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0010-mpegvideoparse-Need-detect-picture-coding-type-when-.patch new file mode 100644 index 000000000..3a5921bec --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0010-mpegvideoparse-Need-detect-picture-coding-type-when-.patch @@ -0,0 +1,48 @@ +From af20e70625ca3cd521c32feb0d53f18bdfbaf5e0 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Wed, 20 May 2015 15:15:08 +0800 +Subject: [PATCH 2/2] mpegvideoparse: Need detect picture coding type when + drain +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Need detect picture coding type when drain + +Upstream Status: Waiting for review. + +https://bugzilla.gnome.org/show_bug.cgi?id=749617 +--- + gst/videoparsers/gstmpegvideoparse.c | 16 ++++++++++++++++ + 1 file changed, 16 insertions(+) + +diff --git a/gst/videoparsers/gstmpegvideoparse.c b/gst/videoparsers/gstmpegvideoparse.c +index dadab94..5ba4e9f 100644 +--- a/gst/videoparsers/gstmpegvideoparse.c ++++ b/gst/videoparsers/gstmpegvideoparse.c +@@ -717,6 +717,22 @@ need_more: + if (GST_BASE_PARSE_DRAINING (parse)) { + GST_LOG_OBJECT (mpvparse, "draining, accepting all data"); + off = size; ++ /* decide picture codding type */ ++ if (mpvparse->pic_offset >= 0 && mpvparse->pic_offset < off) { ++ GstMpegVideoPacket header; ++ ++ header.data = map.data; ++ header.type = GST_MPEG_VIDEO_PACKET_PICTURE; ++ header.offset = mpvparse->pic_offset; ++ header.size = map.size - mpvparse->pic_offset; ++ if (gst_mpeg_video_packet_parse_picture_header (&header, &mpvparse->pichdr)) ++ GST_LOG_OBJECT (mpvparse, "picture_coding_type %d (%s), ending" ++ "frame of size %d", mpvparse->pichdr.pic_type, ++ picture_type_name (mpvparse->pichdr.pic_type), off - 4); ++ else ++ GST_LOG_OBJECT (mpvparse, "Couldn't parse picture at offset %d", ++ mpvparse->pic_offset); ++ } + ret = TRUE; + } else { + GST_LOG_OBJECT (mpvparse, "need more data"); +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0011-videoparse-modifiy-the-videoparse-rank.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0011-videoparse-modifiy-the-videoparse-rank.patch new file mode 100644 index 000000000..ba896262d --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0011-videoparse-modifiy-the-videoparse-rank.patch @@ -0,0 +1,62 @@ +From 7146faaa2c7a6add79c290870e5de90cb5f72479 Mon Sep 17 00:00:00 2001 +From: Lyon Wang +Date: Fri, 29 May 2015 09:54:56 +0800 +Subject: [PATCH] [videoparse] modifiy the videoparse rank + +- Modify the videparsers rank down to avoid link them in +. h263parse rank down to 63 +. h264parse rank down to 63 +. mpegvideoparse rank down to 63 +. mpeg4videpparse rank down to 63 +. pngparse, rank down to 63 +. h265parse rank down to 63 + +Upstream status: [i.MX specific] internal use only + +Signed-off-by: Lyon Wang +--- + gst/videoparsers/plugin.c | 21 +++++++++++++++++++-- + 1 file changed, 19 insertions(+), 2 deletions(-) + +diff --git a/gst/videoparsers/plugin.c b/gst/videoparsers/plugin.c +index 79d1df6..c070b93 100644 +--- a/gst/videoparsers/plugin.c ++++ b/gst/videoparsers/plugin.c +@@ -35,7 +35,7 @@ static gboolean + plugin_init (GstPlugin * plugin) + { + gboolean ret = FALSE; +- ++#if 0 + ret |= gst_element_register (plugin, "h263parse", + GST_RANK_PRIMARY + 1, GST_TYPE_H263_PARSE); + ret |= gst_element_register (plugin, "h264parse", +@@ -52,7 +52,24 @@ plugin_init (GstPlugin * plugin) + GST_RANK_SECONDARY, GST_TYPE_H265_PARSE); + ret |= gst_element_register (plugin, "vc1parse", + GST_RANK_NONE, GST_TYPE_VC1_PARSE); +- ++#else ++ ret |= gst_element_register (plugin, "h263parse", ++ GST_RANK_MARGINAL - 1, GST_TYPE_H263_PARSE); ++ ret |= gst_element_register (plugin, "h264parse", ++ GST_RANK_MARGINAL - 1, GST_TYPE_H264_PARSE); ++ ret |= gst_element_register (plugin, "diracparse", ++ GST_RANK_NONE, GST_TYPE_DIRAC_PARSE); ++ ret |= gst_element_register (plugin, "mpegvideoparse", ++ GST_RANK_MARGINAL - 1, GST_TYPE_MPEGVIDEO_PARSE); ++ ret |= gst_element_register (plugin, "mpeg4videoparse", ++ GST_RANK_MARGINAL -1, GST_TYPE_MPEG4VIDEO_PARSE); ++ ret |= gst_element_register (plugin, "pngparse", ++ GST_RANK_MARGINAL-1, GST_TYPE_PNG_PARSE); ++ ret |= gst_element_register (plugin, "h265parse", ++ GST_RANK_MARGINAL-1, GST_TYPE_H265_PARSE); ++ ret |= gst_element_register (plugin, "vc1parse", ++ GST_RANK_NONE, GST_TYPE_VC1_PARSE); ++#endif + return ret; + } + +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0012-glfilter-Lost-frame-rate-info-when-fixate-caps.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0012-glfilter-Lost-frame-rate-info-when-fixate-caps.patch new file mode 100644 index 000000000..9c4a35959 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0012-glfilter-Lost-frame-rate-info-when-fixate-caps.patch @@ -0,0 +1,52 @@ +From 901e9e6fa16ed9558022f64bdc3cc6b8ac761c71 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Mon, 8 Jun 2015 17:06:22 +0800 +Subject: [PATCH] glfilter: Lost frame rate info when fixate caps +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Lost frame rate info when fixate caps. It will cause +down stream element fail, such avimux. + +Upstream Status: Waiting for review. + +https://bugzilla.gnome.org/show_bug.cgi?id=750545 +--- + gst-libs/gst/gl/gstglfilter.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/gst-libs/gst/gl/gstglfilter.c b/gst-libs/gst/gl/gstglfilter.c +index feff9de..d46e272 100644 +--- a/gst-libs/gst/gl/gstglfilter.c ++++ b/gst-libs/gst/gl/gstglfilter.c +@@ -356,7 +356,8 @@ gst_gl_filter_fixate_caps (GstBaseTransform * bt, + GstPadDirection direction, GstCaps * caps, GstCaps * othercaps) + { + GstStructure *ins, *outs; +- const GValue *from_par, *to_par; ++ const GValue *from_par, *to_par, *from_fps; ++ gint framerate_num, framerate_den; + GValue fpar = { 0, }, tpar = { + 0,}; + +@@ -369,6 +370,16 @@ gst_gl_filter_fixate_caps (GstBaseTransform * bt, + ins = gst_caps_get_structure (caps, 0); + outs = gst_caps_get_structure (othercaps, 0); + ++ /* replace frame rate */ ++ from_fps = gst_structure_get_value (ins, "framerate"); ++ if (from_fps) { ++ gst_structure_set_value (outs, "framerate", from_fps); ++ } else { ++ if (gst_structure_get_fraction (ins, "framerate", &framerate_num, &framerate_den)) ++ gst_structure_set (outs, "framerate", GST_TYPE_FRACTION, framerate_num, framerate_den, ++ NULL); ++ } ++ + from_par = gst_structure_get_value (ins, "pixel-aspect-ratio"); + to_par = gst_structure_get_value (outs, "pixel-aspect-ratio"); + +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0014-opencv-rename-gstopencv.c-to-gstopencv.cpp.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0014-opencv-rename-gstopencv.c-to-gstopencv.cpp.patch new file mode 100644 index 000000000..69fc420ca --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0014-opencv-rename-gstopencv.c-to-gstopencv.cpp.patch @@ -0,0 +1,351 @@ +From b3a9be129e25b9c84b2a056b6c9fad50d6b60c88 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Mon, 1 Jun 2015 14:52:45 +0800 +Subject: [PATCH 1/2] opencv: rename gstopencv.c to gstopencv.cpp +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +As Open CV plugin will include many Open CV C++ head files. + +Upstream Status: Waiting for review. + +https://bugzilla.gnome.org/show_bug.cgi?id=751203 +--- + ext/opencv/Makefile.am | 2 +- + ext/opencv/gstopencv.c | 113 ----------------------------------------- + ext/opencv/gstopencv.cpp | 113 +++++++++++++++++++++++++++++++++++++++++ + ext/opencv/gsttemplatematch.c | 14 ++--- + ext/opencv/gsttemplatematch.h | 2 +- + 5 files changed, 122 insertions(+), 122 deletions(-) + delete mode 100644 ext/opencv/gstopencv.c + create mode 100644 ext/opencv/gstopencv.cpp + +diff --git a/ext/opencv/Makefile.am b/ext/opencv/Makefile.am +index 3ba1c34..3c3418e 100644 +--- a/ext/opencv/Makefile.am ++++ b/ext/opencv/Makefile.am +@@ -1,7 +1,7 @@ + plugin_LTLIBRARIES = libgstopencv.la + + # sources used to compile this plug-in +-libgstopencv_la_SOURCES = gstopencv.c \ ++libgstopencv_la_SOURCES = gstopencv.cpp \ + gstopencvvideofilter.c \ + gstopencvutils.c \ + gstcvdilate.c \ +diff --git a/ext/opencv/gstopencv.c b/ext/opencv/gstopencv.c +deleted file mode 100644 +index 3184518..0000000 +--- a/ext/opencv/gstopencv.c ++++ /dev/null +@@ -1,113 +0,0 @@ +-/* GStreamer +- * Copyright (C) <2009> Kapil Agrawal +- * +- * gstopencv.c: plugin registering +- * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Library General Public +- * License as published by the Free Software Foundation; either +- * version 2 of the License, or (at your option) any later version. +- * +- * This library is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * Library General Public License for more details. +- * +- * You should have received a copy of the GNU Library General Public +- * License along with this library; if not, write to the +- * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, +- * Boston, MA 02110-1301, USA. +- */ +- +-#ifdef HAVE_CONFIG_H +-#include "config.h" +-#endif +- +-#include "gstcvdilate.h" +-#include "gstcvequalizehist.h" +-#include "gstcverode.h" +-#include "gstcvlaplace.h" +-#include "gstcvsmooth.h" +-#include "gstcvsobel.h" +-#include "gstedgedetect.h" +-#include "gstfaceblur.h" +-#include "gstfacedetect.h" +-#include "gstmotioncells.h" +-#include "gstpyramidsegment.h" +-#include "gsttemplatematch.h" +-#include "gsttextoverlay.h" +-#include "gsthanddetect.h" +-#include "gstskindetect.h" +-#include "gstretinex.h" +-#include "gstsegmentation.h" +-#include "gstgrabcut.h" +-#include "gstdisparity.h" +- +-static gboolean +-plugin_init (GstPlugin * plugin) +-{ +- if (!gst_cv_dilate_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_cv_equalize_hist_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_cv_erode_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_cv_laplace_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_cv_smooth_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_cv_sobel_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_edge_detect_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_face_blur_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_face_detect_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_motion_cells_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_pyramid_segment_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_template_match_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_opencv_text_overlay_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_handdetect_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_skin_detect_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_retinex_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_segmentation_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_grabcut_plugin_init (plugin)) +- return FALSE; +- +- if (!gst_disparity_plugin_init (plugin)) +- return FALSE; +- +- return TRUE; +-} +- +-GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, +- GST_VERSION_MINOR, +- opencv, +- "GStreamer OpenCV Plugins", +- plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) +diff --git a/ext/opencv/gstopencv.cpp b/ext/opencv/gstopencv.cpp +new file mode 100644 +index 0000000..3184518 +--- /dev/null ++++ b/ext/opencv/gstopencv.cpp +@@ -0,0 +1,113 @@ ++/* GStreamer ++ * Copyright (C) <2009> Kapil Agrawal ++ * ++ * gstopencv.c: plugin registering ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "gstcvdilate.h" ++#include "gstcvequalizehist.h" ++#include "gstcverode.h" ++#include "gstcvlaplace.h" ++#include "gstcvsmooth.h" ++#include "gstcvsobel.h" ++#include "gstedgedetect.h" ++#include "gstfaceblur.h" ++#include "gstfacedetect.h" ++#include "gstmotioncells.h" ++#include "gstpyramidsegment.h" ++#include "gsttemplatematch.h" ++#include "gsttextoverlay.h" ++#include "gsthanddetect.h" ++#include "gstskindetect.h" ++#include "gstretinex.h" ++#include "gstsegmentation.h" ++#include "gstgrabcut.h" ++#include "gstdisparity.h" ++ ++static gboolean ++plugin_init (GstPlugin * plugin) ++{ ++ if (!gst_cv_dilate_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_cv_equalize_hist_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_cv_erode_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_cv_laplace_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_cv_smooth_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_cv_sobel_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_edge_detect_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_face_blur_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_face_detect_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_motion_cells_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_pyramid_segment_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_template_match_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_opencv_text_overlay_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_handdetect_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_skin_detect_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_retinex_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_segmentation_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_grabcut_plugin_init (plugin)) ++ return FALSE; ++ ++ if (!gst_disparity_plugin_init (plugin)) ++ return FALSE; ++ ++ return TRUE; ++} ++ ++GST_PLUGIN_DEFINE (GST_VERSION_MAJOR, ++ GST_VERSION_MINOR, ++ opencv, ++ "GStreamer OpenCV Plugins", ++ plugin_init, VERSION, "LGPL", GST_PACKAGE_NAME, GST_PACKAGE_ORIGIN) +diff --git a/ext/opencv/gsttemplatematch.c b/ext/opencv/gsttemplatematch.c +index 507b218..12c92cd 100644 +--- a/ext/opencv/gsttemplatematch.c ++++ b/ext/opencv/gsttemplatematch.c +@@ -176,7 +176,7 @@ gst_template_match_init (GstTemplateMatch * filter) + + gst_element_add_pad (GST_ELEMENT (filter), filter->sinkpad); + gst_element_add_pad (GST_ELEMENT (filter), filter->srcpad); +- filter->template = NULL; ++ filter->templatename = NULL; + filter->display = TRUE; + filter->cvTemplateImage = NULL; + filter->cvDistImage = NULL; +@@ -215,7 +215,7 @@ gst_template_match_set_property (GObject * object, guint prop_id, + } + break; + case PROP_TEMPLATE: +- filter->template = (char *) g_value_get_string (value); ++ filter->templatename = (char *) g_value_get_string (value); + gst_template_match_load_template (filter); + break; + case PROP_DISPLAY: +@@ -238,7 +238,7 @@ gst_template_match_get_property (GObject * object, guint prop_id, + g_value_set_int (value, filter->method); + break; + case PROP_TEMPLATE: +- g_value_set_string (value, filter->template); ++ g_value_set_string (value, filter->templatename); + break; + case PROP_DISPLAY: + g_value_set_boolean (value, filter->display); +@@ -321,7 +321,7 @@ gst_template_match_chain (GstPad * pad, GstObject * parent, GstBuffer * buf) + + /* FIXME Why template == NULL returns OK? + * shouldn't it be a passthrough instead? */ +- if ((!filter) || (!buf) || filter->template == NULL) { ++ if ((!filter) || (!buf) || filter->templatename == NULL) { + return GST_FLOW_OK; + } + GST_LOG_OBJECT (filter, "Buffer size %u", (guint) gst_buffer_get_size (buf)); +@@ -410,17 +410,17 @@ gst_template_match_match (IplImage * input, IplImage * template, + static void + gst_template_match_load_template (GstTemplateMatch * filter) + { +- if (filter->template) { ++ if (filter->templatename) { + + if (filter->cvTemplateImage) { + cvReleaseImage (&filter->cvTemplateImage); + } + filter->cvTemplateImage = +- cvLoadImage (filter->template, CV_LOAD_IMAGE_COLOR); ++ cvLoadImage (filter->templatename, CV_LOAD_IMAGE_COLOR); + + if (!filter->cvTemplateImage) { + GST_WARNING ("Couldn't load template image: %s. error: %s", +- filter->template, g_strerror (errno)); ++ filter->templatename, g_strerror (errno)); + } + } + } +diff --git a/ext/opencv/gsttemplatematch.h b/ext/opencv/gsttemplatematch.h +index 6b67000..4a716d8 100644 +--- a/ext/opencv/gsttemplatematch.h ++++ b/ext/opencv/gsttemplatematch.h +@@ -79,7 +79,7 @@ struct _GstTemplateMatch + gint method; + gboolean display; + +- gchar *template; ++ gchar *templatename; + + IplImage *cvImage, *cvGray, *cvTemplateImage, *cvDistImage; + }; +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0015-opencv-Add-video-stitching-support.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0015-opencv-Add-video-stitching-support.patch new file mode 100644 index 000000000..719c22a73 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0015-opencv-Add-video-stitching-support.patch @@ -0,0 +1,1923 @@ +From aa485cfba8a06f767498bf707175134629fe2377 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Mon, 1 Jun 2015 13:30:11 +0800 +Subject: [PATCH 2/2] opencv: Add video stitching support. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Add video stitching element. + +Upstream Status: Waiting for review. + +https://bugzilla.gnome.org/show_bug.cgi?id=751203 +--- + docs/plugins/Makefile.am | 1 + + ext/opencv/Makefile.am | 12 +- + ext/opencv/gstcvstitching.cpp | 834 ++++++++++++++++++++++++++++++++++++++ + ext/opencv/gstcvstitching.h | 130 ++++++ + ext/opencv/gstopencv.cpp | 4 + + ext/opencv/gstopencvaggregator.c | 708 ++++++++++++++++++++++++++++++++ + ext/opencv/gstopencvaggregator.h | 118 ++++++ + 7 files changed, 1806 insertions(+), 1 deletion(-) + create mode 100644 ext/opencv/gstcvstitching.cpp + create mode 100644 ext/opencv/gstcvstitching.h + create mode 100644 ext/opencv/gstopencvaggregator.c + create mode 100644 ext/opencv/gstopencvaggregator.h + +diff --git a/docs/plugins/Makefile.am b/docs/plugins/Makefile.am +index b093bcf..77593ed 100644 +--- a/docs/plugins/Makefile.am ++++ b/docs/plugins/Makefile.am +@@ -98,6 +98,7 @@ EXTRA_HFILES = \ + $(top_srcdir)/ext/opencv/gstpyramidsegment.h \ + $(top_srcdir)/ext/opencv/gsttemplatematch.h \ + $(top_srcdir)/ext/opencv/gsttextoverlay.h \ ++ $(top_srcdir)/ext/opencv/gstcvstitching.h \ + $(top_srcdir)/ext/openni2/gstopenni2src.h \ + $(top_srcdir)/ext/rsvg/gstrsvgdec.h \ + $(top_srcdir)/ext/rsvg/gstrsvgoverlay.h \ +diff --git a/ext/opencv/Makefile.am b/ext/opencv/Makefile.am +index 3c3418e..38f67fd 100644 +--- a/ext/opencv/Makefile.am ++++ b/ext/opencv/Makefile.am +@@ -24,10 +24,15 @@ libgstopencv_la_SOURCES = gstopencv.cpp \ + gstsegmentation.cpp \ + gstgrabcut.cpp \ + gstdisparity.cpp \ ++ gstopencvaggregator.c \ ++ gstcvstitching.cpp \ + motioncells_wrapper.cpp \ + MotionCells.cpp + +-libgstopencv_la_CXXFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CXXFLAGS) $(OPENCV_CFLAGS) ++libgstopencv_la_CXXFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \ ++ $(GST_CXXFLAGS) $(OPENCV_CFLAGS) \ ++ -I$(top_srcdir)/gst-libs \ ++ -I$(top_builddir)/gst-libs + + # flags used to compile this facedetect + # add other _CFLAGS and _LIBS as needed +@@ -36,11 +41,14 @@ libgstopencv_la_CXXFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_C + # OpenCV's define isn't good enough to avoid 'unused' gcc warnings (at v2.1.0) + libgstopencv_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) \ + $(GST_CFLAGS) $(OPENCV_CFLAGS) \ ++ -I$(top_srcdir)/gst-libs \ ++ -I$(top_builddir)/gst-libs \ + -DGST_HAAR_CASCADES_DIR=\"$(pkgdatadir)/@GST_API_VERSION@/opencv_haarcascades\" \ + -DCV_INLINE="static inline" \ + -DCV_NO_BACKWARD_COMPATIBILITY + + libgstopencv_la_LIBADD = $(GST_LIBS) $(GST_BASE_LIBS) $(OPENCV_LIBS) \ ++ $(top_builddir)/gst-libs/gst/video/libgstbadvideo-$(GST_API_VERSION).la \ + $(GSTPB_BASE_LIBS) -lgstvideo-$(GST_API_VERSION) + + libgstopencv_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) +@@ -67,6 +75,8 @@ noinst_HEADERS = gstopencvvideofilter.h gstopencvutils.h \ + gstsegmentation.h \ + gstgrabcut.h \ + gstdisparity.h \ ++ gstopencvaggregator.h \ ++ gstcvstitching.h \ + gstmotioncells.h \ + motioncells_wrapper.h \ + MotionCells.h +diff --git a/ext/opencv/gstcvstitching.cpp b/ext/opencv/gstcvstitching.cpp +new file mode 100644 +index 0000000..47105f7 +--- /dev/null ++++ b/ext/opencv/gstcvstitching.cpp +@@ -0,0 +1,834 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Song Bing ++ * ++ * 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., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++/** ++ * SECTION:element-cvstitching ++ * ++ * video or image stitching. ++ * ++ * video or image stitching. ++ * ++ * ++ * Example launch line ++ * |[ ++ * gst-launch-1.0 filesrc location=IMG_20150529_152901.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152907.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. cvstitching name=stitcher stitcher.src ! videoconvert ! ximagesink sync=false ++ * ]| image stitching. ++ * |[ ++ * gst-launch-1.0 filesrc location=IMG_20150529_152901.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152907.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152913.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152918.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152924.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152929.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152933.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152938.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152942.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152947.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. filesrc location=IMG_20150529_152951.jpg ! jpegdec ! videoconvert ! imagefreeze ! stitcher. cvstitching name=stitcher stitcher.src ! videoconvert ! ximagesink sync=false ++ * ]| images stitching. ++ * ++ * ++ */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include "gstopencvutils.h" ++#include "gstcvstitching.h" ++ ++// default settings. ++bool preview = false; ++bool try_gpu = false; ++double work_megapix = 0.6; ++double seam_megapix = 0.1; ++double compose_megapix = -1; ++float conf_thresh = 1.f; ++string ba_refine_mask = "xxxxx"; ++bool do_wave_correct = true; ++WaveCorrectKind wave_correct = detail::WAVE_CORRECT_HORIZ; ++int expos_comp_type = ExposureCompensator::GAIN_BLOCKS; ++float match_conf = 0.3f; ++int blend_type = Blender::MULTI_BAND; ++float blend_strength = 5; ++ ++#define gst_cv_stitching_parent_class parent_class ++ ++#define GST_CAT_DEFAULT gst_cv_stitching_debug ++GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); ++ ++#define DEFAULT_FEATURE_TYPE 0 ++#define DEFAULT_WARP_TYPE 0 ++#define DEFAULT_SEAM_FIND 0 ++#define DEFAULT_BA_COST_FUNC 0 ++enum ++{ ++ PROP_0, ++ PROP_FEATURE_TYPE, ++ PROP_WARP_TYPE, ++ PROP_SEAM_FIND_TYPE, ++ PROP_BA_COST_FUNC ++}; ++ ++static GstStaticPadTemplate sink_factory = GST_STATIC_PAD_TEMPLATE ("sink_%u", ++ GST_PAD_SINK, ++ GST_PAD_REQUEST, ++ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB")) ++ ); ++ ++static GstStaticPadTemplate src_factory = GST_STATIC_PAD_TEMPLATE ("src", ++ GST_PAD_SRC, ++ GST_PAD_ALWAYS, ++ GST_STATIC_CAPS (GST_VIDEO_CAPS_MAKE ("RGB")) ++ ); ++ ++G_DEFINE_TYPE (GstCvStitching, gst_cv_stitching, GST_TYPE_OPENCV_AGGREGATOR); ++ ++G_DEFINE_TYPE (GstCvStitchingPad, gst_cv_stitching_pad, ++ GST_TYPE_OPENCV_AGGREGATOR_PAD); ++ ++static void gst_cv_stitching_pad_set_property (GObject * object, ++ guint prop_id, const GValue * value, GParamSpec * pspec); ++static void gst_cv_stitching_pad_get_property (GObject * object, ++ guint prop_id, GValue * value, GParamSpec * pspec); ++ ++enum ++{ ++ PROP_PAD_0, ++}; ++ ++static void ++gst_cv_stitching_pad_class_init (GstCvStitchingPadClass * klass) ++{ ++ GObjectClass *gobject_class = (GObjectClass *) klass; ++ ++ gobject_class->set_property = gst_cv_stitching_pad_set_property; ++ gobject_class->get_property = gst_cv_stitching_pad_get_property; ++} ++ ++static void ++gst_cv_stitching_pad_init (GstCvStitchingPad * pad) ++{ ++} ++ ++static void ++gst_cv_stitching_pad_get_property (GObject * object, guint prop_id, ++ GValue * value, GParamSpec * pspec) ++{ ++ switch (prop_id) { ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void ++gst_cv_stitching_pad_set_property (GObject * object, guint prop_id, ++ const GValue * value, GParamSpec * pspec) ++{ ++ switch (prop_id) { ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void gst_cv_stitching_set_property (GObject * object, guint prop_id, ++ const GValue * value, GParamSpec * pspec); ++static void gst_cv_stitching_get_property (GObject * object, guint prop_id, ++ GValue * value, GParamSpec * pspec); ++static gboolean gst_cv_stitching_start (GstAggregator * agg); ++static gboolean gst_cv_stitching_stop (GstAggregator * agg); ++static gboolean ++gst_cv_stitching_process (GstOpencvAggregator * agg, GPtrArray *imgs, ++ IplImage *outimg); ++ ++enum _GstCvStitchingFeatureTypes { ++ GST_CV_STITCHING_FEATURE_TYPES_SURF = 0, ++ GST_CV_STITCHING_FEATURE_TYPES_ORB = 1 ++}; ++ ++#define GST_TYPE_CV_STITCHING_FEATURE_TYPES (cv_stitching_feature_type_get_type ()) ++ ++static GType ++cv_stitching_feature_type_get_type (void) ++{ ++ static GType cv_stitching_feature_type_type = 0; ++ static const GEnumValue cv_stitching_feature_type[] = { ++ {GST_CV_STITCHING_FEATURE_TYPES_SURF, "feature type surf", "surf"}, ++ {GST_CV_STITCHING_FEATURE_TYPES_ORB, "feature type surf", "orb"}, ++ {0, NULL, NULL}, ++ }; ++ ++ if (!cv_stitching_feature_type_type) { ++ cv_stitching_feature_type_type = ++ g_enum_register_static ("GstCvStitchingFeatureTypes", cv_stitching_feature_type); ++ } ++ return cv_stitching_feature_type_type; ++} ++ ++enum _GstCvStitchingWarpTypes { ++ GST_CV_STITCHING_WARP_TYPES_PLANE = 0, ++ GST_CV_STITCHING_WARP_TYPES_CYLINDRICAL = 1, ++ GST_CV_STITCHING_WARP_TYPES_SPHERICAL = 2, ++ GST_CV_STITCHING_WARP_TYPES_FISHEYE = 3, ++ GST_CV_STITCHING_WARP_TYPES_STEREOGRAPHIC = 4, ++ GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEA2B1 = 5, ++ GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEA1_5B1 = 6, ++ GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEPORTRAITA2B1 = 7, ++ GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEPORTRAITA1_5B1 = 8, ++ GST_CV_STITCHING_WARP_TYPES_PANINIA2B1 = 9, ++ GST_CV_STITCHING_WARP_TYPES_PANINIA1_5B1 = 10, ++ GST_CV_STITCHING_WARP_TYPES_PANINIPORTRAITA2B1 = 11, ++ GST_CV_STITCHING_WARP_TYPES_PANINIPORTRAITA1_5B1 = 12, ++ GST_CV_STITCHING_WARP_TYPES_MERCATOR = 13, ++ GST_CV_STITCHING_WARP_TYPES_TRANSVERSEMERCATOR = 14 ++}; ++ ++#define GST_TYPE_CV_STITCHING_WARP_TYPES (cv_stitching_warp_type_get_type ()) ++ ++static GType ++cv_stitching_warp_type_get_type (void) ++{ ++ static GType cv_stitching_warp_type_type = 0; ++ static const GEnumValue cv_stitching_warp_type[] = { ++ {GST_CV_STITCHING_WARP_TYPES_PLANE, "warp type plane", "plane"}, ++ {GST_CV_STITCHING_WARP_TYPES_CYLINDRICAL, "warp type cylindrical", "cylindrical"}, ++ {GST_CV_STITCHING_WARP_TYPES_SPHERICAL, "warp type spherical", "spherical"}, ++ {GST_CV_STITCHING_WARP_TYPES_FISHEYE, "warp type fisheye", "fisheye"}, ++ {GST_CV_STITCHING_WARP_TYPES_STEREOGRAPHIC, "warp type stereographic", "stereographic"}, ++ {GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEA2B1, "warp type compressedPlaneA2B1", "compressedPlaneA2B1"}, ++ {GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEA1_5B1, "warp type compressedPlaneA1.5B1", "compressedPlaneA1.5B1"}, ++ {GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEPORTRAITA2B1, "warp type compressedPlanePortraitA2B1", "compressedPlanePortraitA2B1"}, ++ {GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEPORTRAITA1_5B1, "warp type compressedPlanePortraitA1.5B1", "compressedPlanePortraitA1.5B1"}, ++ {GST_CV_STITCHING_WARP_TYPES_PANINIA2B1, "warp type paniniA2B1", "paniniA2B1"}, ++ {GST_CV_STITCHING_WARP_TYPES_PANINIA1_5B1, "warp type paniniA1.5B1", "paniniA1.5B1"}, ++ {GST_CV_STITCHING_WARP_TYPES_PANINIPORTRAITA2B1, "warp type paniniPortraitA2B1", "paniniPortraitA2B1"}, ++ {GST_CV_STITCHING_WARP_TYPES_PANINIPORTRAITA1_5B1, "warp type paniniPortraitA1.5B1", "paniniPortraitA1.5B1"}, ++ {GST_CV_STITCHING_WARP_TYPES_MERCATOR, "warp type mercator", "mercator"}, ++ {GST_CV_STITCHING_WARP_TYPES_TRANSVERSEMERCATOR, "warp type transverseMercator", "transverseMercator"}, ++ {0, NULL, NULL}, ++ }; ++ ++ if (!cv_stitching_warp_type_type) { ++ cv_stitching_warp_type_type = ++ g_enum_register_static ("GstCvStitchingWarpTypes", cv_stitching_warp_type); ++ } ++ return cv_stitching_warp_type_type; ++} ++ ++enum _GstCvStitchingSeamFindTypes { ++ GST_CV_STITCHING_SEAM_FIND_TYPES_NO = 0, ++ GST_CV_STITCHING_SEAM_FIND_TYPES_VORONOI = 1, ++ GST_CV_STITCHING_SEAM_FIND_TYPES_GC_COLOR = 2, ++ GST_CV_STITCHING_SEAM_FIND_TYPES_GC_COLORGRAD = 3, ++ GST_CV_STITCHING_SEAM_FIND_TYPES_DP_COLOR = 4, ++ GST_CV_STITCHING_SEAM_FIND_TYPES_DP_COLORGRAD = 5 ++}; ++ ++#define GST_TYPE_CV_STITCHING_SEAM_FIND_TYPES (cv_stitching_seam_find_type_get_type ()) ++ ++static GType ++cv_stitching_seam_find_type_get_type (void) ++{ ++ static GType cv_stitching_seam_find_type_type = 0; ++ static const GEnumValue cv_stitching_seam_find_type[] = { ++ {GST_CV_STITCHING_SEAM_FIND_TYPES_NO, "seam_find type no", "no"}, ++ {GST_CV_STITCHING_SEAM_FIND_TYPES_VORONOI, "seam_find type voronoi", "voronoi"}, ++ {GST_CV_STITCHING_SEAM_FIND_TYPES_GC_COLOR, "seam_find type gc_color", "gc_color"}, ++ {GST_CV_STITCHING_SEAM_FIND_TYPES_GC_COLORGRAD, "seam_find type gc_colorgrad", "gc_colorgrad"}, ++ {GST_CV_STITCHING_SEAM_FIND_TYPES_DP_COLOR, "seam_find type dp_color", "dp_color"}, ++ {GST_CV_STITCHING_SEAM_FIND_TYPES_DP_COLORGRAD, "seam_find type dp_colorgrad", "dp_colorgrad"}, ++ {0, NULL, NULL}, ++ }; ++ ++ if (!cv_stitching_seam_find_type_type) { ++ cv_stitching_seam_find_type_type = ++ g_enum_register_static ("GstCvStitchingSeamFindTypes", cv_stitching_seam_find_type); ++ } ++ return cv_stitching_seam_find_type_type; ++} ++ ++enum _GstCvStitchingBACostFuncs { ++ GST_CV_STITCHING_BA_COST_FUNCS_REPROJ = 0, ++ GST_CV_STITCHING_BA_COST_FUNCS_RAY = 1 ++}; ++ ++#define GST_TYPE_CV_STITCHING_BA_COST_FUNCS (cv_stitching_ba_cost_func_get_type ()) ++ ++static GType ++cv_stitching_ba_cost_func_get_type (void) ++{ ++ static GType cv_stitching_ba_cost_func_type = 0; ++ static const GEnumValue cv_stitching_ba_cost_func[] = { ++ {GST_CV_STITCHING_BA_COST_FUNCS_REPROJ, "ba cost func reproj", "reproj"}, ++ {GST_CV_STITCHING_BA_COST_FUNCS_RAY, "ba cost func ray", "ray"}, ++ {0, NULL, NULL}, ++ }; ++ ++ if (!cv_stitching_ba_cost_func_type) { ++ cv_stitching_ba_cost_func_type = ++ g_enum_register_static ("GstCvStitchingBACostFuncs", cv_stitching_ba_cost_func); ++ } ++ return cv_stitching_ba_cost_func_type; ++} ++ ++static void ++gst_cv_stitching_class_init (GstCvStitchingClass * klass) ++{ ++ GObjectClass *gobject_class; ++ GstElementClass *element_class; ++ GstAggregatorClass *agg_class = (GstAggregatorClass *) klass; ++ GstOpencvAggregatorClass *cvagg_class = (GstOpencvAggregatorClass *) klass; ++ ++ gobject_class = (GObjectClass *) klass; ++ element_class = GST_ELEMENT_CLASS (klass); ++ ++ gobject_class->set_property = gst_cv_stitching_set_property; ++ gobject_class->get_property = gst_cv_stitching_get_property; ++ ++ gst_element_class_add_pad_template (element_class, ++ gst_static_pad_template_get (&src_factory)); ++ gst_element_class_add_pad_template (element_class, ++ gst_static_pad_template_get (&sink_factory)); ++ ++ g_object_class_install_property (gobject_class, PROP_FEATURE_TYPE, ++ g_param_spec_enum ("feturetypes", "Featuretypes", "match feature type", ++ GST_TYPE_CV_STITCHING_FEATURE_TYPES, DEFAULT_FEATURE_TYPE, ++ G_PARAM_READWRITE)); ++ g_object_class_install_property (gobject_class, PROP_WARP_TYPE, ++ g_param_spec_enum ("warptypes", "Warptypes", "Warp type", ++ GST_TYPE_CV_STITCHING_WARP_TYPES, DEFAULT_WARP_TYPE, ++ G_PARAM_READWRITE)); ++ g_object_class_install_property (gobject_class, PROP_SEAM_FIND_TYPE, ++ g_param_spec_enum ("seamfindtypes", "Seamfindtypes", "Seam find type", ++ GST_TYPE_CV_STITCHING_SEAM_FIND_TYPES, DEFAULT_SEAM_FIND, ++ G_PARAM_READWRITE)); ++ g_object_class_install_property (gobject_class, PROP_BA_COST_FUNC, ++ g_param_spec_enum ("bacostfuncs", "Bacostfuncs", "Ba cost func", ++ GST_TYPE_CV_STITCHING_BA_COST_FUNCS, DEFAULT_BA_COST_FUNC, ++ G_PARAM_READWRITE)); ++ ++ gst_element_class_set_metadata (element_class, "OpenCV video_stitcher", ++ "Aggregator/VideoAggregator/CvStitching", "OpenCV video_stitcher", ++ "Song Bing "); ++ ++ agg_class->start = gst_cv_stitching_start; ++ agg_class->stop = gst_cv_stitching_stop; ++ ++ cvagg_class->GstOpencvAggregatorProcess = gst_cv_stitching_process; ++ ++ agg_class->sinkpads_type = GST_TYPE_CV_STITCHING_PAD; ++} ++ ++static void ++gst_cv_stitching_init (GstCvStitching * stitcher) ++{ ++ stitcher->features_type = DEFAULT_FEATURE_TYPE; ++ stitcher->warp_type = DEFAULT_WARP_TYPE; ++ stitcher->seam_find_type = DEFAULT_SEAM_FIND; ++ stitcher->ba_cost_func = DEFAULT_BA_COST_FUNC; ++} ++ ++static void ++gst_cv_stitching_set_property (GObject * object, guint prop_id, ++ const GValue * value, GParamSpec * pspec) ++{ ++ GstCvStitching *stitcher = GST_CV_STITCHING (object); ++ ++ switch (prop_id) { ++ case PROP_FEATURE_TYPE: ++ stitcher->features_type = g_value_get_enum (value); ++ break; ++ case PROP_WARP_TYPE: ++ stitcher->warp_type = g_value_get_enum (value); ++ break; ++ case PROP_SEAM_FIND_TYPE: ++ stitcher->seam_find_type = g_value_get_enum (value); ++ break; ++ case PROP_BA_COST_FUNC: ++ stitcher->ba_cost_func = g_value_get_enum (value); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void ++gst_cv_stitching_get_property (GObject * object, guint prop_id, ++ GValue * value, GParamSpec * pspec) ++{ ++ GstCvStitching *stitcher = GST_CV_STITCHING (object); ++ ++ switch (prop_id) { ++ case PROP_FEATURE_TYPE: ++ g_value_set_enum (value, stitcher->features_type); ++ break; ++ case PROP_WARP_TYPE: ++ g_value_set_enum (value, stitcher->warp_type); ++ break; ++ case PROP_SEAM_FIND_TYPE: ++ g_value_set_enum (value, stitcher->seam_find_type); ++ break; ++ case PROP_BA_COST_FUNC: ++ g_value_set_enum (value, stitcher->ba_cost_func); ++ break; ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static gboolean ++gst_cv_stitching_start (GstAggregator * agg) ++{ ++ GstCvStitching *stitcher = GST_CV_STITCHING (agg); ++ ++ if (!GST_AGGREGATOR_CLASS (parent_class)->start (agg)) ++ return FALSE; ++ ++ if (stitcher->features_type == GST_CV_STITCHING_FEATURE_TYPES_SURF) { ++ stitcher->finder = new SurfFeaturesFinder(); ++ } else if (stitcher->features_type == GST_CV_STITCHING_FEATURE_TYPES_ORB) { ++ stitcher->finder = new OrbFeaturesFinder(); ++ } else { ++ GST_ERROR_OBJECT (stitcher, "Unknown 2D features type: %d", stitcher->features_type); ++ return FALSE; ++ } ++ ++ if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_PLANE) ++ stitcher->warper_creator = new cv::PlaneWarper(); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_CYLINDRICAL) ++ stitcher->warper_creator = new cv::CylindricalWarper(); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_SPHERICAL) ++ stitcher->warper_creator = new cv::SphericalWarper(); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_FISHEYE) ++ stitcher->warper_creator = new cv::FisheyeWarper(); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_STEREOGRAPHIC) ++ stitcher->warper_creator = new cv::StereographicWarper(); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEA2B1) ++ stitcher->warper_creator = new cv::CompressedRectilinearWarper(2, 1); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEA1_5B1) ++ stitcher->warper_creator = new cv::CompressedRectilinearWarper(1.5, 1); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEPORTRAITA2B1) ++ stitcher->warper_creator = new cv::CompressedRectilinearPortraitWarper(2, 1); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_COMPRESSEDPLANEPORTRAITA1_5B1) ++ stitcher->warper_creator = new cv::CompressedRectilinearPortraitWarper(1.5, 1); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_PANINIA2B1) ++ stitcher->warper_creator = new cv::PaniniWarper(2, 1); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_PANINIA1_5B1) ++ stitcher->warper_creator = new cv::PaniniWarper(1.5, 1); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_PANINIPORTRAITA2B1) ++ stitcher->warper_creator = new cv::PaniniPortraitWarper(2, 1); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_PANINIPORTRAITA1_5B1) ++ stitcher->warper_creator = new cv::PaniniPortraitWarper(1.5, 1); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_MERCATOR) ++ stitcher->warper_creator = new cv::MercatorWarper(); ++ else if (stitcher->warp_type == GST_CV_STITCHING_WARP_TYPES_TRANSVERSEMERCATOR) ++ stitcher->warper_creator = new cv::TransverseMercatorWarper(); ++ if (stitcher->warper_creator.empty()) { ++ GST_ERROR_OBJECT (stitcher, "Can't create the following warper: %d", ++ stitcher->warp_type); ++ return FALSE; ++ } ++ ++ if (stitcher->seam_find_type == GST_CV_STITCHING_SEAM_FIND_TYPES_NO) ++ stitcher->seam_finder = new detail::NoSeamFinder(); ++ else if (stitcher->seam_find_type == GST_CV_STITCHING_SEAM_FIND_TYPES_VORONOI) ++ stitcher->seam_finder = new detail::VoronoiSeamFinder(); ++ else if (stitcher->seam_find_type == GST_CV_STITCHING_SEAM_FIND_TYPES_GC_COLOR) { ++ stitcher->seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR); ++ } else if (stitcher->seam_find_type == GST_CV_STITCHING_SEAM_FIND_TYPES_GC_COLORGRAD) { ++ stitcher->seam_finder = new detail::GraphCutSeamFinder(GraphCutSeamFinderBase::COST_COLOR_GRAD); ++ } else if (stitcher->seam_find_type == GST_CV_STITCHING_SEAM_FIND_TYPES_DP_COLOR) ++ stitcher->seam_finder = new detail::DpSeamFinder(DpSeamFinder::COLOR); ++ else if (stitcher->seam_find_type == GST_CV_STITCHING_SEAM_FIND_TYPES_DP_COLORGRAD) ++ stitcher->seam_finder = new detail::DpSeamFinder(DpSeamFinder::COLOR_GRAD); ++ if (stitcher->seam_finder.empty()) { ++ GST_ERROR_OBJECT (stitcher, "Can't create the following seam finder: %d", ++ stitcher->seam_find_type); ++ return FALSE; ++ } ++ ++ if (stitcher->ba_cost_func == GST_CV_STITCHING_BA_COST_FUNCS_REPROJ) ++ stitcher->adjuster = new detail::BundleAdjusterReproj(); ++ else if (stitcher->ba_cost_func == GST_CV_STITCHING_BA_COST_FUNCS_RAY) ++ stitcher->adjuster = new detail::BundleAdjusterRay(); ++ else { ++ GST_ERROR_OBJECT (stitcher, "Unknown bundle adjustment cost function: %d", ++ stitcher->ba_cost_func); ++ return FALSE; ++ } ++ ++ return TRUE; ++} ++ ++static gboolean ++gst_cv_stitching_stop (GstAggregator * agg) ++{ ++ GstCvStitching *stitcher = GST_CV_STITCHING (agg); ++ ++ stitcher->finder.release(); ++ stitcher->warper_creator.release(); ++ stitcher->seam_finder.release(); ++ stitcher->adjuster.release(); ++ ++ return GST_AGGREGATOR_CLASS (parent_class)->stop (agg); ++} ++ ++static gboolean ++gst_cv_stitching_process (GstOpencvAggregator * agg, GPtrArray *imgs, ++ IplImage *outimg) ++{ ++ GstCvStitching *stitcher = GST_CV_STITCHING (agg); ++ int64 app_start_time = getTickCount(); ++ ++ GST_LOG_OBJECT (stitcher, "video stitching process"); ++ int num_images = imgs->len; ++ if (num_images < 2) { ++ GST_ERROR_OBJECT (stitcher, "Need more images"); ++ return FALSE; ++ } ++ ++ double work_scale = 1, seam_scale = 1, compose_scale = 1; ++ bool is_work_scale_set = false, is_seam_scale_set = false, is_compose_scale_set = false; ++ ++ GST_LOG_OBJECT (stitcher, "Finding features..."); ++ int64 t = getTickCount(); ++ ++ Mat full_img, img; ++ vector features(num_images); ++ vector images(num_images); ++ vector full_img_sizes(num_images); ++ double seam_work_aspect = 1; ++ ++ for (int i = 0; i < num_images; ++i) { ++ IplImage *cvImage = (IplImage *) g_ptr_array_index (imgs, i); ++ Mat in_mat(cvImage, false); ++ ++ full_img = in_mat; ++ full_img_sizes[i] = full_img.size(); ++ ++ if (full_img.empty()) { ++ GST_ERROR_OBJECT (stitcher, "No input data"); ++ return FALSE; ++ } ++ if (work_megapix < 0) { ++ img = full_img; ++ work_scale = 1; ++ is_work_scale_set = true; ++ } else { ++ if (!is_work_scale_set) { ++ work_scale = min(1.0, sqrt(work_megapix * 1e6 / full_img.size().area())); ++ is_work_scale_set = true; ++ } ++ resize(full_img, img, Size(), work_scale, work_scale); ++ } ++ if (!is_seam_scale_set) { ++ seam_scale = min(1.0, sqrt(seam_megapix * 1e6 / full_img.size().area())); ++ seam_work_aspect = seam_scale / work_scale; ++ is_seam_scale_set = true; ++ } ++ ++ (*stitcher->finder)(img, features[i]); ++ features[i].img_idx = i; ++ //LOGLN("Features in image #" << i+1 << ": " << features[i].keypoints.size()); ++ ++ resize(full_img, img, Size(), seam_scale, seam_scale); ++ images[i] = img.clone(); ++ } ++ ++ stitcher->finder->collectGarbage(); ++ full_img.release(); ++ img.release(); ++ ++ GST_LOG_OBJECT (stitcher, "Finding features, time: %f sec", ++ ((getTickCount() - t) / getTickFrequency())); ++ ++ GST_LOG_OBJECT (stitcher, "Pairwise matching"); ++ t = getTickCount(); ++ BestOf2NearestMatcher matcher(try_gpu, match_conf); ++ vector pairwise_matches; ++ ++ matcher(features, pairwise_matches); ++ matcher.collectGarbage(); ++ GST_LOG_OBJECT (stitcher, "Pairwise matching, time: %f sec", ++ ((getTickCount() - t) / getTickFrequency())); ++ ++ // Leave only images we are sure are from the same panorama ++ vector indices = leaveBiggestComponent(features, pairwise_matches, conf_thresh); ++ vector img_subset; ++ vector full_img_sizes_subset; ++ for (size_t i = 0; i < indices.size(); ++i) { ++ img_subset.push_back(images[indices[i]]); ++ full_img_sizes_subset.push_back(full_img_sizes[indices[i]]); ++ } ++ ++ images = img_subset; ++ full_img_sizes = full_img_sizes_subset; ++ ++ // Check if we still have enough images ++ num_images = static_cast(images.size()); ++ if (num_images < 2) { ++ GST_WARNING_OBJECT (stitcher, "Can't find overlap images"); ++ return FALSE; ++ } ++ HomographyBasedEstimator estimator; ++ vector cameras; ++ estimator(features, pairwise_matches, cameras); ++ ++ for (size_t i = 0; i < cameras.size(); ++i) { ++ Mat R; ++ cameras[i].R.convertTo(R, CV_32F); ++ cameras[i].R = R; ++ //LOGLN("Initial intrinsics #" << indices[i]+1 << ":\n" << cameras[i].K()); ++ } ++ ++ stitcher->adjuster->setConfThresh(conf_thresh); ++ Mat_ refine_mask = Mat::zeros(3, 3, CV_8U); ++ if (ba_refine_mask[0] == 'x') refine_mask(0,0) = 1; ++ if (ba_refine_mask[1] == 'x') refine_mask(0,1) = 1; ++ if (ba_refine_mask[2] == 'x') refine_mask(0,2) = 1; ++ if (ba_refine_mask[3] == 'x') refine_mask(1,1) = 1; ++ if (ba_refine_mask[4] == 'x') refine_mask(1,2) = 1; ++ stitcher->adjuster->setRefinementMask(refine_mask); ++ (*stitcher->adjuster)(features, pairwise_matches, cameras); ++ ++ // Find median focal length ++ vector focals; ++ for (size_t i = 0; i < cameras.size(); ++i) { ++ //LOGLN("Camera #" << indices[i]+1 << ":\n" << cameras[i].K()); ++ focals.push_back(cameras[i].focal); ++ } ++ ++ sort(focals.begin(), focals.end()); ++ float warped_image_scale; ++ if (focals.size() % 2 == 1) ++ warped_image_scale = static_cast(focals[focals.size() / 2]); ++ else ++ warped_image_scale = static_cast(focals[focals.size() / 2 - 1] ++ + focals[focals.size() / 2]) * 0.5f; ++ ++ if (do_wave_correct) { ++ vector rmats; ++ for (size_t i = 0; i < cameras.size(); ++i) ++ rmats.push_back(cameras[i].R); ++ waveCorrect(rmats, wave_correct); ++ for (size_t i = 0; i < cameras.size(); ++i) ++ cameras[i].R = rmats[i]; ++ } ++ ++ GST_LOG_OBJECT (stitcher, "Warping images (auxiliary)... "); ++ t = getTickCount(); ++ ++ vector corners(num_images); ++ vector masks_warped(num_images); ++ vector images_warped(num_images); ++ vector sizes(num_images); ++ vector masks(num_images); ++ ++ // Preapre images masks ++ for (int i = 0; i < num_images; ++i) { ++ masks[i].create(images[i].size(), CV_8U); ++ masks[i].setTo(Scalar::all(255)); ++ } ++ ++ Ptr warper = stitcher->warper_creator->create( ++ static_cast(warped_image_scale * seam_work_aspect)); ++ ++ for (int i = 0; i < num_images; ++i) { ++ Mat_ K; ++ cameras[i].K().convertTo(K, CV_32F); ++ float swa = (float)seam_work_aspect; ++ K(0,0) *= swa; K(0,2) *= swa; ++ K(1,1) *= swa; K(1,2) *= swa; ++ ++ corners[i] = warper->warp(images[i], K, cameras[i].R, ++ INTER_LINEAR, BORDER_REFLECT, images_warped[i]); ++ sizes[i] = images_warped[i].size(); ++ ++ warper->warp(masks[i], K, cameras[i].R, INTER_NEAREST, ++ BORDER_CONSTANT, masks_warped[i]); ++ } ++ ++ vector images_warped_f(num_images); ++ for (int i = 0; i < num_images; ++i) ++ images_warped[i].convertTo(images_warped_f[i], CV_32F); ++ ++ GST_LOG_OBJECT (stitcher, "Warping images, time: %f sec", ++ ((getTickCount() - t) / getTickFrequency())); ++ ++ GST_LOG_OBJECT (stitcher, "seam finder..."); ++ t = getTickCount(); ++ ++ Ptr compensator = ExposureCompensator::createDefault(expos_comp_type); ++ compensator->feed(corners, images_warped, masks_warped); ++ ++ stitcher->seam_finder->find(images_warped_f, corners, masks_warped); ++ ++ // Release unused memory ++ images.clear(); ++ images_warped.clear(); ++ images_warped_f.clear(); ++ masks.clear(); ++ GST_LOG_OBJECT (stitcher, "seam finder, time: %f sec", ++ ((getTickCount() - t) / getTickFrequency())); ++ ++ GST_LOG_OBJECT (stitcher, "Compositing..."); ++ t = getTickCount(); ++ ++ Mat img_warped, img_warped_s; ++ Mat dilated_mask, seam_mask, mask, mask_warped; ++ //double compose_seam_aspect = 1; ++ double compose_work_aspect = 1; ++ Ptr blender; ++ ++ for (int img_idx = 0; img_idx < num_images; ++img_idx) { ++ //LOGLN("Compositing image #" << indices[img_idx]+1); ++ // Read image and resize it if necessary ++ IplImage *cvImage = (IplImage *) g_ptr_array_index (imgs, img_idx); ++ Mat in_mat(cvImage, false); ++ ++ full_img = in_mat; ++ if (!is_compose_scale_set) { ++ if (compose_megapix > 0) ++ compose_scale = min(1.0, sqrt(compose_megapix * 1e6 / full_img.size().area())); ++ is_compose_scale_set = true; ++ ++ // Compute relative scales ++ //compose_seam_aspect = compose_scale / seam_scale; ++ compose_work_aspect = compose_scale / work_scale; ++ ++ // Update warped image scale ++ warped_image_scale *= static_cast(compose_work_aspect); ++ warper = stitcher->warper_creator->create(warped_image_scale); ++ ++ // Update corners and sizes ++ for (int i = 0; i < num_images; ++i) { ++ // Update intrinsics ++ cameras[i].focal *= compose_work_aspect; ++ cameras[i].ppx *= compose_work_aspect; ++ cameras[i].ppy *= compose_work_aspect; ++ ++ // Update corner and size ++ Size sz = full_img_sizes[i]; ++ if (std::abs(compose_scale - 1) > 1e-1) { ++ sz.width = cvRound(full_img_sizes[i].width * compose_scale); ++ sz.height = cvRound(full_img_sizes[i].height * compose_scale); ++ } ++ ++ Mat K; ++ cameras[i].K().convertTo(K, CV_32F); ++ Rect roi = warper->warpRoi(sz, K, cameras[i].R); ++ corners[i] = roi.tl(); ++ sizes[i] = roi.size(); ++ } ++ } ++ if (abs(compose_scale - 1) > 1e-1) ++ resize(full_img, img, Size(), compose_scale, compose_scale); ++ else ++ img = full_img; ++ full_img.release(); ++ Size img_size = img.size(); ++ ++ Mat K; ++ cameras[img_idx].K().convertTo(K, CV_32F); ++ ++ // Warp the current image ++ warper->warp(img, K, cameras[img_idx].R, INTER_LINEAR, BORDER_REFLECT, img_warped); ++ ++ // Warp the current image mask ++ mask.create(img_size, CV_8U); ++ mask.setTo(Scalar::all(255)); ++ warper->warp(mask, K, cameras[img_idx].R, INTER_NEAREST, BORDER_CONSTANT, mask_warped); ++ ++ // Compensate exposure ++ compensator->apply(img_idx, corners[img_idx], img_warped, mask_warped); ++ ++ img_warped.convertTo(img_warped_s, CV_16S); ++ img_warped.release(); ++ img.release(); ++ mask.release(); ++ ++ dilate(masks_warped[img_idx], dilated_mask, Mat()); ++ resize(dilated_mask, seam_mask, mask_warped.size()); ++ mask_warped = seam_mask & mask_warped; ++ ++ if (blender.empty()) { ++ blender = Blender::createDefault(blend_type, try_gpu); ++ Size dst_sz = resultRoi(corners, sizes).size(); ++ float blend_width = sqrt(static_cast(dst_sz.area())) * blend_strength / 100.f; ++ if (blend_width < 1.f) ++ blender = Blender::createDefault(Blender::NO, try_gpu); ++ else if (blend_type == Blender::MULTI_BAND) { ++ MultiBandBlender* mb = dynamic_cast(static_cast(blender)); ++ mb->setNumBands(static_cast(ceil(log(blend_width)/log(2.)) - 1.)); ++ //LOGLN("Multi-band blender, number of bands: " << mb->numBands()); ++ } else if (blend_type == Blender::FEATHER) { ++ FeatherBlender* fb = dynamic_cast(static_cast(blender)); ++ fb->setSharpness(1.f/blend_width); ++ //LOGLN("Feather blender, sharpness: " << fb->sharpness()); ++ } ++ blender->prepare(corners, sizes); ++ } ++ ++ // Blend the current image ++ blender->feed(img_warped_s, mask_warped, corners[img_idx]); ++ } ++ ++ Mat result, result_mask; ++ blender->blend(result, result_mask); ++ ++ GST_LOG_OBJECT (stitcher, "Compositing, time: %f sec", ((getTickCount() - t) / getTickFrequency())); ++ ++ Mat m1(outimg->height, outimg->width, CV_8UC3), m2; ++ resize(result, m1, m1.size()); ++ m1.convertTo(m2, CV_8UC3); ++ memcpy(outimg->imageData, m2.data, outimg->imageSize); ++ ++ GST_LOG_OBJECT (stitcher, "Finished, total time: %f sec", ( ++ (getTickCount() - app_start_time) / getTickFrequency())); ++ ++ return TRUE; ++} ++ ++gboolean ++gst_cv_stitching_plugin_init (GstPlugin * plugin) ++{ ++ GST_DEBUG_CATEGORY_INIT (gst_cv_stitching_debug, "cvstitching", ++ 0, "Video or image stitching"); ++ ++ return gst_element_register (plugin, "cvstitching", GST_RANK_NONE, ++ GST_TYPE_CV_STITCHING); ++} +diff --git a/ext/opencv/gstcvstitching.h b/ext/opencv/gstcvstitching.h +new file mode 100644 +index 0000000..ec955d0 +--- /dev/null ++++ b/ext/opencv/gstcvstitching.h +@@ -0,0 +1,130 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Song Bing ++ * ++ * 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., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __GST_CV_STITCHING_H__ ++#define __GST_CV_STITCHING_H__ ++ ++#include ++#include "opencv2/opencv_modules.hpp" ++#include "opencv2/highgui/highgui.hpp" ++#include "opencv2/stitching/detail/autocalib.hpp" ++#include "opencv2/stitching/detail/blenders.hpp" ++#include "opencv2/stitching/detail/camera.hpp" ++#include "opencv2/stitching/detail/exposure_compensate.hpp" ++#include "opencv2/stitching/detail/matchers.hpp" ++#include "opencv2/stitching/detail/motion_estimators.hpp" ++#include "opencv2/stitching/detail/seam_finders.hpp" ++#include "opencv2/stitching/detail/util.hpp" ++#include "opencv2/stitching/detail/warpers.hpp" ++#include "opencv2/stitching/warpers.hpp" ++#include "gstopencvaggregator.h" ++ ++using namespace std; ++using namespace cv; ++using namespace cv::detail; ++ ++G_BEGIN_DECLS ++#define GST_TYPE_CV_STITCHING_PAD (gst_cv_stitching_pad_get_type()) ++#define GST_CV_STITCHING_PAD(obj) \ ++ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CV_STITCHING_PAD, GstCvStitchingPad)) ++#define GST_CV_STITCHING_PAD_CLASS(klass) \ ++ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CV_STITCHING_PAD, GstCvStitchingPadClass)) ++#define GST_IS_CV_STITCHING_PAD(obj) \ ++ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CV_STITCHING_PAD)) ++#define GST_IS_CV_STITCHING_PAD_CLASS(klass) \ ++ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CV_STITCHING_PAD)) ++ ++typedef struct _GstCvStitchingPad GstCvStitchingPad; ++typedef struct _GstCvStitchingPadClass GstCvStitchingPadClass; ++ ++struct _GstCvStitchingPad ++{ ++ GstOpencvAggregatorPad parent; ++}; ++ ++struct _GstCvStitchingPadClass ++{ ++ GstOpencvAggregatorPadClass parent_class; ++}; ++ ++GType gst_cv_stitching_pad_get_type (void); ++ ++#define GST_TYPE_CV_STITCHING \ ++ (gst_cv_stitching_get_type()) ++#define GST_CV_STITCHING(obj) \ ++ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_CV_STITCHING,GstCvStitching)) ++#define GST_CV_STITCHING_CLASS(klass) \ ++ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_CV_STITCHING,GstCvStitchingClass)) ++#define GST_IS_CV_STITCHING(obj) \ ++ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_CV_STITCHING)) ++#define GST_IS_CV_STITCHING_CLASS(klass) \ ++ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_CV_STITCHING)) ++ ++typedef struct _GstCvStitching GstCvStitching; ++typedef struct _GstCvStitchingClass GstCvStitchingClass; ++ ++struct _GstCvStitching ++{ ++ GstOpencvAggregator parent; ++ ++ Ptr finder; ++ Ptr warper_creator; ++ Ptr seam_finder; ++ Ptr adjuster; ++ gint features_type; ++ gint warp_type; ++ gint seam_find_type; ++ gint ba_cost_func; ++}; ++ ++struct _GstCvStitchingClass ++{ ++ GstOpencvAggregatorClass parent_class; ++}; ++ ++GType gst_cv_stitching_get_type (void); ++ ++gboolean gst_cv_stitching_plugin_init (GstPlugin * plugin); ++ ++G_END_DECLS ++#endif /* __GST_CV_STITCHING_H__ */ +diff --git a/ext/opencv/gstopencv.cpp b/ext/opencv/gstopencv.cpp +index 3184518..f01aa1d 100644 +--- a/ext/opencv/gstopencv.cpp ++++ b/ext/opencv/gstopencv.cpp +@@ -42,6 +42,7 @@ + #include "gstsegmentation.h" + #include "gstgrabcut.h" + #include "gstdisparity.h" ++#include "gstcvstitching.h" + + static gboolean + plugin_init (GstPlugin * plugin) +@@ -103,6 +104,9 @@ plugin_init (GstPlugin * plugin) + if (!gst_disparity_plugin_init (plugin)) + return FALSE; + ++ if (!gst_cv_stitching_plugin_init (plugin)) ++ return FALSE; ++ + return TRUE; + } + +diff --git a/ext/opencv/gstopencvaggregator.c b/ext/opencv/gstopencvaggregator.c +new file mode 100644 +index 0000000..3c69edf +--- /dev/null ++++ b/ext/opencv/gstopencvaggregator.c +@@ -0,0 +1,708 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Song Bing ++ * ++ * 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., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++# include ++#endif ++ ++#include ++#include "gstopencvaggregator.h" ++#include "gstopencvutils.h" ++ ++#define gst_opencv_aggregator_parent_class parent_class ++G_DEFINE_ABSTRACT_TYPE (GstOpencvAggregator, gst_opencv_aggregator, ++ GST_TYPE_VIDEO_AGGREGATOR); ++ ++G_DEFINE_TYPE (GstOpencvAggregatorPad, gst_opencv_aggregator_pad, ++ GST_TYPE_VIDEO_AGGREGATOR_PAD); ++ ++#define GST_CAT_DEFAULT gst_opencv_aggregator_debug ++GST_DEBUG_CATEGORY (gst_opencv_aggregator_debug); ++ ++static void gst_opencv_aggregator_pad_get_property (GObject * object, ++ guint prop_id, GValue * value, GParamSpec * pspec); ++static void gst_opencv_aggregator_pad_set_property (GObject * object, ++ guint prop_id, const GValue * value, GParamSpec * pspec); ++ ++enum ++{ ++ PROP_PAD_0 ++}; ++ ++#define GST_OPENCV_AGGREGATOR_GET_PRIVATE(obj) \ ++ (G_TYPE_INSTANCE_GET_PRIVATE ((obj), GST_TYPE_OPENCV_AGGREGATOR, \ ++ GstOpencvAggregatorPrivate)) ++ ++struct _GstOpencvAggregatorPrivate ++{ ++ gboolean set_caps; ++ GstBufferPool *pool; ++ gboolean pool_active; ++ GstAllocator *allocator; ++ GstAllocationParams params; ++ GstQuery *query; ++ ++ GPtrArray *imgs; ++ GPtrArray *in_infos; ++ IplImage *out_cvImage; ++}; ++ ++static void ++gst_opencv_aggregator_pad_class_init (GstOpencvAggregatorPadClass * klass) ++{ ++ GObjectClass *gobject_class = (GObjectClass *) klass; ++ ++ gobject_class->set_property = gst_opencv_aggregator_pad_set_property; ++ gobject_class->get_property = gst_opencv_aggregator_pad_get_property; ++} ++ ++static void ++gst_opencv_aggregator_pad_init (GstOpencvAggregatorPad * aggregatorerpad) ++{ ++} ++ ++static void ++gst_opencv_aggregator_pad_get_property (GObject * object, guint prop_id, ++ GValue * value, GParamSpec * pspec) ++{ ++ switch (prop_id) { ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void ++gst_opencv_aggregator_pad_set_property (GObject * object, guint prop_id, ++ const GValue * value, GParamSpec * pspec) ++{ ++ switch (prop_id) { ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++enum ++{ ++ PROP_0 ++}; ++ ++static void gst_opencv_aggregator_set_property (GObject * object, guint prop_id, ++ const GValue * value, GParamSpec * pspec); ++static void gst_opencv_aggregator_get_property (GObject * object, guint prop_id, ++ GValue * value, GParamSpec * pspec); ++static gboolean gst_opencv_aggregator_start (GstAggregator * agg); ++static gboolean gst_opencv_aggregator_stop (GstAggregator * agg); ++static GstFlowReturn ++gst_opencv_aggregator_get_output_buffer (GstVideoAggregator * videoaggregator, ++ GstBuffer ** outbuf); ++static GstFlowReturn ++gst_opencv_aggregator_aggregate_frames (GstVideoAggregator * vagg, ++ GstBuffer * outbuffer); ++static gboolean ++gst_opencv_aggregator_sink_query (GstAggregator * agg, GstAggregatorPad * bpad, ++ GstQuery * query); ++static gboolean ++gst_opencv_aggregator_negotiated_caps (GstVideoAggregator * vagg, ++ GstCaps * caps); ++static gboolean ++gst_opencv_aggregator_decide_allocation_default (GstOpencvAggregator * ++ aggregator, GstQuery * query); ++static gboolean ++gst_opencv_aggregator_propose_allocation_default (GstOpencvAggregator * ++ aggregator, GstQuery * query); ++ ++static void ++gst_opencv_aggregator_class_init (GstOpencvAggregatorClass * klass) ++{ ++ GObjectClass *gobject_class; ++ ++ GstVideoAggregatorClass *videoaggregator_class = ++ (GstVideoAggregatorClass *) klass; ++ GstAggregatorClass *agg_class = (GstAggregatorClass *) klass; ++ ++ GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, "opencvaggregator", 0, ++ "opencv aggregator"); ++ ++ gobject_class = (GObjectClass *) klass; ++ ++ g_type_class_add_private (klass, sizeof (GstOpencvAggregatorPrivate)); ++ ++ gobject_class->get_property = gst_opencv_aggregator_get_property; ++ gobject_class->set_property = gst_opencv_aggregator_set_property; ++ ++ agg_class->sinkpads_type = GST_TYPE_OPENCV_AGGREGATOR_PAD; ++ agg_class->sink_query = gst_opencv_aggregator_sink_query; ++ agg_class->stop = gst_opencv_aggregator_stop; ++ agg_class->start = gst_opencv_aggregator_start; ++ ++ videoaggregator_class->disable_frame_conversion = TRUE; ++ videoaggregator_class->aggregate_frames = ++ gst_opencv_aggregator_aggregate_frames; ++ videoaggregator_class->get_output_buffer = ++ gst_opencv_aggregator_get_output_buffer; ++ videoaggregator_class->negotiated_caps = ++ gst_opencv_aggregator_negotiated_caps; ++ ++ klass->decide_allocation = gst_opencv_aggregator_decide_allocation_default; ++ klass->propose_allocation = gst_opencv_aggregator_propose_allocation_default; ++} ++ ++static void ++gst_opencv_aggregator_reset (GstOpencvAggregator * aggregator) ++{ ++ aggregator->priv->set_caps = FALSE; ++} ++ ++static void ++gst_opencv_aggregator_init (GstOpencvAggregator * aggregator) ++{ ++ aggregator->priv = GST_OPENCV_AGGREGATOR_GET_PRIVATE (aggregator); ++ ++ gst_opencv_aggregator_reset (aggregator); ++} ++ ++static void ++gst_opencv_aggregator_get_property (GObject * object, ++ guint prop_id, GValue * value, GParamSpec * pspec) ++{ ++ switch (prop_id) { ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void ++gst_opencv_aggregator_set_property (GObject * object, ++ guint prop_id, const GValue * value, GParamSpec * pspec) ++{ ++ switch (prop_id) { ++ default: ++ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); ++ break; ++ } ++} ++ ++static void ++_free_opencv_aggregator_img (IplImage * img) ++{ ++ cvReleaseImage (&img); ++} ++ ++static void ++_free_opencv_aggregator_in_info (GstMapInfo * info) ++{ ++ g_slice_free1 (sizeof (GstMapInfo), info); ++} ++ ++static gboolean ++gst_opencv_aggregator_start (GstAggregator * agg) ++{ ++ GstOpencvAggregator *aggregator = GST_OPENCV_AGGREGATOR (agg); ++ GstElement *element = GST_ELEMENT (agg); ++ ++ if (!GST_AGGREGATOR_CLASS (parent_class)->start (agg)) ++ return FALSE; ++ ++ GST_OBJECT_LOCK (aggregator); ++ aggregator->priv->imgs = g_ptr_array_new_full (element->numsinkpads, ++ (GDestroyNotify) _free_opencv_aggregator_img); ++ g_ptr_array_set_size (aggregator->priv->imgs, element->numsinkpads); ++ ++ aggregator->priv->in_infos = g_ptr_array_new_full (element->numsinkpads, ++ (GDestroyNotify) _free_opencv_aggregator_in_info); ++ g_ptr_array_set_size (aggregator->priv->in_infos, element->numsinkpads); ++ GST_OBJECT_UNLOCK (aggregator); ++ ++ return TRUE; ++} ++ ++static gboolean ++gst_opencv_aggregator_stop (GstAggregator * agg) ++{ ++ GstOpencvAggregator *aggregator = GST_OPENCV_AGGREGATOR (agg); ++ ++ GST_OBJECT_LOCK (agg); ++ g_ptr_array_free (aggregator->priv->imgs, TRUE); ++ aggregator->priv->imgs = NULL; ++ g_ptr_array_free (aggregator->priv->in_infos, TRUE); ++ aggregator->priv->in_infos = NULL; ++ GST_OBJECT_UNLOCK (agg); ++ ++ if (aggregator->priv->pool) { ++ gst_object_unref (aggregator->priv->pool); ++ aggregator->priv->pool = NULL; ++ } ++ ++ if (aggregator->priv->out_cvImage) ++ cvReleaseImage (&aggregator->priv->out_cvImage); ++ ++ gst_opencv_aggregator_reset (aggregator); ++ ++ return GST_AGGREGATOR_CLASS (parent_class)->stop (agg); ++} ++ ++static gboolean ++gst_opencv_aggregator_sink_query (GstAggregator * agg, GstAggregatorPad * bpad, ++ GstQuery * query) ++{ ++ gboolean ret = FALSE; ++ GstOpencvAggregator *aggregator = GST_OPENCV_AGGREGATOR (agg); ++ GstOpencvAggregatorClass *klass = GST_OPENCV_AGGREGATOR_GET_CLASS (agg); ++ ++ GST_TRACE ("QUERY %" GST_PTR_FORMAT, query); ++ ++ switch (GST_QUERY_TYPE (query)) { ++ case GST_QUERY_ALLOCATION:{ ++ if (klass->propose_allocation) ++ ret = klass->propose_allocation (aggregator, query); ++ break; ++ } ++ default: ++ ret = GST_AGGREGATOR_CLASS (parent_class)->sink_query (agg, bpad, query); ++ break; ++ } ++ ++ return ret; ++} ++ ++static gboolean ++gst_opencv_aggregator_decide_allocation_default (GstOpencvAggregator * ++ aggregator, GstQuery * query) ++{ ++ GstCaps *outcaps = NULL; ++ GstBufferPool *pool = NULL; ++ guint size, min, max; ++ GstAllocator *allocator = NULL; ++ GstAllocationParams params; ++ GstStructure *config; ++ gboolean update_pool, update_allocator; ++ GstVideoInfo vinfo; ++ ++ gst_query_parse_allocation (query, &outcaps, NULL); ++ gst_video_info_init (&vinfo); ++ if (outcaps) ++ gst_video_info_from_caps (&vinfo, outcaps); ++ ++ /* we got configuration from our peer or the decide_allocation method, ++ * parse them */ ++ if (gst_query_get_n_allocation_params (query) > 0) { ++ /* try the allocator */ ++ gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms); ++ update_allocator = TRUE; ++ } else { ++ allocator = NULL; ++ gst_allocation_params_init (¶ms); ++ update_allocator = FALSE; ++ } ++ ++ if (gst_query_get_n_allocation_pools (query) > 0) { ++ gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); ++ size = MAX (size, vinfo.size); ++ update_pool = TRUE; ++ } else { ++ pool = NULL; ++ size = vinfo.size; ++ min = max = 0; ++ ++ update_pool = FALSE; ++ } ++ ++ if (pool == NULL) { ++ /* no pool, we can make our own */ ++ GST_DEBUG_OBJECT (aggregator, "no pool, making new pool"); ++ pool = gst_video_buffer_pool_new (); ++ } ++ ++ /* now configure */ ++ config = gst_buffer_pool_get_config (pool); ++ gst_buffer_pool_config_set_params (config, outcaps, size, min, max); ++ gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); ++ ++ if (!gst_buffer_pool_set_config (pool, config)) { ++ config = gst_buffer_pool_get_config (pool); ++ ++ /* If change are not acceptable, fallback to generic pool */ ++ if (!gst_buffer_pool_config_validate_params (config, outcaps, size, min, ++ max)) { ++ GST_DEBUG_OBJECT (aggregator, "unsuported pool, making new pool"); ++ ++ gst_object_unref (pool); ++ pool = gst_video_buffer_pool_new (); ++ gst_buffer_pool_config_set_params (config, outcaps, size, min, max); ++ gst_buffer_pool_config_set_allocator (config, allocator, ¶ms); ++ } ++ ++ if (!gst_buffer_pool_set_config (pool, config)) ++ goto config_failed; ++ } ++ ++ if (update_allocator) ++ gst_query_set_nth_allocation_param (query, 0, allocator, ¶ms); ++ else ++ gst_query_add_allocation_param (query, allocator, ¶ms); ++ if (allocator) ++ gst_object_unref (allocator); ++ ++ if (update_pool) ++ gst_query_set_nth_allocation_pool (query, 0, pool, size, min, max); ++ else ++ gst_query_add_allocation_pool (query, pool, size, min, max); ++ ++ if (pool) ++ gst_object_unref (pool); ++ ++ return TRUE; ++ ++config_failed: ++ if (allocator) ++ gst_object_unref (allocator); ++ if (pool) ++ gst_object_unref (pool); ++ GST_ELEMENT_ERROR (aggregator, RESOURCE, SETTINGS, ++ ("Failed to configure the buffer pool"), ++ ("Configuration is most likely invalid, please report this issue.")); ++ return FALSE; ++} ++ ++static gboolean ++gst_opencv_aggregator_propose_allocation_default (GstOpencvAggregator * ++ aggregator, GstQuery * query) ++{ ++ GstCaps *caps; ++ GstVideoInfo info; ++ GstBufferPool *pool; ++ guint size; ++ ++ gst_query_parse_allocation (query, &caps, NULL); ++ ++ if (caps == NULL) ++ return FALSE; ++ ++ if (!gst_video_info_from_caps (&info, caps)) ++ return FALSE; ++ ++ size = GST_VIDEO_INFO_SIZE (&info); ++ ++ if (gst_query_get_n_allocation_pools (query) == 0) { ++ GstStructure *structure; ++ GstAllocator *allocator = NULL; ++ GstAllocationParams params = { 0, 15, 0, 0 }; ++ ++ if (gst_query_get_n_allocation_params (query) > 0) ++ gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms); ++ else ++ gst_query_add_allocation_param (query, allocator, ¶ms); ++ ++ pool = gst_video_buffer_pool_new (); ++ ++ structure = gst_buffer_pool_get_config (pool); ++ gst_buffer_pool_config_set_params (structure, caps, size, 0, 0); ++ gst_buffer_pool_config_set_allocator (structure, allocator, ¶ms); ++ ++ if (allocator) ++ gst_object_unref (allocator); ++ ++ if (!gst_buffer_pool_set_config (pool, structure)) ++ goto config_failed; ++ ++ gst_query_add_allocation_pool (query, pool, size, 0, 0); ++ gst_object_unref (pool); ++ gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, NULL); ++ } ++ ++ return TRUE; ++ ++ /* ERRORS */ ++config_failed: ++ { ++ GST_ERROR_OBJECT (aggregator, "failed to set config"); ++ gst_object_unref (pool); ++ return FALSE; ++ } ++} ++ ++static gboolean ++gst_opencv_aggregator_negotiate_pool (GstOpencvAggregator * aggregator, ++ GstCaps * caps) ++{ ++ GstAggregator *agg = GST_AGGREGATOR (aggregator); ++ GstOpencvAggregatorClass *klass; ++ GstQuery *query = NULL; ++ GstBufferPool *pool = NULL; ++ GstAllocator *allocator; ++ GstAllocationParams params; ++ gboolean ret = TRUE; ++ ++ klass = GST_OPENCV_AGGREGATOR_GET_CLASS (aggregator); ++ ++ query = gst_query_new_allocation (caps, TRUE); ++ ++ if (!gst_pad_peer_query (agg->srcpad, query)) { ++ GST_DEBUG_OBJECT (aggregator, "didn't get downstream ALLOCATION hints"); ++ } ++ ++ g_assert (klass->decide_allocation != NULL); ++ ret = klass->decide_allocation (aggregator, query); ++ ++ GST_DEBUG_OBJECT (aggregator, "ALLOCATION (%d) params: %" GST_PTR_FORMAT, ret, ++ query); ++ ++ if (!ret) ++ goto no_decide_allocation; ++ ++ /* we got configuration from our peer or the decide_allocation method, ++ * parse them */ ++ if (gst_query_get_n_allocation_params (query) > 0) { ++ gst_query_parse_nth_allocation_param (query, 0, &allocator, ¶ms); ++ } else { ++ allocator = NULL; ++ gst_allocation_params_init (¶ms); ++ } ++ ++ if (gst_query_get_n_allocation_pools (query) > 0) ++ gst_query_parse_nth_allocation_pool (query, 0, &pool, NULL, NULL, NULL); ++ if (!pool) { ++ if (allocator) ++ gst_object_unref (allocator); ++ ret = FALSE; ++ goto no_decide_allocation; ++ } ++ ++ if (aggregator->priv->allocator) ++ gst_object_unref (aggregator->priv->allocator); ++ aggregator->priv->allocator = allocator; ++ aggregator->priv->params = params; ++ ++ if (aggregator->priv->pool) { ++ /* do not set the bufferpool to inactive here, it will be done ++ * on its finalize function. As videoaggregator do late renegotiation ++ * it might happen that some element downstream is already using this ++ * same bufferpool and deactivating it will make it fail. ++ * Happens when a downstream element changes from passthrough to ++ * non-passthrough and gets this same bufferpool to use */ ++ gst_object_unref (aggregator->priv->pool); ++ } ++ aggregator->priv->pool = pool; ++ ++ /* and activate */ ++ gst_buffer_pool_set_active (pool, TRUE); ++ ++done: ++ if (query) ++ gst_query_unref (query); ++ ++ return ret; ++ ++ /* Errors */ ++no_decide_allocation: ++ { ++ GST_WARNING_OBJECT (aggregator, "Subclass failed to decide allocation"); ++ goto done; ++ } ++} ++ ++static gboolean ++gst_opencv_aggregator_negotiated_caps (GstVideoAggregator * vagg, ++ GstCaps * caps) ++{ ++ GstOpencvAggregator *aggregator = GST_OPENCV_AGGREGATOR (vagg); ++ gint out_width, out_height; ++ gint out_depth, out_channels; ++ GError *out_err = NULL; ++ ++ if (!gst_opencv_parse_iplimage_params_from_caps (caps, &out_width, ++ &out_height, &out_depth, &out_channels, &out_err)) { ++ GST_WARNING_OBJECT (aggregator, "Failed to parse output caps: %s", ++ out_err->message); ++ g_error_free (out_err); ++ return FALSE; ++ } ++ ++ if (aggregator->priv->out_cvImage) ++ cvReleaseImage (&aggregator->priv->out_cvImage); ++ ++ aggregator->priv->out_cvImage = ++ cvCreateImageHeader (cvSize (out_width, out_height), out_depth, ++ out_channels); ++ ++ return gst_opencv_aggregator_negotiate_pool (aggregator, caps); ++} ++ ++static GstFlowReturn ++gst_opencv_aggregator_get_output_buffer (GstVideoAggregator * videoaggregator, ++ GstBuffer ** outbuf) ++{ ++ GstOpencvAggregator *aggregator = GST_OPENCV_AGGREGATOR (videoaggregator); ++ ++ return gst_buffer_pool_acquire_buffer (aggregator->priv->pool, outbuf, NULL); ++} ++ ++static GstFlowReturn ++gst_opencv_aggregator_aggregate_frames (GstVideoAggregator * vagg, ++ GstBuffer * outbuf) ++{ ++ GstOpencvAggregator *aggregator = GST_OPENCV_AGGREGATOR (vagg); ++ GstOpencvAggregatorClass *aggregator_class = ++ GST_OPENCV_AGGREGATOR_GET_CLASS (vagg); ++ GstElement *element = GST_ELEMENT (aggregator); ++ GstMapInfo out_info; ++ guint array_index = 0; ++ gboolean res = FALSE; ++ GList *walk; ++ guint i; ++ ++ if (!aggregator->priv->set_caps) { ++ gint in_width, in_height; ++ gint in_depth, in_channels; ++ GError *in_err = NULL; ++ ++ GST_OBJECT_LOCK (aggregator); ++ walk = element->sinkpads; ++ while (walk) { ++ GstVideoAggregatorPad *vaggpad = walk->data; ++ GstCaps *caps = gst_video_info_to_caps (&vaggpad->info); ++ ++ walk = g_list_next (walk); ++ ++ GST_WARNING_OBJECT (aggregator, "sink pad caps: %" ++ GST_PTR_FORMAT, caps); ++ if (!gst_opencv_parse_iplimage_params_from_caps (caps, &in_width, ++ &in_height, &in_depth, &in_channels, ++ &in_err)) { ++ GST_WARNING_OBJECT (aggregator, "Failed to parse input caps: %s", ++ in_err->message); ++ g_error_free (in_err); ++ gst_caps_unref (caps); ++ return FALSE; ++ } ++ gst_caps_unref (caps); ++ ++ aggregator->priv->imgs->pdata[array_index] = ++ cvCreateImageHeader (cvSize (in_width, in_height), in_depth, ++ in_channels); ++ aggregator->priv->in_infos->pdata[array_index] = ++ g_slice_new0 (GstMapInfo); ++ array_index++; ++ } ++ GST_OBJECT_UNLOCK (aggregator); ++ aggregator->priv->set_caps = TRUE; ++ } ++ ++ array_index = 0; ++ GST_OBJECT_LOCK (aggregator); ++ walk = GST_ELEMENT (aggregator)->sinkpads; ++ while (walk) { ++ GstVideoAggregatorPad *vaggpad = walk->data; ++ IplImage *cvImage; ++ GstMapInfo *in_info = aggregator->priv->in_infos->pdata[array_index]; ++ ++ walk = g_list_next (walk); ++ ++ if (!gst_buffer_map (vaggpad->buffer, in_info, GST_MAP_READ)) ++ goto inbuf_map_failed; ++ ++ cvImage = aggregator->priv->imgs->pdata[array_index]; ++ cvImage->imageData = (char *) in_info->data; ++ ++array_index; ++ } ++ GST_OBJECT_UNLOCK (aggregator); ++ ++ if (!gst_buffer_map (outbuf, &out_info, GST_MAP_WRITE)) ++ goto outbuf_map_failed; ++ ++ aggregator->priv->out_cvImage->imageData = (char *) out_info.data; ++ ++ res = ++ aggregator_class->GstOpencvAggregatorProcess (aggregator, ++ aggregator->priv->imgs, aggregator->priv->out_cvImage); ++ ++ GST_OBJECT_LOCK (aggregator); ++ walk = GST_ELEMENT (aggregator)->sinkpads; ++ array_index = 0; ++ while (walk) { ++ GstVideoAggregatorPad *vaggpad = walk->data; ++ GstMapInfo *in_info = aggregator->priv->in_infos->pdata[array_index]; ++ walk = g_list_next (walk); ++ gst_buffer_unmap (vaggpad->buffer, in_info); ++ ++array_index; ++ } ++ GST_OBJECT_UNLOCK (aggregator); ++ ++ gst_buffer_unmap (outbuf, &out_info); ++ ++ return res ? GST_FLOW_OK : GST_FLOW_ERROR; ++ ++inbuf_map_failed: ++ GST_ELEMENT_ERROR (aggregator, RESOURCE, READ, ++ ("Failed to map buffer for reading"), (NULL)); ++ walk = GST_ELEMENT (aggregator)->sinkpads; ++ for (i = 0; i < array_index; i++) { ++ GstVideoAggregatorPad *vaggpad = walk->data; ++ GstMapInfo *in_info = aggregator->priv->in_infos->pdata[array_index]; ++ walk = g_list_next (walk); ++ gst_buffer_unmap (vaggpad->buffer, in_info); ++ ++array_index; ++ } ++ GST_OBJECT_UNLOCK (aggregator); ++ return GST_FLOW_ERROR; ++ ++outbuf_map_failed: ++ GST_ELEMENT_ERROR (aggregator, RESOURCE, WRITE, ++ ("Failed to map buffer for writing"), (NULL)); ++ GST_OBJECT_LOCK (aggregator); ++ walk = GST_ELEMENT (aggregator)->sinkpads; ++ array_index = 0; ++ while (walk) { ++ GstVideoAggregatorPad *vaggpad = walk->data; ++ GstMapInfo *in_info = aggregator->priv->in_infos->pdata[array_index]; ++ walk = g_list_next (walk); ++ gst_buffer_unmap (vaggpad->buffer, in_info); ++ ++array_index; ++ } ++ GST_OBJECT_UNLOCK (aggregator); ++ ++ return GST_FLOW_ERROR; ++} +diff --git a/ext/opencv/gstopencvaggregator.h b/ext/opencv/gstopencvaggregator.h +new file mode 100644 +index 0000000..1fc65a5 +--- /dev/null ++++ b/ext/opencv/gstopencvaggregator.h +@@ -0,0 +1,118 @@ ++/* ++ * GStreamer ++ * Copyright (C) 2015 Song Bing ++ * ++ * 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., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifndef __GST_OPENCV_AGGREGATOR_H__ ++#define __GST_OPENCV_AGGREGATOR_H__ ++ ++#include ++#include ++#include ++ ++G_BEGIN_DECLS ++#define GST_TYPE_OPENCV_AGGREGATOR_PAD (gst_opencv_aggregator_pad_get_type()) ++#define GST_OPENCV_AGGREGATOR_PAD(obj) \ ++ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OPENCV_AGGREGATOR_PAD, GstOpencvAggregatorPad)) ++#define GST_OPENCV_AGGREGATOR_PAD_CLASS(klass) \ ++ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OPENCV_AGGREGATOR_PAD, GstOpencvAggregatorPadClass)) ++#define GST_IS_OPENCV_AGGREGATOR_PAD(obj) \ ++ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OPENCV_AGGREGATOR_PAD)) ++#define GST_IS_OPENCV_AGGREGATOR_PAD_CLASS(klass) \ ++ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OPENCV_AGGREGATOR_PAD)) ++#define GST_OPENCV_AGGREGATOR_PAD_GET_CLASS(obj) \ ++ (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OPENCV_AGGREGATOR_PAD,GstOpencvAggregatorPadClass)) ++typedef struct _GstOpencvAggregatorPad GstOpencvAggregatorPad; ++typedef struct _GstOpencvAggregatorPadClass GstOpencvAggregatorPadClass; ++ ++struct _GstOpencvAggregatorPad ++{ ++ GstVideoAggregatorPad parent; ++}; ++ ++struct _GstOpencvAggregatorPadClass ++{ ++ GstVideoAggregatorPadClass parent_class; ++}; ++ ++GType gst_opencv_aggregator_pad_get_type (void); ++ ++#define GST_TYPE_OPENCV_AGGREGATOR \ ++ (gst_opencv_aggregator_get_type()) ++#define GST_OPENCV_AGGREGATOR(obj) \ ++ (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_OPENCV_AGGREGATOR,GstOpencvAggregator)) ++#define GST_OPENCV_AGGREGATOR_CLASS(klass) \ ++ (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_OPENCV_AGGREGATOR,GstOpencvAggregatorClass)) ++#define GST_IS_OPENCV_AGGREGATOR(obj) \ ++ (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_OPENCV_AGGREGATOR)) ++#define GST_IS_OPENCV_AGGREGATOR_CLASS(klass) \ ++ (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_OPENCV_AGGREGATOR)) ++#define GST_OPENCV_AGGREGATOR_GET_CLASS(obj) \ ++ (G_TYPE_INSTANCE_GET_CLASS((obj),GST_TYPE_OPENCV_AGGREGATOR,GstOpencvAggregatorClass)) ++#define GST_OPENCV_AGGREGATOR_CAST(obj) ((GstOpencvAggregator *) (obj)) ++ ++typedef struct _GstOpencvAggregator GstOpencvAggregator; ++typedef struct _GstOpencvAggregatorClass GstOpencvAggregatorClass; ++typedef struct _GstOpencvAggregatorPrivate GstOpencvAggregatorPrivate; ++ ++struct _GstOpencvAggregator ++{ ++ GstVideoAggregator parent; ++ ++ GstOpencvAggregatorPrivate *priv; ++}; ++ ++struct _GstOpencvAggregatorClass ++{ ++ GstVideoAggregatorClass parent_class; ++ ++ gboolean (*GstOpencvAggregatorProcess) (GstOpencvAggregator * aggregrator, ++ GPtrArray * imgs, IplImage * outimg); ++ gboolean (*decide_allocation) (GstOpencvAggregator * aggretator, ++ GstQuery * query); ++ gboolean (*propose_allocation) (GstOpencvAggregator * aggretator, ++ GstQuery * query); ++}; ++ ++GType gst_opencv_aggregator_get_type (void); ++ ++G_END_DECLS ++#endif /* __GST_OPENCV_AGGREGATOR_H__ */ +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0016-PATCH-gstaggregator-memory-leak-increasing-a-lot-aft.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0016-PATCH-gstaggregator-memory-leak-increasing-a-lot-aft.patch new file mode 100644 index 000000000..9e29d6be0 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0016-PATCH-gstaggregator-memory-leak-increasing-a-lot-aft.patch @@ -0,0 +1,323 @@ +From d7a28c5c7edcbceb13d35577d61a466ba750b3d9 Mon Sep 17 00:00:00 2001 +From: Mingke Wang +Date: Wed, 8 Jul 2015 15:34:57 +0800 +Subject: [PATCH] [PATCH] gstaggregator: memory leak increasing a lot after + overnight + +this patch picks from community fix: + +aggregator: Replace GMainContext with GAsyncQueue (v2) +The previous implementation kept accumulating GSources, +slowing down the iteration and leaking memory. + +Instead of trying to fix the main context flushing, replace +it with a GAsyncQueue which is simple to flush and has +less overhead. + +https://bugzilla.gnome.org/show_bug.cgi?id=736782 + +Upstream Status: Backport + +Signed-off-by: Mingke Wang + +diff --git a/gst-libs/gst/base/gstaggregator.c b/gst-libs/gst/base/gstaggregator.c +old mode 100644 +new mode 100755 +index e12ed93..47eb1e7 +--- a/gst-libs/gst/base/gstaggregator.c ++++ b/gst-libs/gst/base/gstaggregator.c +@@ -106,6 +106,48 @@ GST_DEBUG_CATEGORY_STATIC (aggregator_debug); + g_cond_broadcast(&(((GstAggregatorPad* )pad)->priv->event_cond)); \ + } + ++#define GST_AGGREGATOR_SETCAPS_LOCK(self) G_STMT_START { \ ++ GST_LOG_OBJECT (self, "Taking SETCAPS lock from thread %p", \ ++ g_thread_self()); \ ++ g_mutex_lock(&self->priv->setcaps_lock); \ ++ GST_LOG_OBJECT (self, "Took SETCAPS lock from thread %p", \ ++ g_thread_self()); \ ++ } G_STMT_END ++ ++#define GST_AGGREGATOR_SETCAPS_UNLOCK(self) G_STMT_START { \ ++ GST_LOG_OBJECT (self, "Releasing SETCAPS lock from thread %p", \ ++ g_thread_self()); \ ++ g_mutex_unlock(&self->priv->setcaps_lock); \ ++ GST_LOG_OBJECT (self, "Took SETCAPS lock from thread %p", \ ++ g_thread_self()); \ ++ } G_STMT_END ++ ++#define AGGREGATOR_QUEUE(self) (((GstAggregator*)self)->priv->queue) ++ ++#define QUEUE_PUSH(self) G_STMT_START { \ ++ GST_LOG_OBJECT (self, "Pushing to QUEUE in thread %p", \ ++ g_thread_self()); \ ++ g_async_queue_push (AGGREGATOR_QUEUE (self), GINT_TO_POINTER (1)); \ ++} G_STMT_END ++ ++#define QUEUE_POP(self) G_STMT_START { \ ++ GST_LOG_OBJECT (self, "Waiting on QUEUE in thread %p", \ ++ g_thread_self()); \ ++ g_async_queue_pop (AGGREGATOR_QUEUE (self)); \ ++ GST_LOG_OBJECT (self, "Waited on QUEUE in thread %p", \ ++ g_thread_self()); \ ++ } G_STMT_END ++ ++#define QUEUE_FLUSH(self) G_STMT_START { \ ++ GST_LOG_OBJECT (self, "Flushing QUEUE in thread %p", \ ++ g_thread_self()); \ ++ g_async_queue_lock (AGGREGATOR_QUEUE (self)); \ ++ while (g_async_queue_try_pop_unlocked (AGGREGATOR_QUEUE (self))); \ ++ g_async_queue_unlock (AGGREGATOR_QUEUE (self)); \ ++ GST_LOG_OBJECT (self, "Flushed QUEUE in thread %p", \ ++ g_thread_self()); \ ++ } G_STMT_END ++ + struct _GstAggregatorPadPrivate + { + gboolean pending_flush_start; +@@ -136,35 +178,15 @@ _aggpad_flush (GstAggregatorPad * aggpad, GstAggregator * agg) + *************************************/ + static GstElementClass *aggregator_parent_class = NULL; + +-#define MAIN_CONTEXT_LOCK(self) G_STMT_START { \ +- GST_LOG_OBJECT (self, "Getting MAIN_CONTEXT_LOCK in thread %p", \ +- g_thread_self()); \ +- g_mutex_lock(&((GstAggregator*)self)->priv->mcontext_lock); \ +- GST_LOG_OBJECT (self, "Got MAIN_CONTEXT_LOCK in thread %p", \ +- g_thread_self()); \ +-} G_STMT_END +- +-#define MAIN_CONTEXT_UNLOCK(self) G_STMT_START { \ +- g_mutex_unlock(&((GstAggregator*)self)->priv->mcontext_lock); \ +- GST_LOG_OBJECT (self, "Unlocked MAIN_CONTEXT_LOCK in thread %p", \ +- g_thread_self()); \ +-} G_STMT_END +- + struct _GstAggregatorPrivate + { + gint padcount; + +- GMainContext *mcontext; ++ GAsyncQueue *queue; + + /* Our state is >= PAUSED */ + gboolean running; + +- /* Ensure that when we remove all sources from the maincontext +- * we can not add any source, avoiding: +- * "g_source_attach: assertion '!SOURCE_DESTROYED (source)' failed" */ +- GMutex mcontext_lock; +- GList *gsources; +- + gint seqnum; + gboolean send_stream_start; + gboolean send_segment; +@@ -177,6 +199,9 @@ struct _GstAggregatorPrivate + + GstTagList *tags; + gboolean tags_changed; ++ ++ /* Lock to prevent two src setcaps from happening at the same time */ ++ GMutex setcaps_lock; + }; + + typedef struct +@@ -287,7 +312,9 @@ _check_all_pads_with_data_or_eos (GstAggregator * self, + void + gst_aggregator_set_src_caps (GstAggregator * self, GstCaps * caps) + { ++ GST_AGGREGATOR_SETCAPS_LOCK (self); + gst_caps_replace (&self->priv->srccaps, caps); ++ GST_AGGREGATOR_SETCAPS_UNLOCK (self); + } + + static void +@@ -390,29 +417,19 @@ _push_eos (GstAggregator * self) + + + static void +-_destroy_gsource (GSource * source) +-{ +- g_source_destroy (source); +- g_source_unref (source); +-} +- +-static void +-_remove_all_sources (GstAggregator * self) +-{ +- GstAggregatorPrivate *priv = self->priv; +- +- MAIN_CONTEXT_LOCK (self); +- g_list_free_full (priv->gsources, (GDestroyNotify) _destroy_gsource); +- priv->gsources = NULL; +- MAIN_CONTEXT_UNLOCK (self); +-} +- +-static gboolean + aggregate_func (GstAggregator * self) + { + GstAggregatorPrivate *priv = self->priv; + GstAggregatorClass *klass = GST_AGGREGATOR_GET_CLASS (self); + ++ if (self->priv->running == FALSE) { ++ GST_DEBUG_OBJECT (self, "Not running anymore"); ++ ++ return; ++ } ++ ++ QUEUE_POP (self); ++ + GST_LOG_OBJECT (self, "Checking aggregate"); + while (priv->send_eos && gst_aggregator_iterate_sinkpads (self, + (GstAggregatorPadForeachFunc) _check_all_pads_with_data_or_eos, +@@ -422,8 +439,7 @@ aggregate_func (GstAggregator * self) + priv->flow_return = klass->aggregate (self); + + if (priv->flow_return == GST_FLOW_EOS) { +- g_main_context_wakeup (self->priv->mcontext); +- _remove_all_sources (self); ++ QUEUE_FLUSH (self); + _push_eos (self); + } + +@@ -437,20 +453,6 @@ aggregate_func (GstAggregator * self) + if (priv->flow_return != GST_FLOW_OK) + break; + } +- +- return G_SOURCE_REMOVE; +-} +- +-static void +-iterate_main_context_func (GstAggregator * self) +-{ +- if (self->priv->running == FALSE) { +- GST_DEBUG_OBJECT (self, "Not running anymore"); +- +- return; +- } +- +- g_main_context_iteration (self->priv->mcontext, TRUE); + } + + static gboolean +@@ -481,15 +483,14 @@ _stop_srcpad_task (GstAggregator * self, GstEvent * flush_start) + flush_start ? "Pausing" : "Stopping"); + + self->priv->running = FALSE; ++ QUEUE_PUSH (self); + +- /* Clean the stack of GSource set on the MainContext */ +- g_main_context_wakeup (self->priv->mcontext); +- _remove_all_sources (self); + if (flush_start) { + res = gst_pad_push_event (self->srcpad, flush_start); + } + + gst_pad_stop_task (self->srcpad); ++ QUEUE_FLUSH (self); + + return res; + } +@@ -501,21 +502,7 @@ _start_srcpad_task (GstAggregator * self) + + self->priv->running = TRUE; + gst_pad_start_task (GST_PAD (self->srcpad), +- (GstTaskFunction) iterate_main_context_func, self, NULL); +-} +- +-static inline void +-_add_aggregate_gsource (GstAggregator * self) +-{ +- GSource *source; +- GstAggregatorPrivate *priv = self->priv; +- +- MAIN_CONTEXT_LOCK (self); +- source = g_idle_source_new (); +- g_source_set_callback (source, (GSourceFunc) aggregate_func, self, NULL); +- priv->gsources = g_list_prepend (priv->gsources, source); +- g_source_attach (source, priv->mcontext); +- MAIN_CONTEXT_UNLOCK (self); ++ (GstTaskFunction) aggregate_func, self, NULL); + } + + static GstFlowReturn +@@ -617,7 +604,7 @@ _sink_event (GstAggregator * self, GstAggregatorPad * aggpad, GstEvent * event) + gst_pad_push_event (self->srcpad, event); + priv->send_eos = TRUE; + event = NULL; +- _add_aggregate_gsource (self); ++ QUEUE_PUSH (self); + + GST_INFO_OBJECT (self, "Releasing source pad STREAM_LOCK"); + GST_PAD_STREAM_UNLOCK (self->srcpad); +@@ -645,7 +632,7 @@ _sink_event (GstAggregator * self, GstAggregatorPad * aggpad, GstEvent * event) + } + PAD_UNLOCK_EVENT (aggpad); + +- _add_aggregate_gsource (self); ++ QUEUE_PUSH (self); + goto eat; + } + case GST_EVENT_SEGMENT: +@@ -769,7 +756,7 @@ _release_pad (GstElement * element, GstPad * pad) + gst_element_remove_pad (element, pad); + + /* Something changed make sure we try to aggregate */ +- _add_aggregate_gsource (self); ++ QUEUE_PUSH (self); + } + + static GstPad * +@@ -1055,7 +1042,7 @@ gst_aggregator_finalize (GObject * object) + { + GstAggregator *self = (GstAggregator *) object; + +- g_mutex_clear (&self->priv->mcontext_lock); ++ g_mutex_clear (&self->priv->setcaps_lock); + + G_OBJECT_CLASS (aggregator_parent_class)->finalize (object); + } +@@ -1067,8 +1054,10 @@ gst_aggregator_dispose (GObject * object) + + G_OBJECT_CLASS (aggregator_parent_class)->dispose (object); + +- g_main_context_unref (self->priv->mcontext); +- _remove_all_sources (self); ++ if (AGGREGATOR_QUEUE (self)) { ++ g_async_queue_unref (AGGREGATOR_QUEUE (self)); ++ AGGREGATOR_QUEUE (self) = NULL; ++ } + } + + /* GObject vmethods implementations */ +@@ -1124,7 +1113,7 @@ gst_aggregator_init (GstAggregator * self, GstAggregatorClass * klass) + priv->tags_changed = FALSE; + _reset_flow_values (self); + +- priv->mcontext = g_main_context_new (); ++ AGGREGATOR_QUEUE (self) = g_async_queue_new (); + self->srcpad = gst_pad_new_from_template (pad_template, "src"); + + gst_pad_set_event_function (self->srcpad, +@@ -1136,7 +1125,7 @@ gst_aggregator_init (GstAggregator * self, GstAggregatorClass * klass) + + gst_element_add_pad (GST_ELEMENT (self), self->srcpad); + +- g_mutex_init (&self->priv->mcontext_lock); ++ g_mutex_init (&self->priv->setcaps_lock); + } + + /* we can't use G_DEFINE_ABSTRACT_TYPE because we need the klass in the _init +@@ -1205,7 +1194,7 @@ _chain (GstPad * pad, GstObject * object, GstBuffer * buffer) + aggpad->buffer = actual_buf; + PAD_UNLOCK_EVENT (aggpad); + +- _add_aggregate_gsource (self); ++ QUEUE_PUSH (self); + + GST_DEBUG_OBJECT (aggpad, "Done chaining"); + +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0017-MMFMWK-6778-Support-more-format-in-direct-viv.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0017-MMFMWK-6778-Support-more-format-in-direct-viv.patch new file mode 100644 index 000000000..3a6412ca0 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/0017-MMFMWK-6778-Support-more-format-in-direct-viv.patch @@ -0,0 +1,56 @@ +From a639dc1c5bd4e5ff6f3c98995149f556e8528985 Mon Sep 17 00:00:00 2001 +From: Jian Li +Date: Tue, 4 Aug 2015 17:11:17 +0800 +Subject: [PATCH] MMFMWK-6778 Support more format in direct viv +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Supports I420, YV12, NV12, NV21, YUY2, UYVY, + RGBA, BGRA, RGB16 + +Upstream-Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian Li +--- + gst-libs/gst/gl/gstglvivdirecttexture.c | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/gst-libs/gst/gl/gstglvivdirecttexture.c b/gst-libs/gst/gl/gstglvivdirecttexture.c +index 9131101..c19b617 100644 +--- a/gst-libs/gst/gl/gstglvivdirecttexture.c ++++ b/gst-libs/gst/gl/gstglvivdirecttexture.c +@@ -105,12 +105,30 @@ gst_gl_viv_direct_bind_gstbuffer (GstGLContext * context, guint tex_id, GstVideo + case GST_VIDEO_FORMAT_I420: + viv_fmt = GL_VIV_I420; + break; ++ case GST_VIDEO_FORMAT_YV12: ++ viv_fmt = GL_VIV_YV12; ++ break; + case GST_VIDEO_FORMAT_NV12: + viv_fmt = GL_VIV_NV12; + break; ++ case GST_VIDEO_FORMAT_NV21: ++ viv_fmt = GL_VIV_NV21; ++ break; ++ case GST_VIDEO_FORMAT_YUY2: ++ viv_fmt = GL_VIV_YUY2; ++ break; ++ case GST_VIDEO_FORMAT_UYVY: ++ viv_fmt = GL_VIV_UYVY; ++ break; + case GST_VIDEO_FORMAT_RGBA: + viv_fmt = GL_RGBA; + break; ++ case GST_VIDEO_FORMAT_BGRA: ++ viv_fmt = GL_BGRA_EXT; ++ break; ++ case GST_VIDEO_FORMAT_RGB16: ++ viv_fmt = GL_RGB565_OES; ++ break; + default: + GST_ERROR ("Not supported format %d for viv direct texture upload.", fmt); + viv_fmt = GL_NONE; +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/1.4.5-Use-viv-direct-texture-to-bind-buffer.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/1.4.5-Use-viv-direct-texture-to-bind-buffer.patch new file mode 100644 index 000000000..27a27cd61 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/1.4.5-Use-viv-direct-texture-to-bind-buffer.patch @@ -0,0 +1,266 @@ +From 60e055de185f0d911ad2bbd4e842fb5b088530e2 Mon Sep 17 00:00:00 2001 +From: Jian +Date: Wed, 4 Mar 2015 16:41:53 +0800 +Subject: [PATCH] Use viv direct texture to bind buffer +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + Use viv direct texture to bind physical continious + buffer with texture to avoid memory copy from video + buffer to texture to gain good performance. + + Upstream Status: Inappropriate [i.MX specific] + + Signed-off-by: Jian +--- + gst-libs/gst/gl/Makefile.am | 4 +- + gst-libs/gst/gl/gstglfilter.c | 8 +- + gst-libs/gst/gl/gstglupload.c | 10 ++- + gst-libs/gst/gl/gstglvivdirecttexture.c | 123 +++++++++++++++++++++++++++++++ + gst-libs/gst/gl/gstglvivdirecttexture.h | 34 +++++++++ + 5 files changed, 176 insertions(+), 3 deletions(-) + create mode 100644 gst-libs/gst/gl/gstglvivdirecttexture.c + create mode 100644 gst-libs/gst/gl/gstglvivdirecttexture.h + +diff --git a/gst-libs/gst/gl/Makefile.am b/gst-libs/gst/gl/Makefile.am +index ed35144..86bc439 100644 +--- a/gst-libs/gst/gl/Makefile.am ++++ b/gst-libs/gst/gl/Makefile.am +@@ -24,7 +24,8 @@ libgstgl_@GST_API_VERSION@_la_SOURCES = \ + gstglapi.c \ + gstglfeature.c \ + gstglutils.c \ +- gstglframebuffer.c ++ gstglframebuffer.c \ ++ gstglvivdirecttexture.c + + libgstgl_@GST_API_VERSION@includedir = $(includedir)/gstreamer-@GST_API_VERSION@/gst/gl + libgstgl_@GST_API_VERSION@include_HEADERS = \ +@@ -44,6 +45,7 @@ libgstgl_@GST_API_VERSION@include_HEADERS = \ + gstglfeature.h \ + gstglutils.h \ + gstglframebuffer.h \ ++ gstglvivdirecttexture.h \ + gstgl_fwd.h \ + gl.h + +diff --git a/gst-libs/gst/gl/gstglfilter.c b/gst-libs/gst/gl/gstglfilter.c +index 26bf3f9..eef4ec7 100644 +--- a/gst-libs/gst/gl/gstglfilter.c ++++ b/gst-libs/gst/gl/gstglfilter.c +@@ -1202,7 +1202,13 @@ gst_gl_filter_filter_texture (GstGLFilter * filter, GstBuffer * inbuf, + + if (!to_download) { + out_tex = *(guint *) out_frame.data[0]; +- } else { ++ } else if (gst_is_physical_buffer (outbuf)) { ++ GST_DEBUG ("Physical continious buffer, attempting viv direct texture binding"); ++ gst_gl_viv_direct_bind_gstbuffer (filter->context, filter->out_tex_id, &filter->out_info, outbuf); ++ to_download = FALSE; ++ out_tex = filter->out_tex_id; ++ } ++ else { + GST_LOG ("Output Buffer does not contain correct memory, " + "attempting to wrap for download"); + +diff --git a/gst-libs/gst/gl/gstglupload.c b/gst-libs/gst/gl/gstglupload.c +index ecf6ebb..38185bb 100644 +--- a/gst-libs/gst/gl/gstglupload.c ++++ b/gst-libs/gst/gl/gstglupload.c +@@ -68,7 +68,7 @@ struct _GstGLUploadPrivate + gboolean released; + }; + +-GST_DEBUG_CATEGORY_STATIC (gst_gl_upload_debug); ++GST_DEBUG_CATEGORY (gst_gl_upload_debug); + #define GST_CAT_DEFAULT gst_gl_upload_debug + + #define DEBUG_INIT \ +@@ -307,6 +307,14 @@ gst_gl_upload_perform_with_buffer (GstGLUpload * upload, GstBuffer * buffer, + } + } + ++ GST_LOG_OBJECT (upload, "Attempting viv direct upload"); ++ if (gst_is_physical_buffer (buffer)) { ++ if (gst_gl_viv_direct_bind_gstbuffer (upload->context, upload->priv->tex_id, &upload->in_info, buffer)) { ++ *tex_id = upload->priv->tex_id; ++ return TRUE; ++ } ++ } ++ + raw_data_upload: + GST_LOG_OBJECT (upload, "Attempting upload with raw data"); + /* GstVideoMeta map */ +diff --git a/gst-libs/gst/gl/gstglvivdirecttexture.c b/gst-libs/gst/gl/gstglvivdirecttexture.c +new file mode 100644 +index 0000000..4806335 +--- /dev/null ++++ b/gst-libs/gst/gl/gstglvivdirecttexture.c +@@ -0,0 +1,123 @@ ++/* ++ * GStreamer ++ * Copyright (c) 2015, Freescale Semiconductor, Inc. ++ * ++ * This library is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU Library General Public ++ * License as published by the Free Software Foundation; either ++ * version 2 of the License, or (at your option) any later version. ++ * ++ * This library is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU ++ * Library General Public License for more details. ++ * ++ * You should have received a copy of the GNU Library General Public ++ * License along with this library; if not, write to the ++ * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, ++ * Boston, MA 02110-1301, USA. ++ */ ++ ++#ifdef HAVE_CONFIG_H ++#include "config.h" ++#endif ++ ++#include "gl.h" ++ ++GST_DEBUG_CATEGORY_EXTERN (gst_gl_upload_debug); ++#define GST_CAT_DEFAULT gst_gl_upload_debug ++ ++typedef struct { ++ guint tex_id; ++ guint w; ++ guint h; ++ guint fmt; ++ void *vaddr; ++ guint paddr; ++ gboolean ret; ++} GstVivDirectTexture; ++ ++gboolean ++gst_is_physical_buffer (GstBuffer *buffer) ++{ ++ ++ GstMemory *mem; ++ ++ mem = gst_buffer_peek_memory (buffer, 0); ++ if (!mem->allocator) ++ return FALSE; ++ ++ return g_type_check_instance_is_a (mem->allocator, g_type_from_name("GstAllocatorPhyMem")); ++} ++ ++static void ++_do_viv_direct_tex_bind_mem (GstGLContext * context, GstVivDirectTexture * viv_tex) ++{ ++ GST_DEBUG ("viv direct upload, tex_id %d, fmt: %d, res: (%dx%d)", viv_tex->tex_id, viv_tex->fmt, viv_tex->w, viv_tex->h); ++ GST_DEBUG ("Physical memory buffer, vaddr: %p, paddr: %p", viv_tex->vaddr, viv_tex->paddr); ++ ++ glBindTexture (GL_TEXTURE_2D, viv_tex->tex_id); ++ glTexDirectVIVMap (GL_TEXTURE_2D, viv_tex->w, viv_tex->h, viv_tex->fmt, &viv_tex->vaddr, &viv_tex->paddr); ++ glTexDirectInvalidateVIV (GL_TEXTURE_2D); ++ viv_tex->ret = TRUE; ++ ++ return; ++} ++ ++gboolean ++gst_gl_viv_direct_bind_gstbuffer (GstGLContext * context, guint tex_id, GstVideoInfo * info, GstBuffer * buffer) ++{ ++ typedef struct { ++ guint8 *vaddr; ++ guint8 *paddr; ++ guint8 *caddr; ++ gsize size; ++ gpointer *user_data; ++ } PhyMemBlock; ++ //Note: structure PhyMemBlock is copied from gst1.0-fsl-plugin/libs/allocator/gstallocatorphymem.h ++ ++ typedef struct { ++ GstMemory mem; ++ guint8 *vaddr; ++ guint8 *paddr; ++ PhyMemBlock block; ++ } GstMemoryPhy; ++ //Note: structure GstMemoryPhy is copied from gst1.0-fsl-plugin/libs/allocator/gstallocatorphymem.c ++ ++ GstMemory *mem = gst_buffer_peek_memory (buffer, 0); ++ GstMemoryPhy *memphy = (GstMemoryPhy*) mem; ++ PhyMemBlock *memblk = &memphy->block; ++ ++ GstVideoFormat fmt = GST_VIDEO_INFO_FORMAT (info); ++ guint viv_fmt; ++ ++ switch (fmt) { ++ case GST_VIDEO_FORMAT_I420: ++ viv_fmt = GL_VIV_I420; ++ break; ++ case GST_VIDEO_FORMAT_NV12: ++ viv_fmt = GL_VIV_NV12; ++ break; ++ case GST_VIDEO_FORMAT_RGBA: ++ viv_fmt = GL_RGBA; ++ break; ++ default: ++ GST_ERROR ("Not supported format %d for viv direct texture upload.", fmt); ++ viv_fmt = GL_NONE; ++ return FALSE; ++ } ++ ++ GstVivDirectTexture viv_tex = { ++ tex_id, ++ GST_VIDEO_INFO_WIDTH (info), ++ GST_VIDEO_INFO_HEIGHT (info), ++ viv_fmt, ++ memblk->vaddr, ++ memblk->paddr, ++ FALSE}; ++ ++ gst_gl_context_thread_add (context, (GstGLContextThreadFunc) _do_viv_direct_tex_bind_mem, &viv_tex); ++ ++ return viv_tex.ret; ++} ++ +diff --git a/gst-libs/gst/gl/gstglvivdirecttexture.h b/gst-libs/gst/gl/gstglvivdirecttexture.h +new file mode 100644 +index 0000000..c94403b +--- /dev/null ++++ b/gst-libs/gst/gl/gstglvivdirecttexture.h +@@ -0,0 +1,34 @@ ++/* ++ * GStreamer ++ * Copyright (c) 2015, Freescale Semiconductor, Inc. ++ * ++ * 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_GL_VIVDIRECT_H__ ++#define __GST_GL_VIVDIRECT_H__ ++ ++#include ++#include ++ ++G_BEGIN_DECLS ++ ++gboolean gst_is_physical_buffer (GstBuffer *buffer); ++gboolean gst_gl_viv_direct_bind_gstbuffer (GstGLContext * context, guint tex_id, GstVideoInfo * info, GstBuffer * buffer) ++ ++G_END_DECLS ++ ++#endif /* __GST_GL_VIVDIRECT_H__ */ +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Adding-some-fragment-shaders-for-glshader-plugin.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Adding-some-fragment-shaders-for-glshader-plugin.patch new file mode 100644 index 000000000..69186411e --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Adding-some-fragment-shaders-for-glshader-plugin.patch @@ -0,0 +1,125 @@ +From 8489b90f5ed6b7f9b98b123b521d41aec00cc8bd Mon Sep 17 00:00:00 2001 +From: Jian +Date: Wed, 25 Mar 2015 13:45:57 +0800 +Subject: [PATCH] Adding some fragment shaders for glshader plugin +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + + Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian +--- + ext/gl/Makefile.am | 3 +++ + ext/gl/shaders/fisheye_shader.fs | 14 ++++++++++++++ + ext/gl/shaders/gray_shader.fs | 12 ++++++++++++ + ext/gl/shaders/tunnel_shader.fs | 14 ++++++++++++++ + ext/gl/shaders/twirl_shader.fs | 21 +++++++++++++++++++++ + 5 files changed, 64 insertions(+) + create mode 100755 ext/gl/shaders/fisheye_shader.fs + create mode 100755 ext/gl/shaders/gray_shader.fs + create mode 100755 ext/gl/shaders/tunnel_shader.fs + create mode 100755 ext/gl/shaders/twirl_shader.fs + +diff --git a/ext/gl/Makefile.am b/ext/gl/Makefile.am +index b1796f6..b8442f8 100644 +--- a/ext/gl/Makefile.am ++++ b/ext/gl/Makefile.am +@@ -110,6 +110,9 @@ libgstopengl_la_LIBADD = \ + $(LIBM) \ + $(GRAPHENE_LIBS) + ++data_DATA = shaders/gray_shader.fs shaders/fisheye_shader.fs shaders/tunnel_shader.fs shaders/twirl_shader.fs ++EXTRA_DIST = shaders/gray_shader.fs shaders/fisheye_shader.fs shaders/tunnel_shader.fs shaders/twirl_shader.fs ++ + libgstopengl_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS) + libgstopengl_la_LIBTOOLFLAGS = $(GST_PLUGIN_LIBTOOLFLAGS) + +diff --git a/ext/gl/shaders/fisheye_shader.fs b/ext/gl/shaders/fisheye_shader.fs +new file mode 100755 +index 0000000..a57a203 +--- /dev/null ++++ b/ext/gl/shaders/fisheye_shader.fs +@@ -0,0 +1,14 @@ ++precision mediump float; ++varying vec2 v_texcoord; ++uniform sampler2D tex; ++void main () { ++ vec2 texturecoord = v_texcoord.xy; ++ vec2 normcoord; ++ normcoord = texturecoord - 0.5; ++ float r = length (normcoord); ++ normcoord *= r * 1.414; ++ texturecoord = normcoord + 0.5; ++ vec4 color = texture2D (tex, texturecoord); ++ gl_FragColor = color; ++} ++ +diff --git a/ext/gl/shaders/gray_shader.fs b/ext/gl/shaders/gray_shader.fs +new file mode 100755 +index 0000000..75e9790 +--- /dev/null ++++ b/ext/gl/shaders/gray_shader.fs +@@ -0,0 +1,12 @@ ++precision mediump float; ++varying vec2 v_texcoord; ++uniform sampler2D tex; ++void main () { ++ vec4 color = texture2D (tex, v_texcoord.xy); ++ float y = dot(color.rgb, vec3(0.2125, 0.7154, 0.0721)); ++ color.r = y; ++ color.g = y; ++ color.b = y; ++ gl_FragColor = color; ++} ++ +diff --git a/ext/gl/shaders/tunnel_shader.fs b/ext/gl/shaders/tunnel_shader.fs +new file mode 100755 +index 0000000..5888c92 +--- /dev/null ++++ b/ext/gl/shaders/tunnel_shader.fs +@@ -0,0 +1,14 @@ ++precision mediump float; ++varying vec2 v_texcoord; ++uniform sampler2D tex; ++void main () { ++ vec2 texturecoord = v_texcoord.xy; ++ vec2 normcoord; ++ normcoord = (texturecoord - 0.5); ++ float r = length(normcoord); ++ normcoord *= clamp (r, 0.0, 0.275) / r; ++ texturecoord = normcoord + 0.5; ++ vec4 color = texture2D (tex, texturecoord); ++ gl_FragColor = color; ++} ++ +diff --git a/ext/gl/shaders/twirl_shader.fs b/ext/gl/shaders/twirl_shader.fs +new file mode 100755 +index 0000000..2b9d5fd +--- /dev/null ++++ b/ext/gl/shaders/twirl_shader.fs +@@ -0,0 +1,21 @@ ++precision mediump float; ++varying vec2 v_texcoord; ++uniform sampler2D tex; ++void main () { ++ vec2 texturecoord = v_texcoord.xy; ++ vec2 normcoord; ++ normcoord = texturecoord - 0.5; ++ float r = length (normcoord); ++ // calculate rotation angle: maximum (about pi/2) at the origin and ++ // gradually decrease it up to 0.6 of each quadrant ++ float phi = (1.0 - smoothstep (0.0, 0.3, r)) * 1.6; ++ // precalculate sin phi and cos phi, save some alu ++ float s = sin(phi); ++ float c = cos(phi); ++ // rotate ++ normcoord *= mat2(c, s, -s, c); ++ texturecoord = normcoord + 0.5; ++ vec4 color = texture2D (tex, texturecoord); ++ gl_FragColor = color; ++} ++ +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Fix-for-gl-plugin-not-built-in-wayland-backend.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Fix-for-gl-plugin-not-built-in-wayland-backend.patch new file mode 100644 index 000000000..f7ea52aaa --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Fix-for-gl-plugin-not-built-in-wayland-backend.patch @@ -0,0 +1,31 @@ +From 7cf34dcec06acaf3278ef48feafe68b5cb3c7789 Mon Sep 17 00:00:00 2001 +From: Jian +Date: Fri, 24 Apr 2015 17:12:02 +0800 +Subject: [PATCH] Fix for gl plugin not built in wayland backend +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian +--- + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index cd55e22..099d0eb 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -745,7 +745,7 @@ case $host in + LIBS=$old_LIBS + CFLAGS=$old_CFLAGS + +- PKG_CHECK_MODULES(WAYLAND_EGL, wayland-client >= 1.0 wayland-cursor >= 1.0 wayland-egl >= 9.0, HAVE_WAYLAND_EGL=yes, HAVE_WAYLAND_EGL=no) ++ PKG_CHECK_MODULES(WAYLAND_EGL, wayland-client >= 1.0 wayland-cursor >= 1.0 wayland-egl >= 1.0, HAVE_WAYLAND_EGL=yes, HAVE_WAYLAND_EGL=no) + ;; + esac + +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Fix-warnnig-log-in-glfilter.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Fix-warnnig-log-in-glfilter.patch new file mode 100644 index 000000000..a8b956389 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/Fix-warnnig-log-in-glfilter.patch @@ -0,0 +1,57 @@ +From 1be24d5658bd01b2e622be54b7d7f862560d8181 Mon Sep 17 00:00:00 2001 +From: Jian +Date: Wed, 25 Mar 2015 16:05:09 +0800 +Subject: [PATCH] Fix warnnig log in glfilter +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Jian +--- + gst-libs/gst/gl/gstglfilter.c | 19 +++++-------------- + 1 file changed, 5 insertions(+), 14 deletions(-) + +diff --git a/gst-libs/gst/gl/gstglfilter.c b/gst-libs/gst/gl/gstglfilter.c +index eef4ec7..d038dcc 100644 +--- a/gst-libs/gst/gl/gstglfilter.c ++++ b/gst-libs/gst/gl/gstglfilter.c +@@ -759,12 +759,13 @@ gst_gl_filter_transform_caps (GstBaseTransform * bt, + + tmp = gst_caps_new_empty (); + +- tmp = gst_caps_merge (tmp, glcaps); ++ tmp = gst_caps_merge (tmp, gst_gl_filter_caps_remove_format_info (glcaps)); + #if GST_GL_HAVE_PLATFORM_EGL +- tmp = gst_caps_merge (tmp, eglcaps); ++ tmp = gst_caps_merge (tmp, gst_gl_filter_caps_remove_format_info (eglcaps)); + #endif +- tmp = gst_caps_merge (tmp, uploadcaps); +- tmp = gst_caps_merge (tmp, raw_caps); ++ tmp = ++ gst_caps_merge (tmp, gst_gl_filter_caps_remove_format_info (uploadcaps)); ++ tmp = gst_caps_merge (tmp, gst_gl_filter_caps_remove_format_info (raw_caps)); + + tmp = gst_caps_merge (tmp, gst_gl_filter_caps_remove_format_info (caps)); + +@@ -775,16 +776,6 @@ gst_gl_filter_transform_caps (GstBaseTransform * bt, + result = tmp; + } + +- /* if output still intersects input then prefer the intersection */ +- f = gst_caps_get_features (caps, 0); +- +- if (!gst_caps_features_is_any (f) +- && !gst_caps_features_is_equal (f, +- GST_CAPS_FEATURES_MEMORY_SYSTEM_MEMORY)) { +- tmp = gst_caps_intersect_full (result, caps, GST_CAPS_INTERSECT_FIRST); +- result = gst_caps_merge (tmp, result); +- } +- + GST_DEBUG_OBJECT (bt, "returning caps: %" GST_PTR_FORMAT, result); + + return result; +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-Add-one-property-to-set-sink-element-for-video.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-Add-one-property-to-set-sink-element-for-video.patch new file mode 100644 index 000000000..a2fcb2066 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-Add-one-property-to-set-sink-element-for-video.patch @@ -0,0 +1,182 @@ +From 59726a9af8d439f2a4bbe51d0cac909c936d86f3 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Fri, 13 Mar 2015 17:31:29 +0800 +Subject: [PATCH] camerabin: Add one property to set sink element for video + recording pipeline + +Add one property to set sink element for video recording. Default is +filesink. + +https://bugzilla.gnome.org/show_bug.cgi?id=744508 + +Upstream Status: Inappropriate [i.MX specific] + +--- + gst/camerabin2/gstcamerabin2.c | 73 ++++++++++++++++++++++++++++++++++------ + gst/camerabin2/gstcamerabin2.h | 1 + + 2 files changed, 63 insertions(+), 11 deletions(-) + +diff --git a/gst/camerabin2/gstcamerabin2.c b/gst/camerabin2/gstcamerabin2.c +index c77585a..01037ff 100644 +--- a/gst/camerabin2/gstcamerabin2.c ++++ b/gst/camerabin2/gstcamerabin2.c +@@ -226,6 +226,7 @@ enum + PROP_MUTE_AUDIO, + PROP_AUDIO_CAPTURE_SUPPORTED_CAPS, + PROP_AUDIO_CAPTURE_CAPS, ++ PROP_VIDEO_SINK, + PROP_ZOOM, + PROP_MAX_ZOOM, + PROP_IMAGE_ENCODING_PROFILE, +@@ -365,7 +366,7 @@ gst_camera_bin_start_capture (GstCameraBin2 * camerabin) + + /* check that we have a valid location */ + if (camerabin->mode == MODE_VIDEO) { +- if (camerabin->location == NULL) { ++ if (camerabin->location == NULL && !camerabin->user_video_sink) { + GST_ELEMENT_ERROR (camerabin, RESOURCE, OPEN_WRITE, + (_("File location is set to NULL, please set it to a valid filename")), (NULL)); + return; +@@ -500,10 +501,13 @@ gst_camera_bin_src_notify_readyforcapture (GObject * obj, GParamSpec * pspec, + if (camera->mode == MODE_VIDEO) { + /* a video recording is about to start, change the filesink location */ + gst_element_set_state (camera->videosink, GST_STATE_NULL); +- location = g_strdup_printf (camera->location, camera->capture_index); +- GST_DEBUG_OBJECT (camera, "Switching videobin location to %s", location); +- g_object_set (camera->videosink, "location", location, NULL); +- g_free (location); ++ /* shouldn't set location for user_video_sink */ ++ if (!camera->user_video_sink) { ++ location = g_strdup_printf (camera->location, camera->capture_index); ++ GST_DEBUG_OBJECT (camera, "Switching videobin location to %s", location); ++ g_object_set (camera->videosink, "location", location, NULL); ++ g_free (location); ++ } + if (gst_element_set_state (camera->videosink, GST_STATE_PLAYING) == + GST_STATE_CHANGE_FAILURE) { + /* Resets the latest state change return, that would be a failure +@@ -558,6 +562,8 @@ gst_camera_bin_dispose (GObject * object) + + if (camerabin->videosink) + gst_object_unref (camerabin->videosink); ++ if (camerabin->user_video_sink) ++ gst_object_unref (camerabin->user_video_sink); + if (camerabin->video_encodebin) + gst_object_unref (camerabin->video_encodebin); + if (camerabin->videobin_capsfilter) +@@ -678,6 +684,12 @@ gst_camera_bin_class_init (GstCameraBin2Class * klass) + " taken into use on the next null to ready transition", + GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + ++ g_object_class_install_property (object_class, PROP_VIDEO_SINK, ++ g_param_spec_object ("video-sink", "Video sink", ++ "The video sink element to be used on video recordings. It is only" ++ " taken into use on the next null to ready transition", ++ GST_TYPE_ELEMENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); ++ + g_object_class_install_property (object_class, PROP_MUTE_AUDIO, + g_param_spec_boolean ("mute", "Mute", + "If the audio recording should be muted. Note that this still " +@@ -1534,13 +1546,30 @@ gst_camera_bin_create_elements (GstCameraBin2 * camera) + g_signal_connect (camera->video_encodebin, "element-added", + (GCallback) encodebin_element_added, camera); + +- camera->videosink = +- gst_element_factory_make ("filesink", "videobin-filesink"); ++ /* check if we need to replace the videosink */ ++ if (camera->videosink) { ++ if (camera->user_video_sink && camera->user_video_sink != camera->videosink) { ++ gst_bin_remove (GST_BIN_CAST (camera), camera->videosink); ++ gst_object_unref (camera->videosink); ++ camera->videosink = NULL; ++ } ++ } ++ + if (!camera->videosink) { +- missing_element_name = "filesink"; +- goto missing_element; ++ if (camera->user_video_sink) { ++ camera->videosink = gst_object_ref (camera->user_video_sink); ++ } else { ++ camera->videosink = ++ gst_element_factory_make ("filesink", "videobin-filesink"); ++ if (!camera->videosink) { ++ missing_element_name = "filesink"; ++ goto missing_element; ++ } ++ g_object_set (camera->videosink, "async", FALSE, NULL); ++ } + } +- g_object_set (camera->videosink, "async", FALSE, NULL); ++ ++ g_assert (camera->videosink != NULL); + + /* audio elements */ + if (!camera->audio_volume) { +@@ -1663,7 +1692,9 @@ gst_camera_bin_create_elements (GstCameraBin2 * camera) + gst_element_set_locked_state (camera->videosink, TRUE); + gst_element_set_locked_state (camera->imagesink, TRUE); + +- g_object_set (camera->videosink, "location", camera->location, NULL); ++ if (!camera->user_video_sink) { ++ g_object_set (camera->videosink, "location", camera->location, NULL); ++ } + g_object_set (camera->imagesink, "location", camera->location, NULL); + } + +@@ -2029,6 +2060,20 @@ gst_camera_bin_set_audio_src (GstCameraBin2 * camera, GstElement * src) + } + + static void ++gst_camera_bin_set_video_sink (GstCameraBin2 * camera, GstElement * sink) ++{ ++ GST_DEBUG_OBJECT (GST_OBJECT (camera), ++ "Setting video sink %" GST_PTR_FORMAT, sink); ++ ++ if (camera->user_video_sink) ++ g_object_unref (camera->user_video_sink); ++ ++ if (sink) ++ g_object_ref (sink); ++ camera->user_video_sink = sink; ++} ++ ++static void + gst_camera_bin_set_camera_src (GstCameraBin2 * camera, GstElement * src) + { + GST_DEBUG_OBJECT (GST_OBJECT (camera), +@@ -2061,6 +2106,9 @@ gst_camera_bin_set_property (GObject * object, guint prop_id, + case PROP_AUDIO_SRC: + gst_camera_bin_set_audio_src (camera, g_value_get_object (value)); + break; ++ case PROP_VIDEO_SINK: ++ gst_camera_bin_set_video_sink (camera, g_value_get_object (value)); ++ break; + case PROP_MUTE_AUDIO: + g_object_set (camera->audio_volume, "mute", g_value_get_boolean (value), + NULL); +@@ -2244,6 +2292,9 @@ gst_camera_bin_get_property (GObject * object, guint prop_id, + case PROP_AUDIO_SRC: + g_value_set_object (value, camera->user_audio_src); + break; ++ case PROP_VIDEO_SINK: ++ g_value_set_object (value, camera->user_video_sink); ++ break; + case PROP_MUTE_AUDIO:{ + gboolean mute; + +diff --git a/gst/camerabin2/gstcamerabin2.h b/gst/camerabin2/gstcamerabin2.h +index ba55a7e..9e090b6 100644 +--- a/gst/camerabin2/gstcamerabin2.h ++++ b/gst/camerabin2/gstcamerabin2.h +@@ -71,6 +71,7 @@ struct _GstCameraBin2 + GstElement *video_encodebin; + gulong video_encodebin_signal_id; + GstElement *videosink; ++ GstElement *user_video_sink; + GstElement *videobin_capsfilter; + + GstElement *viewfinderbin; +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-examples-memory-leak-in-camerabin-examples-01.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-examples-memory-leak-in-camerabin-examples-01.patch new file mode 100644 index 000000000..24e58c0c5 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-examples-memory-leak-in-camerabin-examples-01.patch @@ -0,0 +1,63 @@ +From b50d8cf5301afc160fbe7cb720b362c40e42978f Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Tue, 10 Feb 2015 15:53:21 +0800 +Subject: [PATCH 1/2] camerabin examples: memory leak in camerabin examples + code + +should unref after set object. The object will be refed when set +property. + +Upstream Status: Accepted + https://bugzilla.gnome.org/show_bug.cgi?id=744219 + +Signed-off-by: Song Bing + +--- + tests/examples/camerabin2/gst-camerabin2-test.c | 10 ++++++++-- + 1 file changed, 8 insertions(+), 2 deletions(-) + +diff --git a/tests/examples/camerabin2/gst-camerabin2-test.c b/tests/examples/camerabin2/gst-camerabin2-test.c +index dfbd055..b68ec51 100644 +--- a/tests/examples/camerabin2/gst-camerabin2-test.c ++++ b/tests/examples/camerabin2/gst-camerabin2-test.c +@@ -595,6 +595,7 @@ setup_pipeline_element (GstElement * element, const gchar * property_name, + elem = gst_parse_launch (element_name, &error); + if (elem) { + g_object_set (element, property_name, elem, NULL); ++ g_object_unref (elem); + } else { + GST_WARNING ("can't create element '%s' for property '%s'", element_name, + property_name); +@@ -695,6 +696,7 @@ setup_pipeline (void) + + if (setup_pipeline_element (wrapper, "video-source", videosrc_name, NULL)) { + g_object_set (camerabin, "camera-source", wrapper, NULL); ++ g_object_unref (wrapper); + } else { + GST_WARNING ("Failed to set videosrc to %s", videosrc_name); + } +@@ -718,15 +720,19 @@ setup_pipeline (void) + + if (imagepp_name) { + ipp = create_ipp_bin (); +- if (ipp) ++ if (ipp) { + g_object_set (camerabin, "image-filter", ipp, NULL); ++ g_object_unref (ipp); ++ } + else + GST_WARNING ("Could not create ipp elements"); + } + + prof = load_encoding_profile (); +- if (prof) ++ if (prof) { + g_object_set (G_OBJECT (camerabin), "video-profile", prof, NULL); ++ gst_encoding_profile_unref (prof); ++ } + + GST_INFO_OBJECT (camerabin, "elements created"); + +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-examples-memory-leak-in-camerabin-examples-02.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-examples-memory-leak-in-camerabin-examples-02.patch new file mode 100644 index 000000000..12fcaf6b9 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/camerabin-examples-memory-leak-in-camerabin-examples-02.patch @@ -0,0 +1,109 @@ +From 2213750b7568c08846a71866fc53d9807545d298 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Tue, 10 Feb 2015 15:55:50 +0800 +Subject: [PATCH 2/2] camerabin examples: memory leak in camerabin examples + code + +should unref caps after set to profile. profile will ref it. + +Upstream Status: Accepted + https://bugzilla.gnome.org/show_bug.cgi?id=744219 + +Signed-off-by: Song Bing +--- + tests/examples/camerabin2/gst-camera2.c | 53 ++++++++++++++++++++----------- + 1 file changed, 34 insertions(+), 19 deletions(-) + +diff --git a/tests/examples/camerabin2/gst-camera2.c b/tests/examples/camerabin2/gst-camera2.c +index 45047f5..2eb544c 100644 +--- a/tests/examples/camerabin2/gst-camera2.c ++++ b/tests/examples/camerabin2/gst-camera2.c +@@ -56,16 +56,21 @@ static GstEncodingProfile * + create_ogg_profile (void) + { + GstEncodingContainerProfile *container; ++ GstCaps *caps = NULL; + +- container = gst_encoding_container_profile_new ("ogg", NULL, +- gst_caps_new_empty_simple ("application/ogg"), NULL); ++ caps = gst_caps_new_empty_simple ("application/ogg"); ++ container = gst_encoding_container_profile_new ("ogg", NULL, caps, NULL); ++ gst_caps_unref (caps); + ++ caps = gst_caps_new_empty_simple ("video/x-theora"); + gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *) +- gst_encoding_video_profile_new (gst_caps_new_empty_simple +- ("video/x-theora"), NULL, NULL, 1)); ++ gst_encoding_video_profile_new (caps, NULL, NULL, 1)); ++ gst_caps_unref (caps); ++ ++ caps = gst_caps_new_empty_simple ("audio/x-vorbis"); + gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *) +- gst_encoding_audio_profile_new (gst_caps_new_empty_simple +- ("audio/x-vorbis"), NULL, NULL, 1)); ++ gst_encoding_audio_profile_new (caps, NULL, NULL, 1)); ++ gst_caps_unref (caps); + + return (GstEncodingProfile *) container; + } +@@ -74,16 +79,21 @@ static GstEncodingProfile * + create_webm_profile (void) + { + GstEncodingContainerProfile *container; ++ GstCaps *caps = NULL; + +- container = gst_encoding_container_profile_new ("webm", NULL, +- gst_caps_new_empty_simple ("video/webm"), NULL); ++ caps = gst_caps_new_empty_simple ("video/webm"); ++ container = gst_encoding_container_profile_new ("webm", NULL, caps, NULL); ++ gst_caps_unref (caps); + ++ caps = gst_caps_new_empty_simple ("video/x-vp8"); + gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *) +- gst_encoding_video_profile_new (gst_caps_new_empty_simple ("video/x-vp8"), +- NULL, NULL, 1)); ++ gst_encoding_video_profile_new (caps, NULL, NULL, 1)); ++ gst_caps_unref (caps); ++ ++ caps = gst_caps_new_empty_simple ("audio/x-vorbis"); + gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *) +- gst_encoding_audio_profile_new (gst_caps_new_empty_simple +- ("audio/x-vorbis"), NULL, NULL, 1)); ++ gst_encoding_audio_profile_new (caps, NULL, NULL, 1)); ++ gst_caps_unref (caps); + + return (GstEncodingProfile *) container; + } +@@ -92,17 +102,22 @@ static GstEncodingProfile * + create_mp4_profile (void) + { + GstEncodingContainerProfile *container; ++ GstCaps *caps = NULL; + +- container = gst_encoding_container_profile_new ("mp4", NULL, +- gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, "iso", +- NULL), NULL); ++ caps = gst_caps_new_simple ("video/quicktime", "variant", G_TYPE_STRING, "iso", ++ NULL); ++ container = gst_encoding_container_profile_new ("mp4", NULL, caps, NULL); ++ gst_caps_unref (caps); + ++ caps = gst_caps_new_empty_simple ("video/x-h264"); + gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *) +- gst_encoding_video_profile_new (gst_caps_new_empty_simple +- ("video/x-h264"), NULL, NULL, 1)); ++ gst_encoding_video_profile_new (caps, NULL, NULL, 1)); ++ gst_caps_unref (caps); ++ ++ caps = gst_caps_new_simple ("audio/mpeg", "version", G_TYPE_INT, 4, NULL); + gst_encoding_container_profile_add_profile (container, (GstEncodingProfile *) +- gst_encoding_audio_profile_new (gst_caps_new_simple ("audio/mpeg", +- "version", G_TYPE_INT, 4, NULL), NULL, NULL, 1)); ++ gst_encoding_audio_profile_new (caps, NULL, NULL, 1)); ++ gst_caps_unref (caps); + + return (GstEncodingProfile *) container; + } +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/dvbsuboverlay-Set-query-ALLOCATION-need_pool-to-FALSE.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/dvbsuboverlay-Set-query-ALLOCATION-need_pool-to-FALSE.patch new file mode 100644 index 000000000..f0420866b --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/dvbsuboverlay-Set-query-ALLOCATION-need_pool-to-FALSE.patch @@ -0,0 +1,33 @@ +From 518cc8a9af3797fbed2916497bb1cf83725265c4 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Tue, 3 Mar 2015 10:12:11 +0800 +Subject: [PATCH] dvbsuboverlay: Set query ALLOCATION need_pool to FALSE + +Set query ALLOCATION need_pool to FALSE as it only need query if can +support video overlay composition meta. + +https://bugzilla.gnome.org/show_bug.cgi?id=745495 + +Upstream Status: Accepted  + +Signed-off-by: Song Bing +--- + gst/dvbsuboverlay/gstdvbsuboverlay.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/gst/dvbsuboverlay/gstdvbsuboverlay.c b/gst/dvbsuboverlay/gstdvbsuboverlay.c +index 3965b65..341b153 100644 +--- a/gst/dvbsuboverlay/gstdvbsuboverlay.c ++++ b/gst/dvbsuboverlay/gstdvbsuboverlay.c +@@ -720,7 +720,7 @@ gst_dvbsub_overlay_negotiate (GstDVBSubOverlay * overlay, GstCaps * caps) + GstQuery *query; + + /* find supported meta */ +- query = gst_query_new_allocation (caps, TRUE); ++ query = gst_query_new_allocation (caps, FALSE); + + if (!gst_pad_peer_query (overlay->srcpad, query)) { + /* no problem, we use the query defaults */ +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/egl-workaround-for-eglCreateContext-isn-t-thread-safe.patch b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/egl-workaround-for-eglCreateContext-isn-t-thread-safe.patch new file mode 100644 index 000000000..35ffb0dc6 --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad-1.4.5/egl-workaround-for-eglCreateContext-isn-t-thread-safe.patch @@ -0,0 +1,42 @@ +From 0d979b3a2a4e2db571545e84aeb854b326fa2234 Mon Sep 17 00:00:00 2001 +From: Song Bing +Date: Tue, 17 Mar 2015 10:21:28 +0800 +Subject: [PATCH] [egl] workaround for eglCreateContext () isn't thread safe + +Workaround for eglCreateContext () isn't thread safe + +Upstream Status: Inappropriate [i.MX specific] + +Signed-off-by: Song Bing b06498@freescale.com +--- + gst-libs/gst/gl/egl/gstglcontext_egl.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/gst-libs/gst/gl/egl/gstglcontext_egl.c b/gst-libs/gst/gl/egl/gstglcontext_egl.c +index 4ccec8d..7ba1782 100644 +--- a/gst-libs/gst/gl/egl/gstglcontext_egl.c ++++ b/gst-libs/gst/gl/egl/gstglcontext_egl.c +@@ -208,6 +208,8 @@ failure: + return FALSE; + } + ++static GMutex test_mutex; ++ + static gboolean + gst_gl_context_egl_create_context (GstGLContext * context, + GstGLAPI gl_api, GstGLContext * other_context, GError ** error) +@@ -336,9 +338,11 @@ gst_gl_context_egl_create_context (GstGLContext * context, + } + context_attrib[i++] = EGL_NONE; + ++ g_mutex_lock (&test_mutex); + egl->egl_context = + eglCreateContext (egl->egl_display, egl->egl_config, + (EGLContext) external_gl_context, context_attrib); ++ g_mutex_unlock (&test_mutex); + + if (egl->egl_context != EGL_NO_CONTEXT) { + GST_INFO ("gl context created: %" G_GUINTPTR_FORMAT, +-- +1.7.9.5 + diff --git a/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.4.5.bbappend b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.4.5.bbappend new file mode 100644 index 000000000..bbc5c39ae --- /dev/null +++ b/meta-digi-dey/recipes-multimedia/gstreamer/gstreamer1.0-plugins-bad_1.4.5.bbappend @@ -0,0 +1,41 @@ +# Copyright (C) 2015 Digi International + +FILESEXTRAPATHS_prepend := "${THISDIR}/${BP}:" + +SRC_URI_append_ccimx6 = " \ + file://egl-workaround-for-eglCreateContext-isn-t-thread-safe.patch \ + file://camerabin-Add-one-property-to-set-sink-element-for-video.patch \ + file://0011-videoparse-modifiy-the-videoparse-rank.patch \ + file://camerabin-examples-memory-leak-in-camerabin-examples-01.patch \ + file://camerabin-examples-memory-leak-in-camerabin-examples-02.patch \ + file://dvbsuboverlay-Set-query-ALLOCATION-need_pool-to-FALSE.patch \ + file://0002-mpegtsmux-Need-get-pid-when-create-streams.patch \ + file://0006-h263parse_fix_CPFMT_parsing.patch \ + file://0009-mpeg4videoparse-Need-detect-picture-coding-type-when.patch \ + file://0010-mpegvideoparse-Need-detect-picture-coding-type-when-.patch \ + file://0012-glfilter-Lost-frame-rate-info-when-fixate-caps.patch \ + file://0014-opencv-rename-gstopencv.c-to-gstopencv.cpp.patch \ + file://0015-opencv-Add-video-stitching-support.patch \ + file://0016-PATCH-gstaggregator-memory-leak-increasing-a-lot-aft.patch \ + file://1.4.5-Use-viv-direct-texture-to-bind-buffer.patch \ + file://0001-Support-croping-and-alignment-handling.patch \ + file://Fix-warnnig-log-in-glfilter.patch \ + file://Adding-some-fragment-shaders-for-glshader-plugin.patch \ + file://Fix-for-gl-plugin-not-built-in-wayland-backend.patch \ + file://0003-glimagesink-Add-fps-print-in-glimagesink.patch \ + file://0004-gl-fb-Support-fb-backend-for-gl-plugins.patch \ + file://0005-gl-wayland-Make-it-always-fullscreen-1024x768.patch \ + file://0007-glfilter-Fix-video-is-tearing-after-enab.patch \ + file://0008-gl-Fix-glimagesink-loop-playback-failed-in-wayland.patch \ + file://0017-MMFMWK-6778-Support-more-format-in-direct-viv.patch \ +" + + +# Revert Poky commit cdc2c8aeaa96b07dfc431a4cf0bf51ef7f8802a3 (move EGL to Wayland) +# Otherwise 'glimagesink' for X11 is not compiled and for example this sink is needed +# by 'imxcamera' application (distributed by FSL in binary form) +PACKAGECONFIG[gles2] = "--enable-gles2 --enable-egl,--disable-gles2 --disable-egl,virtual/libgles2 virtual/egl" +PACKAGECONFIG[wayland] = "--enable-wayland --disable-x11,--disable-wayland,wayland" + +# include fragment shaders +FILES_${PN}-opengl += "/usr/share/*.fs"