static void _set_window_handle_cb (GstSetWindowHandleCb * data) { GstGLContext *context = gst_gl_window_get_context (data->window); GstGLWindowClass *window_class = GST_GL_WINDOW_GET_CLASS (data->window); GThread *thread = NULL; /* deactivate if necessary */ if (context) { thread = gst_gl_context_get_thread (context); if (thread) { /* This is only thread safe iff the context thread == g_thread_self() */ g_assert (thread == g_thread_self ()); gst_gl_context_activate (context, FALSE); } } window_class->set_window_handle (data->window, data->handle); /* reactivate */ if (context && thread) gst_gl_context_activate (context, TRUE); if (context) gst_object_unref (context); if (thread) g_thread_unref (thread); }
static void gst_gl_context_gpu_process_finalize (GObject * object) { GstGLContext *context = GST_GL_CONTEXT (object); if (context->window) GST_GL_WINDOW_GET_CLASS (context->window)->close (context->window); G_OBJECT_CLASS (parent_class)->finalize (object); }
/** * gst_gl_window_draw_unlocked: * @window: a #GstGLWindow * @width: requested width of the window * @height: requested height of the window * * Redraw the window contents. Implementations should invoke the draw callback. */ void gst_gl_window_draw_unlocked (GstGLWindow * window, guint width, guint height) { GstGLWindowClass *window_class; g_return_if_fail (GST_GL_IS_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->draw_unlocked != NULL); window_class->draw_unlocked (window, width, height); }
/** * gst_gl_window_set_preferred_size: * @window: a #GstGLWindow * @width: new preferred width * @height: new preferred height * * Set the preferred width and height of the window. Implementations are free * to ignore this information. * * Since: 1.6 */ void gst_gl_window_set_preferred_size (GstGLWindow * window, gint width, gint height) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); if (window_class->set_preferred_size) window_class->set_preferred_size (window, width, height); }
/** * gst_gl_window_show: * @window: a #GstGLWindow * * Present the window to the screen. * * Since: 1.6 */ void gst_gl_window_show (GstGLWindow * window) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); if (window_class->show) window_class->show (window); }
/** * gst_gl_window_get_window_handle: * @window: a #GstGLWindow * * Returns: the window handle we are currently rendering into * * Since: 1.4 */ guintptr gst_gl_window_get_window_handle (GstGLWindow * window) { GstGLWindowClass *window_class; g_return_val_if_fail (GST_IS_GL_WINDOW (window), 0); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_val_if_fail (window_class->get_window_handle != NULL, 0); return window_class->get_window_handle (window); }
/** * gst_gl_window_handle_events: * @window: a #GstGLWindow * @handle_events: a #gboolean indicating if events should be handled or not. * * Tell a @window that it should handle events from the window system. These * events are forwarded upstream as navigation events. In some window systems * events are not propagated in the window hierarchy if a client is listening * for them. This method allows you to disable events handling completely * from the @window. */ void gst_gl_window_handle_events (GstGLWindow * window, gboolean handle_events) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); if (window_class->handle_events) window_class->handle_events (window, handle_events); }
/** * gst_gl_window_run: * @window: a #GstGLWindow * * Start the execution of the runloop. * * Since: 1.4 */ void gst_gl_window_run (GstGLWindow * window) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->run != NULL); window->priv->alive = TRUE; window_class->run (window); }
/** * gst_gl_window_set_window_handle: * @window: a #GstGLWindow * @handle: handle to the window * * Sets the window that this @window should render into. Some implementations * require this to be called with a valid handle before drawing can commence. */ void gst_gl_window_set_window_handle (GstGLWindow * window, guintptr handle) { GstGLWindowClass *window_class; g_return_if_fail (GST_GL_IS_WINDOW (window)); g_return_if_fail (handle != 0); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->set_window_handle != NULL); window_class->set_window_handle (window, handle); }
void gst_gl_window_queue_resize (GstGLWindow * window) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); window->queue_resize = TRUE; if (window_class->queue_resize) window_class->queue_resize (window); }
/** * gst_gl_window_send_message_async: * @window: a #GstGLWindow * @callback: (scope async): function to invoke * @data: (closure): data to invoke @callback with * @destroy: called when @data is not needed anymore * * Invoke @callback with @data on the window thread. The callback may not * have been executed when this function returns. * * Since: 1.4 */ void gst_gl_window_send_message_async (GstGLWindow * window, GstGLWindowCB callback, gpointer data, GDestroyNotify destroy) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); g_return_if_fail (callback != NULL); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->send_message_async != NULL); window_class->send_message_async (window, callback, data, destroy); }
/** * gst_gl_window_send_message: * @window: a #GstGLWindow * @callback: (scope async): function to invoke * @data: (closure): data to invoke @callback with * * Invoke @callback with data on the window thread. @callback is guarenteed to * have executed when this function returns. * * Since: 1.4 */ void gst_gl_window_send_message (GstGLWindow * window, GstGLWindowCB callback, gpointer data) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); g_return_if_fail (callback != NULL); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->send_message != NULL); window_class->send_message (window, callback, data); }
/** * gst_gl_window_draw: * @window: a #GstGLWindow * * Redraw the window contents. Implementations should invoke the draw callback. * * Since: 1.4 */ void gst_gl_window_draw (GstGLWindow * window) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->draw != NULL); /* avoid to overload the drawer */ if (window->is_drawing) { return; } window_class->draw (window); }
/** * gst_gl_window_set_render_rectangle: * @window: a #GstGLWindow * @x: x position * @y: y position * @width: width * @height: height * * Tell a @window that it should render into a specific region of the window * according to the #GstVideoOverlay interface. * * Returns: whether the specified region could be set */ gboolean gst_gl_window_set_render_rectangle (GstGLWindow * window, gint x, gint y, gint width, gint height) { GstGLWindowClass *window_class; gboolean ret = FALSE; g_return_val_if_fail (GST_IS_GL_WINDOW (window), FALSE); window_class = GST_GL_WINDOW_GET_CLASS (window); if (x < 0 || y < 0 || width <= 0 || height <= 0) return FALSE; if (window_class->set_render_rectangle) ret = window_class->set_render_rectangle (window, x, y, width, height); return ret; }
/** * gst_gl_window_quit: * @window: a #GstGLWindow * * Quit the runloop's execution. * * Since: 1.4 */ void gst_gl_window_quit (GstGLWindow * window) { GstGLWindowClass *window_class; g_return_if_fail (GST_IS_GL_WINDOW (window)); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->quit != NULL); GST_GL_WINDOW_LOCK (window); window->priv->alive = FALSE; window_class->quit (window); GST_INFO ("quit sent to gl window loop"); GST_GL_WINDOW_UNLOCK (window); }
GstGLContext * gst_gl_context_gpu_process_new (GstGLDisplay * display, GstGLAPI gl_api, GstGLProcAddrFunc proc_addr) { GstGLContext *context = NULL; GstGLContextGPUProcess *gpu_context = NULL; GstGLContextClass *context_class = NULL; GstGLWindow *window = NULL; GError *error = NULL; g_return_val_if_fail ((gst_gl_display_get_gl_api (display) & gl_api) != GST_GL_API_NONE, NULL); gpu_context = g_object_new (GST_GL_TYPE_CONTEXT_GPU_PROCESS, NULL); gpu_context->priv->gl_api = gl_api; context = GST_GL_CONTEXT (gpu_context); context->display = display; gst_gl_display_add_context (display, context); context_class = GST_GL_CONTEXT_GET_CLASS (context); context_class->get_current_context = NULL; context_class->get_proc_address = GST_DEBUG_FUNCPTR (proc_addr); gst_gl_context_activate (context, TRUE); gst_gl_context_fill_info (context, &error); if (error) { GST_ERROR_OBJECT (context, "Failed to create gpu process context: %s", error->message); g_error_free (error); gst_object_unref (context); return NULL; } window = GST_GL_WINDOW (gst_gl_window_gpu_process_new (display)); gst_gl_context_set_window (context, window); GST_GL_WINDOW_GET_CLASS (window)->open (window, NULL); gst_object_unref (window); return context; }
/** * gst_gl_window_set_window_handle: * @window: a #GstGLWindow * @handle: handle to the window * * Sets the window that this @window should render into. Some implementations * require this to be called with a valid handle before drawing can commence. * * Since: 1.4 */ void gst_gl_window_set_window_handle (GstGLWindow * window, guintptr handle) { GstGLWindowClass *window_class; GstSetWindowHandleCb *data; g_return_if_fail (GST_IS_GL_WINDOW (window)); g_return_if_fail (handle != 0); window_class = GST_GL_WINDOW_GET_CLASS (window); g_return_if_fail (window_class->set_window_handle != NULL); data = g_slice_new (GstSetWindowHandleCb); data->window = gst_object_ref (window); data->handle = handle; /* FIXME: Move to a message which deactivates, calls implementation, activates */ gst_gl_window_send_message_async (window, (GstGLWindowCB) _set_window_handle_cb, data, (GDestroyNotify) _free_swh_cb); /* window_class->set_window_handle (window, handle); */ }
//gboolean //gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error) static gpointer gst_gl_context_create_thread (GstGLContext * context) { GstGLContextClass *context_class; GstGLWindowClass *window_class; GstGLFuncs *gl; gboolean ret = FALSE; GstGLAPI compiled_api, user_api, gl_api; gchar *api_string; gchar *compiled_api_s; gchar *user_api_string; const gchar *user_choice; GError **error; GstGLContext *other_context; GString *ext_g_str = NULL; const gchar *ext_const_c_str = NULL; g_mutex_lock (&context->priv->render_lock); error = context->priv->error; other_context = context->priv->other_context; context_class = GST_GL_CONTEXT_GET_CLASS (context); window_class = GST_GL_WINDOW_GET_CLASS (context->window); if (window_class->open) { if (!window_class->open (context->window, error)) { g_assert (error == NULL || *error != NULL); goto failure; } } gl = context->gl_vtable; compiled_api = _compiled_api (); user_choice = g_getenv ("GST_GL_API"); user_api = gst_gl_api_from_string (user_choice); user_api_string = gst_gl_api_to_string (user_api); compiled_api_s = gst_gl_api_to_string (compiled_api); if ((user_api & compiled_api) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "Cannot create context with the user requested api (%s). " "We have support for (%s)", user_api_string, compiled_api_s); g_free (user_api_string); g_free (compiled_api_s); goto failure; } if (context_class->choose_format && !context_class->choose_format (context, error)) { g_assert (error == NULL || *error != NULL); g_free (compiled_api_s); g_free (user_api_string); goto failure; } GST_INFO ("Attempting to create opengl context. user chosen api(s) (%s), " "compiled api support (%s)", user_api_string, compiled_api_s); if (!context_class->create_context (context, compiled_api & user_api, other_context, error)) { g_assert (error == NULL || *error != NULL); g_free (compiled_api_s); g_free (user_api_string); goto failure; } GST_INFO ("created context"); if (!context_class->activate (context, TRUE)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to activate the GL Context"); g_free (compiled_api_s); g_free (user_api_string); goto failure; } gl_api = gst_gl_context_get_gl_api (context); g_assert (gl_api != GST_GL_API_NONE && gl_api != GST_GL_API_ANY); api_string = gst_gl_api_to_string (gl_api); GST_INFO ("available GL APIs: %s", api_string); if (((compiled_api & gl_api) & user_api) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "failed to create context, context " "could not provide correct api. user (%s), compiled (%s), context (%s)", user_api_string, compiled_api_s, api_string); g_free (api_string); g_free (compiled_api_s); g_free (user_api_string); goto failure; } g_free (api_string); g_free (compiled_api_s); g_free (user_api_string); gl->GetError = gst_gl_context_get_proc_address (context, "glGetError"); gl->GetString = gst_gl_context_get_proc_address (context, "glGetString"); gl->GetStringi = gst_gl_context_get_proc_address (context, "glGetStringi"); gl->GetIntegerv = gst_gl_context_get_proc_address (context, "glGetIntegerv"); if (!gl->GetError || !gl->GetString) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_FAILED, "could not GetProcAddress core opengl functions"); goto failure; } /* gl api specific code */ ret = _create_context_info (context, gl_api, &context->priv->gl_major, &context->priv->gl_minor, error); if (!ret) { g_assert (error == NULL || *error != NULL); goto failure; } /* GL core contexts and GLES3 */ if (gl->GetIntegerv && gl->GetStringi && context->priv->gl_major >= 3) ext_g_str = _build_extension_string (context); if (ext_g_str && ext_g_str->len) { GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_g_str->str); _gst_gl_feature_check_ext_functions (context, context->priv->gl_major, context->priv->gl_minor, ext_g_str->str); context->priv->gl_exts = g_string_free (ext_g_str, FALSE); } else { ext_const_c_str = (const gchar *) gl->GetString (GL_EXTENSIONS); if (!ext_const_c_str) ext_const_c_str = ""; GST_DEBUG_OBJECT (context, "GL_EXTENSIONS: %s", ext_const_c_str); _gst_gl_feature_check_ext_functions (context, context->priv->gl_major, context->priv->gl_minor, ext_const_c_str); context->priv->gl_exts = g_strdup (ext_const_c_str); } context->priv->alive = TRUE; g_cond_signal (&context->priv->create_cond); // g_mutex_unlock (&context->priv->render_lock); gst_gl_window_send_message_async (context->window, (GstGLWindowCB) _unlock_create_thread, context, NULL); gst_gl_window_run (context->window); GST_INFO ("loop exited\n"); g_mutex_lock (&context->priv->render_lock); context->priv->alive = FALSE; context_class->activate (context, FALSE); context_class->destroy_context (context); /* User supplied callback */ if (context->window->close) context->window->close (context->window->close_data); /* window specific shutdown */ if (window_class->close) { window_class->close (context->window); } g_cond_signal (&context->priv->destroy_cond); g_mutex_unlock (&context->priv->render_lock); return NULL; failure: { g_cond_signal (&context->priv->create_cond); g_mutex_unlock (&context->priv->render_lock); return NULL; } }
//gboolean //gst_gl_context_create (GstGLContext * context, GstGLContext * other_context, GError ** error) static gpointer gst_gl_context_create_thread (GstGLContext * context) { GstGLContextClass *context_class; GstGLWindowClass *window_class; GstGLFuncs *gl; GstGLAPI compiled_api, user_api, gl_api, display_api; gchar *api_string; gchar *compiled_api_s; gchar *user_api_s; gchar *display_api_s; const gchar *user_choice; GError **error; GstGLContext *other_context; g_mutex_lock (&context->priv->render_lock); GST_DEBUG_OBJECT (context, "Creating thread"); error = context->priv->error; other_context = g_weak_ref_get (&context->priv->other_context_ref); context_class = GST_GL_CONTEXT_GET_CLASS (context); window_class = GST_GL_WINDOW_GET_CLASS (context->window); display_api = gst_gl_display_get_gl_api_unlocked (context->display); if (display_api == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "Cannot create context with satisfying requested apis " "(display has no GL api!)"); goto failure; } if (window_class->open) { if (!window_class->open (context->window, error)) { GST_WARNING_OBJECT (context, "Failed to open window"); g_assert (error == NULL || *error != NULL); goto failure; } } gl = context->gl_vtable; compiled_api = _compiled_api (); compiled_api_s = gst_gl_api_to_string (compiled_api); user_choice = g_getenv ("GST_GL_API"); user_api = gst_gl_api_from_string (user_choice); user_api_s = gst_gl_api_to_string (user_api); display_api_s = gst_gl_api_to_string (display_api); if ((user_api & compiled_api & display_api) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "Cannot create context with the user requested api (%s). " "We have support for (%s), display api (%s)", user_api_s, compiled_api_s, display_api_s); g_free (user_api_s); g_free (compiled_api_s); g_free (display_api_s); goto failure; } if (context_class->choose_format && !context_class->choose_format (context, error)) { GST_WARNING_OBJECT (context, "Failed to choose format"); g_assert (error == NULL || *error != NULL); g_free (compiled_api_s); g_free (user_api_s); g_free (display_api_s); goto failure; } GST_INFO_OBJECT (context, "Attempting to create opengl context. user chosen api(s) (%s), " "compiled api support (%s) display api (%s)", user_api_s, compiled_api_s, display_api_s); if (!context_class->create_context (context, compiled_api & user_api & display_api, other_context, error)) { GST_WARNING_OBJECT (context, "Failed to create context"); g_assert (error == NULL || *error != NULL); g_free (compiled_api_s); g_free (user_api_s); g_free (display_api_s); goto failure; } GST_INFO_OBJECT (context, "created context"); if (!gst_gl_context_activate (context, TRUE)) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_RESOURCE_UNAVAILABLE, "Failed to activate the GL Context"); g_free (compiled_api_s); g_free (user_api_s); g_free (display_api_s); goto failure; } gl_api = gst_gl_context_get_gl_api (context); g_assert (gl_api != GST_GL_API_NONE && gl_api != GST_GL_API_ANY); api_string = gst_gl_api_to_string (gl_api); GST_INFO_OBJECT (context, "available GL APIs: %s", api_string); if (((compiled_api & gl_api & display_api) & user_api) == GST_GL_API_NONE) { g_set_error (error, GST_GL_CONTEXT_ERROR, GST_GL_CONTEXT_ERROR_WRONG_API, "failed to create context, context " "could not provide correct api. user (%s), compiled (%s), context (%s)", user_api_s, compiled_api_s, api_string); g_free (api_string); g_free (compiled_api_s); g_free (user_api_s); g_free (display_api_s); goto failure; } g_free (api_string); g_free (compiled_api_s); g_free (user_api_s); g_free (display_api_s); GST_DEBUG_OBJECT (context, "Filling info"); if (!gst_gl_context_fill_info (context, error)) { g_assert (error == NULL || *error != NULL); goto failure; } context->priv->alive = TRUE; if (gl->DebugMessageCallback) { #if !defined(GST_DISABLE_GST_DEBUG) GST_INFO_OBJECT (context, "Enabling GL context debugging"); /* enable them all */ gl->DebugMessageControl (GL_DONT_CARE, GL_DONT_CARE, GL_DONT_CARE, 0, 0, GL_TRUE); gl->DebugMessageCallback (_gst_gl_debug_callback, context); #endif } if (other_context) { GST_DEBUG_OBJECT (context, "Unreffing other_context %" GST_PTR_FORMAT, other_context); gst_object_unref (other_context); } g_cond_signal (&context->priv->create_cond); // g_mutex_unlock (&context->priv->render_lock); gst_gl_window_send_message_async (context->window, (GstGLWindowCB) _unlock_create_thread, context, NULL); gst_gl_window_run (context->window); GST_INFO_OBJECT (context, "loop exited"); g_mutex_lock (&context->priv->render_lock); context->priv->alive = FALSE; gst_gl_context_activate (context, FALSE); context_class->destroy_context (context); /* User supplied callback */ if (context->window->close) context->window->close (context->window->close_data); /* window specific shutdown */ if (window_class->close) { window_class->close (context->window); } g_cond_signal (&context->priv->destroy_cond); g_mutex_unlock (&context->priv->render_lock); return NULL; failure: { if (other_context) gst_object_unref (other_context); g_cond_signal (&context->priv->create_cond); g_mutex_unlock (&context->priv->render_lock); return NULL; } }