static gboolean
plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin,
    GstBuffer * inbuf, GstBuffer * outbuf)
{
  GstVideoInfo *const vip = &plugin->sinkpad_info;
  GstVaapiVideoMeta *meta;
  GstVaapiSurface *surface;
  GstVaapiSurfaceProxy *proxy;
  gint fd;

  fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0));
  if (fd < 0)
    return FALSE;

  if (!plugin_update_sinkpad_info_from_buffer (plugin, inbuf))
    goto error_update_sinkpad_info;

  meta = gst_buffer_get_vaapi_video_meta (outbuf);
  g_return_val_if_fail (meta != NULL, FALSE);

  /* Check for a VASurface cached in the buffer */
  surface = _get_cached_surface (inbuf);
  if (!surface) {
    /* otherwise create one and cache it */
    surface =
        gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd, vip);
    if (!surface)
      goto error_create_surface;
    _set_cached_surface (inbuf, surface);
  }

  proxy = gst_vaapi_surface_proxy_new (surface);
  if (!proxy)
    goto error_create_proxy;
  gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
  gst_vaapi_surface_proxy_unref (proxy);
  gst_buffer_add_parent_buffer_meta (outbuf, inbuf);
  return TRUE;

  /* ERRORS */
error_update_sinkpad_info:
  {
    GST_ERROR_OBJECT (plugin,
        "failed to update sink pad video info from video meta");
    return FALSE;
  }
error_create_surface:
  {
    GST_ERROR_OBJECT (plugin,
        "failed to create VA surface from dma_buf handle");
    return FALSE;
  }
error_create_proxy:
  {
    GST_ERROR_OBJECT (plugin,
        "failed to create VA surface proxy from wrapped VA surface");
    return FALSE;
  }
}
static gboolean
plugin_bind_dma_to_vaapi_buffer (GstVaapiPluginBase * plugin,
    GstBuffer * inbuf, GstBuffer * outbuf)
{
  GstVideoInfo *const vip = &plugin->sinkpad_info;
  GstVaapiVideoMeta *meta;
  GstVaapiSurface *surface;
  GstVaapiSurfaceProxy *proxy;
  gint fd;

  fd = gst_dmabuf_memory_get_fd (gst_buffer_peek_memory (inbuf, 0));
  if (fd < 0)
    return FALSE;

  if (!plugin_update_sinkpad_info_from_buffer (plugin, inbuf))
    goto error_update_sinkpad_info;

  meta = gst_buffer_get_vaapi_video_meta (outbuf);
  g_return_val_if_fail (meta != NULL, FALSE);

  surface = gst_vaapi_surface_new_with_dma_buf_handle (plugin->display, fd,
      GST_VIDEO_INFO_SIZE (vip), GST_VIDEO_INFO_FORMAT (vip),
      GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip),
      vip->offset, vip->stride);
  if (!surface)
    goto error_create_surface;

  proxy = gst_vaapi_surface_proxy_new (surface);
  gst_vaapi_object_unref (surface);
  if (!proxy)
    goto error_create_proxy;

  gst_vaapi_surface_proxy_set_destroy_notify (proxy,
      (GDestroyNotify) gst_buffer_unref, (gpointer) gst_buffer_ref (inbuf));
  gst_vaapi_video_meta_set_surface_proxy (meta, proxy);
  gst_vaapi_surface_proxy_unref (proxy);
  return TRUE;

  /* ERRORS */
error_update_sinkpad_info:
  GST_ERROR ("failed to update sink pad video info from video meta");
  return FALSE;
error_create_surface:
  GST_ERROR ("failed to create VA surface from dma_buf handle");
  return FALSE;
