/**
 * gst_gl_context_destroy:
 * @context: a #GstGLContext:
 *
 * Destroys an OpenGL context.
 *
 * Should only be called after gst_gl_context_create() has been successfully
 * called for this context.
 *
 * Since: 1.6
 */
void
gst_gl_context_destroy (GstGLContext * context)
{
  GstGLContextClass *context_class;

  g_return_if_fail (GST_GL_IS_CONTEXT (context));
  context_class = GST_GL_CONTEXT_GET_CLASS (context);
  g_return_if_fail (context_class->destroy_context != NULL);

  context_class->destroy_context (context);
}
/**
 * gst_gl_context_get_gl_platform:
 * @context: a #GstGLContext:
 *
 * Gets the OpenGL platform that used by @context.
 *
 * Returns: The platform specific backing OpenGL context
 */
GstGLPlatform
gst_gl_context_get_gl_platform (GstGLContext * context)
{
  GstGLContextClass *context_class;

  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), 0);
  context_class = GST_GL_CONTEXT_GET_CLASS (context);
  g_return_val_if_fail (context_class->get_gl_platform != NULL, 0);

  return context_class->get_gl_platform (context);
}
/**
 * gst_gl_context_get_gl_api:
 * @context: a #GstGLContext
 *
 * Get the currently enabled OpenGL api.
 *
 * The currently available API may be limited by the #GstGLDisplay in use and/or
 * the #GstGLWindow chosen.
 *
 * Returns: the currently available OpenGL api
 */
GstGLAPI
gst_gl_context_get_gl_api (GstGLContext * context)
{
  GstGLContextClass *context_class;

  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), GST_GL_API_NONE);
  context_class = GST_GL_CONTEXT_GET_CLASS (context);
  g_return_val_if_fail (context_class->get_gl_api != NULL, GST_GL_API_NONE);

  return context_class->get_gl_api (context);
}
/**
 * gst_gl_context_get_gl_context:
 * @context: a #GstGLContext:
 *
 * Gets the backing OpenGL context used by @context.
 *
 * Returns: The platform specific backing OpenGL context
 */
guintptr
gst_gl_context_get_gl_context (GstGLContext * context)
{
  GstGLContextClass *context_class;
  guintptr result;

  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), 0);
  context_class = GST_GL_CONTEXT_GET_CLASS (context);
  g_return_val_if_fail (context_class->get_gl_context != NULL, 0);

  result = context_class->get_gl_context (context);

  return result;
}
/**
 * gst_gl_context_get_proc_address:
 * @context: a #GstGLContext
 * @name: an opengl function name
 *
 * Get a function pointer to a specified opengl function, @name.  If the the
 * specific function does not exist, NULL is returned instead.
 *
 * Platform specfic functions (names starting 'egl', 'glX', 'wgl', etc) can also
 * be retreived using this method.
 *
 * Returns: a function pointer or NULL
 *
 * Since: 1.4
 */
gpointer
gst_gl_context_get_proc_address (GstGLContext * context, const gchar * name)
{
  gpointer ret;
  GstGLContextClass *context_class;

  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), NULL);
  context_class = GST_GL_CONTEXT_GET_CLASS (context);
  g_return_val_if_fail (context_class->get_proc_address != NULL, NULL);

  ret = context_class->get_proc_address (context, name);

  return ret;
}
/**
 * gst_gl_context_activate:
 * @context: a #GstGLContext
 * @activate: %TRUE to activate, %FALSE to deactivate
 *
 * (De)activate the OpenGL context represented by this @context.
 *
 * In OpenGL terms, calls eglMakeCurrent or similar with this context and the
 * currently set window.  See gst_gl_context_set_window() for details.
 *
 * Returns: Whether the activation succeeded
 */
