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