static gboolean _init_download (GstGLDownload * download) { GstVideoFormat v_format; guint out_width, out_height; GstVideoInfo in_info; v_format = GST_VIDEO_INFO_FORMAT (&download->info); out_width = GST_VIDEO_INFO_WIDTH (&download->info); out_height = GST_VIDEO_INFO_HEIGHT (&download->info); if (download->initted) return TRUE; GST_TRACE ("initializing texture download for format %s", gst_video_format_to_string (v_format)); if (USING_GLES2 (download->context) && !USING_GLES3 (download->context)) { /* GL_RGBA is the only officially supported texture format in GLES2 */ if (v_format == GST_VIDEO_FORMAT_RGB || v_format == GST_VIDEO_FORMAT_BGR) { gst_gl_context_set_error (download->context, "Cannot download RGB " "textures in GLES2"); return FALSE; } } gst_video_info_set_format (&in_info, GST_VIDEO_FORMAT_RGBA, out_width, out_height); gst_gl_color_convert_set_format (download->convert, &in_info, &download->info); return TRUE; }
static void gst_glimage_sink_on_close (GstGLImageSink * gl_sink) { gst_gl_context_set_error (gl_sink->context, "Output window was closed"); g_atomic_int_set (&gl_sink->to_quit, 1); }
/* Called in the gl thread */ static void gst_glimage_sink_thread_init_redisplay (GstGLImageSink * gl_sink) { GError *error = NULL; gl_sink->redisplay_shader = gst_gl_shader_new (gl_sink->context); gst_gl_shader_set_vertex_source (gl_sink->redisplay_shader, redisplay_vertex_shader_str_gles2); gst_gl_shader_set_fragment_source (gl_sink->redisplay_shader, redisplay_fragment_shader_str_gles2); gst_gl_shader_compile (gl_sink->redisplay_shader, &error); if (error) { gst_gl_context_set_error (gl_sink->context, "%s", error->message); g_error_free (error); error = NULL; gst_gl_context_clear_shader (gl_sink->context); } else { gl_sink->redisplay_attr_position_loc = gst_gl_shader_get_attribute_location (gl_sink->redisplay_shader, "a_position"); gl_sink->redisplay_attr_texture_loc = gst_gl_shader_get_attribute_location (gl_sink->redisplay_shader, "a_texCoord"); } }
static void gst_gl_effects_squeeze_callback (gint width, gint height, guint texture, gpointer data) { GstGLShader *shader; GstGLFilter *filter = GST_GL_FILTER (data); GstGLEffects *effects = GST_GL_EFFECTS (data); GstGLContext *context = filter->context; GstGLFuncs *gl = context->gl_vtable; shader = g_hash_table_lookup (effects->shaderstable, "squeeze0"); if (!shader) { shader = gst_gl_shader_new (context); g_hash_table_insert (effects->shaderstable, (gchar *) "squeeze0", shader); if (USING_GLES2 (context) || USING_OPENGL3 (context)) { if (!gst_gl_shader_compile_with_default_v_and_check (shader, squeeze_fragment_source_gles2, &filter->draw_attr_position_loc, &filter->draw_attr_texture_loc)) { /* gst gl context error is already set */ GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND, ("Failed to initialize squeeze shader, %s", gst_gl_context_get_error ()), (NULL)); return; } } #if GST_GL_HAVE_OPENGL if (USING_OPENGL (context)) { if (!gst_gl_shader_compile_and_check (shader, squeeze_fragment_source_opengl, GST_GL_SHADER_FRAGMENT_SOURCE)) { gst_gl_context_set_error (context, "Failed to initialize squeeze shader"); GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return; } } #endif } #if GST_GL_HAVE_OPENGL if (USING_OPENGL (context)) { gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); } #endif gst_gl_shader_use (shader); gl->ActiveTexture (GL_TEXTURE0); if (USING_OPENGL (context)) gl->Enable (GL_TEXTURE_2D); gl->BindTexture (GL_TEXTURE_2D, texture); gst_gl_shader_set_uniform_1i (shader, "tex", 0); gst_gl_filter_draw_texture (filter, texture, width, height); }
static void _compile_shader (GstGLContext * context, GstGLShader ** shader) { GError *error = NULL; gst_gl_shader_compile (*shader, &error); if (error) { gst_gl_context_set_error (context, "%s", error->message); g_error_free (error); error = NULL; gst_gl_context_clear_shader (context); gst_object_unref (*shader); *shader = NULL; } }
static void gst_glimage_sink_on_close (GstGLImageSink * gl_sink) { GstGLWindow *window; gst_gl_context_set_error (gl_sink->context, "Output window was closed"); window = gst_gl_context_get_window (gl_sink->context); g_signal_handler_disconnect (window, gl_sink->key_sig_id); g_signal_handler_disconnect (window, gl_sink->mouse_sig_id); g_atomic_int_set (&gl_sink->to_quit, 1); gst_object_unref (window); }
void gst_gl_effects_xray_step_five (gint width, gint height, guint texture, gpointer data) { GstGLShader *shader; GstGLEffects *effects = GST_GL_EFFECTS (data); GstGLFilter *filter = GST_GL_FILTER (effects); GstGLContext *context = filter->context; GstGLFuncs *gl = context->gl_vtable; shader = g_hash_table_lookup (effects->shaderstable, "xray4"); if (!shader) { shader = gst_gl_shader_new (context); g_hash_table_insert (effects->shaderstable, "xray4", shader); } if (!gst_gl_shader_compile_and_check (shader, multiply_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) { gst_gl_context_set_error (context, "Failed to initialize multiply shader"); GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return; } gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); gst_gl_shader_use (shader); gl->ActiveTexture (GL_TEXTURE2); gl->Enable (GL_TEXTURE_2D); gl->BindTexture (GL_TEXTURE_2D, effects->midtexture[2]); gl->Disable (GL_TEXTURE_2D); gst_gl_shader_set_uniform_1i (shader, "base", 2); gl->ActiveTexture (GL_TEXTURE1); gl->Enable (GL_TEXTURE_2D); gl->BindTexture (GL_TEXTURE_2D, texture); gl->Disable (GL_TEXTURE_2D); gst_gl_shader_set_uniform_1f (shader, "alpha", (gfloat) 0.5f); gst_gl_shader_set_uniform_1i (shader, "blend", 1); gst_gl_filter_draw_texture (filter, texture, width, height); }
static void gst_gl_effects_xray_step_two (gint width, gint height, guint texture, gpointer data) { GstGLShader *shader; GstGLEffects *effects = GST_GL_EFFECTS (data); GstGLFilter *filter = GST_GL_FILTER (effects); GstGLContext *context = filter->context; GstGLFuncs *gl = context->gl_vtable; shader = g_hash_table_lookup (effects->shaderstable, "xray1"); if (!shader) { shader = gst_gl_shader_new (context); g_hash_table_insert (effects->shaderstable, "xray1", shader); } if (!kernel_ready) { fill_gaussian_kernel (gauss_kernel, 7, 1.5); kernel_ready = TRUE; } if (!gst_gl_shader_compile_and_check (shader, hconv7_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) { gst_gl_context_set_error (context, "Failed to initialize hconv7 shader"); GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return; } gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); gst_gl_shader_use (shader); gl->ActiveTexture (GL_TEXTURE1); gl->Enable (GL_TEXTURE_2D); gl->BindTexture (GL_TEXTURE_2D, texture); gl->Disable (GL_TEXTURE_2D); gst_gl_shader_set_uniform_1i (shader, "tex", 1); gst_gl_shader_set_uniform_1fv (shader, "kernel", 9, gauss_kernel); gst_gl_shader_set_uniform_1f (shader, "width", width); gst_gl_filter_draw_texture (filter, texture, width, height); }
static gboolean _2d_texture_renderer_init (GstAmc2DTextureRenderer * renderer) { GstGLFuncs *gl; gboolean res; gl = renderer->context->gl_vtable; if (renderer->initialized) return TRUE; if (!gl->CreateProgramObject && !gl->CreateProgram) { gst_gl_context_set_error (renderer->context, "Cannot perform conversion without OpenGL shaders"); return FALSE; } _gen_oes_texture (renderer->context, &renderer->oes_tex_id); res = gst_gl_context_gen_shader (renderer->context, vert_COPY_OES, frag_COPY_OES, &renderer->shader); if (!res) return FALSE; renderer->shader_attr_position_loc = gst_gl_shader_get_attribute_location (renderer->shader, "a_position"); renderer->shader_attr_texture_loc = gst_gl_shader_get_attribute_location (renderer->shader, "a_texcoord"); gst_gl_shader_use (renderer->shader); gst_gl_shader_set_uniform_1i (renderer->shader, "u_tex", 0); gst_gl_context_clear_shader (renderer->context); if (!_2d_texture_renderer_init_fbo (renderer)) return FALSE; gl->BindTexture (GL_TEXTURE_2D, 0); renderer->initialized = TRUE; return TRUE; }
static gboolean gst_gl_colorscale_gen_gl_resources (GstGLFilter * filter) { GstGLColorscale *colorscale = GST_GL_COLORSCALE (filter); if (gst_gl_context_get_gl_api (filter->context) & GST_GL_API_GLES2) { gst_gl_context_thread_add (filter->context, (GstGLContextThreadFunc) _compile_identity_shader, colorscale); if (!colorscale->shader) { gst_gl_context_set_error (filter->context, "Failed to initialize identity shader"); GST_ELEMENT_ERROR (colorscale, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return FALSE; } } return TRUE; }
static void gst_gl_effects_xray_sobel_length (gint width, gint height, guint texture, gpointer data) { GstGLShader *shader; GstGLEffects *effects = GST_GL_EFFECTS (data); GstGLFilter *filter = GST_GL_FILTER (effects); GstGLContext *context = filter->context; GstGLFuncs *gl = context->gl_vtable; shader = g_hash_table_lookup (effects->shaderstable, "xray_sob_len"); if (!shader) { shader = gst_gl_shader_new (context); g_hash_table_insert (effects->shaderstable, (gchar *) "xray_sob_len", shader); } if (!gst_gl_shader_compile_and_check (shader, sep_sobel_length_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) { gst_gl_context_set_error (context, "Failed to initialize seobel length shader"); GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return; } gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); gst_gl_shader_use (shader); gl->ActiveTexture (GL_TEXTURE1); gl->Enable (GL_TEXTURE_2D); gl->BindTexture (GL_TEXTURE_2D, texture); gl->Disable (GL_TEXTURE_2D); gst_gl_shader_set_uniform_1i (shader, "tex", 1); gst_gl_shader_set_uniform_1i (shader, "invert", TRUE); gst_gl_filter_draw_texture (filter, texture, width, height); }
static void gst_gl_effects_square_callback (gint width, gint height, guint texture, gpointer data) { GstGLShader *shader; GstGLEffects *effects = GST_GL_EFFECTS (data); GstGLFilter *filter = GST_GL_FILTER (effects); GstGLContext *context = filter->context; GstGLFuncs *gl = context->gl_vtable; shader = g_hash_table_lookup (effects->shaderstable, "square0"); if (!shader) { shader = gst_gl_shader_new (context); g_hash_table_insert (effects->shaderstable, "square0", shader); } if (!gst_gl_shader_compile_and_check (shader, square_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) { gst_gl_context_set_error (context, "Failed to initialize square shader"); GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return; } gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); gst_gl_shader_use (shader); gl->ActiveTexture (GL_TEXTURE0); gl->Enable (GL_TEXTURE_2D); gl->BindTexture (GL_TEXTURE_2D, texture); gst_gl_shader_set_uniform_1i (shader, "tex", 0); gst_gl_shader_set_uniform_1f (shader, "width", (gfloat) width / 2.0f); gst_gl_shader_set_uniform_1f (shader, "height", (gfloat) height / 2.0f); gst_gl_filter_draw_texture (filter, texture, width, height); }
/* Called in the gl thread */ static gboolean _init_upload (GstGLUpload * upload) { GstGLFuncs *gl; GstVideoFormat v_format; GstVideoInfo out_info; gl = upload->context->gl_vtable; v_format = GST_VIDEO_INFO_FORMAT (&upload->in_info); GST_INFO ("Initializing texture upload for format:%s", gst_video_format_to_string (v_format)); if (!gl->CreateProgramObject && !gl->CreateProgram) { gst_gl_context_set_error (upload->context, "Cannot upload YUV formats without OpenGL shaders"); goto error; } gst_video_info_set_format (&out_info, GST_VIDEO_FORMAT_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info), GST_VIDEO_INFO_HEIGHT (&upload->in_info)); gst_gl_color_convert_set_format (upload->convert, &upload->in_info, &out_info); upload->out_tex = gst_gl_memory_wrapped_texture (upload->context, 0, GST_VIDEO_GL_TEXTURE_TYPE_RGBA, GST_VIDEO_INFO_WIDTH (&upload->in_info), GST_VIDEO_INFO_HEIGHT (&upload->in_info), NULL, NULL); upload->initted = TRUE; return TRUE; error: return FALSE; }
/* Called by the idle function in the gl thread */ void _do_convert (GstGLContext * context, GstGLColorConvert * convert) { guint in_width, in_height, out_width, out_height; struct ConvertInfo *c_info = &convert->priv->convert_info; GstMapInfo out_info[GST_VIDEO_MAX_PLANES], in_info[GST_VIDEO_MAX_PLANES]; gboolean res = TRUE; gint i, j = 0; out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info); in_width = GST_VIDEO_INFO_WIDTH (&convert->in_info); in_height = GST_VIDEO_INFO_HEIGHT (&convert->in_info); convert->outbuf = NULL; if (!_init_convert (convert)) { convert->priv->result = FALSE; return; } convert->outbuf = gst_buffer_new (); if (!gst_gl_memory_setup_buffer (convert->context, &convert->out_info, convert->outbuf)) { convert->priv->result = FALSE; return; } gst_buffer_add_video_meta_full (convert->outbuf, 0, GST_VIDEO_INFO_FORMAT (&convert->out_info), GST_VIDEO_INFO_WIDTH (&convert->out_info), GST_VIDEO_INFO_HEIGHT (&convert->out_info), GST_VIDEO_INFO_N_PLANES (&convert->out_info), convert->out_info.offset, convert->out_info.stride); for (i = 0; i < c_info->in_n_textures; i++) { convert->priv->in_tex[i] = (GstGLMemory *) gst_buffer_peek_memory (convert->inbuf, i); if (!gst_is_gl_memory ((GstMemory *) convert->priv->in_tex[i])) { GST_ERROR_OBJECT (convert, "input must be GstGLMemory"); res = FALSE; goto out; } if (!gst_memory_map ((GstMemory *) convert->priv->in_tex[i], &in_info[i], GST_MAP_READ | GST_MAP_GL)) { GST_ERROR_OBJECT (convert, "failed to map input memory %p", convert->priv->in_tex[i]); res = FALSE; goto out; } } for (j = 0; j < c_info->out_n_textures; j++) { GstGLMemory *out_tex = (GstGLMemory *) gst_buffer_peek_memory (convert->outbuf, j); gint mem_width, mem_height; if (!gst_is_gl_memory ((GstMemory *) out_tex)) { GST_ERROR_OBJECT (convert, "output must be GstGLMemory"); res = FALSE; goto out; } mem_width = gst_gl_memory_get_texture_width (out_tex); mem_height = gst_gl_memory_get_texture_height (out_tex); if (out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE || out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA || out_width != mem_width || out_height != mem_height) { /* Luminance formats are not color renderable */ /* renderering to a framebuffer only renders the intersection of all * the attachments i.e. the smallest attachment size */ GstVideoInfo temp_info; gst_video_info_set_format (&temp_info, GST_VIDEO_FORMAT_RGBA, out_width, out_height); if (!convert->priv->out_tex[j]) convert->priv->out_tex[j] = (GstGLMemory *) gst_gl_memory_alloc (context, &temp_info, 0); } else { convert->priv->out_tex[j] = out_tex; } if (!gst_memory_map ((GstMemory *) convert->priv->out_tex[j], &out_info[j], GST_MAP_WRITE | GST_MAP_GL)) { GST_ERROR_OBJECT (convert, "failed to map output memory %p", convert->priv->out_tex[i]); res = FALSE; goto out; } } GST_LOG_OBJECT (convert, "converting to textures:%p,%p,%p,%p " "dimensions:%ux%u, from textures:%p,%p,%p,%p dimensions:%ux%u", convert->priv->out_tex[0], convert->priv->out_tex[1], convert->priv->out_tex[2], convert->priv->out_tex[3], out_width, out_height, convert->priv->in_tex[0], convert->priv->in_tex[1], convert->priv->in_tex[2], convert->priv->in_tex[3], in_width, in_height); if (!_do_convert_draw (context, convert)) res = FALSE; out: for (j--; j >= 0; j--) { GstGLMemory *out_tex = (GstGLMemory *) gst_buffer_peek_memory (convert->outbuf, j); gint mem_width, mem_height; gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &out_info[j]); mem_width = gst_gl_memory_get_texture_width (out_tex); mem_height = gst_gl_memory_get_texture_height (out_tex); if (out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE || out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA || out_width != mem_width || out_height != mem_height) { GstMapInfo to_info, from_info; if (!gst_memory_map ((GstMemory *) convert->priv->out_tex[j], &from_info, GST_MAP_READ | GST_MAP_GL)) { gst_gl_context_set_error (convert->context, "Failed to map " "intermediate memory"); res = FALSE; continue; } if (!gst_memory_map ((GstMemory *) out_tex, &to_info, GST_MAP_WRITE | GST_MAP_GL)) { gst_gl_context_set_error (convert->context, "Failed to map " "intermediate memory"); res = FALSE; continue; } gst_gl_memory_copy_into_texture (convert->priv->out_tex[j], out_tex->tex_id, out_tex->tex_type, mem_width, mem_height, GST_VIDEO_INFO_PLANE_STRIDE (&out_tex->info, out_tex->plane), FALSE); gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &from_info); gst_memory_unmap ((GstMemory *) out_tex, &to_info); } else { convert->priv->out_tex[j] = NULL; } } /* YV12 the same as I420 except planes 1+2 swapped */ if (GST_VIDEO_INFO_FORMAT (&convert->out_info) == GST_VIDEO_FORMAT_YV12) { GstMemory *mem1 = gst_buffer_get_memory (convert->outbuf, 1); GstMemory *mem2 = gst_buffer_get_memory (convert->outbuf, 2); gst_buffer_replace_memory (convert->outbuf, 1, mem2); gst_buffer_replace_memory (convert->outbuf, 2, mem1); } for (i--; i >= 0; i--) { gst_memory_unmap ((GstMemory *) convert->priv->in_tex[i], &in_info[i]); } if (!res) { gst_buffer_unref (convert->outbuf); convert->outbuf = NULL; } convert->priv->result = res; return; }
void gst_gl_effects_luma_to_curve (GstGLEffects * effects, GstGLEffectsCurve curve, gint curve_index, gint width, gint height, GLuint texture) { GstGLShader *shader; GstGLFilter *filter = GST_GL_FILTER (effects); GstGLContext *context = filter->context; GstGLFuncs *gl = context->gl_vtable; shader = g_hash_table_lookup (effects->shaderstable, "lumamap0"); if (!shader) { shader = gst_gl_shader_new (context); g_hash_table_insert (effects->shaderstable, "lumamap0", shader); } if (!gst_gl_shader_compile_and_check (shader, luma_to_curve_fragment_source, GST_GL_SHADER_FRAGMENT_SOURCE)) { gst_gl_context_set_error (context, "Failed to initialize luma to curve shader"); GST_ELEMENT_ERROR (effects, RESOURCE, NOT_FOUND, ("%s", gst_gl_context_get_error ()), (NULL)); return; } gl->MatrixMode (GL_PROJECTION); gl->LoadIdentity (); gst_gl_shader_use (shader); if (effects->curve[curve_index] == 0) { /* this parameters are needed to have a right, predictable, mapping */ gl->GenTextures (1, &effects->curve[curve_index]); gl->Enable (GL_TEXTURE_1D); gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]); gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_CLAMP); gl->TexParameteri (GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_CLAMP); gl->TexImage1D (GL_TEXTURE_1D, 0, curve.bytes_per_pixel, curve.width, 0, GL_RGB, GL_UNSIGNED_BYTE, curve.pixel_data); gl->Disable (GL_TEXTURE_1D); } gl->ActiveTexture (GL_TEXTURE2); gl->Enable (GL_TEXTURE_2D); gl->BindTexture (GL_TEXTURE_2D, texture); gst_gl_shader_set_uniform_1i (shader, "tex", 2); gl->Disable (GL_TEXTURE_2D); gl->ActiveTexture (GL_TEXTURE1); gl->Enable (GL_TEXTURE_1D); gl->BindTexture (GL_TEXTURE_1D, effects->curve[curve_index]); gst_gl_shader_set_uniform_1i (shader, "curve", 1); gl->Disable (GL_TEXTURE_1D); gst_gl_filter_draw_texture (filter, texture, width, height); }
static gboolean _2d_texture_renderer_init_fbo (GstAmc2DTextureRenderer * renderer) { GstGLFuncs *gl; GLuint fake_texture = 0; guint out_width, out_height; out_width = GST_VIDEO_INFO_WIDTH (&renderer->info); out_height = GST_VIDEO_INFO_HEIGHT (&renderer->info); gl = renderer->context->gl_vtable; if (!gl->GenFramebuffers) { /* turn off the pipeline because Frame buffer object is a not present */ gst_gl_context_set_error (renderer->context, "Context, EXT_framebuffer_object supported: no"); return FALSE; } GST_INFO ("Context, EXT_framebuffer_object supported: yes"); /* setup FBO */ gl->GenFramebuffers (1, &renderer->fbo); gl->BindFramebuffer (GL_FRAMEBUFFER, renderer->fbo); /* setup the render buffer for depth */ gl->GenRenderbuffers (1, &renderer->depth_buffer); gl->BindRenderbuffer (GL_RENDERBUFFER, renderer->depth_buffer); gl->RenderbufferStorage (GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, out_width, out_height); /* a fake texture is attached to the render FBO (cannot init without it) */ gl->GenTextures (1, &fake_texture); gl->BindTexture (GL_TEXTURE_2D, fake_texture); gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA8, out_width, out_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); /* attach the texture to the FBO to renderer to */ gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fake_texture, 0); /* attach the depth render buffer to the FBO */ gl->FramebufferRenderbuffer (GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, renderer->depth_buffer); if (!gst_gl_context_check_framebuffer_status (renderer->context)) { gst_gl_context_set_error (renderer->context, "GL framebuffer status incomplete"); return FALSE; } /* unbind the FBO */ gl->BindFramebuffer (GL_FRAMEBUFFER, 0); gl->DeleteTextures (1, &fake_texture); return TRUE; }
//Called in the gl thread static void gst_gl_bumper_init_resources (GstGLFilter * filter) { GstGLBumper *bumper = GST_GL_BUMPER (filter); GstGLContext *context = filter->context; const GstGLFuncs *gl = context->gl_vtable; png_structp png_ptr; png_infop info_ptr; png_uint_32 width = 0; png_uint_32 height = 0; gint bit_depth = 0; gint color_type = 0; gint interlace_type = 0; png_FILE_p fp = NULL; guint y = 0; guchar *raw_data = NULL; guchar **rows = NULL; png_byte magic[8]; gint n_read; if (!bumper->location) { gst_gl_context_set_error (context, "A filename is required"); return; } /* BEGIN load png image file */ if ((fp = fopen (bumper->location, "rb")) == NULL) LOAD_ERROR (context, "file not found"); /* Read magic number */ n_read = fread (magic, 1, sizeof (magic), fp); if (n_read != sizeof (magic)) { fclose (fp); LOAD_ERROR (context, "can't read PNG magic number"); } /* Check for valid magic number */ if (png_sig_cmp (magic, 0, sizeof (magic))) { fclose (fp); LOAD_ERROR (context, "not a valid PNG image"); } png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); if (png_ptr == NULL) { fclose (fp); LOAD_ERROR (context, "failed to initialize the png_struct"); } png_set_error_fn (png_ptr, NULL, NULL, user_warning_fn); info_ptr = png_create_info_struct (png_ptr); if (info_ptr == NULL) { fclose (fp); png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL); LOAD_ERROR (context, "failed to initialize the memory for image information"); } png_init_io (png_ptr, fp); png_set_sig_bytes (png_ptr, sizeof (magic)); png_read_info (png_ptr, info_ptr); png_get_IHDR (png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, &interlace_type, int_p_NULL, int_p_NULL); if (color_type != PNG_COLOR_TYPE_RGB) { fclose (fp); png_destroy_read_struct (&png_ptr, png_infopp_NULL, png_infopp_NULL); LOAD_ERROR (context, "color type is not rgb"); } raw_data = (guchar *) malloc (sizeof (guchar) * width * height * 3); rows = (guchar **) malloc (sizeof (guchar *) * height); for (y = 0; y < height; ++y) rows[y] = (guchar *) (raw_data + y * width * 3); png_read_image (png_ptr, rows); free (rows); png_read_end (png_ptr, info_ptr); png_destroy_read_struct (&png_ptr, &info_ptr, png_infopp_NULL); fclose (fp); /* END load png image file */ bumper->bumpmap_width = width; bumper->bumpmap_height = height; gl->GenTextures (1, &bumper->bumpmap); gl->BindTexture (GL_TEXTURE_2D, bumper->bumpmap); gl->TexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, bumper->bumpmap_width, bumper->bumpmap_height, 0, GL_RGB, GL_UNSIGNED_BYTE, raw_data); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); gl->TexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); free (raw_data); }
/* Called in the gl thread */ static gboolean _init_convert (GstGLColorConvert * convert) { GstGLFuncs *gl; gboolean res; struct ConvertInfo *info = &convert->priv->convert_info; gint i; gl = convert->context->gl_vtable; if (convert->initted) return TRUE; GST_INFO ("Initializing color conversion from %s to %s", gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)), gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info))); if (!gl->CreateProgramObject && !gl->CreateProgram) { gst_gl_context_set_error (convert->context, "Cannot perform color conversion without OpenGL shaders"); goto error; } if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) { if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) { _RGB_to_RGB (convert); } } if (GST_VIDEO_INFO_IS_YUV (&convert->in_info)) { if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) { _YUV_to_RGB (convert); } } if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) { if (GST_VIDEO_INFO_IS_YUV (&convert->out_info)) { _RGB_to_YUV (convert); } } if (GST_VIDEO_INFO_IS_RGB (&convert->in_info)) { if (GST_VIDEO_INFO_IS_GRAY (&convert->out_info)) { _RGB_to_GRAY (convert); } } if (GST_VIDEO_INFO_IS_GRAY (&convert->in_info)) { if (GST_VIDEO_INFO_IS_RGB (&convert->out_info)) { _GRAY_to_RGB (convert); } } if (!info->frag_prog || info->in_n_textures == 0 || info->out_n_textures == 0) goto unhandled_format; /* multiple draw targets not supported on GLES2...yet */ if (info->out_n_textures > 1 && (!gl->DrawBuffers || USING_GLES2 (convert->context))) { g_free (info->frag_prog); GST_ERROR ("Conversion requires output to multiple draw buffers"); goto incompatible_api; } /* Requires reading from a RG/LA framebuffer... */ if (USING_GLES2 (convert->context) && (GST_VIDEO_INFO_FORMAT (&convert->out_info) == GST_VIDEO_FORMAT_YUY2 || GST_VIDEO_INFO_FORMAT (&convert->out_info) == GST_VIDEO_FORMAT_UYVY)) { g_free (info->frag_prog); GST_ERROR ("Conversion requires reading with an unsupported format"); goto incompatible_api; } res = gst_gl_context_gen_shader (convert->context, text_vertex_shader, info->frag_prog, &convert->shader); g_free (info->frag_prog); if (!res) goto error; convert->shader_attr_position_loc = gst_gl_shader_get_attribute_location (convert->shader, "a_position"); convert->shader_attr_texture_loc = gst_gl_shader_get_attribute_location (convert->shader, "a_texcoord"); gst_gl_shader_use (convert->shader); if (info->cms_offset && info->cms_coeff1 && info->cms_coeff2 && info->cms_coeff3) { gst_gl_shader_set_uniform_3fv (convert->shader, "offset", 1, info->cms_offset); gst_gl_shader_set_uniform_3fv (convert->shader, "coeff1", 1, info->cms_coeff1); gst_gl_shader_set_uniform_3fv (convert->shader, "coeff2", 1, info->cms_coeff2); gst_gl_shader_set_uniform_3fv (convert->shader, "coeff3", 1, info->cms_coeff3); } for (i = info->in_n_textures; i >= 0; i--) { if (info->shader_tex_names[i]) gst_gl_shader_set_uniform_1i (convert->shader, info->shader_tex_names[i], i); } gst_gl_shader_set_uniform_1f (convert->shader, "width", GST_VIDEO_INFO_WIDTH (&convert->in_info)); gst_gl_shader_set_uniform_1f (convert->shader, "height", GST_VIDEO_INFO_HEIGHT (&convert->in_info)); if (info->chroma_sampling[0] > 0.0f && info->chroma_sampling[1] > 0.0f) { gst_gl_shader_set_uniform_2fv (convert->shader, "chroma_sampling", 1, info->chroma_sampling); } gst_gl_context_clear_shader (convert->context); if (!_init_convert_fbo (convert)) { goto error; } gl->BindTexture (GL_TEXTURE_2D, 0); convert->initted = TRUE; return TRUE; unhandled_format: gst_gl_context_set_error (convert->context, "Don't know how to convert from %s to %s", gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)), gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info))); error: return FALSE; incompatible_api: { gst_gl_context_set_error (convert->context, "Converting from %s to %s requires " "functionality that the current OpenGL setup does not support", gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->in_info)), gst_video_format_to_string (GST_VIDEO_INFO_FORMAT (&convert->out_info))); return FALSE; } }
static void _gl_mem_copy_thread (GstGLContext * context, gpointer data) { const GstGLFuncs *gl; GstGLMemoryPBOCopyParams *copy_params; GstGLMemoryPBO *src; guint tex_id; guint out_tex_target; GLuint fboId; gsize out_width, out_height, out_stride; GLuint out_gl_format, out_gl_type; GLuint in_gl_format, in_gl_type; gsize in_size, out_size; copy_params = (GstGLMemoryPBOCopyParams *) data; src = copy_params->src; tex_id = copy_params->tex_id; out_tex_target = gst_gl_texture_target_to_gl (copy_params->tex_target); out_width = copy_params->out_width; out_height = copy_params->out_height; out_stride = copy_params->out_stride; gl = context->gl_vtable; out_gl_format = gst_gl_format_from_gl_texture_type (copy_params->out_format); out_gl_type = GL_UNSIGNED_BYTE; if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) out_gl_type = GL_UNSIGNED_SHORT_5_6_5; in_gl_format = gst_gl_format_from_gl_texture_type (src->mem.tex_type); in_gl_type = GL_UNSIGNED_BYTE; if (src->mem.tex_type == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) in_gl_type = GL_UNSIGNED_SHORT_5_6_5; if (!gl->GenFramebuffers) { gst_gl_context_set_error (context, "Context, EXT_framebuffer_object not supported"); goto error; } in_size = GL_MEM_HEIGHT (src) * GL_MEM_STRIDE (src); out_size = out_height * out_stride; if (copy_params->respecify) { if (in_size != out_size) { GST_ERROR ("Cannot copy between textures with backing data of different" "sizes. input %" G_GSIZE_FORMAT " output %" G_GSIZE_FORMAT, in_size, out_size); goto error; } } if (!tex_id) { guint internal_format; guint out_gl_type; out_gl_type = GL_UNSIGNED_BYTE; if (copy_params->out_format == GST_VIDEO_GL_TEXTURE_TYPE_RGB16) out_gl_type = GL_UNSIGNED_SHORT_5_6_5; internal_format = gst_gl_sized_gl_format_from_gl_format_type (context, out_gl_format, out_gl_type); tex_id = _new_texture (context, out_tex_target, internal_format, out_gl_format, out_gl_type, copy_params->out_width, copy_params->out_height); } if (!tex_id) { GST_WARNING ("Could not create GL texture with context:%p", context); } GST_LOG ("copying memory %p, tex %u into texture %i", src, src->mem.tex_id, tex_id); /* FIXME: try and avoid creating and destroying fbo's every copy... */ /* create a framebuffer object */ gl->GenFramebuffers (1, &fboId); gl->BindFramebuffer (GL_FRAMEBUFFER, fboId); gl->FramebufferTexture2D (GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, gst_gl_texture_target_to_gl (src->mem.tex_target), src->mem.tex_id, 0); // if (!gst_gl_context_check_framebuffer_status (src->mem.mem.context)) // goto fbo_error; gl->BindTexture (out_tex_target, tex_id); if (copy_params->respecify) { GstMapInfo pbo_info; if (!gl->GenBuffers || !src->pbo) { gst_gl_context_set_error (context, "Cannot reinterpret texture contents " "without pixel buffer objects"); gl->BindTexture (out_tex_target, 0); goto fbo_error; } if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2 && (in_gl_format != GL_RGBA || in_gl_type != GL_UNSIGNED_BYTE)) { gst_gl_context_set_error (context, "Cannot copy non RGBA/UNSIGNED_BYTE " "textures on GLES2"); gl->BindTexture (out_tex_target, 0); goto fbo_error; } GST_TRACE ("copying texture data with size of %u*%u*%u", gst_gl_format_type_n_bytes (in_gl_format, in_gl_type), src->mem.tex_width, GL_MEM_HEIGHT (src)); /* copy tex */ _read_pixels_to_pbo (src); src->pbo->target = GL_PIXEL_UNPACK_BUFFER; if (!gst_memory_map (GST_MEMORY_CAST (src->pbo), &pbo_info, GST_MAP_READ | GST_MAP_GL)) { GST_CAT_ERROR (GST_CAT_GL_MEMORY, "Failed to map pbo for reading"); goto fbo_error; } gl->TexSubImage2D (out_tex_target, 0, 0, 0, out_width, out_height, out_gl_format, out_gl_type, 0); gst_memory_unmap (GST_MEMORY_CAST (src->pbo), &pbo_info); } else { /* different sizes */ gst_gl_memory_copy_teximage (GST_GL_MEMORY_CAST (src), tex_id, copy_params->tex_target, copy_params->out_format, out_width, out_height); } gl->BindTexture (out_tex_target, 0); gl->BindFramebuffer (GL_FRAMEBUFFER, 0); gl->DeleteFramebuffers (1, &fboId); copy_params->tex_id = tex_id; copy_params->result = TRUE; return; /* ERRORS */ fbo_error: { gl->DeleteFramebuffers (1, &fboId); copy_params->tex_id = 0; copy_params->result = FALSE; return; } error: { copy_params->result = FALSE; return; } }