Extraction of YUV planes using mmap API - Single buffer vs separate buffers

Hi Guys,

I wish to extract the YUV planes and use the values to perform some operations. When I try to obtain the YUV using nvbuffer and mmap API to map the buffer to a single character buffer, somehow the planes extracted show some corrupted data. However, when I try to extract the planes into three separate buffers using offset given by NVBufferParam there is no corruption.

The code for single buffer implementation is as follows :

char *m_datamem ;
 while (true)
    {

        // Acquire a Frame.
        UniqueObj<Frame> frame(iFrameConsumer->acquireFrame());

	cout<<"frame instantiated"<<endl;

        IFrame *iFrame = interface_cast<IFrame>(frame);

	cout<<"iFrame instantiated : "<<iFrame<< endl;

        if (!iFrame)
            break;

        // Get the Frame's Image.
        Image *image = iFrame->getImage();

        EGLStream::NV::IImageNativeBuffer *iImageNativeBuffer
              = interface_cast<EGLStream::NV::IImageNativeBuffer>(image);

        TEST_ERROR_RETURN(!iImageNativeBuffer, "Failed to create an IImageNativeBuffer");

	fd = iImageNativeBuffer->createNvBuffer(Argus::Size {m_framesize.width, m_framesize.height},
		       NvBufferColorFormat_YUV420, NvBufferLayout_Pitch, &status);

	if (status != STATUS_OK)
		       TEST_ERROR_RETURN(status != STATUS_OK, "Failed to create a native buffer");

        NvBufferParams params;
        NvBufferGetParams(fd, &params);
  
        int fsize = params.pitch[0] * m_framesize.height ;
    
        m_datamem = (char *)mmap(NULL, 1.5*fsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, params.offset[0]);

        Mat data = cv::Mat(params.height[0] ,params.width[0], 8UC1, (void *) m_datamem ,  params.pitch[0]);
        imshow("data" , data);
  
        Mat dataU = cv::Mat(params.height[1] ,params.width[1], 8UC1, (void *) m_datamem + params.offset[1],  params.pitch[1]);
        imshow("dataU" , dataU);
    
        Mat dataV = cv::Mat(params.height[2] ,params.width[2], 8UC1, (void *) m_datamem + params.offset[2],  params.pitch[2]);
        imshow("dataV" , dataV);
  
         NvBufferDestroy(fd);

}

The code for separate buffers is as follows :

char *m_datamem ;
char *m_datamemU;
char *m_datamemV;

 while (true)
    {

        // Acquire a Frame.
        UniqueObj<Frame> frame(iFrameConsumer->acquireFrame());

	cout<<"frame instantiated"<<endl;

        IFrame *iFrame = interface_cast<IFrame>(frame);

	cout<<"iFrame instantiated : "<<iFrame<< endl;

        if (!iFrame)
            break;

        // Get the Frame's Image.
        Image *image = iFrame->getImage();

        EGLStream::NV::IImageNativeBuffer *iImageNativeBuffer
              = interface_cast<EGLStream::NV::IImageNativeBuffer>(image);

        TEST_ERROR_RETURN(!iImageNativeBuffer, "Failed to create an IImageNativeBuffer");

	fd = iImageNativeBuffer->createNvBuffer(Argus::Size {m_framesize.width, m_framesize.height},
		       NvBufferColorFormat_YUV420, NvBufferLayout_Pitch, &status);

	if (status != STATUS_OK)
		       TEST_ERROR_RETURN(status != STATUS_OK, "Failed to create a native buffer");

        NvBufferParams params;
        NvBufferGetParams(fd, &params);
  
        int fsize = params.pitch[0] * params.height[0] ;
        int fsizeU = params.pitch[1]*params.height[1];
        int fsizeV = params.pitch[2]*params.height[2];

        m_datamem = (char *)mmap(NULL, fsize, PROT_READ | PROT_WRITE, MAP_SHARED, fd, params.offset[0]);
        m_datamemU = (char *)mmap(NULL, fsizeU, PROT_READ | PROT_WRITE, MAP_SHARED, fd, params.offset[1]);
        m_datamemV = (char *)mmap(NULL, fsizeV, PROT_READ | PROT_WRITE, MAP_SHARED, fd, params.offset[2]);


   Mat data = cv::Mat(params.height[0] ,params.width[0], 8UC1, (void *) m_datamem ,  params.pitch[0]);
        imshow("data" , data);
  
        Mat dataU = cv::Mat(params.height[1] ,params.width[1], 8UC1, (void *)m_datamemU,  params.pitch[1]);
        imshow("dataU" , dataU);
    
        Mat dataV = cv::Mat(params.height[2] ,params.width[2], 8UC1, (void *) m_datamemV,  params.pitch[2]);
        imshow("dataV" , dataV);
         NvBufferDestroy(fd);

}

When I try to imshow the buffers, the buffers are corrupted using single buffer code (offset added to base pointer). When I try to use separate buffers, there is no corruption. Kindly let me know what is wrong with single buffer access.

Thanks.

Can you try to map/umap NvBuffers via new APIS on r28.1?
NvBufferMemMap
NvBufferMemUnMap

Hi lamegeorge

Have you tried to map/umap NvBuffers via new APIS on r28.1?
Any result can be shared?

Thanks

Hi kayccc,

Is there any sample which I can follow to implement these APIs ? I have just upgraded API set version.

Thanks.

hi lamegeorge,
These are defined in ~/tegra_multimedia_api/include/nvbuf_utils.h

And detail is in https://developer.nvidia.com/embedded/dlc/l4t-documentation-28-1