gboolean
gst_gl_context_activate (GstGLContext * context, gboolean activate)
{
  GstGLContextClass *context_class;
  gboolean result;

  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), FALSE);
  context_class = GST_GL_CONTEXT_GET_CLASS (context);
  g_return_val_if_fail (context_class->activate != NULL, FALSE);

  result = context_class->activate (context, activate);

  return result;
}
static void
draw_cb (gpointer data)
{
  GstGLWindowWaylandEGL *window_egl = data;
  GstGLWindow *window = GST_GL_WINDOW (window_egl);
  GstGLContext *context = gst_gl_window_get_context (window);
  GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);

  if (window->draw)
    window->draw (window->draw_data);

  context_class->swap_buffers (context);

  gst_object_unref (context);
}
static void
draw_cb (gpointer data)
{
  struct draw *draw_data = data;
  GstGLDummyWindow *dummy = draw_data->window;
  GstGLWindow *window = GST_GL_WINDOW (dummy);
  GstGLContext *context = gst_gl_window_get_context (window);
  GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);

  if (window->draw)
    window->draw (window->draw_data);

  context_class->swap_buffers (context);

  gst_object_unref (context);
}
/**
 * gst_gl_context_check_feature:
 * @context: a #GstGLContext
 * @feature: a platform specific feature
 *
 * Some features require that the context be created before it is possible to
 * determine their existence and so will fail if that is not the case.
 *
 * Returns: Whether @feature is supported by @context
 */
