static gboolean ensure_context (GstGLStereoSplit * self) { GError *error = NULL; if (!gst_gl_ensure_element_data (self, &self->display, &self->other_context)) return FALSE; gst_gl_display_filter_gl_api (self->display, SUPPORTED_GL_APIS); _find_local_gl_context (self); if (!self->context) { GST_OBJECT_LOCK (self->display); do { if (self->context) gst_object_unref (self->context); /* just get a GL context. we don't care */ self->context = gst_gl_display_get_gl_context_for_thread (self->display, NULL); if (!self->context) { if (!gst_gl_display_create_context (self->display, self->other_context, &self->context, &error)) { GST_OBJECT_UNLOCK (self->display); goto context_error; } } } while (!gst_gl_display_add_context (self->display, self->context)); GST_OBJECT_UNLOCK (self->display); } return TRUE; context_error: { GST_ELEMENT_ERROR (self, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); g_clear_error (&error); return FALSE; } }
/** * gst_vaapi_plugin_base_create_gl_context: * @plugin: a #GstVaapiPluginBase * * It queries downstream and upstream for a #GstGLDisplay and a other * #GstGLContext. If not found, a new #GstGLDisplay and #GstGLContext * are created, if it is possible. * * Returns: (transfer full) a new created #GstGLContext or %NULL **/ GstObject * gst_vaapi_plugin_base_create_gl_context (GstVaapiPluginBase * plugin) { #if USE_GST_GL_HELPERS GstGLContext *gl_other_context, *gl_context = NULL; GstGLDisplay *gl_display; gst_gl_ensure_element_data (plugin, (GstGLDisplay **) & plugin->gl_display, (GstGLContext **) & plugin->gl_other_context); gl_display = (GstGLDisplay *) plugin->gl_display; if (!gl_display || gst_gl_display_get_handle_type (gl_display) == GST_GL_DISPLAY_TYPE_ANY) { gst_object_replace (&plugin->gl_display, NULL); gst_object_replace (&plugin->gl_other_context, NULL); return NULL; } gl_other_context = (GstGLContext *) plugin->gl_other_context; GST_INFO_OBJECT (plugin, "creating a new GstGL context"); GST_OBJECT_LOCK (gl_display); do { if (gl_context) gst_object_unref (gl_context); gl_context = gst_gl_display_get_gl_context_for_thread (gl_display, NULL); if (!gl_context) { if (!gst_gl_display_create_context (gl_display, gl_other_context, &gl_context, NULL)) break; } } while (!gst_gl_display_add_context (gl_display, gl_context)); GST_OBJECT_UNLOCK (gl_display); return GST_OBJECT_CAST (gl_context); #else return NULL; #endif }
static GstFlowReturn gst_glimage_sink_render (GstBaseSink * bsink, GstBuffer * buf) { GstGLImageSink *glimage_sink = NULL; GstGLBuffer *gl_buffer = NULL; glimage_sink = GST_GLIMAGE_SINK (bsink); GST_INFO ("buffer size: %d", GST_BUFFER_SIZE (buf)); //is gl if (glimage_sink->is_gl) { //increment gl buffer ref before storage gl_buffer = GST_GL_BUFFER (gst_buffer_ref (buf)); //if glimagesink has not the display yet if (glimage_sink->display == NULL) { glimage_sink->display = g_object_ref (gl_buffer->display); gst_gl_display_set_client_reshape_callback (glimage_sink->display, glimage_sink->clientReshapeCallback); gst_gl_display_set_client_draw_callback (glimage_sink->display, glimage_sink->clientDrawCallback); } } //is not gl else { //if glimagesink has not the display yet if (glimage_sink->display == NULL) { //create a display glimage_sink->display = gst_gl_display_new (); //init opengl context gst_gl_display_create_context (glimage_sink->display, glimage_sink->width, glimage_sink->height, 0); //init colorspace conversion if needed gst_gl_display_init_upload (glimage_sink->display, glimage_sink->format, glimage_sink->width, glimage_sink->height, glimage_sink->width, glimage_sink->height); gst_gl_display_set_client_reshape_callback (glimage_sink->display, glimage_sink->clientReshapeCallback); gst_gl_display_set_client_draw_callback (glimage_sink->display, glimage_sink->clientDrawCallback); } //blocking call gl_buffer = gst_gl_buffer_new (glimage_sink->display, glimage_sink->width, glimage_sink->height); //blocking call gst_gl_display_do_upload (glimage_sink->display, gl_buffer->texture, glimage_sink->width, glimage_sink->height, GST_BUFFER_DATA (buf)); //gl_buffer is created in this block, so the gl buffer is already referenced } if (glimage_sink->window_id != glimage_sink->new_window_id) { glimage_sink->window_id = glimage_sink->new_window_id; gst_gl_display_set_window_id (glimage_sink->display, glimage_sink->window_id); } //the buffer is cleared when an other comes in if (glimage_sink->stored_buffer) { gst_buffer_unref (GST_BUFFER_CAST (glimage_sink->stored_buffer)); glimage_sink->stored_buffer = NULL; } //store current buffer glimage_sink->stored_buffer = gl_buffer; //redisplay opengl scene if (gl_buffer->texture && gst_gl_display_redisplay (glimage_sink->display, gl_buffer->texture, gl_buffer->width, gl_buffer->height, glimage_sink->keep_aspect_ratio)) return GST_FLOW_OK; else return GST_FLOW_UNEXPECTED; }
static GstStateChangeReturn gst_glimage_sink_change_state (GstElement * element, GstStateChange transition) { GstGLImageSink *glimage_sink; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GST_DEBUG ("change state"); glimage_sink = GST_GLIMAGE_SINK (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: if (!glimage_sink->display) { gboolean ok = FALSE; glimage_sink->display = gst_gl_display_new (); /* init opengl context */ ok = gst_gl_display_create_context (glimage_sink->display, 0); if (!ok) { GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, GST_GL_DISPLAY_ERR_MSG (glimage_sink->display), (NULL)); if (glimage_sink->display) { g_object_unref (glimage_sink->display); glimage_sink->display = NULL; } return GST_STATE_CHANGE_FAILURE; } } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: { if (glimage_sink->stored_buffer) { gst_buffer_unref (GST_BUFFER_CAST (glimage_sink->stored_buffer)); glimage_sink->stored_buffer = NULL; } if (glimage_sink->display) { g_object_unref (glimage_sink->display); glimage_sink->display = NULL; } glimage_sink->window_id = 0; //but do not reset glimage_sink->new_window_id glimage_sink->fps_n = 0; glimage_sink->fps_d = 1; GST_VIDEO_SINK_WIDTH (glimage_sink) = 0; GST_VIDEO_SINK_HEIGHT (glimage_sink) = 0; } break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }
static gboolean gst_gl_base_mixer_decide_allocation (GstGLBaseMixer * mix, GstQuery * query) { GstGLBaseMixerClass *mix_class = GST_GL_BASE_MIXER_GET_CLASS (mix); GError *error = NULL; gboolean ret = TRUE; if (!gst_gl_ensure_element_data (mix, &mix->display, &mix->priv->other_context)) return FALSE; gst_gl_display_filter_gl_api (mix->display, mix_class->supported_gl_api); _find_local_gl_context (mix); if (!mix->context) { GST_OBJECT_LOCK (mix->display); do { if (mix->context) { gst_object_unref (mix->context); mix->context = NULL; } /* just get a GL context. we don't care */ mix->context = gst_gl_display_get_gl_context_for_thread (mix->display, NULL); if (!mix->context) { if (!gst_gl_display_create_context (mix->display, mix->priv->other_context, &mix->context, &error)) { GST_OBJECT_UNLOCK (mix->display); goto context_error; } } } while (!gst_gl_display_add_context (mix->display, mix->context)); GST_OBJECT_UNLOCK (mix->display); } { GstGLAPI current_gl_api = gst_gl_context_get_gl_api (mix->context); if ((current_gl_api & mix_class->supported_gl_api) == 0) goto unsupported_gl_api; } if (mix_class->decide_allocation) ret = mix_class->decide_allocation (mix, query); return ret; unsupported_gl_api: { GstGLAPI gl_api = gst_gl_context_get_gl_api (mix->context); gchar *gl_api_str = gst_gl_api_to_string (gl_api); gchar *supported_gl_api_str = gst_gl_api_to_string (mix_class->supported_gl_api); GST_ELEMENT_ERROR (mix, RESOURCE, BUSY, ("GL API's not compatible context: %s supported: %s", gl_api_str, supported_gl_api_str), (NULL)); g_free (supported_gl_api_str); g_free (gl_api_str); return FALSE; } context_error: { GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); g_clear_error (&error); return FALSE; } }
static GstStateChangeReturn gst_visual_gl_change_state (GstElement * element, GstStateChange transition) { GstVisualGL *visual = GST_VISUAL_GL (element); GstStateChangeReturn ret; switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: { GstElement *parent = GST_ELEMENT (gst_element_get_parent (visual)); GstStructure *structure = NULL; GstQuery *query = NULL; gboolean isPerformed = FALSE; gchar *name; if (!parent) { GST_ELEMENT_ERROR (visual, CORE, STATE_CHANGE, (NULL), ("A parent bin is required")); return FALSE; } name = gst_element_get_name (visual); structure = gst_structure_new (name, NULL); query = gst_query_new_application (GST_QUERY_CUSTOM, structure); g_free (name); isPerformed = gst_element_query (parent, query); if (isPerformed) { const GValue *id_value = gst_structure_get_value (structure, "gstgldisplay"); if (G_VALUE_HOLDS_POINTER (id_value)) /* at least one gl element is after in our gl chain */ visual->display = gst_object_ref (GST_GL_DISPLAY (g_value_get_pointer (id_value))); else { /* this gl filter is a sink in terms of the gl chain */ visual->display = gst_gl_display_new (); gst_gl_display_create_context (visual->display, 0); //TODO visual->external_gl_context); } gst_visual_gl_reset (visual); visual->actor = visual_actor_new (GST_VISUAL_GL_GET_CLASS (visual)->plugin->info-> plugname); visual->video = visual_video_new (); visual->audio = visual_audio_new (); if (!visual->actor || !visual->video) goto actor_setup_failed; gst_gl_display_thread_add (visual->display, (GstGLDisplayThreadFunc) actor_setup, visual); if (visual->actor_setup_result != 0) goto actor_setup_failed; else visual_actor_set_video (visual->actor, visual->video); } gst_query_unref (query); gst_object_unref (GST_OBJECT (parent)); if (!isPerformed) return GST_STATE_CHANGE_FAILURE; } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: { if (visual->fbo) { gst_gl_display_del_fbo (visual->display, visual->fbo, visual->depthbuffer); visual->fbo = 0; visual->depthbuffer = 0; } if (visual->midtexture) { gst_gl_display_del_texture (visual->display, visual->midtexture, visual->width, visual->height); visual->midtexture = 0; } if (visual->display) { gst_object_unref (visual->display); visual->display = NULL; } gst_visual_gl_clear_actors (visual); } break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; /* ERRORS */ actor_setup_failed: { GST_ELEMENT_ERROR (visual, LIBRARY, INIT, (NULL), ("could not set up actor")); gst_visual_gl_clear_actors (visual); return GST_STATE_CHANGE_FAILURE; } }
static gboolean gst_gl_test_src_decide_allocation (GstBaseSrc * basesrc, GstQuery * query) { GstGLTestSrc *src = GST_GL_TEST_SRC (basesrc); GstBufferPool *pool = NULL; GstStructure *config; GstCaps *caps; guint min, max, size; gboolean update_pool; GError *error = NULL; if (!gst_gl_ensure_element_data (src, &src->display, &src->other_context)) return FALSE; gst_gl_display_filter_gl_api (src->display, SUPPORTED_GL_APIS); _find_local_gl_context (src); if (!src->context) { GST_OBJECT_LOCK (src->display); do { if (src->context) { gst_object_unref (src->context); src->context = NULL; } /* just get a GL context. we don't care */ src->context = gst_gl_display_get_gl_context_for_thread (src->display, NULL); if (!src->context) { if (!gst_gl_display_create_context (src->display, src->other_context, &src->context, &error)) { GST_OBJECT_UNLOCK (src->display); goto context_error; } } } while (!gst_gl_display_add_context (src->display, src->context)); GST_OBJECT_UNLOCK (src->display); } if ((gst_gl_context_get_gl_api (src->context) & SUPPORTED_GL_APIS) == 0) goto unsupported_gl_api; gst_gl_context_thread_add (src->context, (GstGLContextThreadFunc) _src_generate_fbo_gl, src); if (!src->fbo) goto context_error; 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 (!pool || !GST_IS_GL_BUFFER_POOL (pool)) { /* can't use this pool */ if (pool) gst_object_unref (pool); pool = gst_gl_buffer_pool_new (src->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); if (gst_query_find_allocation_meta (query, GST_GL_SYNC_META_API_TYPE, NULL)) gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_GL_SYNC_META); gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_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_gl_test_src_init_shader (src); gst_object_unref (pool); return TRUE; unsupported_gl_api: { GstGLAPI gl_api = gst_gl_context_get_gl_api (src->context); gchar *gl_api_str = gst_gl_api_to_string (gl_api); gchar *supported_gl_api_str = gst_gl_api_to_string (SUPPORTED_GL_APIS); GST_ELEMENT_ERROR (src, RESOURCE, BUSY, ("GL API's not compatible context: %s supported: %s", gl_api_str, supported_gl_api_str), (NULL)); g_free (supported_gl_api_str); g_free (gl_api_str); return FALSE; } context_error: { GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); g_clear_error (&error); if (src->context) gst_object_unref (src->context); src->context = NULL; return FALSE; } }
void gst_gl_context_helper_ensure_context (GstGLContextHelper * ctxh) { GError *error = NULL; GstGLContext *context; g_return_if_fail (ctxh != NULL); if (!ctxh->display) gst_gl_ensure_element_data (ctxh->element, &ctxh->display, &ctxh->other_context); if (!ctxh->display) goto display_error; context = _find_local_gl_context (ctxh); if (context) { GST_INFO_OBJECT (ctxh->element, "found local context %p, old context %p", context, ctxh->context); if (ctxh->context) gst_object_unref (ctxh->context); ctxh->context = context; } if (!ctxh->context) { GST_OBJECT_LOCK (ctxh->display); do { if (ctxh->context) gst_object_unref (ctxh->context); ctxh->context = gst_gl_display_get_gl_context_for_thread (ctxh->display, NULL); if (!ctxh->context) { if (!gst_gl_display_create_context (ctxh->display, ctxh->other_context, &ctxh->context, &error)) { GST_OBJECT_UNLOCK (ctxh->display); goto context_error; } } } while (!gst_gl_display_add_context (ctxh->display, ctxh->context)); GST_OBJECT_UNLOCK (ctxh->display); } return; context_error: { GST_ELEMENT_ERROR (ctxh->element, RESOURCE, NOT_FOUND, ("%s", error->message), (NULL)); g_clear_error (&error); return; } display_error: { GST_ELEMENT_ERROR (ctxh->element, RESOURCE, NOT_FOUND, ("Failed to obtain display"), (NULL)); return; } }
static GstStateChangeReturn gst_egl_sink_change_state (GstElement * element, GstStateChange transition) { GstEGLSink *egl_sink; GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS; GST_DEBUG ("change state"); egl_sink = GST_EGL_SINK (element); switch (transition) { case GST_STATE_CHANGE_NULL_TO_READY: break; case GST_STATE_CHANGE_READY_TO_PAUSED: if (!egl_sink->display && !egl_sink->draw_callback) { GST_INFO("Create GLDisplay"); egl_sink->display = gst_gl_display_new (); egl_sink->display->keep_aspect_ratio = egl_sink->keep_aspect_ratio; /* init opengl context */ gst_gl_display_create_context (egl_sink->display, 0); } break; case GST_STATE_CHANGE_PAUSED_TO_PLAYING: break; default: break; } ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition); if (ret == GST_STATE_CHANGE_FAILURE) return ret; switch (transition) { case GST_STATE_CHANGE_PLAYING_TO_PAUSED: break; case GST_STATE_CHANGE_PAUSED_TO_READY: { if (egl_sink->display) { gst_gl_display_destroy_context(egl_sink->display); g_object_unref (egl_sink->display); egl_sink->display = NULL; } egl_sink->window_id = 0; //but do not reset egl_sink->new_window_id egl_sink->fps_n = 0; egl_sink->fps_d = 1; egl_sink->par_n = 1; egl_sink->par_d = 1; GST_VIDEO_SINK_WIDTH (egl_sink) = 0; GST_VIDEO_SINK_HEIGHT (egl_sink) = 0; } break; case GST_STATE_CHANGE_READY_TO_NULL: break; default: break; } return ret; }