error_create_proxy:
  GST_ERROR ("failed to create VA surface proxy from wrapped VA surface");
  return FALSE;
}
static gboolean
import_dmabuf_to_msdk_surface (GstMsdkVPP * thiz, GstBuffer * buf,
    MsdkSurface * msdk_surface)
{
  GstMemory *mem = NULL;
  GstVideoInfo vinfo;
  GstVideoMeta *vmeta;
  GstMsdkMemoryID *msdk_mid = NULL;
  mfxFrameSurface1 *mfx_surface = NULL;
  gint fd, i;

  mem = gst_buffer_peek_memory (buf, 0);
  fd = gst_dmabuf_memory_get_fd (mem);
  if (fd < 0)
    return FALSE;

  vinfo = thiz->sinkpad_info;

  /* Update offset/stride/size if there is VideoMeta attached to
   * the buffer */
  vmeta = gst_buffer_get_video_meta (buf);
  if (vmeta) {
    if (GST_VIDEO_INFO_FORMAT (&vinfo) != vmeta->format ||
        GST_VIDEO_INFO_WIDTH (&vinfo) != vmeta->width ||
        GST_VIDEO_INFO_HEIGHT (&vinfo) != vmeta->height ||
        GST_VIDEO_INFO_N_PLANES (&vinfo) != vmeta->n_planes) {
      GST_ERROR_OBJECT (thiz, "VideoMeta attached to buffer is not matching"
          "the negotiated width/height/format");
      return FALSE;
    }
    for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&vinfo); ++i) {
      GST_VIDEO_INFO_PLANE_OFFSET (&vinfo, i) = vmeta->offset[i];
      GST_VIDEO_INFO_PLANE_STRIDE (&vinfo, i) = vmeta->stride[i];
    }
    GST_VIDEO_INFO_SIZE (&vinfo) = gst_buffer_get_size (buf);
  }

  /* Upstream neither accepted the msdk pool nor the msdk buffer size restrictions.
   * Current media-driver and GMMLib will fail due to strict memory size restrictions.
   * Ideally, media-driver should accept what ever memory coming from other drivers
   * in case of dmabuf-import and this is how the intel-vaapi-driver works.
   * For now, in order to avoid any crash we check the buffer size and fallback
   * to copy frame method.
   *
   * See this: https://github.com/intel/media-driver/issues/169
   * */
  if (GST_VIDEO_INFO_SIZE (&vinfo) <
      GST_VIDEO_INFO_SIZE (&thiz->sinkpad_buffer_pool_info))
    return FALSE;

  mfx_surface = msdk_surface->surface;
  msdk_mid = (GstMsdkMemoryID *) mfx_surface->Data.MemId;

  /* release the internal memory storage of associated mfxSurface */
  gst_msdk_replace_mfx_memid (thiz->context, mfx_surface, VA_INVALID_ID);

  /* export dmabuf to vasurface */
  if (!gst_msdk_export_dmabuf_to_vasurface (thiz->context, &vinfo, fd,
          msdk_mid->surface))
    return FALSE;

  return TRUE;
}
gboolean
gst_v4l2_allocator_import_dmabuf (GstV4l2Allocator * allocator,
    GstV4l2MemoryGroup * group, gint n_mem, GstMemory ** dma_mem)
{
  GstV4l2Memory *mem;
  gint i;

  g_return_val_if_fail (allocator->memory == V4L2_MEMORY_DMABUF, FALSE);

  if (group->n_mem != n_mem)
    goto n_mem_missmatch;

  for (i = 0; i < group->n_mem; i++) {
    gint dmafd;
    gsize size, offset, maxsize;

    if (!gst_is_dmabuf_memory (dma_mem[i]))
      goto not_dmabuf;

    size = gst_memory_get_sizes (dma_mem[i], &offset, &maxsize);

    if ((dmafd = dup (gst_dmabuf_memory_get_fd (dma_mem[i]))) < 0)
      goto dup_failed;

    GST_LOG_OBJECT (allocator, "imported DMABUF as fd %i plane %d", dmafd, i);

    mem = (GstV4l2Memory *) group->mem[i];

    /* Update memory */
    mem->mem.maxsize = maxsize;
    mem->mem.offset = offset;
    mem->mem.size = size;
    mem->dmafd = dmafd;

    /* Update v4l2 structure */
    group->planes[i].length = maxsize;
    group->planes[i].bytesused = size;
    group->planes[i].m.fd = dmafd;
    group->planes[i].data_offset = offset;
  }

  /* Copy into buffer structure if not using planes */
  if (!V4L2_TYPE_IS_MULTIPLANAR (allocator->type)) {
    group->buffer.bytesused = group->planes[0].bytesused;
    group->buffer.length = group->planes[0].length;
    group->buffer.m.fd = group->planes[0].m.userptr;
  } else {
    group->buffer.length = group->n_mem;
  }

  return TRUE;

n_mem_missmatch:
  {
    GST_ERROR_OBJECT (allocator, "Got %i dmabuf but needed %i", n_mem,
        group->n_mem);
    return FALSE;
  }
not_dmabuf:
  {
    GST_ERROR_OBJECT (allocator, "Memory %i is not of DMABUF", i);
    return FALSE;
  }
dup_failed:
  {
    GST_ERROR_OBJECT (allocator, "Failed to dup DMABUF descriptor: %s",
        g_strerror (errno));
    return FALSE;
  }
}
static gboolean
gst_kms_sink_import_dmabuf (GstKMSSink * self, GstBuffer * inbuf,
    GstBuffer ** outbuf)
{
  gint prime_fds[GST_VIDEO_MAX_PLANES] = { 0, };
  GstVideoMeta *meta;
  guint i, n_mem, n_planes;
  GstKMSMemory *kmsmem;
  guint mems_idx[GST_VIDEO_MAX_PLANES];
  gsize mems_skip[GST_VIDEO_MAX_PLANES];
  GstMemory *mems[GST_VIDEO_MAX_PLANES];

  if (!self->has_prime_import)
    return FALSE;

  /* This will eliminate most non-dmabuf out there */
  if (!gst_is_dmabuf_memory (gst_buffer_peek_memory (inbuf, 0)))
    return FALSE;

  n_planes = GST_VIDEO_INFO_N_PLANES (&self->vinfo);
  n_mem = gst_buffer_n_memory (inbuf);
  meta = gst_buffer_get_video_meta (inbuf);

  GST_TRACE_OBJECT (self, "Found a dmabuf with %u planes and %u memories",
      n_planes, n_mem);

  /* We cannot have multiple dmabuf per plane */
  if (n_mem > n_planes)
    return FALSE;

  /* Update video info based on video meta */
  if (meta) {
    GST_VIDEO_INFO_WIDTH (&self->vinfo) = meta->width;
    GST_VIDEO_INFO_HEIGHT (&self->vinfo) = meta->height;

    for (i = 0; i < meta->n_planes; i++) {
      GST_VIDEO_INFO_PLANE_OFFSET (&self->vinfo, i) = meta->offset[i];
      GST_VIDEO_INFO_PLANE_STRIDE (&self->vinfo, i) = meta->stride[i];
    }
  }

  /* Find and validate all memories */
  for (i = 0; i < n_planes; i++) {
    guint length;

    if (!gst_buffer_find_memory (inbuf,
            GST_VIDEO_INFO_PLANE_OFFSET (&self->vinfo, i), 1,
            &mems_idx[i], &length, &mems_skip[i]))
      return FALSE;

    mems[i] = gst_buffer_peek_memory (inbuf, mems_idx[i]);

    /* And all memory found must be dmabuf */
    if (!gst_is_dmabuf_memory (mems[i]))
      return FALSE;
  }

  kmsmem = (GstKMSMemory *) get_cached_kmsmem (mems[0]);
  if (kmsmem) {
    GST_LOG_OBJECT (self, "found KMS mem %p in DMABuf mem %p with fb id = %d",
        kmsmem, mems[0], kmsmem->fb_id);
    goto wrap_mem;
  }

  for (i = 0; i < n_planes; i++)
    prime_fds[i] = gst_dmabuf_memory_get_fd (mems[i]);

  GST_LOG_OBJECT (self, "found these prime ids: %d, %d, %d, %d", prime_fds[0],
      prime_fds[1], prime_fds[2], prime_fds[3]);

  kmsmem = gst_kms_allocator_dmabuf_import (self->allocator, prime_fds,
      n_planes, mems_skip, &self->vinfo);
  if (!kmsmem)
    return FALSE;

  GST_LOG_OBJECT (self, "setting KMS mem %p to DMABuf mem %p with fb id = %d",
      kmsmem, mems[0], kmsmem->fb_id);
  set_cached_kmsmem (mems[0], GST_MEMORY_CAST (kmsmem));

wrap_mem:
  *outbuf = gst_buffer_new ();
  if (!*outbuf)
    return FALSE;
  gst_buffer_append_memory (*outbuf, gst_memory_ref (GST_MEMORY_CAST (kmsmem)));
  gst_buffer_add_parent_buffer_meta (*outbuf, inbuf);

  return TRUE;
}