struct wl_buffer *
gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
    const GstVideoInfo * info)
{
  GstWlShmMemory *shm_mem = (GstWlShmMemory *) mem;
  gint width, height, stride;
  gsize size;
  enum wl_shm_format format;
  struct wl_shm_pool *wl_pool;
  struct wl_buffer *wbuffer;

  width = GST_VIDEO_INFO_WIDTH (info);
  height = GST_VIDEO_INFO_HEIGHT (info);
  stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
  size = GST_VIDEO_INFO_SIZE (info);
  format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));

  g_return_val_if_fail (gst_is_wl_shm_memory (mem), NULL);
  g_return_val_if_fail (size <= mem->size, NULL);
  g_return_val_if_fail (shm_mem->fd != -1, NULL);

  GST_DEBUG_OBJECT (mem->allocator, "Creating wl_buffer of size %"
      G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
      stride, gst_wl_shm_format_to_string (format));

  wl_pool = wl_shm_create_pool (display->shm, shm_mem->fd, mem->size);
  wbuffer = wl_shm_pool_create_buffer (wl_pool, 0, width, height, stride,
      format);

  close (shm_mem->fd);
  shm_mem->fd = -1;
  wl_shm_pool_destroy (wl_pool);

  return wbuffer;
}
static GstCaps *
gst_wayland_sink_get_caps (GstBaseSink * bsink, GstCaps * filter)
{
  GstWaylandSink *sink;
  GstCaps *caps;

  sink = GST_WAYLAND_SINK (bsink);

  caps = gst_pad_get_pad_template_caps (GST_VIDEO_SINK_PAD (sink));

  g_mutex_lock (&sink->display_lock);

  if (sink->display) {
    GValue list = G_VALUE_INIT;
    GValue value = G_VALUE_INIT;
    GArray *formats;
    gint i;
    enum wl_shm_format fmt;

    g_value_init (&list, GST_TYPE_LIST);
    g_value_init (&value, G_TYPE_STRING);

    formats = sink->display->shm_formats;
    for (i = 0; i < formats->len; i++) {
      fmt = g_array_index (formats, uint32_t, i);
      g_value_set_string (&value, gst_wl_shm_format_to_string (fmt));
      gst_value_list_append_value (&list, &value);
    }

    caps = gst_caps_make_writable (caps);
    gst_structure_set_value (gst_caps_get_structure (caps, 0), "format", &list);

    GST_DEBUG_OBJECT (sink, "display caps: %" GST_PTR_FORMAT, caps);
  }

  g_mutex_unlock (&sink->display_lock);

  if (filter) {
    GstCaps *intersection;

    intersection =
        gst_caps_intersect_full (filter, caps, GST_CAPS_INTERSECT_FIRST);
    gst_caps_unref (caps);
    caps = intersection;
  }

  return caps;
}
struct wl_buffer *
gst_wl_shm_memory_construct_wl_buffer (GstMemory * mem, GstWlDisplay * display,
    const GstVideoInfo * info)
{
  gint width, height, stride;
  gsize offset, size, memsize, maxsize;
  enum wl_shm_format format;
  struct wl_shm_pool *wl_pool;
  struct wl_buffer *wbuffer;

  if (!gst_wl_shm_validate_video_info (info)) {
    GST_DEBUG_OBJECT (display, "Unsupported strides and offsets.");
    return NULL;
  }

  width = GST_VIDEO_INFO_WIDTH (info);
  height = GST_VIDEO_INFO_HEIGHT (info);
  stride = GST_VIDEO_INFO_PLANE_STRIDE (info, 0);
  size = GST_VIDEO_INFO_SIZE (info);
  format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (info));

  memsize = gst_memory_get_sizes (mem, &offset, &maxsize);
  offset += GST_VIDEO_INFO_PLANE_OFFSET (info, 0);

  g_return_val_if_fail (gst_is_fd_memory (mem), NULL);
  g_return_val_if_fail (size <= memsize, NULL);
  g_return_val_if_fail (gst_wl_display_check_format_for_shm (display,
          GST_VIDEO_INFO_FORMAT (info)), NULL);

  GST_DEBUG_OBJECT (display, "Creating wl_buffer from SHM of size %"
      G_GSSIZE_FORMAT " (%d x %d, stride %d), format %s", size, width, height,
      stride, gst_wl_shm_format_to_string (format));

  wl_pool = wl_shm_create_pool (display->shm, gst_fd_memory_get_fd (mem),
      memsize);
  wbuffer = wl_shm_pool_create_buffer (wl_pool, offset, width, height, stride,
      format);
  wl_shm_pool_destroy (wl_pool);

  return wbuffer;
}
static gboolean
gst_wayland_sink_set_caps (GstBaseSink * bsink, GstCaps * caps)
{
  GstWaylandSink *sink;
  GstBufferPool *newpool;
  GstVideoInfo info;
  enum wl_shm_format format;
  GArray *formats;
  gint i;
  GstStructure *structure;

  sink = GST_WAYLAND_SINK (bsink);

  GST_DEBUG_OBJECT (sink, "set caps %" GST_PTR_FORMAT, caps);

  /* extract info from caps */
  if (!gst_video_info_from_caps (&info, caps))
    goto invalid_format;

  format = gst_video_format_to_wl_shm_format (GST_VIDEO_INFO_FORMAT (&info));
  if ((gint) format == -1)
    goto invalid_format;

  /* verify we support the requested format */
  formats = sink->display->shm_formats;
  for (i = 0; i < formats->len; i++) {
    if (g_array_index (formats, uint32_t, i) == format)
      break;
  }

  if (i >= formats->len)
    goto unsupported_format;

  /* create a new pool for the new configuration */
  newpool = gst_video_buffer_pool_new ();
  if (!newpool)
    goto pool_failed;

  structure = gst_buffer_pool_get_config (newpool);
  gst_buffer_pool_config_set_params (structure, caps, info.size, 2, 0);
  gst_buffer_pool_config_set_allocator (structure, gst_wl_shm_allocator_get (),
      NULL);
  if (!gst_buffer_pool_set_config (newpool, structure))
    goto config_failed;

  /* store the video info */
  sink->video_info = info;
  sink->video_info_changed = TRUE;

  gst_object_replace ((GstObject **) & sink->pool, (GstObject *) newpool);
  gst_object_unref (newpool);

  return TRUE;

invalid_format:
  {
    GST_DEBUG_OBJECT (sink,
        "Could not locate image format from caps %" GST_PTR_FORMAT, caps);
    return FALSE;
  }
unsupported_format:
  {
    GST_DEBUG_OBJECT (sink, "Format %s is not available on the display",
        gst_wl_shm_format_to_string (format));
    return FALSE;
  }
pool_failed:
  {
    GST_DEBUG_OBJECT (sink, "Failed to create new pool");
    return FALSE;
  }
config_failed:
  {
    GST_DEBUG_OBJECT (bsink, "failed setting config");
    gst_object_unref (newpool);
    return FALSE;
  }
}