static GstGLShader * gst_gl_deinterlace_get_fragment_shader (GstGLFilter * filter, const gchar * shader_name, const gchar * shader_source) { GstGLShader *shader = NULL; GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); GstGLContext *context = GST_GL_BASE_FILTER (filter)->context; shader = g_hash_table_lookup (deinterlace_filter->shaderstable, shader_name); if (!shader) { GError *error = NULL; if (!(shader = gst_gl_shader_new_link_with_stages (context, &error, gst_glsl_stage_new_default_vertex (context), gst_glsl_stage_new_with_string (context, GL_FRAGMENT_SHADER, GST_GLSL_VERSION_NONE, GST_GLSL_PROFILE_ES | GST_GLSL_PROFILE_COMPATIBILITY, shader_source), NULL))) { GST_ELEMENT_ERROR (deinterlace_filter, RESOURCE, NOT_FOUND, ("Failed to initialize %s shader", shader_name), (NULL)); } filter->draw_attr_position_loc = gst_gl_shader_get_attribute_location (shader, "a_position"); filter->draw_attr_texture_loc = gst_gl_shader_get_attribute_location (shader, "a_texcoord"); } g_hash_table_insert (deinterlace_filter->shaderstable, (gchar *) shader_name, shader); return shader; }
static gboolean gst_gl_deinterlace_init_shader (GstGLFilter * filter) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); //blocking call, wait the opengl thread has compiled the shader return gst_gl_context_gen_shader (GST_GL_BASE_FILTER (filter)->context, 0, greedyh_fragment_source, &deinterlace_filter->shader); }
static gboolean gst_gl_deinterlace_start (GstBaseTransform * trans) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (trans); deinterlace_filter->shaderstable = g_hash_table_new (g_str_hash, g_str_equal); return GST_BASE_TRANSFORM_CLASS (parent_class)->start (trans); }
//opengl scene, params: input texture (not the output filter->texture) static void gst_gl_deinterlace_callback (gint width, gint height, guint texture, gpointer stuff) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (stuff); GstGLFilter *filter = GST_GL_FILTER (stuff); GstGLBuffer *gl_buffer_prev = deinterlace_filter->gl_buffer_prev; glMatrixMode (GL_PROJECTION); glLoadIdentity (); gst_gl_shader_use (deinterlace_filter->shader); glEnable (GL_TEXTURE_RECTANGLE_ARB); if (gl_buffer_prev) { glActiveTexture (GL_TEXTURE1_ARB); gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "tex_prev", 1); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, gl_buffer_prev->texture); } glActiveTexture (GL_TEXTURE0_ARB); gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "tex", 0); glBindTexture (GL_TEXTURE_RECTANGLE_ARB, texture); gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "max_comb", 5.0f / 255.0f); gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "motion_threshold", 25.0f / 255.0f); gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "motion_sense", 30.0f / 255.0f); gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "width", filter->width); gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "height", filter->height); glBegin (GL_QUADS); glMultiTexCoord2iARB (GL_TEXTURE0_ARB, 0, 0); glMultiTexCoord2iARB (GL_TEXTURE1_ARB, 0, 0); glVertex2i (-1, -1); glMultiTexCoord2iARB (GL_TEXTURE0_ARB, width, 0); glMultiTexCoord2iARB (GL_TEXTURE1_ARB, width, 0); glVertex2i (1, -1); glMultiTexCoord2iARB (GL_TEXTURE0_ARB, width, height); glMultiTexCoord2iARB (GL_TEXTURE1_ARB, width, height); glVertex2i (1, 1); glMultiTexCoord2iARB (GL_TEXTURE0_ARB, 0, height); glMultiTexCoord2iARB (GL_TEXTURE1_ARB, 0, height); glVertex2i (-1, 1); glEnd (); glDisable (GL_TEXTURE_RECTANGLE_ARB); }
static gboolean gst_gl_deinterlace_filter (GstGLFilter * filter, GstBuffer * inbuf, GstBuffer * outbuf) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); gst_gl_filter_filter_texture (filter, inbuf, outbuf); gst_buffer_replace (&deinterlace_filter->prev_buffer, inbuf); return TRUE; }
static gboolean gst_gl_deinterlace_filter_texture (GstGLFilter * filter, guint in_tex, guint out_tex) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); //blocking call, use a FBO gst_gl_filter_render_to_target (filter, TRUE, in_tex, out_tex, gst_gl_deinterlace_callback, deinterlace_filter); return TRUE; }
static void gst_gl_deinterlace_reset (GstGLFilter * filter) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); if (deinterlace_filter->gl_buffer_prev) { gst_buffer_unref (GST_BUFFER_CAST (deinterlace_filter->gl_buffer_prev)); deinterlace_filter->gl_buffer_prev = NULL; } //blocking call, wait the opengl thread has destroyed the shader gst_gl_display_del_shader (filter->display, deinterlace_filter->shader); }
static gboolean gst_gl_deinterlace_filter_texture (GstGLFilter * filter, GstGLMemory * in_tex, GstGLMemory * out_tex) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); //blocking call, use a FBO gst_gl_filter_render_to_target (filter, in_tex, out_tex, deinterlace_filter->deinterlacefunc, deinterlace_filter); return TRUE; }
static gboolean gst_gl_deinterlace_greedyh_callback (GstGLFilter * filter, GstGLMemory * in_tex, gpointer user_data) { GstGLShader *shader; GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); GstGLContext *context = GST_GL_BASE_FILTER (filter)->context; GstGLFuncs *gl = context->gl_vtable; shader = gst_gl_deinterlace_get_fragment_shader (filter, "greedhy", greedyh_fragment_source); if (!shader) return FALSE; #if GST_GL_HAVE_OPENGL if (USING_OPENGL (context)) { gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); } #endif gst_gl_shader_use (shader); if (G_LIKELY (deinterlace_filter->prev_tex != NULL)) { gl->ActiveTexture (GL_TEXTURE1); gst_gl_shader_set_uniform_1i (shader, "tex_prev", 1); gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (deinterlace_filter->prev_tex)); } gl->ActiveTexture (GL_TEXTURE0); gl->BindTexture (GL_TEXTURE_2D, gst_gl_memory_get_texture_id (in_tex)); gst_gl_shader_set_uniform_1i (shader, "tex", 0); gst_gl_shader_set_uniform_1f (shader, "max_comb", 5.0f / 255.0f); gst_gl_shader_set_uniform_1f (shader, "motion_threshold", 25.0f / 255.0f); gst_gl_shader_set_uniform_1f (shader, "motion_sense", 30.0f / 255.0f); gst_gl_shader_set_uniform_1f (shader, "width", GST_VIDEO_INFO_WIDTH (&filter->out_info)); gst_gl_shader_set_uniform_1f (shader, "height", GST_VIDEO_INFO_HEIGHT (&filter->out_info)); gst_gl_filter_draw_fullscreen_quad (filter); /* we keep the previous buffer around so this is safe */ deinterlace_filter->prev_tex = in_tex; return TRUE; }
static gboolean gst_gl_deinterlace_reset (GstBaseTransform * trans) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (trans); gst_buffer_replace (&deinterlace_filter->prev_buffer, NULL); //blocking call, wait the opengl thread has destroyed the shader if (deinterlace_filter->shader) gst_gl_context_del_shader (GST_GL_BASE_FILTER (trans)->context, deinterlace_filter->shader); deinterlace_filter->shader = NULL; return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (trans); }
static void gst_gl_deinterlace_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstGLDeinterlace *filter = GST_GL_DEINTERLACE (object); switch (prop_id) { case PROP_METHOD: g_value_set_enum (value, filter->current_method); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static gboolean gst_gl_deinterlace_filter (GstGLFilter * filter, GstGLBuffer * inbuf, GstGLBuffer * outbuf) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (filter); //blocking call, use a FBO gst_gl_display_use_fbo (filter->display, filter->width, filter->height, filter->fbo, filter->depthbuffer, outbuf->texture, gst_gl_deinterlace_callback, inbuf->width, inbuf->height, inbuf->texture, 0, filter->width, 0, filter->height, GST_GL_DISPLAY_PROJECTION_ORTHO2D, (gpointer) deinterlace_filter); if (deinterlace_filter->gl_buffer_prev) gst_buffer_unref (GST_BUFFER_CAST (deinterlace_filter->gl_buffer_prev)); deinterlace_filter->gl_buffer_prev = GST_GL_BUFFER (gst_buffer_ref (GST_BUFFER_CAST (inbuf))); return TRUE; }
static gboolean gst_gl_deinterlace_reset (GstBaseTransform * trans) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (trans); gst_buffer_replace (&deinterlace_filter->prev_buffer, NULL); //blocking call, wait the opengl thread has destroyed the shader if (deinterlace_filter->shaderstable) { /* release shaders in the gl thread */ g_hash_table_foreach (deinterlace_filter->shaderstable, gst_gl_deinterlace_ghash_func_clean, deinterlace_filter); /* clean the htable without calling values destructors * because shaders have been released in the glthread * through the foreach func */ g_hash_table_unref (deinterlace_filter->shaderstable); deinterlace_filter->shaderstable = NULL; } return GST_BASE_TRANSFORM_CLASS (parent_class)->stop (trans); }
//opengl scene, params: input texture (not the output filter->texture) static void gst_gl_deinterlace_callback (gint width, gint height, guint texture, gpointer stuff) { GstGLDeinterlace *deinterlace_filter = GST_GL_DEINTERLACE (stuff); GstGLFilter *filter = GST_GL_FILTER (stuff); GstGLFuncs *gl = GST_GL_BASE_FILTER (filter)->context->gl_vtable; guint temp; GLfloat verts[] = { -1.0, -1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0 }; GLfloat texcoords0[] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }; GLfloat texcoords1[] = { 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f }; gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); gst_gl_shader_use (deinterlace_filter->shader); if (G_UNLIKELY (deinterlace_filter->prev_tex == 0)) { gst_gl_context_gen_texture (GST_GL_BASE_FILTER (filter)->context, &deinterlace_filter->prev_tex, GST_VIDEO_INFO_FORMAT (&filter->out_info), GST_VIDEO_INFO_WIDTH (&filter->out_info), GST_VIDEO_INFO_HEIGHT (&filter->out_info)); } else { gl->ActiveTexture (GL_TEXTURE1); gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "tex_prev", 1); gl->BindTexture (GL_TEXTURE_2D, deinterlace_filter->prev_tex); } gl->ActiveTexture (GL_TEXTURE0); gst_gl_shader_set_uniform_1i (deinterlace_filter->shader, "tex", 0); gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "max_comb", 5.0f / 255.0f); gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "motion_threshold", 25.0f / 255.0f); gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "motion_sense", 30.0f / 255.0f); gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "width", GST_VIDEO_INFO_WIDTH (&filter->out_info)); gst_gl_shader_set_uniform_1f (deinterlace_filter->shader, "height", GST_VIDEO_INFO_HEIGHT (&filter->out_info)); gl->ClientActiveTexture (GL_TEXTURE0); gl->EnableClientState (GL_TEXTURE_COORD_ARRAY); gl->EnableClientState (GL_VERTEX_ARRAY); gl->VertexPointer (2, GL_FLOAT, 0, &verts); gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords0); gl->ClientActiveTexture (GL_TEXTURE1); gl->EnableClientState (GL_TEXTURE_COORD_ARRAY); gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords1); gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4); gl->DisableClientState (GL_VERTEX_ARRAY); gl->DisableClientState (GL_TEXTURE_COORD_ARRAY); gl->ClientActiveTexture (GL_TEXTURE0); gl->DisableClientState (GL_TEXTURE_COORD_ARRAY); if (texture == filter->in_tex_id) { temp = filter->in_tex_id; filter->in_tex_id = deinterlace_filter->prev_tex; deinterlace_filter->prev_tex = temp; } else { deinterlace_filter->prev_tex = texture; } }