diff options
author | Matthew Waters <ystreet00@gmail.com> | 2013-10-23 21:46:04 +1100 |
---|---|---|
committer | Matthew Waters <ystreet00@gmail.com> | 2014-03-15 18:37:03 +0100 |
commit | 7f3ad8f445a5360106377fe2383d032f09e593f1 (patch) | |
tree | af582fc8ce5ebae3461c031672d57a9a95c5b2c0 /gst | |
parent | 9c1d2eeafd69ef0b0f44c378f954c745e5512c5e (diff) | |
download | gstreamer-plugins-bad-7f3ad8f445a5360106377fe2383d032f09e593f1.tar.gz |
[830/906] glvideomixer: Add a new simple glvideomixer element
that simply uses glBlendFunc to blend each imput frame
https://bugzilla.gnome.org/show_bug.cgi?id=710714
Diffstat (limited to 'gst')
-rw-r--r-- | gst/gl/Makefile.am | 2 | ||||
-rw-r--r-- | gst/gl/gstglvideomixer.c | 299 | ||||
-rw-r--r-- | gst/gl/gstglvideomixer.h | 56 | ||||
-rw-r--r-- | gst/gl/gstopengl.c | 6 |
4 files changed, 363 insertions, 0 deletions
diff --git a/gst/gl/Makefile.am b/gst/gl/Makefile.am index 2c2b53701..c7a59b648 100644 --- a/gst/gl/Makefile.am +++ b/gst/gl/Makefile.am @@ -31,6 +31,8 @@ OPENGL_SOURCES = \ gstgltestsrc.h \ gstglmosaic.c \ gstglmosaic.h \ + gstglvideomixer.c \ + gstglvideomixer.h \ effects/gstgleffectscurves.h \ effects/gstgleffectstretch.c \ effects/gstgleffecttunnel.c \ diff --git a/gst/gl/gstglvideomixer.c b/gst/gl/gstglvideomixer.c new file mode 100644 index 000000000..0275d67d3 --- /dev/null +++ b/gst/gl/gstglvideomixer.c @@ -0,0 +1,299 @@ +/* + * GStreamer + * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +/** + * SECTION:element-glvideomixer + * + * glmixer sub element. N gl sink pads to 1 source pad. + * N + 1 OpenGL contexts shared together. + * N <= 6 because the rendering is more a like a cube than a video_mixer + * Each opengl input stream is rendered on a cube face + * + * <refsect2> + * <title>Examples</title> + * |[ + * gst-launch-0.10 videotestsrc ! "video/x-raw-yuv, format=(fourcc)YUY2" ! glupload ! queue ! glvideomixer name=m ! glimagesink videotestsrc pattern=12 ! "video/x-raw-yuv, format=(fourcc)I420, framerate=(fraction)5/1, width=100, height=200" ! glupload ! queue ! m. videotestsrc ! "video/x-raw-rgb, framerate=(fraction)15/1, width=1500, height=1500" ! glupload ! gleffects effect=3 ! queue ! m. videotestsrc ! glupload ! gleffects effect=2 ! queue ! m. videotestsrc ! glupload ! glfiltercube ! queue ! m. videotestsrc ! glupload ! gleffects effect=6 ! queue ! m. + * ]| + * FBO (Frame Buffer Object) is required. + * </refsect2> + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "gstglvideomixer.h" + +#define GST_CAT_DEFAULT gst_gl_video_mixer_debug +GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT); + +enum +{ + PROP_0, +}; + +#define DEBUG_INIT \ + GST_DEBUG_CATEGORY_INIT (gst_gl_video_mixer_debug, "glvideomixer", 0, "glvideomixer element"); + +G_DEFINE_TYPE_WITH_CODE (GstGLVideoMixer, gst_gl_video_mixer, GST_TYPE_GL_MIXER, + DEBUG_INIT); + +static void gst_gl_video_mixer_set_property (GObject * object, guint prop_id, + const GValue * value, GParamSpec * pspec); +static void gst_gl_video_mixer_get_property (GObject * object, guint prop_id, + GValue * value, GParamSpec * pspec); + +static void gst_gl_video_mixer_reset (GstGLMixer * mixer); +static gboolean gst_gl_video_mixer_init_shader (GstGLMixer * mixer, + GstCaps * outcaps); + +static gboolean gst_gl_video_mixer_process_textures (GstGLMixer * mixer, + GArray * in_textures, GPtrArray * in_frames, guint out_tex); +static void gst_gl_video_mixer_callback (gpointer stuff); + +/* vertex source */ +static const gchar *video_mixer_v_src = + "#extension GL_ARB_texture_rectangle : enable\n" + "attribute vec4 a_position; \n" + "attribute vec2 a_texCoord; \n" + "uniform float x_scale; \n" + "uniform float y_scale; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " gl_Position = a_position * vec4(x_scale, y_scale, 1.0, 1.0);\n" + " v_texCoord = a_texCoord; \n" "}"; + +/* fragment source */ +static const gchar *video_mixer_f_src = + "#extension GL_ARB_texture_rectangle : enable\n" + "uniform sampler2DRect texture; \n" + "varying vec2 v_texCoord; \n" + "void main() \n" + "{ \n" + " vec4 rgba = texture2DRect( texture, v_texCoord );\n" + " gl_FragColor = vec4(rgba.rgb, 1.0);\n" + "} \n"; + +static void +gst_gl_video_mixer_class_init (GstGLVideoMixerClass * klass) +{ + GObjectClass *gobject_class; + GstElementClass *element_class; + + gobject_class = (GObjectClass *) klass; + element_class = GST_ELEMENT_CLASS (klass); + + gobject_class->set_property = gst_gl_video_mixer_set_property; + gobject_class->get_property = gst_gl_video_mixer_get_property; + + gst_element_class_set_metadata (element_class, "OpenGL video_mixer", + "Filter/Effect/Video", "OpenGL video_mixer", + "Julien Isorce <julien.isorce@gmail.com>"); + + GST_GL_MIXER_CLASS (klass)->set_caps = gst_gl_video_mixer_init_shader; + GST_GL_MIXER_CLASS (klass)->reset = gst_gl_video_mixer_reset; + GST_GL_MIXER_CLASS (klass)->process_textures = + gst_gl_video_mixer_process_textures; +} + +static void +gst_gl_video_mixer_init (GstGLVideoMixer * video_mixer) +{ + video_mixer->shader = NULL; + video_mixer->input_textures = NULL; + video_mixer->input_frames = NULL; +} + +static void +gst_gl_video_mixer_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_gl_video_mixer_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_gl_video_mixer_reset (GstGLMixer * mixer) +{ + GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer); + + video_mixer->input_textures = NULL; + video_mixer->input_frames = NULL; + + if (video_mixer->shader) + gst_gl_context_del_shader (mixer->context, video_mixer->shader); + video_mixer->shader = NULL; +} + +static gboolean +gst_gl_video_mixer_init_shader (GstGLMixer * mixer, GstCaps * outcaps) +{ + GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mixer); + + return gst_gl_context_gen_shader (mixer->context, video_mixer_v_src, + video_mixer_f_src, &video_mixer->shader); +} + +static gboolean +gst_gl_video_mixer_process_textures (GstGLMixer * mix, GArray * in_textures, + GPtrArray * in_frames, guint out_tex) +{ + GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (mix); + + video_mixer->input_textures = in_textures; + video_mixer->input_frames = in_frames; + + gst_gl_context_use_fbo_v2 (mix->context, + GST_VIDEO_INFO_WIDTH (&mix->out_info), + GST_VIDEO_INFO_HEIGHT (&mix->out_info), mix->fbo, mix->depthbuffer, + out_tex, gst_gl_video_mixer_callback, (gpointer) video_mixer); + + return TRUE; +} + +/* opengl scene, params: input texture (not the output mixer->texture) */ +static void +gst_gl_video_mixer_callback (gpointer stuff) +{ + GstGLVideoMixer *video_mixer = GST_GL_VIDEO_MIXER (stuff); + GstGLMixer *mixer = GST_GL_MIXER (video_mixer); + GstGLFuncs *gl = mixer->context->gl_vtable; + + GLint attr_position_loc = 0; + GLint attr_texture_loc = 0; + guint out_width, out_height; + + const GLushort indices[] = { + 0, 1, 2, + 0, 2, 3 + }; + + guint count = 0; + + out_width = GST_VIDEO_INFO_WIDTH (&mixer->out_info); + out_height = GST_VIDEO_INFO_HEIGHT (&mixer->out_info); + + gst_gl_context_clear_shader (mixer->context); + gl->BindTexture (GL_TEXTURE_RECTANGLE_ARB, 0); + gl->Disable (GL_TEXTURE_RECTANGLE_ARB); + + gl->Disable (GL_DEPTH_TEST); + gl->Disable (GL_CULL_FACE); + + gl->ClearColor (0.0, 0.0, 0.0, 0.0); + gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + gst_gl_shader_use (video_mixer->shader); + + attr_position_loc = + gst_gl_shader_get_attribute_location (video_mixer->shader, "a_position"); + attr_texture_loc = + gst_gl_shader_get_attribute_location (video_mixer->shader, "a_texCoord"); + + gl->Enable (GL_BLEND); + + while (count < video_mixer->input_textures->len) { + GstVideoFrame *in_frame; + GLfloat *v_vertices; + guint in_tex; + guint in_width, in_height; + gfloat w, h; + + in_frame = g_ptr_array_index (video_mixer->input_frames, count); + in_tex = g_array_index (video_mixer->input_textures, guint, count); + in_width = GST_VIDEO_FRAME_WIDTH (in_frame); + in_height = GST_VIDEO_FRAME_HEIGHT (in_frame); + + if (!in_frame || !in_tex || in_width <= 0 || in_height <= 0) { + GST_DEBUG ("skipping texture:%u frame:%p width:%u height %u", + in_tex, in_frame, in_width, in_height); + count++; + continue; + } + + GST_TRACE ("processing texture:%u dimensions:%ux%u", in_tex, in_width, + in_height); + + w = ((gfloat) in_width / (gfloat) out_width); + h = ((gfloat) in_height / (gfloat) out_height); + GST_TRACE ("processing texture:%u dimensions:%ux%u, %fx%f", in_tex, + in_width, in_height, w, h); + + /* *INDENT-OFF* */ + v_vertices = (GLfloat[]) { + /* front face */ + -1.0, -1.0, -1.0f, + 0.0f, 0.0f, + 1.0, -1.0, -1.0f, + in_width, 0.0f, + 1.0, 1.0, -1.0f, + in_width, in_height, + -1.0, 1.0, -1.0f, + 0.0f, in_height, + }; + /* *INDENT-ON* */ + + gl->VertexAttribPointer (attr_position_loc, 3, GL_FLOAT, + GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[0]); + + gl->VertexAttribPointer (attr_texture_loc, 2, GL_FLOAT, + GL_FALSE, 5 * sizeof (GLfloat), &v_vertices[3]); + + gl->EnableVertexAttribArray (attr_position_loc); + gl->EnableVertexAttribArray (attr_texture_loc); + + gl->BlendFunc (GL_SRC_COLOR, GL_ONE_MINUS_SRC_COLOR); + gl->BlendEquation (GL_FUNC_ADD); + + gl->ActiveTexture (GL_TEXTURE0); + gl->BindTexture (GL_TEXTURE_RECTANGLE_ARB, in_tex); + gst_gl_shader_set_uniform_1i (video_mixer->shader, "texture", 0); + gst_gl_shader_set_uniform_1f (video_mixer->shader, "x_scale", w); + gst_gl_shader_set_uniform_1f (video_mixer->shader, "y_scale", h); + + gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices); + + ++count; + } + + gl->DisableVertexAttribArray (attr_position_loc); + gl->DisableVertexAttribArray (attr_texture_loc); + + gl->BindTexture (GL_TEXTURE_RECTANGLE_ARB, 0); + + gl->Disable (GL_BLEND); + + gst_gl_context_clear_shader (mixer->context); +} diff --git a/gst/gl/gstglvideomixer.h b/gst/gl/gstglvideomixer.h new file mode 100644 index 000000000..6df5f04f3 --- /dev/null +++ b/gst/gl/gstglvideomixer.h @@ -0,0 +1,56 @@ +/* + * GStreamer + * Copyright (C) 2009 Julien Isorce <julien.isorce@gmail.com> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301, USA. + */ + +#ifndef _GST_GL_VIDEO_MIXER_H_ +#define _GST_GL_VIDEO_MIXER_H_ + +#include <gst/gl/gstglmixer.h> + +G_BEGIN_DECLS + +#define GST_TYPE_GL_VIDEO_MIXER (gst_gl_video_mixer_get_type()) +#define GST_GL_VIDEO_MIXER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixer)) +#define GST_IS_GL_VIDEO_MIXER(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_GL_VIDEO_MIXER)) +#define GST_GL_VIDEO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass) ,GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixerClass)) +#define GST_IS_GL_VIDEO_MIXER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass) ,GST_TYPE_GL_VIDEO_MIXER)) +#define GST_GL_VIDEO_MIXER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj) ,GST_TYPE_GL_VIDEO_MIXER,GstGLVideoMixerClass)) + +typedef struct _GstGLVideoMixer GstGLVideoMixer; +typedef struct _GstGLVideoMixerClass GstGLVideoMixerClass; + +struct _GstGLVideoMixer +{ + GstGLMixer mixer; + + GstGLShader *shader; + GArray *input_textures; + GPtrArray *input_frames; +}; + +struct _GstGLVideoMixerClass +{ + GstGLMixerClass mixer_class; +}; + +GType gst_gl_video_mixer_get_type (void); + +G_END_DECLS + +#endif /* _GST_GLFILTERCUBE_H_ */ diff --git a/gst/gl/gstopengl.c b/gst/gl/gstopengl.c index 010a96c0b..b905f51a9 100644 --- a/gst/gl/gstopengl.c +++ b/gst/gl/gstopengl.c @@ -67,6 +67,7 @@ GType gst_gl_effects_get_type (void); #include "gstglcolorscale.h" #include "gstgldeinterlace.h" #include "gstglmosaic.h" +#include "gstglvideomixer.h" GType gst_gl_deinterlace_get_type (void); GType gst_gl_filter_app_get_type (void); @@ -177,6 +178,11 @@ plugin_init (GstPlugin * plugin) GST_RANK_NONE, GST_TYPE_GL_MOSAIC)) { return FALSE; } + + if (!gst_element_register (plugin, "glvideomixer", + GST_RANK_NONE, GST_TYPE_GL_VIDEO_MIXER)) { + return FALSE; + } #if HAVE_PNG if (!gst_element_register (plugin, "gldifferencematte", GST_RANK_NONE, gst_gl_differencematte_get_type ())) { |