Get a VPIIMage from NvBufferSurface

Hello, I have a working code C++ on Jetson AGX Xavier. I get image in NvBufferSurface and create an OpenCV image of type cv::cuda::GpuMat from it to make a preprocessing and pass image to an AI model. Now I would like to try to make a preprocessing with VPI instead of OpenCV. But it doesn’t work.

The working code with OpenCV looks as follows:
GstBuffer* buffer = gst_sample_get_buffer(sample); // get frame from a stream
auto gst_buffer_map_result = gst_buffer_map(buffer, &map, GST_MAP_READ);
NvBufSurface *surface{};
surface = reinterpret_cast<NvBufSurface *>(map.data);

// make a EglImage
NvBufSurfaceMapEglImage(surface, -1);
cuGraphicsEGLRegisterImage(&pCudaResource, surface->surfaceList[0].mappedAddr.eglImage, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);
cuGraphicsResourceGetMappedEglFrame(&eglFrame, pCudaResource, 0, 0);

// make OpenvCV image on GPU
img_gpu_aux = cv::cuda::GpuMat(cv::Size(1920, 1080), CV_8UC4, (void *)(eglFrame.frame.pArray[0]));
cv::cuda::cvtColor(img_gpu_aux, img_gpu, cv::COLOR_BGRA2BGR, 3); // remove one channel
doPreprocessing with img_gpu here…

Now I want to do the same but using VPIImage:
GstBuffer* buffer = gst_sample_get_buffer(sample);
auto gst_buffer_map_result = gst_buffer_map(buffer, &map, GST_MAP_READ);
NvBufSurface *surface{};
surface = reinterpret_cast<NvBufSurface *>(map.data);

// try to build VPIImage from NvBufSurface
VPIIMage img_vpi;
VPIStatus err_vpi = vpiImageCreateWrapper((VPIImageData *)surface, nullptr, VPI_BACKEND_CUDA, &img_vpi);
std::cout << "err = " << vpiStatusGetName(err_vpi) << std::endl;

but I have an error “VPI_ERROR_INVALID_ARGUMENT”. It looks like that pointer conversion from surface to VPIImageData is a bad idea, because VPIImageData has a different structure. But how should I pass the pointer to memory to be wrapped?

With the best wishes,
Valeriy

Hi,

It looks like you are using JetPack 5 + VPI 2, is this correct?

If yes, VPI can wrap EGLImage directly:

https://docs.nvidia.com/vpi/group__VPI__Image.html#ga895b41338ff328601a68383c7ae939d0

Thanks.

Thank you for your fast answer!

yes, JetPack 5 and vpi 2.

I tried to do this also like:
VPIStatus err_vpi = vpiImageCreateWrapper((VPIImageData *)eglFrame.frame.pArray[0], nullptr, VPI_BACKEND_CUDA, &img_vpi);
but it didn’t work (memory access error)

Ok, with the EGL images the following looks to work:

NvBufSurfaceMapEglImage(surface, -1);
cuGraphicsEGLRegisterImage(&pCudaResource, surface->surfaceList[0].mappedAddr.eglImage, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE);
cuGraphicsResourceGetMappedEglFrame(&eglFrame, pCudaResource, 0, 0);

VPIImageData img_data;
img_data.bufferType = VPI_IMAGE_BUFFER_EGLIMAGE;
img_data.buffer.egl = surface->surfaceList[0].mappedAddr.eglImage;
VPIStatus err_vpi = vpiImageCreateWrapper(&img_data, nullptr, VPI_BACKEND_CUDA, &img_vpi);

And my question is: is it necessary to create the EGL image? Cannot I work with the NvBufSurface directly? According to VPI - Vision Programming Interface: Image there is “VPI_IMAGE_BUFFER_NVBUFFER” buffer type.

The problem looks to be solved. For someone who needs it:
NvBufSurfaceMapParams buffer_params;
NvBufSurfaceGetMapParams(surface, 0, &buffer_params);

VPIImageData img_data;
img_data.bufferType = VPI_IMAGE_BUFFER_NVBUFFER;
img_data.buffer.fd = buffer_params.fd;

VPIStatus err_vpi = vpiImageCreateWrapper(&img_data, nullptr, VPI_BACKEND_CUDA, &img_vpi);

Hi,

Sorry for the late update.

Yes, NvBufferSurface is also supported.
Thanks for the feedback.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.