static void gst_gl_filter_stop_gl (GstGLDisplay * display, gpointer data) { GstGLFilter *filter = GST_GL_FILTER (data); GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); filter_class->display_reset_cb (filter); }
static void gst_gl_filter_start_gl (GstGLContext * context, gpointer data) { GstGLFilter *filter = GST_GL_FILTER (data); GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); filter_class->display_init_cb (filter); }
static gboolean gst_gl_filter_do_transform (GstGLFilter * filter, GstGLBuffer * inbuf, GstGLBuffer * outbuf) { GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); filter_class->filter (filter, inbuf, outbuf); return TRUE; }
static gboolean gst_gl_filter_start (GstBaseTransform * bt) { GstGLFilter *filter = GST_GL_FILTER (bt); GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); if (filter_class->onStart) filter_class->onStart (filter); return TRUE; }
static gboolean gst_gl_filter_start (GstBaseTransform * bt) { GstGLFilter *filter = GST_GL_FILTER (bt); GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); if (!gst_gl_ensure_display (filter, &filter->display)) return FALSE; if (filter_class->onStart) filter_class->onStart (filter); return TRUE; }
static void gst_gl_filter_reset (GstGLFilter * filter) { GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); if (filter->upload) { gst_object_unref (filter->upload); filter->upload = NULL; } if (filter->download) { gst_object_unref (filter->download); filter->download = NULL; } if (filter->context) { if (filter_class->onReset) filter_class->onReset (filter); if (filter_class->display_reset_cb != NULL) { gst_gl_context_thread_add (filter->context, gst_gl_filter_stop_gl, filter); } //blocking call, delete the FBO if (filter->fbo != 0) { gst_gl_context_del_fbo (filter->context, filter->fbo, filter->depthbuffer); } gst_object_unref (filter->context); filter->context = NULL; } if (filter->display) { gst_object_unref (filter->display); filter->display = NULL; } filter->fbo = 0; filter->depthbuffer = 0; filter->default_shader = NULL; if (filter->other_context) gst_object_unref (filter->other_context); filter->other_context = NULL; if (filter->context) gst_object_unref (filter->context); filter->context = NULL; }
static gboolean gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, GstCaps * outcaps) { GstGLFilter *filter = GST_GL_FILTER (bt); gboolean ret = FALSE; GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); ret = gst_gl_buffer_parse_caps (outcaps, &filter->width, &filter->height); if (filter_class->set_caps) filter_class->set_caps (filter, incaps, outcaps); if (!ret) { GST_DEBUG ("bad caps"); return FALSE; } GST_DEBUG ("set_caps %d %d", filter->width, filter->height); return ret; }
static GstFlowReturn gst_gl_filter_prepare_output_buffer (GstBaseTransform * trans, GstBuffer * inbuf, gint size, GstCaps * caps, GstBuffer ** buf) { GstGLFilter *filter = NULL; GstGLBuffer *gl_inbuf = GST_GL_BUFFER (inbuf); GstGLBuffer *gl_outbuf = NULL; filter = GST_GL_FILTER (trans); if (filter->display == NULL) { GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); filter->display = g_object_ref (gl_inbuf->display); //blocking call, generate a FBO gst_gl_display_gen_fbo (filter->display, filter->width, filter->height, &filter->fbo, &filter->depthbuffer); if (filter_class->display_init_cb != NULL) { gst_gl_display_thread_add (filter->display, gst_gl_filter_start_gl, filter); } if (filter_class->onInitFBO) filter_class->onInitFBO (filter); } gl_outbuf = gst_gl_buffer_new (filter->display, filter->width, filter->height); *buf = GST_BUFFER (gl_outbuf); gst_buffer_set_caps (*buf, caps); if (gl_outbuf->texture) return GST_FLOW_OK; else return GST_FLOW_UNEXPECTED; }
static GstFlowReturn gst_gl_filter_transform (GstBaseTransform * bt, GstBuffer * inbuf, GstBuffer * outbuf) { GstGLFilter *filter; GstGLFilterClass *filter_class; filter = GST_GL_FILTER (bt); filter_class = GST_GL_FILTER_GET_CLASS (bt); if (!gst_gl_ensure_display (filter, &filter->display)) return GST_FLOW_NOT_NEGOTIATED; g_assert (filter_class->filter || filter_class->filter_texture); if (filter_class->filter) filter_class->filter (filter, inbuf, outbuf); else if (filter_class->filter_texture) gst_gl_filter_filter_texture (filter, inbuf, outbuf); return GST_FLOW_OK; }
static void gst_gl_filter_reset (GstGLFilter * filter) { GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); if (filter->display) { if (filter_class->onReset) filter_class->onReset (filter); if (filter_class->display_reset_cb != NULL) { gst_gl_display_thread_add (filter->display, gst_gl_filter_stop_gl, filter); } //blocking call, delete the FBO gst_gl_display_del_fbo (filter->display, filter->fbo, filter->depthbuffer); g_object_unref (filter->display); filter->display = NULL; } filter->width = 0; filter->height = 0; filter->fbo = 0; filter->depthbuffer = 0; }
static gboolean gst_gl_filter_set_caps (GstBaseTransform * bt, GstCaps * incaps, GstCaps * outcaps) { GstGLFilter *filter; GstGLFilterClass *filter_class; filter = GST_GL_FILTER (bt); filter_class = GST_GL_FILTER_GET_CLASS (filter); if (!gst_video_info_from_caps (&filter->in_info, incaps)) goto wrong_caps; if (!gst_video_info_from_caps (&filter->out_info, outcaps)) goto wrong_caps; if (filter_class->set_caps) { if (!filter_class->set_caps (filter, incaps, outcaps)) goto error; } GST_DEBUG ("set_caps %dx%d", GST_VIDEO_INFO_WIDTH (&filter->out_info), GST_VIDEO_INFO_HEIGHT (&filter->out_info)); return TRUE; /* ERRORS */ wrong_caps: { GST_WARNING ("Wrong caps"); return FALSE; } error: { return FALSE; } }
/** * gst_gl_filter_filter_texture: * @filter: a #GstGLFilter * @inbuf: an input buffer * @outbuf: an output buffer * * Perform automatic upload if needed, call filter_texture vfunc and then an * automatic download if needed. * * Returns: whether the transformation succeeded */ gboolean gst_gl_filter_filter_texture (GstGLFilter * filter, GstBuffer * inbuf, GstBuffer * outbuf) { GstGLFilterClass *filter_class; guint in_tex, out_tex; GstVideoFrame out_frame; gboolean ret, out_gl_mem; GstVideoGLTextureUploadMeta *out_tex_upload_meta; filter_class = GST_GL_FILTER_GET_CLASS (filter); if (!gst_gl_upload_perform_with_buffer (filter->upload, inbuf, &in_tex)) return FALSE; if (!gst_video_frame_map (&out_frame, &filter->out_info, outbuf, GST_MAP_WRITE | GST_MAP_GL)) { ret = FALSE; goto inbuf_error; } out_gl_mem = gst_is_gl_memory (out_frame.map[0].memory); out_tex_upload_meta = gst_buffer_get_video_gl_texture_upload_meta (outbuf); if (out_gl_mem) { out_tex = *(guint *) out_frame.data[0]; } else { GST_LOG ("Output Buffer does not contain correct memory, " "attempting to wrap for download"); if (!filter->download) { filter->download = gst_gl_download_new (filter->context); if (!gst_gl_download_init_format (filter->download, GST_VIDEO_FRAME_FORMAT (&out_frame), GST_VIDEO_FRAME_WIDTH (&out_frame), GST_VIDEO_FRAME_HEIGHT (&out_frame))) { GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, ("%s", "Failed to init download format"), (NULL)); ret = FALSE; goto error; } } out_tex = filter->out_tex_id; } GST_DEBUG ("calling filter_texture with textures in:%i out:%i", in_tex, out_tex); g_assert (filter_class->filter_texture); ret = filter_class->filter_texture (filter, in_tex, out_tex); if (!out_gl_mem && !out_tex_upload_meta) { if (!gst_gl_download_perform_with_data (filter->download, out_tex, out_frame.data)) { GST_ELEMENT_ERROR (filter, RESOURCE, NOT_FOUND, ("%s", "Failed to download video frame"), (NULL)); ret = FALSE; goto error; } } error: gst_video_frame_unmap (&out_frame); inbuf_error: gst_gl_upload_release_buffer (filter->upload); return ret; }
static gboolean gst_gl_filter_decide_allocation (GstBaseTransform * trans, GstQuery * query) { GstGLFilter *filter = GST_GL_FILTER (trans); GstGLFilterClass *filter_class = GST_GL_FILTER_GET_CLASS (filter); GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; guint min, max, size; gboolean update_pool; guint idx; GError *error = NULL; guint in_width, in_height, out_width, out_height; gst_query_parse_allocation (query, &caps, NULL); if (gst_query_get_n_allocation_pools (query) > 0) { gst_query_parse_nth_allocation_pool (query, 0, &pool, &size, &min, &max); update_pool = TRUE; } else { GstVideoInfo vinfo; gst_video_info_init (&vinfo); gst_video_info_from_caps (&vinfo, caps); size = vinfo.size; min = max = 0; update_pool = FALSE; } if (!gst_gl_ensure_display (filter, &filter->display)) return FALSE; if (gst_query_find_allocation_meta (query, GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, &idx)) { GstGLContext *context; const GstStructure *upload_meta_params; gst_query_parse_nth_allocation_meta (query, idx, &upload_meta_params); if (gst_structure_get (upload_meta_params, "gst.gl.GstGLContext", GST_GL_TYPE_CONTEXT, &context, NULL) && context) { GstGLContext *old = filter->context; filter->context = context; if (old) gst_object_unref (old); } } if (!filter->context) { filter->context = gst_gl_context_new (filter->display); if (!gst_gl_context_create (filter->context, filter->other_context, &error)) goto context_error; } in_width = GST_VIDEO_INFO_WIDTH (&filter->in_info); in_height = GST_VIDEO_INFO_HEIGHT (&filter->in_info); out_width = GST_VIDEO_INFO_WIDTH (&filter->out_info); out_height = GST_VIDEO_INFO_HEIGHT (&filter->out_info); if (!filter->upload) { filter->upload = gst_gl_upload_new (filter->context); gst_gl_upload_init_format (filter->upload, filter->in_info, filter->out_info); } //blocking call, generate a FBO if (!gst_gl_context_gen_fbo (filter->context, out_width, out_height, &filter->fbo, &filter->depthbuffer)) goto context_error; gst_gl_context_gen_texture (filter->context, &filter->in_tex_id, GST_VIDEO_FORMAT_RGBA, in_width, in_height); gst_gl_context_gen_texture (filter->context, &filter->out_tex_id, GST_VIDEO_FORMAT_RGBA, out_width, out_height); if (filter_class->display_init_cb != NULL) { gst_gl_context_thread_add (filter->context, gst_gl_filter_start_gl, filter); } if (filter_class->onInitFBO) { if (!filter_class->onInitFBO (filter)) goto error; } if (!pool) pool = gst_gl_buffer_pool_new (filter->context); config = gst_buffer_pool_get_config (pool); gst_buffer_pool_config_set_params (config, caps, size, min, max); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); gst_buffer_pool_set_config (pool, config); 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); gst_object_unref (pool); return TRUE; context_error: { GST_ELEMENT_ERROR (trans, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); return FALSE; } error: { GST_ELEMENT_ERROR (trans, LIBRARY, INIT, ("Subclass failed to initialize."), (NULL)); return FALSE; } }