gboolean
gst_gl_context_check_feature (GstGLContext * context, const gchar * feature)
{
  GstGLContextClass *context_class;

  g_return_val_if_fail (GST_GL_IS_CONTEXT (context), FALSE);
  g_return_val_if_fail (feature != NULL, FALSE);

  context_class = GST_GL_CONTEXT_GET_CLASS (context);

  if (g_strstr_len (feature, 3, "GL_"))
    return gst_gl_check_extension (feature, context->priv->gl_exts);

  if (!context_class->check_feature)
    return FALSE;

  return context_class->check_feature (context, feature);
}
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;
}
static void
draw_render (gpointer data)
{
  GstGLContext *context = data;
  GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
  const GstGLFuncs *gl = context->gl_vtable;
  const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f,
    1.0f, 0.0f,
    -1.0f, 1.0f, 0.0f,
    0.0f, 0.0f,
    -1.0f, -1.0f, 0.0f,
    0.0f, 1.0f,
    1.0f, -1.0f, 0.0f,
    1.0f, 1.0f
  };

  GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

  gl->Clear (GL_COLOR_BUFFER_BIT);

  gst_gl_shader_use (shader);

  /* Load the vertex position */
  gl->VertexAttribPointer (shader_attr_position_loc, 3,
      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);

  /* Load the texture coordinate */
  gl->VertexAttribPointer (shader_attr_texture_loc, 2,
      GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);

  gl->EnableVertexAttribArray (shader_attr_position_loc);
  gl->EnableVertexAttribArray (shader_attr_texture_loc);

  gl->ActiveTexture (GL_TEXTURE0);
  gl->BindTexture (GL_TEXTURE_2D, tex_id);
  gst_gl_shader_set_uniform_1i (shader, "s_texture", 0);

  gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);

  context_class->swap_buffers (context);
}
Exemple #12
0
static void
draw_cb (gpointer data)
{
  GstGLWindow *window = GST_GL_WINDOW (data);
  GstGLContext *context = gst_gl_window_get_context (window);
  GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);

  if (window->queue_resize) {
    guint width, height;

    gst_gl_window_get_surface_dimensions (window, &width, &height);
    gst_gl_window_resize (window, width, height);
  }

  if (window->draw)
    window->draw (window->draw_data);

  if (context_class->swap_buffers)
    context_class->swap_buffers (context);

  gst_object_unref (context);
}
static void
draw_cb (gpointer data)
{
  GstGLWindowDispmanxEGL *window_egl = data;
  GstGLWindow *window = GST_GL_WINDOW (window_egl);
  GstGLContext *context = gst_gl_window_get_context (window);
  GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);

  if (window_egl->native.width != window_egl->preferred_width
      || window_egl->native.height != window_egl->preferred_height) {
    GST_DEBUG ("dimensions don't match, attempting resize");
    window_resize (window_egl, window_egl->preferred_width,
        window_egl->preferred_height);
  }

  if (window->draw)
    window->draw (window->draw_data);

  context_class->swap_buffers (context);

  gst_object_unref (context);
}
//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;
  }
}
static void
draw_render (gpointer data)
{
  GstGLContext *context = data;
  GstGLContextClass *context_class = GST_GL_CONTEXT_GET_CLASS (context);
  const GstGLFuncs *gl = context->gl_vtable;

  /* redraw the texture into the system provided framebuffer */

#if GST_GL_HAVE_OPENGL
  if (gst_gl_context_get_gl_api (context) & GST_GL_API_OPENGL) {
    GLfloat verts[8] = { 1.0f, 1.0f,
      -1.0f, 1.0f,
      -1.0f, -1.0f,
      1.0f, -1.0f
    };
    GLfloat texcoords[8] = { 1.0f, 0.0f,
      0.0f, 0.0f,
      0.0f, 1.0f,
      1.0f, 1.0f
    };

    gl->Viewport (0, 0, 10, 10);

    gl->Clear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    gl->MatrixMode (GL_PROJECTION);
    gl->LoadIdentity ();

    gl->Enable (GL_TEXTURE_2D);
    gl->BindTexture (GL_TEXTURE_2D, tex_id);

    gl->EnableClientState (GL_VERTEX_ARRAY);
    gl->EnableClientState (GL_TEXTURE_COORD_ARRAY);
    gl->VertexPointer (2, GL_FLOAT, 0, &verts);
    gl->TexCoordPointer (2, GL_FLOAT, 0, &texcoords);

    gl->DrawArrays (GL_TRIANGLE_FAN, 0, 4);

    gl->DisableClientState (GL_VERTEX_ARRAY);
    gl->DisableClientState (GL_TEXTURE_COORD_ARRAY);

    gl->Disable (GL_TEXTURE_2D);
  }
#endif
#if GST_GL_HAVE_GLES2
  if (gst_gl_context_get_gl_api (context) & GST_GL_API_GLES2) {
    const GLfloat vVertices[] = { 1.0f, 1.0f, 0.0f,
      1.0f, 0.0f,
      -1.0f, 1.0f, 0.0f,
      0.0f, 0.0f,
      -1.0f, -1.0f, 0.0f,
      0.0f, 1.0f,
      1.0f, -1.0f, 0.0f,
      1.0f, 1.0f
    };

    GLushort indices[] = { 0, 1, 2, 0, 2, 3 };

    gl->Clear (GL_COLOR_BUFFER_BIT);

    gst_gl_shader_use (shader);

    /* Load the vertex position */
    gl->VertexAttribPointer (shader_attr_position_loc, 3,
        GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), vVertices);

    /* Load the texture coordinate */
    gl->VertexAttribPointer (shader_attr_texture_loc, 2,
        GL_FLOAT, GL_FALSE, 5 * sizeof (GLfloat), &vVertices[3]);

    gl->EnableVertexAttribArray (shader_attr_position_loc);
    gl->EnableVertexAttribArray (shader_attr_texture_loc);

    gl->ActiveTexture (GL_TEXTURE0);
    gl->BindTexture (GL_TEXTURE_2D, tex_id);
    gst_gl_shader_set_uniform_1i (shader, "s_texture", 0);

    gl->DrawElements (GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
  }
#endif

  context_class->swap_buffers (context);
}
LRESULT CALLBACK
window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  GstGLWindowWin32 *window_win32;
  if (uMsg == WM_CREATE) {
    window_win32 =
        GST_GL_WINDOW_WIN32 (((LPCREATESTRUCT) lParam)->lpCreateParams);

    GST_TRACE ("WM_CREATE");

    window_win32->device = GetDC (hWnd);
    /* Do this, otherwise we hang on exit. We can still use it (due to the
     * CS_OWNDC flag in the WindowClass) after we have Released.
     */
    ReleaseDC (hWnd, window_win32->device);

    SetProp (hWnd, "gl_window", window_win32);
    return 0;
  } else if (GetProp (hWnd, "gl_window")) {
    GstGLWindow *window;
    GstGLContext *context;
    GstGLContextClass *context_class;

    window_win32 = GST_GL_WINDOW_WIN32 (GetProp (hWnd, "gl_window"));
    window = GST_GL_WINDOW (window_win32);
    context = gst_gl_window_get_context (window);
    context_class = GST_GL_CONTEXT_GET_CLASS (context);

    g_assert (window_win32->internal_win_id == hWnd);

    switch (uMsg) {
      case WM_SIZE:
      {
        if (window->resize) {
          window->resize (window->resize_data, LOWORD (lParam),
              HIWORD (lParam));
        }
        break;
      }
      case WM_PAINT:
      {
        if (window->draw) {
          PAINTSTRUCT ps;
          BeginPaint (hWnd, &ps);
          window->draw (window->draw_data);
          context_class->swap_buffers (context);
          EndPaint (hWnd, &ps);
        }
        break;
      }
      case WM_CLOSE:
      {
        ShowWindowAsync (window_win32->internal_win_id, SW_HIDE);

        GST_TRACE ("WM_CLOSE");

        if (window->close)
          window->close (window->close_data);
        break;
      }
      case WM_GST_GL_WINDOW_QUIT:
      {
        HWND parent_id = 0;

        GST_TRACE ("WM_GST_GL_WINDOW_QUIT");

        parent_id = window_win32->parent_win_id;
        if (parent_id) {
          WNDPROC parent_proc = GetProp (parent_id, "gl_window_parent_proc");

          g_assert (parent_proc);

          SetWindowLongPtr (parent_id, GWLP_WNDPROC, (LONG_PTR) parent_proc);
          SetParent (hWnd, NULL);

          RemoveProp (parent_id, "gl_window_parent_proc");
        }

        window_win32->is_closed = TRUE;
        RemoveProp (hWnd, "gl_window");

        if (window_win32->internal_win_id) {
          if (!DestroyWindow (window_win32->internal_win_id))
            GST_WARNING ("failed to destroy window %" G_GUINTPTR_FORMAT
                ", 0x%x", (guintptr) hWnd, (unsigned int) GetLastError ());
        }

        PostQuitMessage (0);
        break;
      }
      case WM_CAPTURECHANGED:
      {
        GST_DEBUG ("WM_CAPTURECHANGED");
        if (window->draw)
          window->draw (window->draw_data);
        break;
      }
      case WM_GST_GL_WINDOW_CUSTOM:
      {
        if (!window_win32->is_closed) {
          GstGLMessage *message = (GstGLMessage *) wParam;
          _run_message (message);
        }
        break;
      }
      case WM_ERASEBKGND:
        return TRUE;
      default:
      {
        /* transmit messages to the parrent (ex: mouse/keyboard input) */
        HWND parent_id = window_win32->parent_win_id;
        if (parent_id)
          PostMessage (parent_id, uMsg, wParam, lParam);
        return DefWindowProc (hWnd, uMsg, wParam, lParam);
      }
    }

    gst_object_unref (context);

    return 0;
  } else {
    return DefWindowProc (hWnd, uMsg, wParam, lParam);
  }
}
/**
 * gst_gl_context_new_wrapped:
 * @display: a #GstGLDisplay
 * @handle: the OpenGL context to wrap
 * @context_type: a #GstGLPlatform specifying the type of context in @handle
 * @available_apis: a #GstGLAPI containing the available OpenGL apis in @handle
 *
 * Wraps an existing OpenGL context into a #GstGLContext.  
 *
 * Returns: a #GstGLContext wrapping @handle
 *
 * Since: 1.4
 */
