Esempio n. 1
0
static GUBGraphicContext *gub_create_graphic_context_egl(GstPipeline *pipeline, float crop_left, float crop_top, float crop_right, float crop_bottom)
{
    static const GLfloat vVertices[] = {
        -1.f, -1.f,   0.f, 0.f,
        -1.f,  1.f,   0.f, 1.f,
         1.f, -1.f,   1.f, 0.f,
         1.f,  1.f,   1.f, 1.f
    };
    guintptr raw_context;
    GstStructure *s;
    GstGLDisplay *display;
    GstGLContext *gl_context;
    GUBGraphicContextEGL *gcontext;

    raw_context = gst_gl_context_get_current_gl_context(GST_GL_PLATFORM_EGL);
    if (!raw_context) {
        gub_log("Could not retrieve current EGL context");
        return NULL;
    }

    display = (GstGLDisplay *)gst_gl_display_egl_new();
    gl_context = gst_gl_context_new_wrapped(display, raw_context, GST_GL_PLATFORM_EGL, GST_GL_API_GLES2);
    gub_log("Current GL context is %p (GSTGL Platform %s GSTGL API %s)", raw_context,
        gst_gl_platform_to_string(gst_gl_context_get_gl_platform(gl_context)),
        gst_gl_api_to_string(gst_gl_context_get_gl_api(gl_context)));
    gub_log("VENDOR: %s", glGetString(GL_VENDOR));
    gub_log("RENDERER: %s", glGetString(GL_RENDERER));
    gub_log("VERSION: %s", glGetString(GL_VERSION));
    gub_log("GLSL VERSION: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));

    gcontext = (GUBGraphicContextEGL *)malloc(sizeof(GUBGraphicContextEGL));
    gcontext->gl = gl_context;
    gcontext->display = display;
    gcontext->crop_left = crop_left;
    gcontext->crop_top = crop_top;
    gcontext->crop_right = crop_right;
    gcontext->crop_bottom = crop_bottom;

    glGenFramebuffers(1, &gcontext->fbo);

    if (gl_context->gl_vtable->GenVertexArrays)
        gl_context->gl_vtable->GenVertexArrays(1, &gcontext->vao);
    if (gcontext->gl->gl_vtable->BindVertexArray)
        gcontext->gl->gl_vtable->BindVertexArray(gcontext->vao);

    glGenBuffers(1, &gcontext->vbo);
    glBindBuffer(GL_ARRAY_BUFFER, gcontext->vbo);
    glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(GLfloat), vVertices, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    gcontext->po = gub_create_program();

    gcontext->samplerLoc = glGetUniformLocation(gcontext->po, "sTexture");

    return gcontext;
}
Esempio n. 2
0
/**
 * gst_gl_display_filter_gl_api:
 * @display: a #GstGLDisplay
 * @gl_api: a #GstGLAPI to filter with
 *
 * limit the use of OpenGL to the requested @gl_api.  This is intended to allow
 * application and elements to request a specific set of OpenGL API's based on
 * what they support.  See gst_gl_context_get_gl_api() for the retreiving the
 * API supported by a #GstGLContext.
 */
void
gst_gl_display_filter_gl_api (GstGLDisplay * display, GstGLAPI gl_api)
{
  gchar *gl_api_s;

  g_return_if_fail (GST_IS_GL_DISPLAY (display));

  gl_api_s = gst_gl_api_to_string (gl_api);
  GST_TRACE_OBJECT (display, "filtering with api %s", gl_api_s);
  g_free (gl_api_s);

  GST_OBJECT_LOCK (display);
  display->priv->gl_api &= gl_api;
  GST_OBJECT_UNLOCK (display);
}
Esempio n. 3
0
static GstPadProbeReturn
query_cb (GstPad * pad, GstPadProbeInfo * info, gpointer user_data)
{
    APP_STATE_T *state = (APP_STATE_T *) user_data;
    GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);
    GstStructure *external_gl_context_desc = NULL;
    gchar *platform = NULL;
    gchar *gl_apis = NULL;

    switch (GST_QUERY_TYPE (query)) {
    case GST_QUERY_ALLOCATION:
    {
        platform = gst_gl_platform_to_string (GST_GL_PLATFORM_EGL);
        gl_apis = gst_gl_api_to_string (GST_GL_API_GLES2);

        external_gl_context_desc =
            gst_structure_new ("GstVideoGLTextureUploadMeta",
                               "gst.gl.context.handle", G_TYPE_POINTER, state->context,
                               "gst.gl.context.type", G_TYPE_STRING, platform,
                               "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
        gst_query_add_allocation_meta (query,
                                       GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, external_gl_context_desc);
        gst_structure_free (external_gl_context_desc);

        g_free (gl_apis);
        g_free (platform);

        GST_DEBUG ("done alocation");
        return GST_PAD_PROBE_OK;
        break;
    }
    case GST_QUERY_CONTEXT:
    {
        return gst_gl_handle_context_query (state->pipeline, query,
                                            (GstGLDisplay **) & state->gst_display);
        break;
    }
    case GST_QUERY_DRAIN:
    {
        flush_internal (state);
        break;
    }
    default:
        break;
    }

    return GST_PAD_PROBE_OK;
}
static gboolean
gst_glimage_sink_propose_allocation (GstBaseSink * bsink, GstQuery * query)
{
  GstGLImageSink *glimage_sink = GST_GLIMAGE_SINK (bsink);
  GstBufferPool *pool;
  GstStructure *config;
  GstCaps *caps;
  guint size;
  gboolean need_pool;
  GstStructure *gl_context;
  gchar *platform, *gl_apis;
  gpointer handle;

  if (!_ensure_gl_setup (glimage_sink))
    return FALSE;

  gst_query_parse_allocation (query, &caps, &need_pool);

  if (caps == NULL)
    goto no_caps;

  if ((pool = glimage_sink->pool))
    gst_object_ref (pool);

  if (pool != NULL) {
    GstCaps *pcaps;

    /* we had a pool, check caps */
    GST_DEBUG_OBJECT (glimage_sink, "check existing pool caps");
    config = gst_buffer_pool_get_config (pool);
    gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);

    if (!gst_caps_is_equal (caps, pcaps)) {
      GST_DEBUG_OBJECT (glimage_sink, "pool has different caps");
      /* different caps, we can't use this pool */
      gst_object_unref (pool);
      pool = NULL;
    }
    gst_structure_free (config);
  }

  if (pool == NULL && need_pool) {
    GstVideoInfo info;

    if (!gst_video_info_from_caps (&info, caps))
      goto invalid_caps;

    GST_DEBUG_OBJECT (glimage_sink, "create new pool");
    pool = gst_gl_buffer_pool_new (glimage_sink->context);

    /* the normal size of a frame */
    size = info.size;

    config = gst_buffer_pool_get_config (pool);
    gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
    if (!gst_buffer_pool_set_config (pool, config))
      goto config_failed;
  }
  /* we need at least 2 buffer because we hold on to the last one */
  gst_query_add_allocation_pool (query, pool, size, 2, 0);

  /* we also support various metadata */
  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);

  gst_object_unref (pool);

  gl_apis =
      gst_gl_api_to_string (gst_gl_context_get_gl_api (glimage_sink->context));
  platform =
      gst_gl_platform_to_string (gst_gl_context_get_gl_platform
      (glimage_sink->context));
  handle = (gpointer) gst_gl_context_get_gl_context (glimage_sink->context);

  gl_context =
      gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext",
      GST_GL_TYPE_CONTEXT, glimage_sink->context, "gst.gl.context.handle",
      G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform,
      "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
  gst_query_add_allocation_meta (query,
      GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context);

  g_free (gl_apis);
  g_free (platform);
  gst_structure_free (gl_context);

  return TRUE;

  /* ERRORS */
