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;
}
示例#2
0
static GstFlowReturn
gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
{
  GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
  GstBuffer *to_render;
  GstWlBuffer *wlbuffer;
  GstFlowReturn ret = GST_FLOW_OK;

  g_mutex_lock (&sink->render_lock);

  GST_LOG_OBJECT (sink, "render buffer %p", buffer);

  if (G_UNLIKELY (!sink->window)) {
    /* ask for window handle. Unlock render_lock while doing that because
     * set_window_handle & friends will lock it in this context */
    g_mutex_unlock (&sink->render_lock);
    gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
    g_mutex_lock (&sink->render_lock);

    if (!sink->window) {
      /* if we were not provided a window, create one ourselves */
      sink->window =
          gst_wl_window_new_toplevel (sink->display, &sink->video_info);
    }
  }

  /* drop buffers until we get a frame callback */
  if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
    goto done;

  /* make sure that the application has called set_render_rectangle() */
  if (G_UNLIKELY (sink->window->render_rectangle.w == 0))
    goto no_window_size;

  wlbuffer = gst_buffer_get_wl_buffer (buffer);

  if (G_LIKELY (wlbuffer && wlbuffer->display == sink->display)) {
    GST_LOG_OBJECT (sink, "buffer %p has a wl_buffer from our display, "
        "writing directly", buffer);
    to_render = buffer;
  } else {
    GstMemory *mem;
    struct wl_buffer *wbuf = NULL;

    GST_LOG_OBJECT (sink, "buffer %p does not have a wl_buffer from our "
        "display, creating it", buffer);

    mem = gst_buffer_peek_memory (buffer, 0);

    if (gst_is_wl_shm_memory (mem)) {
      wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
          &sink->video_info);
    }

    if (wbuf) {
      gst_buffer_add_wl_buffer (buffer, wbuf, sink->display);
      to_render = buffer;
    } else {
      GstMapInfo src;
      /* we don't know how to create a wl_buffer directly from the provided
       * memory, so we have to copy the data to a memory that we know how
       * to handle... */

      GST_LOG_OBJECT (sink, "buffer %p cannot have a wl_buffer, "
          "copying to wl_shm memory", buffer);

      /* sink->pool always exists (created in set_caps), but it may not
       * be active if upstream is not using it */
      if (!gst_buffer_pool_is_active (sink->pool) &&
          !gst_buffer_pool_set_active (sink->pool, TRUE))
        goto activate_failed;

      ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
      if (ret != GST_FLOW_OK)
        goto no_buffer;

      /* the first time we acquire a buffer,
       * we need to attach a wl_buffer on it */
      wlbuffer = gst_buffer_get_wl_buffer (to_render);
      if (G_UNLIKELY (!wlbuffer)) {
        mem = gst_buffer_peek_memory (to_render, 0);
        wbuf = gst_wl_shm_memory_construct_wl_buffer (mem, sink->display,
            &sink->video_info);
        if (G_UNLIKELY (!wbuf))
          goto no_wl_buffer;

        gst_buffer_add_wl_buffer (to_render, wbuf, sink->display);
      }

      gst_buffer_map (buffer, &src, GST_MAP_READ);
      gst_buffer_fill (to_render, 0, src.data, src.size);
      gst_buffer_unmap (buffer, &src);
    }
  }

  /* drop double rendering */
  if (G_UNLIKELY (to_render == sink->last_buffer)) {
    GST_LOG_OBJECT (sink, "Buffer already being rendered");
    goto done;
  }

  gst_buffer_replace (&sink->last_buffer, to_render);
  render_last_buffer (sink);

  if (buffer != to_render)
    gst_buffer_unref (to_render);
  goto done;

no_window_size:
  {
    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
        ("Window has no size set"),
        ("Make sure you set the size after calling set_window_handle"));
    ret = GST_FLOW_ERROR;
    goto done;
  }
no_buffer:
  {
    GST_WARNING_OBJECT (sink, "could not create buffer");
    goto done;
  }
no_wl_buffer:
  {
    GST_ERROR_OBJECT (sink, "could not create wl_buffer out of wl_shm memory");
    ret = GST_FLOW_ERROR;
    goto done;
  }
activate_failed:
  {
    GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
    ret = GST_FLOW_ERROR;
    goto done;
  }
