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
}
Exemple #3
0
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;
}
Exemple #4
0
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;
}