static GstFlowReturn
gst_vaapi_video_buffer_pool_acquire_buffer (GstBufferPool * pool,
    GstBuffer ** out_buffer_ptr, GstBufferPoolAcquireParams * params)
{
  GstVaapiVideoBufferPoolPrivate *const priv =
      GST_VAAPI_VIDEO_BUFFER_POOL (pool)->priv;
  GstVaapiVideoBufferPoolAcquireParams *const priv_params =
      (GstVaapiVideoBufferPoolAcquireParams *) params;
  GstFlowReturn ret;
  GstBuffer *buffer;
  GstMemory *mem;
  GstVaapiVideoMeta *meta;
  GstVaapiSurface *surface;
  GstVaapiBufferProxy *dmabuf_proxy;

  ret =
      GST_BUFFER_POOL_CLASS
      (gst_vaapi_video_buffer_pool_parent_class)->acquire_buffer (pool, &buffer,
      params);

  if (!priv->use_dmabuf_memory || !params || !priv_params->proxy
      || ret != GST_FLOW_OK) {
    *out_buffer_ptr = buffer;
    return ret;
  }

  /* The point of the following dance is to attach the right GstMemory to the
   * current acquired buffer. Indeed this buffer can contain any of the
   * GstFdmemory since this buffer have been popped out from the buffer pool's
   * FIFO. So there is no garantee that this matches the current surface. The
   * va decoder driver might not even use a FIFO. So there is no way to guess
   * on the ordering. In short acquire_current_buffer on the va driver and on
   * the buffer pool return none matching data. So we have to manually attach
   * the right GstFdMemory to the acquired GstBuffer. The right GstMemory is
   * the one associated with the current surface. */
  g_assert (gst_buffer_n_memory (buffer) == 1);

  /* Find the cached memory associated with the given surface. */
  surface = GST_VAAPI_SURFACE_PROXY_SURFACE (priv_params->proxy);
  dmabuf_proxy = gst_vaapi_surface_peek_buffer_proxy (surface);
  if (dmabuf_proxy) {
    mem = gst_vaapi_buffer_proxy_peek_mem (dmabuf_proxy);
    if (mem == gst_buffer_peek_memory (buffer, 0))
      mem = NULL;
    else
      mem = gst_memory_ref (mem);
  } else {
    /* The given surface has not been exported yet. */
    meta = gst_buffer_get_vaapi_video_meta (buffer);
    if (gst_vaapi_video_meta_get_surface_proxy (meta))
      gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy);

    mem =
        gst_vaapi_dmabuf_memory_new (priv->allocator,
        gst_buffer_get_vaapi_video_meta (buffer));
  }

  /* Attach the GstFdMemory to the output buffer. */
  if (mem) {
    GST_DEBUG_OBJECT (pool, "assigning memory %p to acquired buffer %p", mem,
        buffer);
    gst_buffer_replace_memory (buffer, 0, mem);
    gst_buffer_unset_flags (buffer, GST_BUFFER_FLAG_TAG_MEMORY);
  }

  *out_buffer_ptr = buffer;
  return GST_FLOW_OK;
}
/* Called by the idle function in the gl thread */
void
_do_convert (GstGLContext * context, GstGLColorConvert * convert)
{
  guint in_width, in_height, out_width, out_height;
  struct ConvertInfo *c_info = &convert->priv->convert_info;
  GstMapInfo out_info[GST_VIDEO_MAX_PLANES], in_info[GST_VIDEO_MAX_PLANES];
  gboolean res = TRUE;
  gint i, j = 0;

  out_width = GST_VIDEO_INFO_WIDTH (&convert->out_info);
  out_height = GST_VIDEO_INFO_HEIGHT (&convert->out_info);
  in_width = GST_VIDEO_INFO_WIDTH (&convert->in_info);
  in_height = GST_VIDEO_INFO_HEIGHT (&convert->in_info);

  convert->outbuf = NULL;

  if (!_init_convert (convert)) {
    convert->priv->result = FALSE;
    return;
  }

  convert->outbuf = gst_buffer_new ();
  if (!gst_gl_memory_setup_buffer (convert->context, &convert->out_info,
          convert->outbuf)) {
    convert->priv->result = FALSE;
    return;
  }

  gst_buffer_add_video_meta_full (convert->outbuf, 0,
      GST_VIDEO_INFO_FORMAT (&convert->out_info),
      GST_VIDEO_INFO_WIDTH (&convert->out_info),
      GST_VIDEO_INFO_HEIGHT (&convert->out_info),
      GST_VIDEO_INFO_N_PLANES (&convert->out_info),
      convert->out_info.offset, convert->out_info.stride);

  for (i = 0; i < c_info->in_n_textures; i++) {
    convert->priv->in_tex[i] =
        (GstGLMemory *) gst_buffer_peek_memory (convert->inbuf, i);
    if (!gst_is_gl_memory ((GstMemory *) convert->priv->in_tex[i])) {
      GST_ERROR_OBJECT (convert, "input must be GstGLMemory");
      res = FALSE;
      goto out;
    }
    if (!gst_memory_map ((GstMemory *) convert->priv->in_tex[i], &in_info[i],
            GST_MAP_READ | GST_MAP_GL)) {
      GST_ERROR_OBJECT (convert, "failed to map input memory %p",
          convert->priv->in_tex[i]);
      res = FALSE;
      goto out;
    }
  }

  for (j = 0; j < c_info->out_n_textures; j++) {
    GstGLMemory *out_tex =
        (GstGLMemory *) gst_buffer_peek_memory (convert->outbuf, j);
    gint mem_width, mem_height;

    if (!gst_is_gl_memory ((GstMemory *) out_tex)) {
      GST_ERROR_OBJECT (convert, "output must be GstGLMemory");
      res = FALSE;
      goto out;
    }

    mem_width = gst_gl_memory_get_texture_width (out_tex);
    mem_height = gst_gl_memory_get_texture_height (out_tex);

    if (out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
        || out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA
        || out_width != mem_width || out_height != mem_height) {
      /* Luminance formats are not color renderable */
      /* renderering to a framebuffer only renders the intersection of all
       * the attachments i.e. the smallest attachment size */
      GstVideoInfo temp_info;

      gst_video_info_set_format (&temp_info, GST_VIDEO_FORMAT_RGBA, out_width,
          out_height);

      if (!convert->priv->out_tex[j])
        convert->priv->out_tex[j] =
            (GstGLMemory *) gst_gl_memory_alloc (context, &temp_info, 0);
    } else {
      convert->priv->out_tex[j] = out_tex;
    }

    if (!gst_memory_map ((GstMemory *) convert->priv->out_tex[j], &out_info[j],
            GST_MAP_WRITE | GST_MAP_GL)) {
      GST_ERROR_OBJECT (convert, "failed to map output memory %p",
          convert->priv->out_tex[i]);
      res = FALSE;
      goto out;
    }
  }

  GST_LOG_OBJECT (convert, "converting to textures:%p,%p,%p,%p "
      "dimensions:%ux%u, from textures:%p,%p,%p,%p dimensions:%ux%u",
      convert->priv->out_tex[0], convert->priv->out_tex[1],
      convert->priv->out_tex[2], convert->priv->out_tex[3], out_width,
      out_height, convert->priv->in_tex[0], convert->priv->in_tex[1],
      convert->priv->in_tex[2], convert->priv->in_tex[3], in_width, in_height);

  if (!_do_convert_draw (context, convert))
    res = FALSE;

out:
  for (j--; j >= 0; j--) {
    GstGLMemory *out_tex =
        (GstGLMemory *) gst_buffer_peek_memory (convert->outbuf, j);
    gint mem_width, mem_height;

    gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &out_info[j]);

    mem_width = gst_gl_memory_get_texture_width (out_tex);
    mem_height = gst_gl_memory_get_texture_height (out_tex);

    if (out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE
        || out_tex->tex_type == GST_VIDEO_GL_TEXTURE_TYPE_LUMINANCE_ALPHA
        || out_width != mem_width || out_height != mem_height) {
      GstMapInfo to_info, from_info;

      if (!gst_memory_map ((GstMemory *) convert->priv->out_tex[j], &from_info,
              GST_MAP_READ | GST_MAP_GL)) {
        gst_gl_context_set_error (convert->context, "Failed to map "
            "intermediate memory");
        res = FALSE;
        continue;
      }
      if (!gst_memory_map ((GstMemory *) out_tex, &to_info,
              GST_MAP_WRITE | GST_MAP_GL)) {
        gst_gl_context_set_error (convert->context, "Failed to map "
            "intermediate memory");
        res = FALSE;
        continue;
      }
      gst_gl_memory_copy_into_texture (convert->priv->out_tex[j],
          out_tex->tex_id, out_tex->tex_type, mem_width, mem_height,
          GST_VIDEO_INFO_PLANE_STRIDE (&out_tex->info, out_tex->plane), FALSE);
      gst_memory_unmap ((GstMemory *) convert->priv->out_tex[j], &from_info);
      gst_memory_unmap ((GstMemory *) out_tex, &to_info);
    } else {
      convert->priv->out_tex[j] = NULL;
    }
  }

  /* YV12 the same as I420 except planes 1+2 swapped */
  if (GST_VIDEO_INFO_FORMAT (&convert->out_info) == GST_VIDEO_FORMAT_YV12) {
    GstMemory *mem1 = gst_buffer_get_memory (convert->outbuf, 1);
    GstMemory *mem2 = gst_buffer_get_memory (convert->outbuf, 2);

    gst_buffer_replace_memory (convert->outbuf, 1, mem2);
    gst_buffer_replace_memory (convert->outbuf, 2, mem1);
  }

  for (i--; i >= 0; i--) {
    gst_memory_unmap ((GstMemory *) convert->priv->in_tex[i], &in_info[i]);
  }

  if (!res) {
    gst_buffer_unref (convert->outbuf);
    convert->outbuf = NULL;
  }

  convert->priv->result = res;
  return;
}