GstGLContext *
gst_gl_context_new_wrapped (GstGLDisplay * display, guintptr handle,
    GstGLPlatform context_type, GstGLAPI available_apis)
{
  GstGLContext *context;
  GstGLWrappedContext *context_wrap = NULL;
  GstGLContextClass *context_class;
  GstGLAPI display_api;

  _init_debug ();

  display_api = gst_gl_display_get_gl_api (display);
  g_return_val_if_fail ((display_api & available_apis) != GST_GL_API_NONE,
      NULL);

  context_wrap = g_object_new (GST_GL_TYPE_WRAPPED_CONTEXT, NULL);

  if (!context_wrap) {
    /* subclass returned a NULL context */
    GST_ERROR ("Could not wrap existing context");

    return NULL;
  }

  context = (GstGLContext *) context_wrap;

  context->display = gst_object_ref (display);
  context->priv->sharegroup_id = _new_sharegroup_id ();
  context_wrap->handle = handle;
  context_wrap->platform = context_type;
  context_wrap->available_apis = available_apis;

  context_class = GST_GL_CONTEXT_GET_CLASS (context);

#if GST_GL_HAVE_PLATFORM_GLX
  if (context_type == GST_GL_PLATFORM_GLX) {
    context_class->get_current_context = gst_gl_context_glx_get_current_context;
    context_class->get_proc_address = gst_gl_context_glx_get_proc_address;
  }
#endif
#if GST_GL_HAVE_PLATFORM_EGL
  if (context_type == GST_GL_PLATFORM_EGL) {
    context_class->get_current_context = gst_gl_context_egl_get_current_context;
    context_class->get_proc_address = gst_gl_context_egl_get_proc_address;
  }
#endif
#if GST_GL_HAVE_PLATFORM_CGL
  if (context_type == GST_GL_PLATFORM_CGL) {
    context_class->get_current_context =
        gst_gl_context_cocoa_get_current_context;
    context_class->get_proc_address = gst_gl_context_default_get_proc_address;
  }
#endif
#if GST_GL_HAVE_PLATFORM_WGL
  if (context_type == GST_GL_PLATFORM_WGL) {
    context_class->get_current_context = gst_gl_context_wgl_get_current_context;
    context_class->get_proc_address = gst_gl_context_wgl_get_proc_address;
  }
#endif
#if GST_GL_HAVE_PLATFORM_EAGL
  if (context_type == GST_GL_PLATFORM_EAGL) {
    context_class->get_current_context =
        gst_gl_context_eagl_get_current_context;
    context_class->get_proc_address = gst_gl_context_default_get_proc_address;
  }
#endif

  if (!context_class->get_current_context) {
    /* we don't have API support */
    gst_object_unref (context);
    return NULL;
  }

  return context;
}
//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;
  }
}
LRESULT CALLBACK
window_proc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
  GstGLWindowWin32 *window_win32;
  LRESULT ret = 0;

  if (uMsg == WM_CREATE) {
    window_win32 =
        GST_GL_WINDOW_WIN32 (((LPCREATESTRUCT) lParam)->lpCreateParams);

    GST_TRACE ("WM_CREATE");

    window_win32->device = GetDC (hWnd);
    /* Do this, otherwise we hang on exit. We can still use it (due to the
     * CS_OWNDC flag in the WindowClass) after we have Released.
     */
    ReleaseDC (hWnd, window_win32->device);

    SetProp (hWnd, "gl_window", window_win32);
  } else if (GetProp (hWnd, "gl_window")) {
    GstGLWindow *window;
    GstGLContext *context;
    GstGLContextClass *context_class;

    window_win32 = GST_GL_WINDOW_WIN32 (GetProp (hWnd, "gl_window"));
    window = GST_GL_WINDOW (window_win32);
    context = gst_gl_window_get_context (window);
    context_class = GST_GL_CONTEXT_GET_CLASS (context);

    g_assert (window_win32->internal_win_id == hWnd);

    switch (uMsg) {
      case WM_SIZE:
      {
        if (window->resize) {
          window->resize (window->resize_data, LOWORD (lParam),
              HIWORD (lParam));
        }
        break;
      }
      case WM_PAINT:
      {
        if (window->draw) {
          PAINTSTRUCT ps;
          BeginPaint (hWnd, &ps);
          window->draw (window->draw_data);
          context_class->swap_buffers (context);
          EndPaint (hWnd, &ps);
        }
        break;
      }
      case WM_CLOSE:
      {
        ShowWindowAsync (window_win32->internal_win_id, SW_HIDE);

        GST_TRACE ("WM_CLOSE");

        if (window->close)
          window->close (window->close_data);
        break;
      }
      case WM_CAPTURECHANGED:
      {
        GST_DEBUG ("WM_CAPTURECHANGED");
        if (window->draw)
          window->draw (window->draw_data);
        break;
      }
      case WM_ERASEBKGND:
      {
        ret = TRUE;
        break;
      }
      default:
      {
        /* transmit messages to the parrent (ex: mouse/keyboard input) */
        HWND parent_id = window_win32->parent_win_id;
        if (parent_id)
          PostMessage (parent_id, uMsg, wParam, lParam);
        ret = DefWindowProc (hWnd, uMsg, wParam, lParam);
      }
    }

    gst_object_unref (context);
  } else {
    ret = DefWindowProc (hWnd, uMsg, wParam, lParam);
  }

  return ret;
}