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; }