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:
      g_atomic_int_set (&glimage_sink->to_quit, 0);
      if (!glimage_sink->display) {
        GstGLWindow *window;
        GError *error = NULL;

        if (!gst_gl_ensure_display (glimage_sink, &glimage_sink->display))
          return GST_STATE_CHANGE_FAILURE;

        glimage_sink->context = gst_gl_context_new (glimage_sink->display);
        window = gst_gl_context_get_window (glimage_sink->context);

        if (!glimage_sink->window_id && !glimage_sink->new_window_id)
          gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY
              (glimage_sink));

        if (glimage_sink->window_id != glimage_sink->new_window_id) {
          glimage_sink->window_id = glimage_sink->new_window_id;
          gst_gl_window_set_window_handle (window, glimage_sink->window_id);
        }

        if (!gst_gl_context_create (glimage_sink->context,
                glimage_sink->other_context, &error)) {
          GST_ELEMENT_ERROR (glimage_sink, RESOURCE, NOT_FOUND, ("%s",
                  error->message), (NULL));

          if (glimage_sink->display) {
            gst_object_unref (glimage_sink->display);
            glimage_sink->display = NULL;
          }
          gst_object_unref (glimage_sink->context);
          gst_object_unref (window);

          return GST_STATE_CHANGE_FAILURE;
        }

        /* setup callbacks */
        gst_gl_window_set_resize_callback (window,
            GST_GL_WINDOW_RESIZE_CB (gst_glimage_sink_on_resize),
            gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref);
        gst_gl_window_set_draw_callback (window,
            GST_GL_WINDOW_CB (gst_glimage_sink_on_draw),
            gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref);
        gst_gl_window_set_close_callback (window,
            GST_GL_WINDOW_CB (gst_glimage_sink_on_close),
            gst_object_ref (glimage_sink), (GDestroyNotify) gst_object_unref);

        gst_object_unref (window);
      }
      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:
    {
      /* mark the redisplay_texture as unavailable (=0)
       * to avoid drawing
       */
      GST_GLIMAGE_SINK_LOCK (glimage_sink);
      glimage_sink->redisplay_texture = 0;
      GST_GLIMAGE_SINK_UNLOCK (glimage_sink);

      if (glimage_sink->upload) {
        gst_object_unref (glimage_sink->upload);
        glimage_sink->upload = NULL;
      }

      glimage_sink->window_id = 0;
      //but do not reset glimage_sink->new_window_id

      if (glimage_sink->pool) {
        gst_buffer_pool_set_active (glimage_sink->pool, FALSE);
        gst_object_unref (glimage_sink->pool);
        glimage_sink->pool = NULL;
      }

      GST_VIDEO_SINK_WIDTH (glimage_sink) = 1;
      GST_VIDEO_SINK_HEIGHT (glimage_sink) = 1;
      if (glimage_sink->context) {
        GstGLWindow *window = gst_gl_context_get_window (glimage_sink->context);

        gst_gl_window_send_message (window,
            GST_GL_WINDOW_CB (gst_glimage_sink_cleanup_glthread), glimage_sink);

        gst_gl_window_set_resize_callback (window, NULL, NULL, NULL);
        gst_gl_window_set_draw_callback (window, NULL, NULL, NULL);
        gst_gl_window_set_close_callback (window, NULL, NULL, NULL);

        gst_object_unref (window);
        gst_object_unref (glimage_sink->context);
        glimage_sink->context = NULL;
        gst_object_unref (glimage_sink->display);
        glimage_sink->display = NULL;
      }
      break;
    }
    case GST_STATE_CHANGE_READY_TO_NULL:
      break;
    default:
      break;
  }

  return ret;
}
static gboolean
_ensure_gl_setup (GstGLImageSink * gl_sink)
{
  GError *error = NULL;

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

  if (!gl_sink->context) {
    GstGLWindow *window;

    gl_sink->context = gst_gl_context_new (gl_sink->display);
    if (!gl_sink->context)
      goto context_creation_error;

    window = gst_gl_context_get_window (gl_sink->context);

    if (!gl_sink->window_id && !gl_sink->new_window_id)
      gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (gl_sink));

    if (gl_sink->window_id != gl_sink->new_window_id) {
      gl_sink->window_id = gl_sink->new_window_id;
      gst_gl_window_set_window_handle (window, gl_sink->window_id);
    }

    if (!gst_gl_context_create (gl_sink->context, gl_sink->other_context,
            &error)) {
      gst_object_unref (window);
      goto context_error;
    }

    /* setup callbacks */
    gst_gl_window_set_resize_callback (window,
        GST_GL_WINDOW_RESIZE_CB (gst_glimage_sink_on_resize),
        gst_object_ref (gl_sink), (GDestroyNotify) gst_object_unref);
    gst_gl_window_set_draw_callback (window,
        GST_GL_WINDOW_CB (gst_glimage_sink_on_draw),
        gst_object_ref (gl_sink), (GDestroyNotify) gst_object_unref);
    gst_gl_window_set_close_callback (window,
        GST_GL_WINDOW_CB (gst_glimage_sink_on_close),
        gst_object_ref (gl_sink), (GDestroyNotify) gst_object_unref);
    gl_sink->key_sig_id = g_signal_connect (window, "key-event", G_CALLBACK
        (gst_glimage_sink_key_event_cb), gl_sink);
    gl_sink->mouse_sig_id = g_signal_connect (window, "mouse-event", G_CALLBACK
        (gst_glimage_sink_mouse_event_cb), gl_sink);

    gst_object_unref (window);
  }

  return TRUE;

context_creation_error:
  {
    GST_ELEMENT_ERROR (gl_sink, RESOURCE, NOT_FOUND,
        ("Failed to create GL context"), (NULL));
    return FALSE;
  }

context_error:
  {
    GST_ELEMENT_ERROR (gl_sink, RESOURCE, NOT_FOUND, ("%s", error->message),
        (NULL));
    gst_object_unref (gl_sink->context);
    gl_sink->context = NULL;
    return FALSE;
  }
}