no_caps:
  {
    GST_DEBUG_OBJECT (bsink, "no caps specified");
    return FALSE;
  }
invalid_caps:
  {
    GST_DEBUG_OBJECT (bsink, "invalid caps specified");
    return FALSE;
  }
config_failed:
  {
    GST_DEBUG_OBJECT (bsink, "failed setting config");
    return FALSE;
  }
}
Esempio n. 5
0
//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;
  }
}
Esempio n. 6
0
static gboolean
gst_gl_mixer_propose_allocation (GstGLMixer * mix,
    GstQuery * decide_query, GstQuery * query)
{
  GstBufferPool *pool;
  GstStructure *config;
  GstCaps *caps;
  guint size = 0;
  gboolean need_pool;
  GError *error = NULL;
  GstStructure *gl_context;
  gchar *platform, *gl_apis;
  gpointer handle;
  GstAllocator *allocator = NULL;
  GstAllocationParams params;

  gst_query_parse_allocation (query, &caps, &need_pool);

  if (caps == NULL)
    goto no_caps;

  if ((pool = mix->priv->pool))
    gst_object_ref (pool);

  if (pool != NULL) {
    GstCaps *pcaps;

    /* we had a pool, check caps */
    GST_DEBUG_OBJECT (mix, "check existing pool caps");
    config = gst_buffer_pool_get_config (pool);
    gst_buffer_pool_config_get_params (config, &pcaps, &size, NULL, NULL);

    if (!gst_caps_is_equal (caps, pcaps)) {
      GST_DEBUG_OBJECT (mix, "pool has different caps");
      /* different caps, we can't use this pool */
      gst_object_unref (pool);
      pool = NULL;
    }
    gst_structure_free (config);
  }

  if (!gst_gl_ensure_display (mix, &mix->display))
    return FALSE;

  if (!mix->context) {
    mix->context = gst_gl_context_new (mix->display);
    if (!gst_gl_context_create (mix->context, NULL, &error))
      goto context_error;
  }

  if (pool == NULL && need_pool) {
    GstVideoInfo info;

    if (!gst_video_info_from_caps (&info, caps))
      goto invalid_caps;

    GST_DEBUG_OBJECT (mix, "create new pool");
    pool = gst_gl_buffer_pool_new (mix->context);

    /* the normal size of a frame */
    size = info.size;

    config = gst_buffer_pool_get_config (pool);
    gst_buffer_pool_config_set_params (config, caps, size, 0, 0);
    if (!gst_buffer_pool_set_config (pool, config))
      goto config_failed;
  }

  if (pool) {
    gst_query_add_allocation_pool (query, pool, size, 1, 0);
    gst_object_unref (pool);
  }

  /* we also support various metadata */
  gst_query_add_allocation_meta (query, GST_VIDEO_META_API_TYPE, 0);

  gl_apis = gst_gl_api_to_string (gst_gl_context_get_gl_api (mix->context));
  platform =
      gst_gl_platform_to_string (gst_gl_context_get_gl_platform (mix->context));
  handle = (gpointer) gst_gl_context_get_gl_context (mix->context);

  gl_context =
      gst_structure_new ("GstVideoGLTextureUploadMeta", "gst.gl.GstGLContext",
      GST_GL_TYPE_CONTEXT, mix->context, "gst.gl.context.handle",
      G_TYPE_POINTER, handle, "gst.gl.context.type", G_TYPE_STRING, platform,
      "gst.gl.context.apis", G_TYPE_STRING, gl_apis, NULL);
  gst_query_add_allocation_meta (query,
      GST_VIDEO_GL_TEXTURE_UPLOAD_META_API_TYPE, gl_context);

  g_free (gl_apis);
  g_free (platform);
  gst_structure_free (gl_context);

  gst_allocation_params_init (&params);

  allocator = gst_allocator_find (GST_GL_MEMORY_ALLOCATOR);
  gst_query_add_allocation_param (query, allocator, &params);
  gst_object_unref (allocator);

  return TRUE;

  /* ERRORS */
no_caps:
  {
    GST_DEBUG_OBJECT (mix, "no caps specified");
    return FALSE;
  }
invalid_caps:
  {
    GST_DEBUG_OBJECT (mix, "invalid caps specified");
    return FALSE;
  }
config_failed:
  {
    GST_DEBUG_OBJECT (mix, "failed setting config");
    return FALSE;
  }
context_error:
  {
    GST_ELEMENT_ERROR (mix, RESOURCE, NOT_FOUND, ("%s", error->message),
        (NULL));
    return FALSE;
  }
}
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;
    }
}
Esempio n. 8
0
//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;
  }
}
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;
  }
}