static GstVaapiBufferProxy *
gst_vaapi_surface_get_drm_buf_handle (GstVaapiSurface * surface, guint type)
{
  GstVaapiBufferProxy *proxy;
  GstVaapiImage *image;

  image = gst_vaapi_surface_derive_image (surface);
  if (!image)
    goto error_derive_image;

  proxy =
      gst_vaapi_buffer_proxy_new_from_object (GST_VAAPI_OBJECT (surface),
      image->internal_image.buf, type, gst_vaapi_object_unref, image);
  if (!proxy)
    goto error_alloc_export_buffer;
  return proxy;

  /* ERRORS */
error_derive_image:
  GST_ERROR ("failed to extract image handle from surface");
  return NULL;
error_alloc_export_buffer:
  GST_ERROR ("failed to allocate export buffer proxy");
  gst_vaapi_object_unref (image);
  return NULL;
}
static gboolean
ensure_image (GstVaapiVideoMemory * mem)
{
  if (!mem->image && mem->use_direct_rendering) {
    mem->image = gst_vaapi_surface_derive_image (mem->surface);
    if (!mem->image) {
      GST_WARNING ("failed to derive image, fallbacking to copy");
      mem->use_direct_rendering = FALSE;
    } else if (gst_vaapi_surface_get_format (mem->surface) !=
        GST_VIDEO_INFO_FORMAT (mem->image_info)) {
      gst_vaapi_object_replace (&mem->image, NULL);
      mem->use_direct_rendering = FALSE;
    }
  }

  if (!mem->image) {
    GstVaapiVideoAllocator *const allocator =
        GST_VAAPI_VIDEO_ALLOCATOR_CAST (GST_MEMORY_CAST (mem)->allocator);

    mem->image = gst_vaapi_video_pool_get_object (allocator->image_pool);
    if (!mem->image)
      return FALSE;
  }
  gst_vaapi_video_meta_set_image (mem->meta, mem->image);
  return TRUE;
}
static inline void
allocator_configure_surface_info (GstVaapiDisplay * display,
    GstVaapiVideoAllocator * allocator)
{
  const GstVideoInfo *vinfo;
  GstVaapiSurface *surface = NULL;
  GstVaapiImage *image = NULL;
  gboolean updated;
  GstVideoFormat fmt;

  vinfo = &allocator->video_info;

  fmt = gst_vaapi_video_format_get_best_native (GST_VIDEO_INFO_FORMAT (vinfo));
  gst_video_info_set_format (&allocator->surface_info, fmt,
      GST_VIDEO_INFO_WIDTH (vinfo), GST_VIDEO_INFO_HEIGHT (vinfo));

  /* nothing to configure */
  if (USE_NATIVE_FORMATS ||
      GST_VIDEO_INFO_FORMAT (vinfo) == GST_VIDEO_FORMAT_ENCODED)
    return;

  surface = new_surface (display, vinfo);
  if (!surface)
    goto bail;
  image = gst_vaapi_surface_derive_image (surface);
  if (!image)
    goto bail;
  if (!gst_vaapi_image_map (image))
    goto bail;

  updated = gst_video_info_update_from_image (&allocator->surface_info, image);

  allocator->has_direct_rendering = !USE_NATIVE_FORMATS && updated &&
      (GST_VAAPI_IMAGE_FORMAT (image) == GST_VIDEO_INFO_FORMAT (vinfo));

  GST_INFO ("has direct-rendering for %s surfaces: %s",
      GST_VIDEO_INFO_FORMAT_STRING (&allocator->surface_info),
      allocator->has_direct_rendering ? "yes" : "no");

  gst_vaapi_image_unmap (image);

bail:
  if (surface)
    gst_vaapi_object_unref (surface);
  if (image)
    gst_vaapi_object_unref (image);
}
/**
 * gst_vaapi_surface_get_format:
 * @surface: a #GstVaapiSurface
 *
 * Returns the #GstVideoFormat the @surface was created with.
 *
 * Return value: the #GstVideoFormat, or %GST_VIDEO_FORMAT_ENCODED if
 *   the surface was not created with an explicit video format, or if
 *   the underlying video format could not be determined
 */
GstVideoFormat
gst_vaapi_surface_get_format (GstVaapiSurface * surface)
{
  g_return_val_if_fail (surface != NULL, 0);

  /* Try to determine the underlying VA surface format */
  if (surface->format == GST_VIDEO_FORMAT_UNKNOWN) {
    GstVaapiImage *const image = gst_vaapi_surface_derive_image (surface);
    if (image) {
      surface->format = GST_VAAPI_IMAGE_FORMAT (image);
      gst_vaapi_object_unref (image);
    }
    if (surface->format == GST_VIDEO_FORMAT_UNKNOWN)
      surface->format = GST_VIDEO_FORMAT_ENCODED;
  }
  return GST_VAAPI_SURFACE_FORMAT (surface);
}
GstAllocator *
gst_vaapi_dmabuf_allocator_new (GstVaapiDisplay * display,
    const GstVideoInfo * vip, guint flags)
{
  GstAllocator *allocator = NULL;
  GstVaapiSurface *surface = NULL;
  GstVaapiImage *image = NULL;
  GstVideoInfo alloc_info;

  g_return_val_if_fail (display != NULL, NULL);
  g_return_val_if_fail (vip != NULL, NULL);

  do {
    surface = gst_vaapi_surface_new_full (display, vip, flags);
    if (!surface)
      break;

    image = gst_vaapi_surface_derive_image (surface);
    if (!image || !gst_vaapi_image_map (image))
      break;

    gst_video_info_set_format (&alloc_info, GST_VIDEO_INFO_FORMAT (vip),
        GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip));
    gst_video_info_update_from_image (&alloc_info, image);
    gst_vaapi_image_unmap (image);

    allocator = gst_dmabuf_allocator_new ();
    if (!allocator)
      break;
    gst_allocator_set_vaapi_video_info (allocator, &alloc_info, flags);
  } while (0);

  gst_vaapi_object_replace (&image, NULL);
  gst_vaapi_object_replace (&surface, NULL);
  return allocator;
}