static void gst_vaapi_video_buffer_pool_finalize (GObject * object) { GstVaapiVideoBufferPoolPrivate *const priv = GST_VAAPI_VIDEO_BUFFER_POOL (object)->priv; gst_vaapi_display_replace (&priv->display, NULL); g_clear_object (&priv->allocator); G_OBJECT_CLASS (gst_vaapi_video_buffer_pool_parent_class)->finalize (object); }
static void gst_vaapi_video_buffer_pool_get_property (GObject * object, guint prop_id, GValue * value, GParamSpec * pspec) { GstVaapiVideoBufferPoolPrivate *const priv = GST_VAAPI_VIDEO_BUFFER_POOL (object)->priv; switch (prop_id) { case PROP_DISPLAY: g_value_set_pointer (value, priv->display); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
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; }
static GstFlowReturn gst_vaapi_video_buffer_pool_alloc_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; GstVaapiVideoMeta *meta; GstMemory *mem; GstBuffer *buffer; const gboolean alloc_vaapi_video_meta = !params || !(params->flags & GST_VAAPI_VIDEO_BUFFER_POOL_ACQUIRE_FLAG_NO_ALLOC); if (!priv->allocator) goto error_no_allocator; if (alloc_vaapi_video_meta) { meta = gst_vaapi_video_meta_new (priv->display); if (!meta) goto error_create_meta; buffer = gst_vaapi_video_buffer_new (meta); } else { meta = NULL; buffer = gst_vaapi_video_buffer_new_empty (); } if (!buffer) goto error_create_buffer; if (priv_params && priv_params->proxy) gst_vaapi_video_meta_set_surface_proxy (meta, priv_params->proxy); if (priv->use_dmabuf_memory) mem = gst_vaapi_dmabuf_memory_new (priv->allocator, meta); else mem = gst_vaapi_video_memory_new (priv->allocator, meta); if (!mem) goto error_create_memory; gst_vaapi_video_meta_replace (&meta, NULL); gst_buffer_append_memory (buffer, mem); if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META) { GstVideoInfo *const vip = &priv->vmeta_vinfo; GstVideoMeta *vmeta; vmeta = gst_buffer_add_video_meta_full (buffer, 0, GST_VIDEO_INFO_FORMAT (vip), GST_VIDEO_INFO_WIDTH (vip), GST_VIDEO_INFO_HEIGHT (vip), GST_VIDEO_INFO_N_PLANES (vip), &GST_VIDEO_INFO_PLANE_OFFSET (vip, 0), &GST_VIDEO_INFO_PLANE_STRIDE (vip, 0)); if (GST_VAAPI_IS_VIDEO_MEMORY (mem)) { vmeta->map = gst_video_meta_map_vaapi_memory; vmeta->unmap = gst_video_meta_unmap_vaapi_memory; } } #if (USE_GLX || USE_EGL) if (priv->options & GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD) gst_buffer_add_texture_upload_meta (buffer); #endif *out_buffer_ptr = buffer; return GST_FLOW_OK; /* ERRORS */ error_no_allocator: { GST_ERROR_OBJECT (pool, "no GstAllocator in buffer pool"); return GST_FLOW_ERROR; } error_create_meta: { GST_ERROR_OBJECT (pool, "failed to allocate vaapi video meta"); return GST_FLOW_ERROR; } error_create_buffer: { GST_ERROR_OBJECT (pool, "failed to create video buffer"); gst_vaapi_video_meta_unref (meta); return GST_FLOW_ERROR; } error_create_memory: { GST_ERROR_OBJECT (pool, "failed to create video memory"); gst_buffer_unref (buffer); gst_vaapi_video_meta_unref (meta); return GST_FLOW_ERROR; } }
static gboolean gst_vaapi_video_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) { GstVaapiVideoBufferPoolPrivate *const priv = GST_VAAPI_VIDEO_BUFFER_POOL (pool)->priv; GstCaps *caps; GstVideoInfo new_allocation_vinfo; const GstVideoInfo *allocator_vinfo; const GstVideoInfo *negotiated_vinfo; GstVideoAlignment align; GstAllocator *allocator; gboolean ret, updated = FALSE; guint size, min_buffers, max_buffers; guint surface_alloc_flags; GST_DEBUG_OBJECT (pool, "config %" GST_PTR_FORMAT, config); caps = NULL; if (!gst_buffer_pool_config_get_params (config, &caps, &size, &min_buffers, &max_buffers)) goto error_invalid_config; if (!caps) goto error_no_caps; if (!gst_video_info_from_caps (&new_allocation_vinfo, caps)) goto error_invalid_caps; allocator = NULL; if (!gst_buffer_pool_config_get_allocator (config, &allocator, NULL)) goto error_invalid_allocator; /* it is a valid allocator? */ if (allocator && (g_strcmp0 (allocator->mem_type, GST_VAAPI_VIDEO_MEMORY_NAME) != 0 && g_strcmp0 (allocator->mem_type, GST_VAAPI_DMABUF_ALLOCATOR_NAME) != 0)) allocator = NULL; /* get the allocator properties */ if (allocator) { priv->use_dmabuf_memory = gst_vaapi_is_dmabuf_allocator (allocator); negotiated_vinfo = gst_allocator_get_vaapi_negotiated_video_info (allocator); allocator_vinfo = gst_allocator_get_vaapi_video_info (allocator, &surface_alloc_flags); } else { priv->use_dmabuf_memory = FALSE; negotiated_vinfo = NULL; allocator_vinfo = NULL; surface_alloc_flags = 0; } /* reset or update the allocator if video resolution changed */ if (allocator_vinfo && gst_video_info_changed (allocator_vinfo, &new_allocation_vinfo)) { gst_object_replace ((GstObject **) & priv->allocator, NULL); if (allocator && priv->use_dmabuf_memory) { gst_allocator_set_vaapi_video_info (allocator, &new_allocation_vinfo, surface_alloc_flags); } else { allocator = NULL; } } if (!gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) goto error_no_vaapi_video_meta_option; /* create a new allocator if needed */ if (!allocator) { if (priv->use_dmabuf_memory) { allocator = gst_vaapi_dmabuf_allocator_new (priv->display, &new_allocation_vinfo, /* FIXME: */ 0, GST_PAD_SRC); } else { allocator = gst_vaapi_video_allocator_new (priv->display, &new_allocation_vinfo, surface_alloc_flags, 0); } if (!allocator) goto error_no_allocator; if (negotiated_vinfo) { gst_allocator_set_vaapi_negotiated_video_info (allocator, negotiated_vinfo); } GST_INFO_OBJECT (pool, "created new allocator %" GST_PTR_FORMAT, allocator); gst_buffer_pool_config_set_allocator (config, allocator, NULL); gst_object_unref (allocator); } /* use the allocator and set the video info for the vmeta */ if (allocator) { if (priv->allocator) gst_object_unref (priv->allocator); if ((priv->allocator = allocator)) gst_object_ref (allocator); negotiated_vinfo = gst_allocator_get_vaapi_negotiated_video_info (priv->allocator); allocator_vinfo = gst_allocator_get_vaapi_video_info (allocator, NULL); priv->vmeta_vinfo = (negotiated_vinfo) ? *negotiated_vinfo : *allocator_vinfo; /* last resource to set the correct buffer size */ if (GST_VIDEO_INFO_SIZE (allocator_vinfo) != size) { gst_buffer_pool_config_set_params (config, caps, GST_VIDEO_INFO_SIZE (allocator_vinfo), min_buffers, max_buffers); } } if (!priv->allocator) goto error_no_allocator; priv->options = 0; if (gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META)) { priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META; } else { gint i; for (i = 0; i < GST_VIDEO_INFO_N_PLANES (&new_allocation_vinfo); i++) { if (GST_VIDEO_INFO_PLANE_OFFSET (&new_allocation_vinfo, i) != GST_VIDEO_INFO_PLANE_OFFSET (&priv->vmeta_vinfo, i) || GST_VIDEO_INFO_PLANE_STRIDE (&new_allocation_vinfo, i) != GST_VIDEO_INFO_PLANE_STRIDE (&priv->vmeta_vinfo, i)) { priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_VIDEO_META; gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); updated = TRUE; break; } } } if (gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT)) { fill_video_alignment (GST_VAAPI_VIDEO_BUFFER_POOL (pool), &align); gst_buffer_pool_config_set_video_alignment (config, &align); } if (!priv->use_dmabuf_memory && gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META)) priv->options |= GST_VAAPI_VIDEO_BUFFER_POOL_OPTION_GL_TEXTURE_UPLOAD; ret = GST_BUFFER_POOL_CLASS (gst_vaapi_video_buffer_pool_parent_class)->set_config (pool, config); return !updated && ret; /* ERRORS */ error_invalid_config: { GST_ERROR_OBJECT (pool, "invalid config"); return FALSE; } error_no_caps: { GST_ERROR_OBJECT (pool, "no caps in config"); return FALSE; } error_invalid_caps: { GST_ERROR_OBJECT (pool, "invalid caps %" GST_PTR_FORMAT, caps); return FALSE; } error_invalid_allocator: { GST_ERROR_OBJECT (pool, "no allocator in config"); return FALSE; } error_no_vaapi_video_meta_option: { GST_ERROR_OBJECT (pool, "no GstVaapiVideoMeta option in config"); return FALSE; } error_no_allocator: { GST_ERROR_OBJECT (pool, "no allocator defined"); return FALSE; } }
static gboolean gst_vaapi_video_buffer_pool_set_config (GstBufferPool * pool, GstStructure * config) { GstVaapiVideoBufferPoolPrivate *const priv = GST_VAAPI_VIDEO_BUFFER_POOL (pool)->priv; GstCaps *caps = NULL; GstVideoInfo *const cur_vip = &priv->video_info[priv->video_info_index]; GstVideoInfo *const new_vip = &priv->video_info[!priv->video_info_index]; GstVideoAlignment align; GstAllocator *allocator; gboolean changed_caps, use_dmabuf_memory, ret, updated = FALSE; if (!gst_buffer_pool_config_get_params (config, &caps, NULL, NULL, NULL)) goto error_invalid_config; if (!caps || !gst_video_info_from_caps (new_vip, caps)) goto error_no_caps; use_dmabuf_memory = gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_DMABUF_MEMORY); if (priv->use_dmabuf_memory != use_dmabuf_memory) { priv->use_dmabuf_memory = use_dmabuf_memory; g_clear_object (&priv->allocator); } changed_caps = !priv->allocator || GST_VIDEO_INFO_FORMAT (cur_vip) != GST_VIDEO_INFO_FORMAT (new_vip) || GST_VIDEO_INFO_WIDTH (cur_vip) != GST_VIDEO_INFO_WIDTH (new_vip) || GST_VIDEO_INFO_HEIGHT (cur_vip) != GST_VIDEO_INFO_HEIGHT (new_vip); if (changed_caps) { const GstVideoInfo *alloc_vip; guint flags = 0; if (use_dmabuf_memory) { /* XXX: also needs fixed strides/offsets */ flags |= GST_VAAPI_SURFACE_ALLOC_FLAG_LINEAR_STORAGE; allocator = gst_vaapi_dmabuf_allocator_new (priv->display, new_vip, flags); } else { allocator = gst_vaapi_video_allocator_new (priv->display, new_vip, 0); } if (!allocator) goto error_create_allocator; gst_object_replace ((GstObject **) & priv->allocator, GST_OBJECT_CAST (allocator)); gst_object_unref (allocator); priv->video_info_index ^= 1; alloc_vip = gst_allocator_get_vaapi_video_info (allocator, NULL); if (!alloc_vip) goto error_create_allocator_info; priv->alloc_info = *alloc_vip; } if (!gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VAAPI_VIDEO_META)) goto error_no_vaapi_video_meta_option; priv->has_video_meta = gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); if (!priv->has_video_meta) { gint i; for (i = 0; i < GST_VIDEO_INFO_N_PLANES (new_vip); i++) { if (GST_VIDEO_INFO_PLANE_OFFSET (new_vip, i) != GST_VIDEO_INFO_PLANE_OFFSET (&priv->alloc_info, i) || GST_VIDEO_INFO_PLANE_STRIDE (new_vip, i) != GST_VIDEO_INFO_PLANE_STRIDE (&priv->alloc_info, i)) { priv->has_video_meta = TRUE; gst_buffer_pool_config_add_option (config, GST_BUFFER_POOL_OPTION_VIDEO_META); updated = TRUE; break; } } } priv->has_video_alignment = gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_ALIGNMENT); if (priv->has_video_alignment) { fill_video_alignment (GST_VAAPI_VIDEO_BUFFER_POOL (pool), &align); gst_buffer_pool_config_set_video_alignment (config, &align); } priv->has_texture_upload_meta = gst_buffer_pool_config_has_option (config, GST_BUFFER_POOL_OPTION_VIDEO_GL_TEXTURE_UPLOAD_META); ret = GST_BUFFER_POOL_CLASS (gst_vaapi_video_buffer_pool_parent_class)->set_config (pool, config); return !updated && ret; /* ERRORS */ error_invalid_config: { GST_ERROR ("invalid config"); return FALSE; } error_no_caps: { GST_ERROR ("no valid caps in config"); return FALSE; } error_create_allocator: { GST_ERROR ("failed to create GstVaapiVideoAllocator object"); return FALSE; } error_create_allocator_info: { GST_ERROR ("failed to create GstVaapiVideoAllocator `video-info'"); return FALSE; } error_no_vaapi_video_meta_option: { GST_ERROR ("no GstVaapiVideoMeta option"); return FALSE; } }