Copy image data to custom array from IFrame of EGLStream

Using argus from jetson MMAPI, I have this piece of code working:

            UniqueObj<Frame> frame(iFrameConsumers[i]->acquireFrame());
            IFrame *iFrame = interface_cast<IFrame>(frame);
            if (!iFrame)
                break;

            NV::IImageNativeBuffer *iNativeBuffer =
            interface_cast<NV::IImageNativeBuffer>(iFrame->getImage());
            if (!iNativeBuffer)
                ORIGINATE_ERROR("IImageNativeBuffer not supported by Image.");

	        if (!m_dmabufs[i])
            {
                std::cout<< "Dmabufs\n";
                batch_surf[i] = NULL;
                m_dmabufs[i] = iNativeBuffer->createNvBuffer(
                    iEglOutputStreams[i]->getResolution(),
                    NvBufFMT_,
                	NVBUF_LAYOUT_PITCH
                );

		        if (!m_dmabufs[i])
                    std::cout<< "Failed to create NvBuffer\n";
                    // CONSUMER_PRINT("\tFailed to create NvBuffer\n");

                if (-1 == NvBufSurfaceFromFd(m_dmabufs[i], (void**)(&batch_surf[i])))
                    ORIGINATE_ERROR("Cannot get NvBufSurface from fd");
            }
	        else if (iNativeBuffer->copyToNvBuffer(m_dmabufs[i]) != STATUS_OK)
            {
                ORIGINATE_ERROR("Failed to copy frame to NvBuffer.");
            }
        
            frN++;
            std::cout<< "Frame: "<< frN <<"\n";

	        NvBufSurface *nvbuf_surf = 0;
  	        int ret = NvBufSurfaceFromFd(m_dmabufs[0], (void**)(&nvbuf_surf));
	        if (ret)
	        {
		        printf( "NvBufSurfaceFromFd failed");
		        return -1;
            }

I am able to copy the data from nvbuf_surf using
NvBufSurfaceParams *params = &nvbuf_surf->surfaceList[0]
to my cuda or cpu array with no problem.

However the data on nvbuf_surf seems to be on CPU memory (or accessible only by cpu!). I need to receive the image data from the camera on the cuda memory, how can I do it?

Besides, I would ideally need to transfer the image data to my custom cuda memory allocated array from the iFrame. Is it possible? (From IFrame *iFrame = interface_cast<IFrame>(frame) I mean).

The below code is what I am trying to achieve, but this code throws some error (Invalid argument) in cudaMemcpy2D, so I don’t know what way is the correct way to copy the data direclty from iFrame?

unsigned char* devicePtr;
void* nativePtr = iFrame->getImage();
cudaMalloc((void**)&devicePtr, 4 * CAM_H * CAM_W * sizeof(unsigned char));             
cudaError_t cpy2d_error = cudaMemcpy2D(devicePtr,
/*       */ 4 * CAM_W * sizeof(unsigned char),
/*       */ nativePtr,
/*       */ 4 * CAM_W * sizeof(unsigned char),
/*       */ 4 * CAM_W * sizeof(unsigned char),
/*       */ CAM_H,
/*       */ cudaMemcpyDeviceToDevice
);
std::cout << "cpy2D_error: " << cudaGetErrorString(devicePtrcpy2d_error) << std::endl;

Thank you so much.

You may wish to ask Jetson related questions on the Jetson forum corresponding to your Jetson device.

May I know which JetPack SW and Jetson platform you’re using?

Of course:

NVIDIA Jetson Xavier NX Developer Kit
nvidia-jetpack: 5.1-b147
nvidia-l4t-core: 35.2.1-20230124153320

Hi,
For getting GPU pointer of an NvBufSurface, please refer to the two posts:
Error generated while running the code after connecting the camera - #15 by DaveYYY
How to create opencv gpumat from nvstream? - #18 by DaneLLL

Based on a similar approach (From here: CLOSED. cudaArray from NV::IImageNativeBuffer without copy? - Jetson & Embedded Systems / Jetson TX1 - NVIDIA Developer Forums)

I made the below code. It gets built and run without any error but the final cuda array is empty:

int fdLeft = iNativeBuffer->createNvBuffer( iEglOutputStreams[i]->getResolution(),
        NvBufFMT_, NVBUF_LAYOUT_PITCH );
// iNativeBuffer->copyToNvBuffer(fdLeft);
EGLImageKHR egl_imageLeft{ NvEGLImageFromFd( eglDisplay, fdLeft ) };
CUgraphicsResource pResourceLeft;
cuGraphicsEGLRegisterImage( &pResourceLeft, egl_imageLeft, CU_GRAPHICS_MAP_RESOURCE_FLAGS_NONE );
CUeglFrame eglFrameLeft;
cuGraphicsResourceGetMappedEglFrame( &eglFrameLeft, pResourceLeft, 0, 0 );
unsigned char * newrgba;
size_t tmpitch;
std::cout << "eglFrameLeft.height: " << eglFrameLeft.height<< "  width: "<< eglFrameLeft.width<<"\n";
std::cout << "frameType: " << eglFrameLeft.frameType<< "  pitch: "<< eglFrameLeft.pitch<<"\n";
std::cout << "planeCount: " << eglFrameLeft.planeCount<< "  eglColorFormat : "<< eglFrameLeft.eglColorFormat <<"\n";
cudaError_t mallocerror = cudaMalloc((void**)&newrgba, int(4.0 * eglFrameLeft.height * eglFrameLeft.width * sizeof(unsigned char)) );
cudaError_t gpu_e = cudaMemcpy2DFromArray( 
    newrgba,
    4 * eglFrameLeft.width,
    // tmpitch,
    (cudaArray*)eglFrameLeft.frame.pArray[0], 
    0,
    0,
    4 * eglFrameLeft.width,
    eglFrameLeft.height,
    cudaMemcpyDeviceToDevice
);

I have tried different values of pitch, and also simple cudaMemcpy and cudaMemcpy2D, but it seems the eglFrameLeft.frame.pArray[0] is totally empty.

Hi,
NvBuffer APIs are deprecated on Jetpack 5. Please use NvBufSurface APIs as demonstrated in the samples.

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