done:
  {
    g_mutex_unlock (&sink->render_lock);
    return ret;
  }
}
示例#3
0
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;
  }
}
static gboolean
gst_pvrvideosink_setcaps (GstBaseSink * bsink, GstCaps * caps)
{
  GstPVRVideoSink *pvrvideosink;
  GstVideoInfo info;
  GstStructure *structure;
  GstBufferPool *oldpool, *newpool;

  pvrvideosink = GST_PVRVIDEOSINK (bsink);

  GST_DEBUG_OBJECT (pvrvideosink,
      "sinkconnect possible caps with given caps %" GST_PTR_FORMAT, caps);

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

  GST_VIDEO_SINK_WIDTH (pvrvideosink) = info.width;
  GST_VIDEO_SINK_HEIGHT (pvrvideosink) = info.height;

  /* Notify application to set xwindow id now */
  g_mutex_lock (pvrvideosink->flow_lock);
  if (!pvrvideosink->xwindow) {
    g_mutex_unlock (pvrvideosink->flow_lock);
    gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (pvrvideosink));
  } else {
    g_mutex_unlock (pvrvideosink->flow_lock);
  }

  g_mutex_lock (pvrvideosink->flow_lock);
  if (!pvrvideosink->xwindow)
    pvrvideosink->xwindow = gst_pvrvideosink_create_window (pvrvideosink,
        GST_VIDEO_SINK_WIDTH (pvrvideosink),
        GST_VIDEO_SINK_HEIGHT (pvrvideosink));
  g_mutex_unlock (pvrvideosink->flow_lock);

  pvrvideosink->info = info;

  /* After a resize, we want to redraw the borders in case the new frame size
   * doesn't cover the same area */
  pvrvideosink->redraw_borders = TRUE;

  /* create a new pool for the new configuration */
  newpool = gst_pvr_buffer_pool_new (GST_ELEMENT_CAST (pvrvideosink));

  /* PVR needs at least 3 buffers */
  structure = gst_buffer_pool_get_config (newpool);
  gst_buffer_pool_config_set (structure, caps, GST_VIDEO_INFO_SIZE (&info), 3,
      0, 0, 15);
  if (!gst_buffer_pool_set_config (newpool, structure))
    goto config_failed;

  oldpool = pvrvideosink->pool;
  pvrvideosink->pool = newpool;
  g_mutex_unlock (pvrvideosink->flow_lock);

  /* unref the old sink */
  if (oldpool) {
    /* we don't deactivate, some elements might still be using it, it will
     * be deactivated when the last ref is gone */
    gst_object_unref (oldpool);
  }

  return TRUE;

config_failed:
  {
    GST_ERROR_OBJECT (pvrvideosink, "failed to set config.");
    g_mutex_unlock (pvrvideosink->flow_lock);
    return FALSE;
  }

invalid_format:
  {
    GST_DEBUG_OBJECT (pvrvideosink,
        "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
    return FALSE;
  }
}
示例#5
0
static GstFlowReturn
gst_wayland_sink_render (GstBaseSink * bsink, GstBuffer * buffer)
{
  GstWaylandSink *sink = GST_WAYLAND_SINK (bsink);
  GstBuffer *to_render;
  GstWlMeta *meta;
  GstFlowReturn ret = GST_FLOW_OK;

  g_mutex_lock (&sink->render_lock);

  GST_LOG_OBJECT (sink, "render buffer %p", buffer);

  if (G_UNLIKELY (!sink->window)) {
    /* ask for window handle. Unlock render_lock while doing that because
     * set_window_handle & friends will lock it in this context */
    g_mutex_unlock (&sink->render_lock);
    gst_video_overlay_prepare_window_handle (GST_VIDEO_OVERLAY (sink));
    g_mutex_lock (&sink->render_lock);

    if (sink->window) {
      /* inform the window about our caps */
      gst_wl_window_set_video_info (sink->window, &sink->video_info);
    } else {
      /* if we were not provided a window, create one ourselves */
      sink->window =
          gst_wl_window_new_toplevel (sink->display, &sink->video_info);
    }
    sink->video_info_changed = FALSE;
  }

  /* drop buffers until we get a frame callback */
  if (g_atomic_int_get (&sink->redraw_pending) == TRUE)
    goto done;

  if (G_UNLIKELY (sink->video_info_changed)) {
    gst_wl_window_set_video_info (sink->window, &sink->video_info);
    sink->video_info_changed = FALSE;
  }

  /* now that we have for sure set the video info on the window, it must have
   * a valid size, otherwise this means that the application has called
   * set_window_handle() without calling set_render_rectangle(), which is
   * absolutely necessary for us.
   */
  if (G_UNLIKELY (sink->window->surface_width == 0 ||
          sink->window->surface_height == 0))
    goto no_window_size;

  meta = gst_buffer_get_wl_meta (buffer);

  if (meta && meta->pool->display == sink->display) {
    GST_LOG_OBJECT (sink, "buffer %p from our pool, writing directly", buffer);
    to_render = buffer;
  } else {
    GstMapInfo src;
    GST_LOG_OBJECT (sink, "buffer %p not from our pool, copying", buffer);

    if (!sink->pool)
      goto no_pool;

    if (!gst_buffer_pool_set_active (sink->pool, TRUE))
      goto activate_failed;

    ret = gst_buffer_pool_acquire_buffer (sink->pool, &to_render, NULL);
    if (ret != GST_FLOW_OK)
      goto no_buffer;

    gst_buffer_map (buffer, &src, GST_MAP_READ);
    gst_buffer_fill (to_render, 0, src.data, src.size);
    gst_buffer_unmap (buffer, &src);
  }

  gst_buffer_replace (&sink->last_buffer, to_render);
  render_last_buffer (sink);

  if (buffer != to_render)
    gst_buffer_unref (to_render);
  goto done;

no_window_size:
  {
    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
        ("Window has no size set"),
        ("Make sure you set the size after calling set_window_handle"));
    ret = GST_FLOW_ERROR;
    goto done;
  }
no_buffer:
  {
    GST_WARNING_OBJECT (sink, "could not create image");
    goto done;
  }
no_pool:
  {
    GST_ELEMENT_ERROR (sink, RESOURCE, WRITE,
        ("Internal error: can't allocate images"),
        ("We don't have a bufferpool negotiated"));
    ret = GST_FLOW_ERROR;
    goto done;
  }
activate_failed:
  {
    GST_ERROR_OBJECT (sink, "failed to activate bufferpool.");
    ret = GST_FLOW_ERROR;
    goto done;
  }
done:
  {
    g_mutex_unlock (&sink->render_lock);
    return ret;
  }
}